initial Caanoo port
[gpsp.git] / video.c
1 /* gameplaySP
2  *
3  * Copyright (C) 2006 Exophase <exophase@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of
8  * the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19
20 #include "common.h"
21 #define WANT_FONT_BITS
22 #include "font.h"
23
24 #ifdef PSP_BUILD
25
26 #include <pspctrl.h>
27
28 #include <pspkernel.h>
29 #include <pspdebug.h>
30 #include <pspdisplay.h>
31
32 #include <pspgu.h>
33 #include <psppower.h>
34 #include <psprtc.h>
35
36 static float *screen_vertex = (float *)0x441FC100;
37 static u32 *ge_cmd = (u32 *)0x441FC000;
38 static u16 *psp_gu_vram_base = (u16 *)(0x44000000);
39 static u32 *ge_cmd_ptr = (u32 *)0x441FC000;
40 static u32 gecbid;
41 static u32 video_direct = 0;
42
43 static u32 __attribute__((aligned(16))) display_list[32];
44
45 #define GBA_SCREEN_WIDTH 240
46 #define GBA_SCREEN_HEIGHT 160
47
48 #define PSP_SCREEN_WIDTH 480
49 #define PSP_SCREEN_HEIGHT 272
50 #define PSP_LINE_SIZE 512
51
52 #define PSP_ALL_BUTTON_MASK 0xFFFF
53
54 #define GE_CMD_FBP    0x9C
55 #define GE_CMD_FBW    0x9D
56 #define GE_CMD_TBP0   0xA0
57 #define GE_CMD_TBW0   0xA8
58 #define GE_CMD_TSIZE0 0xB8
59 #define GE_CMD_TFLUSH 0xCB
60 #define GE_CMD_CLEAR  0xD3
61 #define GE_CMD_VTYPE  0x12
62 #define GE_CMD_BASE   0x10
63 #define GE_CMD_VADDR  0x01
64 #define GE_CMD_IADDR  0x02
65 #define GE_CMD_PRIM   0x04
66 #define GE_CMD_FINISH 0x0F
67 #define GE_CMD_SIGNAL 0x0C
68 #define GE_CMD_NOP    0x00
69
70 #define GE_CMD(cmd, operand)                                                \
71   *ge_cmd_ptr = (((GE_CMD_##cmd) << 24) | (operand));                       \
72   ge_cmd_ptr++                                                              \
73
74 static u16 *screen_texture = (u16 *)(0x4000000 + (512 * 272 * 2));
75 static u16 *current_screen_texture = (u16 *)(0x4000000 + (512 * 272 * 2));
76 static u16 *screen_pixels = (u16 *)(0x4000000 + (512 * 272 * 2));
77 static u32 screen_pitch = 240;
78
79 static void Ge_Finish_Callback(int id, void *arg)
80 {
81 }
82
83 #define get_screen_pixels()                                                   \
84   screen_pixels                                                               \
85
86 #define get_screen_pitch()                                                    \
87   screen_pitch                                                                \
88
89 #elif defined(POLLUX_BUILD)
90
91 static u16 rot_buffer[240*4];
92 static u32 rot_lines_total = 4;
93 static u32 rot_line_count = 0;
94 #ifdef WIZ_BUILD
95 static char rot_msg_buff[64];
96 #endif
97
98 static u32 screen_offset = 0;
99 static u16 *screen_pixels = NULL;
100 const u32 screen_pitch = 320;
101
102 #define get_screen_pixels()                                                   \
103   screen_pixels                                                               \
104
105 #define get_screen_pitch()                                                    \
106   screen_pitch                                                                \
107
108 #elif defined(PND_BUILD)
109
110 static u16 *screen_pixels = NULL;
111
112 #define get_screen_pixels()                                                   \
113   screen_pixels                                                               \
114
115 #define get_screen_pitch()                                                    \
116   resolution_width                                                            \
117
118 #else
119
120 #ifdef GP2X_BUILD
121 #include "SDL_gp2x.h"
122 SDL_Surface *hw_screen;
123 #endif
124 SDL_Surface *screen;
125 const u32 video_scale = 1;
126
127 #define get_screen_pixels()                                                   \
128   ((u16 *)screen->pixels)                                                     \
129
130 #define get_screen_pitch()                                                    \
131   (screen->pitch / 2)                                                         \
132
133 #endif
134
135 static void render_scanline_conditional_tile(u32 start, u32 end, u16 *scanline,
136  u32 enable_flags, u32 dispcnt, u32 bldcnt, const tile_layer_render_struct
137  *layer_renderers);
138 static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline,
139  u32 enable_flags, u32 dispcnt, u32 bldcnt, const bitmap_layer_render_struct
140  *layer_renderers);
141
142 #define no_op                                                                 \
143
144 // This old version is not necessary if the palette is either being converted
145 // transparently or the ABGR 1555 format is being used natively. The direct
146 // version (without conversion) is much faster.
147
148 #define tile_lookup_palette_full(palette, source)                             \
149   current_pixel = palette[source];                                            \
150   convert_palette(current_pixel)                                              \
151
152 #define tile_lookup_palette(palette, source)                                  \
153   current_pixel = palette[source];                                            \
154
155
156 #ifdef RENDER_COLOR16_NORMAL
157
158 #define tile_expand_base_normal(index)                                        \
159   tile_expand_base_color16(index)                                             \
160
161 #else
162
163 #define tile_expand_base_normal(index)                                        \
164   tile_lookup_palette(palette, current_pixel);                                \
165   dest_ptr[index] = current_pixel                                             \
166
167 #endif
168
169 #define tile_expand_transparent_normal(index)                                 \
170   tile_expand_base_normal(index)                                              \
171
172 #define tile_expand_copy(index)                                               \
173   dest_ptr[index] = copy_ptr[index]                                           \
174
175
176 #define advance_dest_ptr_base(delta)                                          \
177   dest_ptr += delta                                                           \
178
179 #define advance_dest_ptr_transparent(delta)                                   \
180   advance_dest_ptr_base(delta)                                                \
181
182 #define advance_dest_ptr_copy(delta)                                          \
183   advance_dest_ptr_base(delta);                                               \
184   copy_ptr += delta                                                           \
185
186
187 #define color_combine_mask_a(layer)                                           \
188   ((io_registers[REG_BLDCNT] >> layer) & 0x01)                                \
189
190 // For color blending operations, will create a mask that has in bit
191 // 10 if the layer is target B, and bit 9 if the layer is target A.
192
193 #define color_combine_mask(layer)                                             \
194   (color_combine_mask_a(layer) |                                              \
195    ((io_registers[REG_BLDCNT] >> (layer + 7)) & 0x02)) << 9                   \
196
197 // For alpha blending renderers, draw the palette index (9bpp) and
198 // layer bits rather than the raw RGB. For the base this should write to
199 // the 32bit location directly.
200
201 #define tile_expand_base_alpha(index)                                         \
202   dest_ptr[index] = current_pixel | pixel_combine                             \
203
204 #define tile_expand_base_bg(index)                                            \
205   dest_ptr[index] = bg_combine                                                \
206
207
208 // For layered (transparent) writes this should shift the "stack" and write
209 // to the bottom. This will preserve the topmost pixel and the most recent
210 // one.
211
212 #define tile_expand_transparent_alpha(index)                                  \
213   dest_ptr[index] = (dest_ptr[index] << 16) | current_pixel | pixel_combine   \
214
215
216 // OBJ should only shift if the top isn't already OBJ
217 #define tile_expand_transparent_alpha_obj(index)                              \
218   dest = dest_ptr[index];                                                     \
219   if(dest & 0x00000100)                                                       \
220   {                                                                           \
221     dest_ptr[index] = (dest & 0xFFFF0000) | current_pixel | pixel_combine;    \
222   }                                                                           \
223   else                                                                        \
224   {                                                                           \
225     dest_ptr[index] = (dest << 16) | current_pixel | pixel_combine;           \
226   }                                                                           \
227
228
229 // For color effects that don't need to preserve the previous layer.
230 // The color32 version should be used with 32bit wide dest_ptr so as to be
231 // compatible with alpha combine on top of it.
232
233 #define tile_expand_base_color16(index)                                       \
234   dest_ptr[index] = current_pixel | pixel_combine                             \
235
236 #define tile_expand_transparent_color16(index)                                \
237   tile_expand_base_color16(index)                                             \
238
239 #define tile_expand_base_color32(index)                                       \
240   tile_expand_base_color16(index)                                             \
241
242 #define tile_expand_transparent_color32(index)                                \
243   tile_expand_base_color16(index)                                             \
244
245
246 // Operations for isolation 8bpp pixels within 32bpp pixel blocks.
247
248 #define tile_8bpp_pixel_op_mask(op_param)                                     \
249   current_pixel = current_pixels & 0xFF                                       \
250
251 #define tile_8bpp_pixel_op_shift_mask(shift)                                  \
252   current_pixel = (current_pixels >> shift) & 0xFF                            \
253
254 #define tile_8bpp_pixel_op_shift(shift)                                       \
255   current_pixel = current_pixels >> shift                                     \
256
257 #define tile_8bpp_pixel_op_none(shift)                                        \
258
259 // Base should always draw raw in 8bpp mode; color 0 will be drawn where
260 // color 0 is.
261
262 #define tile_8bpp_draw_base_normal(index)                                     \
263   tile_expand_base_normal(index)                                              \
264
265 #define tile_8bpp_draw_base_alpha(index)                                      \
266   if(current_pixel)                                                           \
267   {                                                                           \
268     tile_expand_base_alpha(index);                                            \
269   }                                                                           \
270   else                                                                        \
271   {                                                                           \
272     tile_expand_base_bg(index);                                               \
273   }                                                                           \
274
275
276 #define tile_8bpp_draw_base_color16(index)                                    \
277   tile_8bpp_draw_base_alpha(index)                                            \
278
279 #define tile_8bpp_draw_base_color32(index)                                    \
280   tile_8bpp_draw_base_alpha(index)                                            \
281
282
283 #define tile_8bpp_draw_base(index, op, op_param, alpha_op)                    \
284   tile_8bpp_pixel_op_##op(op_param);                                          \
285   tile_8bpp_draw_base_##alpha_op(index)                                       \
286
287 // Transparent (layered) writes should only replace what is there if the
288 // pixel is not transparent (zero)
289
290 #define tile_8bpp_draw_transparent(index, op, op_param, alpha_op)             \
291   tile_8bpp_pixel_op_##op(op_param);                                          \
292   if(current_pixel)                                                           \
293   {                                                                           \
294     tile_expand_transparent_##alpha_op(index);                                \
295   }                                                                           \
296
297 #define tile_8bpp_draw_copy(index, op, op_param, alpha_op)                    \
298   tile_8bpp_pixel_op_##op(op_param);                                          \
299   if(current_pixel)                                                           \
300   {                                                                           \
301     tile_expand_copy(index);                                                  \
302   }                                                                           \
303
304 // Get the current tile from the map in 8bpp mode
305
306 #define get_tile_8bpp()                                                       \
307   current_tile = *map_ptr;                                                    \
308   tile_ptr = tile_base + ((current_tile & 0x3FF) * 64)                        \
309
310
311 // Draw half of a tile in 8bpp mode, for base renderer
312
313 #define tile_8bpp_draw_four_noflip(index, combine_op, alpha_op)               \
314   tile_8bpp_draw_##combine_op(index + 0, mask, 0, alpha_op);                  \
315   tile_8bpp_draw_##combine_op(index + 1, shift_mask, 8, alpha_op);            \
316   tile_8bpp_draw_##combine_op(index + 2, shift_mask, 16, alpha_op);           \
317   tile_8bpp_draw_##combine_op(index + 3, shift, 24, alpha_op)                 \
318
319
320 // Like the above, but draws the half-tile horizontally flipped
321
322 #define tile_8bpp_draw_four_flip(index, combine_op, alpha_op)                 \
323   tile_8bpp_draw_##combine_op(index + 3, mask, 0, alpha_op);                  \
324   tile_8bpp_draw_##combine_op(index + 2, shift_mask, 8, alpha_op);            \
325   tile_8bpp_draw_##combine_op(index + 1, shift_mask, 16, alpha_op);           \
326   tile_8bpp_draw_##combine_op(index + 0, shift, 24, alpha_op)                 \
327
328 #define tile_8bpp_draw_four_base(index, alpha_op, flip_op)                    \
329   tile_8bpp_draw_four_##flip_op(index, base, alpha_op)                        \
330
331
332 // Draw half of a tile in 8bpp mode, for transparent renderer; as an
333 // optimization the entire thing is checked against zero (in transparent
334 // capable renders it is more likely for the pixels to be transparent than
335 // opaque)
336
337 #define tile_8bpp_draw_four_transparent(index, alpha_op, flip_op)             \
338   if(current_pixels != 0)                                                     \
339   {                                                                           \
340     tile_8bpp_draw_four_##flip_op(index, transparent, alpha_op);              \
341   }                                                                           \
342
343 #define tile_8bpp_draw_four_copy(index, alpha_op, flip_op)                    \
344   if(current_pixels != 0)                                                     \
345   {                                                                           \
346     tile_8bpp_draw_four_##flip_op(index, copy, alpha_op);                     \
347   }                                                                           \
348
349 // Helper macro for drawing 8bpp tiles clipped against the edge of the screen
350
351 #define partial_tile_8bpp(combine_op, alpha_op)                               \
352   for(i = 0; i < partial_tile_run; i++)                                       \
353   {                                                                           \
354     tile_8bpp_draw_##combine_op(0, mask, 0, alpha_op);                        \
355     current_pixels >>= 8;                                                     \
356     advance_dest_ptr_##combine_op(1);                                         \
357   }                                                                           \
358
359
360 // Draws 8bpp tiles clipped against the left side of the screen,
361 // partial_tile_offset indicates how much clipped in it is, partial_tile_run
362 // indicates how much it should draw.
363
364 #define partial_tile_right_noflip_8bpp(combine_op, alpha_op)                  \
365   if(partial_tile_offset >= 4)                                                \
366   {                                                                           \
367     current_pixels = *((u32 *)(tile_ptr + 4)) >>                              \
368      ((partial_tile_offset - 4) * 8);                                         \
369     partial_tile_8bpp(combine_op, alpha_op);                                  \
370   }                                                                           \
371   else                                                                        \
372   {                                                                           \
373     partial_tile_run -= 4;                                                    \
374     current_pixels = *((u32 *)tile_ptr) >> (partial_tile_offset * 8);         \
375     partial_tile_8bpp(combine_op, alpha_op);                                  \
376     current_pixels = *((u32 *)(tile_ptr + 4));                                \
377     tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip);                    \
378     advance_dest_ptr_##combine_op(4);                                         \
379   }                                                                           \
380
381
382 // Draws 8bpp tiles clipped against both the left and right side of the
383 // screen, IE, runs of less than 8 - partial_tile_offset.
384
385 #define partial_tile_mid_noflip_8bpp(combine_op, alpha_op)                    \
386   if(partial_tile_offset >= 4)                                                \
387   {                                                                           \
388     current_pixels = *((u32 *)(tile_ptr + 4)) >>                              \
389      ((partial_tile_offset - 4) * 8);                                         \
390     partial_tile_8bpp(combine_op, alpha_op);                                  \
391   }                                                                           \
392   else                                                                        \
393   {                                                                           \
394     current_pixels = *((u32 *)tile_ptr) >> (partial_tile_offset * 8);         \
395     if((partial_tile_offset + partial_tile_run) > 4)                          \
396     {                                                                         \
397       u32 old_run = partial_tile_run;                                         \
398       partial_tile_run = 4 - partial_tile_offset;                             \
399       partial_tile_8bpp(combine_op, alpha_op);                                \
400       partial_tile_run = old_run - partial_tile_run;                          \
401       current_pixels = *((u32 *)(tile_ptr + 4));                              \
402       partial_tile_8bpp(combine_op, alpha_op);                                \
403     }                                                                         \
404     else                                                                      \
405     {                                                                         \
406       partial_tile_8bpp(combine_op, alpha_op);                                \
407     }                                                                         \
408   }                                                                           \
409
410
411 // Draws 8bpp tiles clipped against the right side of the screen,
412 // partial_tile_run indicates how much there is to draw.
413
414 #define partial_tile_left_noflip_8bpp(combine_op, alpha_op)                   \
415   if(partial_tile_run >= 4)                                                   \
416   {                                                                           \
417     current_pixels = *((u32 *)tile_ptr);                                      \
418     tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip);                    \
419     advance_dest_ptr_##combine_op(4);                                         \
420     tile_ptr += 4;                                                            \
421     partial_tile_run -= 4;                                                    \
422   }                                                                           \
423                                                                               \
424   current_pixels = *((u32 *)(tile_ptr));                                      \
425   partial_tile_8bpp(combine_op, alpha_op)                                     \
426
427
428 // Draws a non-clipped (complete) 8bpp tile.
429
430 #define tile_noflip_8bpp(combine_op, alpha_op)                                \
431   current_pixels = *((u32 *)tile_ptr);                                        \
432   tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip);                      \
433   current_pixels = *((u32 *)(tile_ptr + 4));                                  \
434   tile_8bpp_draw_four_##combine_op(4, alpha_op, noflip)                       \
435
436
437 // Like the above versions but draws flipped tiles.
438
439 #define partial_tile_flip_8bpp(combine_op, alpha_op)                          \
440   for(i = 0; i < partial_tile_run; i++)                                       \
441   {                                                                           \
442     tile_8bpp_draw_##combine_op(0, shift, 24, alpha_op);                      \
443     current_pixels <<= 8;                                                     \
444     advance_dest_ptr_##combine_op(1);                                         \
445   }                                                                           \
446
447 #define partial_tile_right_flip_8bpp(combine_op, alpha_op)                    \
448   if(partial_tile_offset >= 4)                                                \
449   {                                                                           \
450     current_pixels = *((u32 *)tile_ptr) << ((partial_tile_offset - 4) * 8);   \
451     partial_tile_flip_8bpp(combine_op, alpha_op);                             \
452   }                                                                           \
453   else                                                                        \
454   {                                                                           \
455     partial_tile_run -= 4;                                                    \
456     current_pixels = *((u32 *)(tile_ptr + 4)) <<                              \
457      ((partial_tile_offset - 4) * 8);                                         \
458     partial_tile_flip_8bpp(combine_op, alpha_op);                             \
459     current_pixels = *((u32 *)tile_ptr);                                      \
460     tile_8bpp_draw_four_##combine_op(0, alpha_op, flip);                      \
461     advance_dest_ptr_##combine_op(4);                                         \
462   }                                                                           \
463
464 #define partial_tile_mid_flip_8bpp(combine_op, alpha_op)                      \
465   if(partial_tile_offset >= 4)                                                \
466   {                                                                           \
467     current_pixels = *((u32 *)tile_ptr) << ((partial_tile_offset - 4) * 8);   \
468     partial_tile_flip_8bpp(combine_op, alpha_op);                             \
469   }                                                                           \
470   else                                                                        \
471   {                                                                           \
472     current_pixels = *((u32 *)(tile_ptr + 4)) <<                              \
473      ((partial_tile_offset - 4) * 8);                                         \
474                                                                               \
475     if((partial_tile_offset + partial_tile_run) > 4)                          \
476     {                                                                         \
477       u32 old_run = partial_tile_run;                                         \
478       partial_tile_run = 4 - partial_tile_offset;                             \
479       partial_tile_flip_8bpp(combine_op, alpha_op);                           \
480       partial_tile_run = old_run - partial_tile_run;                          \
481       current_pixels = *((u32 *)(tile_ptr));                                  \
482       partial_tile_flip_8bpp(combine_op, alpha_op);                           \
483     }                                                                         \
484     else                                                                      \
485     {                                                                         \
486       partial_tile_flip_8bpp(combine_op, alpha_op);                           \
487     }                                                                         \
488   }                                                                           \
489
490 #define partial_tile_left_flip_8bpp(combine_op, alpha_op)                     \
491   if(partial_tile_run >= 4)                                                   \
492   {                                                                           \
493     current_pixels = *((u32 *)(tile_ptr + 4));                                \
494     tile_8bpp_draw_four_##combine_op(0, alpha_op, flip);                      \
495     advance_dest_ptr_##combine_op(4);                                         \
496     tile_ptr -= 4;                                                            \
497     partial_tile_run -= 4;                                                    \
498   }                                                                           \
499                                                                               \
500   current_pixels = *((u32 *)(tile_ptr + 4));                                  \
501   partial_tile_flip_8bpp(combine_op, alpha_op)                                \
502
503 #define tile_flip_8bpp(combine_op, alpha_op)                                  \
504   current_pixels = *((u32 *)(tile_ptr + 4));                                  \
505   tile_8bpp_draw_four_##combine_op(0, alpha_op, flip);                        \
506   current_pixels = *((u32 *)tile_ptr);                                        \
507   tile_8bpp_draw_four_##combine_op(4, alpha_op, flip)                         \
508
509
510 // Operations for isolating 4bpp tiles in a 32bit block
511
512 #define tile_4bpp_pixel_op_mask(op_param)                                     \
513   current_pixel = current_pixels & 0x0F                                       \
514
515 #define tile_4bpp_pixel_op_shift_mask(shift)                                  \
516   current_pixel = (current_pixels >> shift) & 0x0F                            \
517
518 #define tile_4bpp_pixel_op_shift(shift)                                       \
519   current_pixel = current_pixels >> shift                                     \
520
521 #define tile_4bpp_pixel_op_none(op_param)                                     \
522
523 // Draws a single 4bpp pixel as base, normal renderer; checks to see if the
524 // pixel is zero because if so the current palette should not be applied.
525 // These ifs can be replaced with a lookup table, may or may not be superior
526 // this way, should be benchmarked. The lookup table would be from 0-255
527 // identity map except for multiples of 16, which would map to 0.
528
529 #define tile_4bpp_draw_base_normal(index)                                     \
530   if(current_pixel)                                                           \
531   {                                                                           \
532     current_pixel |= current_palette;                                         \
533     tile_expand_base_normal(index);                                           \
534   }                                                                           \
535   else                                                                        \
536   {                                                                           \
537     tile_expand_base_normal(index);                                           \
538   }                                                                           \
539
540
541 #define tile_4bpp_draw_base_alpha(index)                                      \
542   if(current_pixel)                                                           \
543   {                                                                           \
544     current_pixel |= current_palette;                                         \
545     tile_expand_base_alpha(index);                                            \
546   }                                                                           \
547   else                                                                        \
548   {                                                                           \
549     tile_expand_base_bg(index);                                               \
550   }                                                                           \
551
552 #define tile_4bpp_draw_base_color16(index)                                    \
553   tile_4bpp_draw_base_alpha(index)                                            \
554
555 #define tile_4bpp_draw_base_color32(index)                                    \
556   tile_4bpp_draw_base_alpha(index)                                            \
557
558
559 #define tile_4bpp_draw_base(index, op, op_param, alpha_op)                    \
560   tile_4bpp_pixel_op_##op(op_param);                                          \
561   tile_4bpp_draw_base_##alpha_op(index)                                       \
562
563
564 // Draws a single 4bpp pixel as layered, if not transparent.
565
566 #define tile_4bpp_draw_transparent(index, op, op_param, alpha_op)             \
567   tile_4bpp_pixel_op_##op(op_param);                                          \
568   if(current_pixel)                                                           \
569   {                                                                           \
570     current_pixel |= current_palette;                                         \
571     tile_expand_transparent_##alpha_op(index);                                \
572   }                                                                           \
573
574 #define tile_4bpp_draw_copy(index, op, op_param, alpha_op)                    \
575   tile_4bpp_pixel_op_##op(op_param);                                          \
576   if(current_pixel)                                                           \
577   {                                                                           \
578     current_pixel |= current_palette;                                         \
579     tile_expand_copy(index);                                                  \
580   }                                                                           \
581
582
583 // Draws eight background pixels in transparent mode, for alpha or normal
584 // renderers.
585
586 #define tile_4bpp_draw_eight_base_zero(value)                                 \
587   dest_ptr[0] = value;                                                        \
588   dest_ptr[1] = value;                                                        \
589   dest_ptr[2] = value;                                                        \
590   dest_ptr[3] = value;                                                        \
591   dest_ptr[4] = value;                                                        \
592   dest_ptr[5] = value;                                                        \
593   dest_ptr[6] = value;                                                        \
594   dest_ptr[7] = value                                                         \
595
596
597 // Draws eight background pixels for the alpha renderer, basically color zero
598 // with the background flag high.
599
600 #define tile_4bpp_draw_eight_base_zero_alpha()                                \
601   tile_4bpp_draw_eight_base_zero(bg_combine)                                  \
602
603 #define tile_4bpp_draw_eight_base_zero_color16()                              \
604   tile_4bpp_draw_eight_base_zero_alpha()                                      \
605
606 #define tile_4bpp_draw_eight_base_zero_color32()                              \
607   tile_4bpp_draw_eight_base_zero_alpha()                                      \
608
609
610 // Draws eight background pixels for the normal renderer, just a bunch of
611 // zeros.
612
613 #ifdef RENDER_COLOR16_NORMAL
614
615 #define tile_4bpp_draw_eight_base_zero_normal()                               \
616   current_pixel = 0;                                                          \
617   tile_4bpp_draw_eight_base_zero(current_pixel)                               \
618
619 #else
620
621 #define tile_4bpp_draw_eight_base_zero_normal()                               \
622   current_pixel = palette[0];                                                 \
623   tile_4bpp_draw_eight_base_zero(current_pixel)                               \
624
625 #endif
626
627
628 // Draws eight 4bpp pixels.
629
630 #define tile_4bpp_draw_eight_noflip(combine_op, alpha_op)                     \
631   tile_4bpp_draw_##combine_op(0, mask, 0, alpha_op);                          \
632   tile_4bpp_draw_##combine_op(1, shift_mask, 4, alpha_op);                    \
633   tile_4bpp_draw_##combine_op(2, shift_mask, 8, alpha_op);                    \
634   tile_4bpp_draw_##combine_op(3, shift_mask, 12, alpha_op);                   \
635   tile_4bpp_draw_##combine_op(4, shift_mask, 16, alpha_op);                   \
636   tile_4bpp_draw_##combine_op(5, shift_mask, 20, alpha_op);                   \
637   tile_4bpp_draw_##combine_op(6, shift_mask, 24, alpha_op);                   \
638   tile_4bpp_draw_##combine_op(7, shift, 28, alpha_op)                         \
639
640
641 // Draws eight 4bpp pixels in reverse order (for hflip).
642
643 #define tile_4bpp_draw_eight_flip(combine_op, alpha_op)                       \
644   tile_4bpp_draw_##combine_op(7, mask, 0, alpha_op);                          \
645   tile_4bpp_draw_##combine_op(6, shift_mask, 4, alpha_op);                    \
646   tile_4bpp_draw_##combine_op(5, shift_mask, 8, alpha_op);                    \
647   tile_4bpp_draw_##combine_op(4, shift_mask, 12, alpha_op);                   \
648   tile_4bpp_draw_##combine_op(3, shift_mask, 16, alpha_op);                   \
649   tile_4bpp_draw_##combine_op(2, shift_mask, 20, alpha_op);                   \
650   tile_4bpp_draw_##combine_op(1, shift_mask, 24, alpha_op);                   \
651   tile_4bpp_draw_##combine_op(0, shift, 28, alpha_op)                         \
652
653
654 // Draws eight 4bpp pixels in base mode, checks if all are zero, if so draws
655 // the appropriate background pixels.
656
657 #define tile_4bpp_draw_eight_base(alpha_op, flip_op)                          \
658   if(current_pixels != 0)                                                     \
659   {                                                                           \
660     tile_4bpp_draw_eight_##flip_op(base, alpha_op);                           \
661   }                                                                           \
662   else                                                                        \
663   {                                                                           \
664     tile_4bpp_draw_eight_base_zero_##alpha_op();                              \
665   }                                                                           \
666
667
668 // Draws eight 4bpp pixels in transparent (layered) mode, checks if all are
669 // zero and if so draws nothing.
670
671 #define tile_4bpp_draw_eight_transparent(alpha_op, flip_op)                   \
672   if(current_pixels != 0)                                                     \
673   {                                                                           \
674     tile_4bpp_draw_eight_##flip_op(transparent, alpha_op);                    \
675   }                                                                           \
676
677
678 #define tile_4bpp_draw_eight_copy(alpha_op, flip_op)                          \
679   if(current_pixels != 0)                                                     \
680   {                                                                           \
681     tile_4bpp_draw_eight_##flip_op(copy, alpha_op);                           \
682   }                                                                           \
683
684 // Gets the current tile in 4bpp mode, also getting the current palette and
685 // the pixel block.
686
687 #define get_tile_4bpp()                                                       \
688   current_tile = *map_ptr;                                                    \
689   current_palette = (current_tile >> 12) << 4;                                \
690   tile_ptr = tile_base + ((current_tile & 0x3FF) * 32);                       \
691
692
693 // Helper macro for drawing clipped 4bpp tiles.
694
695 #define partial_tile_4bpp(combine_op, alpha_op)                               \
696   for(i = 0; i < partial_tile_run; i++)                                       \
697   {                                                                           \
698     tile_4bpp_draw_##combine_op(0, mask, 0, alpha_op);                        \
699     current_pixels >>= 4;                                                     \
700     advance_dest_ptr_##combine_op(1);                                         \
701   }                                                                           \
702
703
704 // Draws a 4bpp tile clipped against the left edge of the screen.
705 // partial_tile_offset is how far in it's clipped, partial_tile_run is
706 // how many to draw.
707
708 #define partial_tile_right_noflip_4bpp(combine_op, alpha_op)                  \
709   current_pixels = *((u32 *)tile_ptr) >> (partial_tile_offset * 4);           \
710   partial_tile_4bpp(combine_op, alpha_op)                                     \
711
712
713 // Draws a 4bpp tile clipped against both edges of the screen, same as right.
714
715 #define partial_tile_mid_noflip_4bpp(combine_op, alpha_op)                    \
716   partial_tile_right_noflip_4bpp(combine_op, alpha_op)                        \
717
718
719 // Draws a 4bpp tile clipped against the right edge of the screen.
720 // partial_tile_offset is how many to draw.
721
722 #define partial_tile_left_noflip_4bpp(combine_op, alpha_op)                   \
723   current_pixels = *((u32 *)tile_ptr);                                        \
724   partial_tile_4bpp(combine_op, alpha_op)                                     \
725
726
727 // Draws a complete 4bpp tile row (not clipped)
728 #define tile_noflip_4bpp(combine_op, alpha_op)                                \
729   current_pixels = *((u32 *)tile_ptr);                                        \
730   tile_4bpp_draw_eight_##combine_op(alpha_op, noflip)                         \
731
732
733 // Like the above, but draws flipped tiles.
734
735 #define partial_tile_flip_4bpp(combine_op, alpha_op)                          \
736   for(i = 0; i < partial_tile_run; i++)                                       \
737   {                                                                           \
738     tile_4bpp_draw_##combine_op(0, shift, 28, alpha_op);                      \
739     current_pixels <<= 4;                                                     \
740     advance_dest_ptr_##combine_op(1);                                         \
741   }                                                                           \
742
743 #define partial_tile_right_flip_4bpp(combine_op, alpha_op)                    \
744   current_pixels = *((u32 *)tile_ptr) << (partial_tile_offset * 4);           \
745   partial_tile_flip_4bpp(combine_op, alpha_op)                                \
746
747 #define partial_tile_mid_flip_4bpp(combine_op, alpha_op)                      \
748   partial_tile_right_flip_4bpp(combine_op, alpha_op)                          \
749
750 #define partial_tile_left_flip_4bpp(combine_op, alpha_op)                     \
751   current_pixels = *((u32 *)tile_ptr);                                        \
752   partial_tile_flip_4bpp(combine_op, alpha_op)                                \
753
754 #define tile_flip_4bpp(combine_op, alpha_op)                                  \
755   current_pixels = *((u32 *)tile_ptr);                                        \
756   tile_4bpp_draw_eight_##combine_op(alpha_op, flip)                           \
757
758
759 // Draws a single (partial or complete) tile from the tilemap, flipping
760 // as necessary.
761
762 #define single_tile_map(tile_type, combine_op, color_depth, alpha_op)         \
763   get_tile_##color_depth();                                                   \
764   if(current_tile & 0x800)                                                    \
765     tile_ptr += vertical_pixel_flip;                                          \
766                                                                               \
767   if(current_tile & 0x400)                                                    \
768   {                                                                           \
769     tile_type##_flip_##color_depth(combine_op, alpha_op);                     \
770   }                                                                           \
771   else                                                                        \
772   {                                                                           \
773     tile_type##_noflip_##color_depth(combine_op, alpha_op);                   \
774   }                                                                           \
775
776
777 // Draws multiple sequential tiles from the tilemap, hflips and vflips as
778 // necessary.
779
780 #define multiple_tile_map(combine_op, color_depth, alpha_op)                  \
781   for(i = 0; i < tile_run; i++)                                               \
782   {                                                                           \
783     single_tile_map(tile, combine_op, color_depth, alpha_op);                 \
784     advance_dest_ptr_##combine_op(8);                                         \
785     map_ptr++;                                                                \
786   }                                                                           \
787
788 // Draws a partial tile from a tilemap clipped against the left edge of the
789 // screen.
790
791 #define partial_tile_right_map(combine_op, color_depth, alpha_op)             \
792   single_tile_map(partial_tile_right, combine_op, color_depth, alpha_op);     \
793   map_ptr++                                                                   \
794
795 // Draws a partial tile from a tilemap clipped against both edges of the
796 // screen.
797
798 #define partial_tile_mid_map(combine_op, color_depth, alpha_op)               \
799   single_tile_map(partial_tile_mid, combine_op, color_depth, alpha_op)        \
800
801 // Draws a partial tile from a tilemap clipped against the right edge of the
802 // screen.
803
804 #define partial_tile_left_map(combine_op, color_depth, alpha_op)              \
805   single_tile_map(partial_tile_left, combine_op, color_depth, alpha_op)       \
806
807
808 // Advances a non-flipped 4bpp obj to the next tile.
809
810 #define obj_advance_noflip_4bpp()                                             \
811   tile_ptr += 32                                                              \
812
813
814 // Advances a non-flipped 8bpp obj to the next tile.
815
816 #define obj_advance_noflip_8bpp()                                             \
817   tile_ptr += 64                                                              \
818
819
820 // Advances a flipped 4bpp obj to the next tile.
821
822 #define obj_advance_flip_4bpp()                                               \
823   tile_ptr -= 32                                                              \
824
825
826 // Advances a flipped 8bpp obj to the next tile.
827
828 #define obj_advance_flip_8bpp()                                               \
829   tile_ptr -= 64                                                              \
830
831
832
833 // Draws multiple sequential tiles from an obj, flip_op determines if it should
834 // be flipped or not (set to flip or noflip)
835
836 #define multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op)         \
837   for(i = 0; i < tile_run; i++)                                               \
838   {                                                                           \
839     tile_##flip_op##_##color_depth(combine_op, alpha_op);                     \
840     obj_advance_##flip_op##_##color_depth();                                  \
841     advance_dest_ptr_##combine_op(8);                                         \
842   }                                                                           \
843
844
845 // Draws an obj's tile clipped against the left side of the screen
846
847 #define partial_tile_right_obj(combine_op, color_depth, alpha_op, flip_op)    \
848   partial_tile_right_##flip_op##_##color_depth(combine_op, alpha_op);         \
849   obj_advance_##flip_op##_##color_depth()                                     \
850
851 // Draws an obj's tile clipped against both sides of the screen
852
853 #define partial_tile_mid_obj(combine_op, color_depth, alpha_op, flip_op)      \
854   partial_tile_mid_##flip_op##_##color_depth(combine_op, alpha_op)            \
855
856 // Draws an obj's tile clipped against the right side of the screen
857
858 #define partial_tile_left_obj(combine_op, color_depth, alpha_op, flip_op)     \
859   partial_tile_left_##flip_op##_##color_depth(combine_op, alpha_op)           \
860
861
862 // Extra variables specific for 8bpp/4bpp tile renderers.
863
864 #define tile_extra_variables_8bpp()                                           \
865
866 #define tile_extra_variables_4bpp()                                           \
867   u32 current_palette                                                         \
868
869
870 // Byte lengths of complete tiles and tile rows in 4bpp and 8bpp.
871
872 #define tile_width_4bpp 4
873 #define tile_size_4bpp 32
874 #define tile_width_8bpp 8
875 #define tile_size_8bpp 64
876
877
878 // Render a single scanline of text tiles
879
880 #define tile_render(color_depth, combine_op, alpha_op)                        \
881 {                                                                             \
882   u32 vertical_pixel_offset = (vertical_offset % 8) *                         \
883    tile_width_##color_depth;                                                  \
884   u32 vertical_pixel_flip =                                                   \
885    ((tile_size_##color_depth - tile_width_##color_depth) -                    \
886    vertical_pixel_offset) - vertical_pixel_offset;                            \
887   tile_extra_variables_##color_depth();                                       \
888   u8 *tile_base = vram + (((bg_control >> 2) & 0x03) * (1024 * 16)) +         \
889    vertical_pixel_offset;                                                     \
890   u32 pixel_run = 256 - (horizontal_offset % 256);                            \
891   u32 current_tile;                                                           \
892                                                                               \
893   map_base += ((vertical_offset % 256) / 8) * 32;                             \
894   partial_tile_offset = (horizontal_offset % 8);                              \
895                                                                               \
896   if(pixel_run >= end)                                                        \
897   {                                                                           \
898     if(partial_tile_offset)                                                   \
899     {                                                                         \
900       partial_tile_run = 8 - partial_tile_offset;                             \
901       if(end < partial_tile_run)                                              \
902       {                                                                       \
903         partial_tile_run = end;                                               \
904         partial_tile_mid_map(combine_op, color_depth, alpha_op);              \
905         return;                                                               \
906       }                                                                       \
907       else                                                                    \
908       {                                                                       \
909         end -= partial_tile_run;                                              \
910         partial_tile_right_map(combine_op, color_depth, alpha_op);            \
911       }                                                                       \
912     }                                                                         \
913                                                                               \
914     tile_run = end / 8;                                                       \
915     multiple_tile_map(combine_op, color_depth, alpha_op);                     \
916                                                                               \
917     partial_tile_run = end % 8;                                               \
918                                                                               \
919     if(partial_tile_run)                                                      \
920     {                                                                         \
921       partial_tile_left_map(combine_op, color_depth, alpha_op);               \
922     }                                                                         \
923   }                                                                           \
924   else                                                                        \
925   {                                                                           \
926     if(partial_tile_offset)                                                   \
927     {                                                                         \
928       partial_tile_run = 8 - partial_tile_offset;                             \
929       partial_tile_right_map(combine_op, color_depth, alpha_op);              \
930     }                                                                         \
931                                                                               \
932     tile_run = (pixel_run - partial_tile_run) / 8;                            \
933     multiple_tile_map(combine_op, color_depth, alpha_op);                     \
934     map_ptr = second_ptr;                                                     \
935     end -= pixel_run;                                                         \
936     tile_run = end / 8;                                                       \
937     multiple_tile_map(combine_op, color_depth, alpha_op);                     \
938                                                                               \
939     partial_tile_run = end % 8;                                               \
940     if(partial_tile_run)                                                      \
941     {                                                                         \
942       partial_tile_left_map(combine_op, color_depth, alpha_op);               \
943     }                                                                         \
944   }                                                                           \
945 }                                                                             \
946
947 #define render_scanline_dest_normal         u16
948 #define render_scanline_dest_alpha          u32
949 #define render_scanline_dest_alpha_obj      u32
950 #define render_scanline_dest_color16        u16
951 #define render_scanline_dest_color32        u32
952 #define render_scanline_dest_partial_alpha  u32
953 #define render_scanline_dest_copy_tile      u16
954 #define render_scanline_dest_copy_bitmap    u16
955
956
957 // If rendering a scanline that is not a target A then there's no point in
958 // keeping what's underneath it because it can't blend with it.
959
960 #define render_scanline_skip_alpha(bg_type, combine_op)                       \
961   if((pixel_combine & 0x00000200) == 0)                                       \
962   {                                                                           \
963     render_scanline_##bg_type##_##combine_op##_color32(layer,                 \
964      start, end, scanline);                                                   \
965     return;                                                                   \
966   }                                                                           \
967
968
969 #ifdef RENDER_COLOR16_NORMAL
970
971 #define render_scanline_extra_variables_base_normal(bg_type)                  \
972   const u32 pixel_combine = 0                                                 \
973
974 #else
975
976 #define render_scanline_extra_variables_base_normal(bg_type)                  \
977   u16 *palette = palette_ram_converted                                        \
978
979 #endif
980
981
982 #define render_scanline_extra_variables_base_alpha(bg_type)                   \
983   u32 bg_combine = color_combine_mask(5);                                     \
984   u32 pixel_combine = color_combine_mask(layer) | (bg_combine << 16);         \
985   render_scanline_skip_alpha(bg_type, base)                                   \
986
987 #define render_scanline_extra_variables_base_color()                          \
988   u32 bg_combine = color_combine_mask(5);                                     \
989   u32 pixel_combine = color_combine_mask(layer)                               \
990
991 #define render_scanline_extra_variables_base_color16(bg_type)                 \
992   render_scanline_extra_variables_base_color()                                \
993
994 #define render_scanline_extra_variables_base_color32(bg_type)                 \
995   render_scanline_extra_variables_base_color()                                \
996
997
998 #define render_scanline_extra_variables_transparent_normal(bg_type)           \
999   render_scanline_extra_variables_base_normal(bg_type)                        \
1000
1001 #define render_scanline_extra_variables_transparent_alpha(bg_type)            \
1002   u32 pixel_combine = color_combine_mask(layer);                              \
1003   render_scanline_skip_alpha(bg_type, transparent)                            \
1004
1005 #define render_scanline_extra_variables_transparent_color()                   \
1006   u32 pixel_combine = color_combine_mask(layer)                               \
1007
1008 #define render_scanline_extra_variables_transparent_color16(bg_type)          \
1009   render_scanline_extra_variables_transparent_color()                         \
1010
1011 #define render_scanline_extra_variables_transparent_color32(bg_type)          \
1012   render_scanline_extra_variables_transparent_color()                         \
1013
1014
1015
1016
1017 static const u32 map_widths[] = { 256, 512, 256, 512 };
1018
1019 // Build text scanline rendering functions.
1020
1021 #define render_scanline_text_builder(combine_op, alpha_op)                    \
1022 static void render_scanline_text_##combine_op##_##alpha_op(u32 layer,         \
1023  u32 start, u32 end, void *scanline)                                          \
1024 {                                                                             \
1025   render_scanline_extra_variables_##combine_op##_##alpha_op(text);            \
1026   u32 bg_control = io_registers[REG_BG0CNT + layer];                          \
1027   u32 map_size = (bg_control >> 14) & 0x03;                                   \
1028   u32 map_width = map_widths[map_size];                                       \
1029   u32 horizontal_offset =                                                     \
1030    (io_registers[REG_BG0HOFS + (layer * 2)] + start) % 512;                   \
1031   u32 vertical_offset = (io_registers[REG_VCOUNT] +                           \
1032    io_registers[REG_BG0VOFS + (layer * 2)]) % 512;                            \
1033   u32 current_pixel;                                                          \
1034   u32 current_pixels;                                                         \
1035   u32 partial_tile_run = 0;                                                   \
1036   u32 partial_tile_offset;                                                    \
1037   u32 tile_run;                                                               \
1038   u32 i;                                                                      \
1039   render_scanline_dest_##alpha_op *dest_ptr =                                 \
1040    ((render_scanline_dest_##alpha_op *)scanline) + start;                     \
1041                                                                               \
1042   u16 *map_base = (u16 *)(vram + ((bg_control >> 8) & 0x1F) * (1024 * 2));    \
1043   u16 *map_ptr, *second_ptr;                                                  \
1044   u8 *tile_ptr;                                                               \
1045                                                                               \
1046   end -= start;                                                               \
1047                                                                               \
1048   if((map_size & 0x02) && (vertical_offset >= 256))                           \
1049   {                                                                           \
1050     map_base += ((map_width / 8) * 32) +                                      \
1051      (((vertical_offset - 256) / 8) * 32);                                    \
1052   }                                                                           \
1053   else                                                                        \
1054   {                                                                           \
1055     map_base += (((vertical_offset % 256) / 8) * 32);                         \
1056   }                                                                           \
1057                                                                               \
1058   if(map_size & 0x01)                                                         \
1059   {                                                                           \
1060     if(horizontal_offset >= 256)                                              \
1061     {                                                                         \
1062       horizontal_offset -= 256;                                               \
1063       map_ptr = map_base + (32 * 32) + (horizontal_offset / 8);               \
1064       second_ptr = map_base;                                                  \
1065     }                                                                         \
1066     else                                                                      \
1067     {                                                                         \
1068       map_ptr = map_base + (horizontal_offset / 8);                           \
1069       second_ptr = map_base + (32 * 32);                                      \
1070     }                                                                         \
1071   }                                                                           \
1072   else                                                                        \
1073   {                                                                           \
1074     horizontal_offset %= 256;                                                 \
1075     map_ptr = map_base + (horizontal_offset / 8);                             \
1076     second_ptr = map_base;                                                    \
1077   }                                                                           \
1078                                                                               \
1079   if(bg_control & 0x80)                                                       \
1080   {                                                                           \
1081     tile_render(8bpp, combine_op, alpha_op);                                  \
1082   }                                                                           \
1083   else                                                                        \
1084   {                                                                           \
1085     tile_render(4bpp, combine_op, alpha_op);                                  \
1086   }                                                                           \
1087 }                                                                             \
1088
1089 render_scanline_text_builder(base, normal);
1090 render_scanline_text_builder(transparent, normal);
1091 render_scanline_text_builder(base, color16);
1092 render_scanline_text_builder(transparent, color16);
1093 render_scanline_text_builder(base, color32);
1094 render_scanline_text_builder(transparent, color32);
1095 render_scanline_text_builder(base, alpha);
1096 render_scanline_text_builder(transparent, alpha);
1097
1098
1099 s32 affine_reference_x[2];
1100 s32 affine_reference_y[2];
1101
1102 #define affine_render_bg_pixel_normal()                                       \
1103   current_pixel = palette_ram_converted[0]                                    \
1104
1105 #define affine_render_bg_pixel_alpha()                                        \
1106   current_pixel = bg_combine                                                  \
1107
1108 #define affine_render_bg_pixel_color16()                                      \
1109   affine_render_bg_pixel_alpha()                                              \
1110
1111 #define affine_render_bg_pixel_color32()                                      \
1112   affine_render_bg_pixel_alpha()                                              \
1113
1114 #define affine_render_bg_pixel_base(alpha_op)                                 \
1115   affine_render_bg_pixel_##alpha_op()                                         \
1116
1117 #define affine_render_bg_pixel_transparent(alpha_op)                          \
1118
1119 #define affine_render_bg_pixel_copy(alpha_op)                                 \
1120
1121 #define affine_render_bg_base(alpha_op)                                       \
1122   dest_ptr[0] = current_pixel
1123
1124 #define affine_render_bg_transparent(alpha_op)                                \
1125
1126 #define affine_render_bg_copy(alpha_op)                                       \
1127
1128 #define affine_render_bg_remainder_base(alpha_op)                             \
1129   affine_render_bg_pixel_##alpha_op();                                        \
1130   for(; i < end; i++)                                                         \
1131   {                                                                           \
1132     affine_render_bg_base(alpha_op);                                          \
1133     advance_dest_ptr_base(1);                                                 \
1134   }                                                                           \
1135
1136 #define affine_render_bg_remainder_transparent(alpha_op)                      \
1137
1138 #define affine_render_bg_remainder_copy(alpha_op)                             \
1139
1140 #define affine_render_next(combine_op)                                        \
1141   source_x += dx;                                                             \
1142   source_y += dy;                                                             \
1143   advance_dest_ptr_##combine_op(1)                                            \
1144
1145 #define affine_render_scale_offset()                                          \
1146   tile_base += ((pixel_y % 8) * 8);                                           \
1147   map_base += (pixel_y / 8) << map_pitch                                      \
1148
1149 #define affine_render_scale_pixel(combine_op, alpha_op)                       \
1150   map_offset = (pixel_x / 8);                                                 \
1151   if(map_offset != last_map_offset)                                           \
1152   {                                                                           \
1153     tile_ptr = tile_base + (map_base[map_offset] * 64);                       \
1154     last_map_offset = map_offset;                                             \
1155   }                                                                           \
1156   tile_ptr = tile_base + (map_base[(pixel_x / 8)] * 64);                      \
1157   current_pixel = tile_ptr[(pixel_x % 8)];                                    \
1158   tile_8bpp_draw_##combine_op(0, none, 0, alpha_op);                          \
1159   affine_render_next(combine_op)                                              \
1160
1161 #define affine_render_scale(combine_op, alpha_op)                             \
1162 {                                                                             \
1163   pixel_y = source_y >> 8;                                                    \
1164   u32 i = 0;                                                                  \
1165   affine_render_bg_pixel_##combine_op(alpha_op);                              \
1166   if((u32)pixel_y < (u32)width_height)                                        \
1167   {                                                                           \
1168     affine_render_scale_offset();                                             \
1169     for(; i < end; i++)                                                       \
1170     {                                                                         \
1171       pixel_x = source_x >> 8;                                                \
1172                                                                               \
1173       if((u32)pixel_x < (u32)width_height)                                    \
1174       {                                                                       \
1175         break;                                                                \
1176       }                                                                       \
1177                                                                               \
1178       affine_render_bg_##combine_op(alpha_op);                                \
1179       affine_render_next(combine_op);                                         \
1180     }                                                                         \
1181                                                                               \
1182     for(; i < end; i++)                                                       \
1183     {                                                                         \
1184       pixel_x = source_x >> 8;                                                \
1185                                                                               \
1186       if((u32)pixel_x >= (u32)width_height)                                   \
1187         break;                                                                \
1188                                                                               \
1189       affine_render_scale_pixel(combine_op, alpha_op);                        \
1190     }                                                                         \
1191   }                                                                           \
1192   affine_render_bg_remainder_##combine_op(alpha_op);                          \
1193 }                                                                             \
1194
1195 #define affine_render_scale_wrap(combine_op, alpha_op)                        \
1196 {                                                                             \
1197   u32 wrap_mask = width_height - 1;                                           \
1198   pixel_y = (source_y >> 8) & wrap_mask;                                      \
1199   if((u32)pixel_y < (u32)width_height)                                        \
1200   {                                                                           \
1201     affine_render_scale_offset();                                             \
1202     for(i = 0; i < end; i++)                                                  \
1203     {                                                                         \
1204       pixel_x = (source_x >> 8) & wrap_mask;                                  \
1205       affine_render_scale_pixel(combine_op, alpha_op);                        \
1206     }                                                                         \
1207   }                                                                           \
1208 }                                                                             \
1209
1210
1211 #define affine_render_rotate_pixel(combine_op, alpha_op)                      \
1212   map_offset = (pixel_x / 8) + ((pixel_y / 8) << map_pitch);                  \
1213   if(map_offset != last_map_offset)                                           \
1214   {                                                                           \
1215     tile_ptr = tile_base + (map_base[map_offset] * 64);                       \
1216     last_map_offset = map_offset;                                             \
1217   }                                                                           \
1218                                                                               \
1219   current_pixel = tile_ptr[(pixel_x % 8) + ((pixel_y % 8) * 8)];              \
1220   tile_8bpp_draw_##combine_op(0, none, 0, alpha_op);                          \
1221   affine_render_next(combine_op)                                              \
1222
1223 #define affine_render_rotate(combine_op, alpha_op)                            \
1224 {                                                                             \
1225   affine_render_bg_pixel_##combine_op(alpha_op);                              \
1226   for(i = 0; i < end; i++)                                                    \
1227   {                                                                           \
1228     pixel_x = source_x >> 8;                                                  \
1229     pixel_y = source_y >> 8;                                                  \
1230                                                                               \
1231     if(((u32)pixel_x < (u32)width_height) &&                                  \
1232      ((u32)pixel_y < (u32)width_height))                                      \
1233     {                                                                         \
1234       break;                                                                  \
1235     }                                                                         \
1236     affine_render_bg_##combine_op(alpha_op);                                  \
1237     affine_render_next(combine_op);                                           \
1238   }                                                                           \
1239                                                                               \
1240   for(; i < end; i++)                                                         \
1241   {                                                                           \
1242     pixel_x = source_x >> 8;                                                  \
1243     pixel_y = source_y >> 8;                                                  \
1244                                                                               \
1245     if(((u32)pixel_x >= (u32)width_height) ||                                 \
1246      ((u32)pixel_y >= (u32)width_height))                                     \
1247     {                                                                         \
1248       affine_render_bg_remainder_##combine_op(alpha_op);                      \
1249       break;                                                                  \
1250     }                                                                         \
1251                                                                               \
1252     affine_render_rotate_pixel(combine_op, alpha_op);                         \
1253   }                                                                           \
1254 }                                                                             \
1255
1256 #define affine_render_rotate_wrap(combine_op, alpha_op)                       \
1257 {                                                                             \
1258   u32 wrap_mask = width_height - 1;                                           \
1259   for(i = 0; i < end; i++)                                                    \
1260   {                                                                           \
1261     pixel_x = (source_x >> 8) & wrap_mask;                                    \
1262     pixel_y = (source_y >> 8) & wrap_mask;                                    \
1263                                                                               \
1264     affine_render_rotate_pixel(combine_op, alpha_op);                         \
1265   }                                                                           \
1266 }                                                                             \
1267
1268
1269 // Build affine background renderers.
1270
1271 #define render_scanline_affine_builder(combine_op, alpha_op)                  \
1272 void render_scanline_affine_##combine_op##_##alpha_op(u32 layer,              \
1273  u32 start, u32 end, void *scanline)                                          \
1274 {                                                                             \
1275   render_scanline_extra_variables_##combine_op##_##alpha_op(affine);          \
1276   u32 bg_control = io_registers[REG_BG0CNT + layer];                          \
1277   u32 current_pixel;                                                          \
1278   s32 source_x, source_y;                                                     \
1279   u32 pixel_x, pixel_y;                                                       \
1280   u32 layer_offset = (layer - 2) * 8;                                         \
1281   s32 dx, dy;                                                                 \
1282   u32 map_size = (bg_control >> 14) & 0x03;                                   \
1283   u32 width_height = 1 << (7 + map_size);                                     \
1284   u32 map_pitch = map_size + 4;                                               \
1285   u8 *map_base = vram + (((bg_control >> 8) & 0x1F) * (1024 * 2));            \
1286   u8 *tile_base = vram + (((bg_control >> 2) & 0x03) * (1024 * 16));          \
1287   u8 *tile_ptr = NULL;                                                        \
1288   u32 map_offset, last_map_offset = (u32)-1;                                  \
1289   u32 i;                                                                      \
1290   render_scanline_dest_##alpha_op *dest_ptr =                                 \
1291    ((render_scanline_dest_##alpha_op *)scanline) + start;                     \
1292                                                                               \
1293   dx = (s16)io_registers[REG_BG2PA + layer_offset];                           \
1294   dy = (s16)io_registers[REG_BG2PC + layer_offset];                           \
1295   source_x = affine_reference_x[layer - 2] + (start * dx);                    \
1296   source_y = affine_reference_y[layer - 2] + (start * dy);                    \
1297                                                                               \
1298   end -= start;                                                               \
1299                                                                               \
1300   switch(((bg_control >> 12) & 0x02) | (dy != 0))                             \
1301   {                                                                           \
1302     case 0x00:                                                                \
1303       affine_render_scale(combine_op, alpha_op);                              \
1304       break;                                                                  \
1305                                                                               \
1306     case 0x01:                                                                \
1307       affine_render_rotate(combine_op, alpha_op);                             \
1308       break;                                                                  \
1309                                                                               \
1310     case 0x02:                                                                \
1311       affine_render_scale_wrap(combine_op, alpha_op);                         \
1312       break;                                                                  \
1313                                                                               \
1314     case 0x03:                                                                \
1315       affine_render_rotate_wrap(combine_op, alpha_op);                        \
1316       break;                                                                  \
1317   }                                                                           \
1318 }                                                                             \
1319
1320 render_scanline_affine_builder(base, normal);
1321 render_scanline_affine_builder(transparent, normal);
1322 render_scanline_affine_builder(base, color16);
1323 render_scanline_affine_builder(transparent, color16);
1324 render_scanline_affine_builder(base, color32);
1325 render_scanline_affine_builder(transparent, color32);
1326 render_scanline_affine_builder(base, alpha);
1327 render_scanline_affine_builder(transparent, alpha);
1328
1329
1330 #define bitmap_render_pixel_mode3(alpha_op)                                   \
1331   convert_palette(current_pixel);                                             \
1332   *dest_ptr = current_pixel                                                   \
1333
1334 #define bitmap_render_pixel_mode4(alpha_op)                                   \
1335   tile_expand_base_##alpha_op(0)                                              \
1336
1337 #define bitmap_render_pixel_mode5(alpha_op)                                   \
1338   bitmap_render_pixel_mode3(alpha_op)                                         \
1339
1340
1341 #define bitmap_render_scale(type, alpha_op, width, height)                    \
1342   pixel_y = (source_y >> 8);                                                  \
1343   if((u32)pixel_y < (u32)height)                                              \
1344   {                                                                           \
1345     pixel_x = (source_x >> 8);                                                \
1346     src_ptr += (pixel_y * width);                                             \
1347     if(dx == 0x100)                                                           \
1348     {                                                                         \
1349       if(pixel_x < 0)                                                         \
1350       {                                                                       \
1351         end += pixel_x;                                                       \
1352         dest_ptr -= pixel_x;                                                  \
1353         pixel_x = 0;                                                          \
1354       }                                                                       \
1355       else                                                                    \
1356                                                                               \
1357       if(pixel_x > 0)                                                         \
1358       {                                                                       \
1359         src_ptr += pixel_x;                                                   \
1360       }                                                                       \
1361                                                                               \
1362       if((pixel_x + end) >= width)                                            \
1363         end = (width - pixel_x);                                              \
1364                                                                               \
1365       for(i = 0; (s32)i < (s32)end; i++)                                      \
1366       {                                                                       \
1367         current_pixel = *src_ptr;                                             \
1368         bitmap_render_pixel_##type(alpha_op);                                 \
1369         src_ptr++;                                                            \
1370         dest_ptr++;                                                           \
1371       }                                                                       \
1372     }                                                                         \
1373     else                                                                      \
1374     {                                                                         \
1375       if((u32)(source_y >> 8) < (u32)height)                                  \
1376       {                                                                       \
1377         for(i = 0; i < end; i++)                                              \
1378         {                                                                     \
1379           pixel_x = (source_x >> 8);                                          \
1380                                                                               \
1381           if((u32)pixel_x < (u32)width)                                       \
1382             break;                                                            \
1383                                                                               \
1384           source_x += dx;                                                     \
1385           dest_ptr++;                                                         \
1386         }                                                                     \
1387                                                                               \
1388         for(; i < end; i++)                                                   \
1389         {                                                                     \
1390           pixel_x = (source_x >> 8);                                          \
1391                                                                               \
1392           if((u32)pixel_x >= (u32)width)                                      \
1393             break;                                                            \
1394                                                                               \
1395           current_pixel = src_ptr[pixel_x];                                   \
1396           bitmap_render_pixel_##type(alpha_op);                               \
1397                                                                               \
1398           source_x += dx;                                                     \
1399           dest_ptr++;                                                         \
1400         }                                                                     \
1401       }                                                                       \
1402     }                                                                         \
1403   }                                                                           \
1404
1405 #define bitmap_render_rotate(type, alpha_op, width, height)                   \
1406   for(i = 0; i < end; i++)                                                    \
1407   {                                                                           \
1408     pixel_x = source_x >> 8;                                                  \
1409     pixel_y = source_y >> 8;                                                  \
1410                                                                               \
1411     if(((u32)pixel_x < (u32)width) && ((u32)pixel_y < (u32)height))           \
1412       break;                                                                  \
1413                                                                               \
1414     source_x += dx;                                                           \
1415     source_y += dy;                                                           \
1416     dest_ptr++;                                                               \
1417   }                                                                           \
1418                                                                               \
1419   for(; i < end; i++)                                                         \
1420   {                                                                           \
1421     pixel_x = (source_x >> 8);                                                \
1422     pixel_y = (source_y >> 8);                                                \
1423                                                                               \
1424     if(((u32)pixel_x >= (u32)width) || ((u32)pixel_y >= (u32)height))         \
1425       break;                                                                  \
1426                                                                               \
1427     current_pixel = src_ptr[pixel_x + (pixel_y * width)];                     \
1428      bitmap_render_pixel_##type(alpha_op);                                    \
1429                                                                               \
1430     source_x += dx;                                                           \
1431     source_y += dy;                                                           \
1432     dest_ptr++;                                                               \
1433   }                                                                           \
1434
1435
1436 #define render_scanline_vram_setup_mode3()                                    \
1437   u16 *src_ptr = (u16 *)vram                                                  \
1438
1439 #define render_scanline_vram_setup_mode5()                                    \
1440   u16 *src_ptr;                                                               \
1441   if(io_registers[REG_DISPCNT] & 0x10)                                        \
1442     src_ptr = (u16 *)(vram + 0xA000);                                         \
1443   else                                                                        \
1444     src_ptr = (u16 *)vram                                                     \
1445
1446
1447 #ifdef RENDER_COLOR16_NORMAL
1448
1449 #define render_scanline_vram_setup_mode4()                                    \
1450   const u32 pixel_combine = 0;                                                \
1451   u8 *src_ptr;                                                                \
1452   if(io_registers[REG_DISPCNT] & 0x10)                                        \
1453     src_ptr = vram + 0xA000;                                                  \
1454   else                                                                        \
1455     src_ptr = vram                                                            \
1456
1457
1458 #else
1459
1460 #define render_scanline_vram_setup_mode4()                                    \
1461   u16 *palette = palette_ram_converted;                                       \
1462   u8 *src_ptr;                                                                \
1463   if(io_registers[REG_DISPCNT] & 0x10)                                        \
1464     src_ptr = vram + 0xA000;                                                  \
1465   else                                                                        \
1466     src_ptr = vram                                                            \
1467
1468 #endif
1469
1470
1471
1472 // Build bitmap scanline rendering functions.
1473
1474 #define render_scanline_bitmap_builder(type, alpha_op, width, height)         \
1475 static void render_scanline_bitmap_##type##_##alpha_op(u32 start, u32 end,    \
1476  void *scanline)                                                              \
1477 {                                                                             \
1478   u32 current_pixel;                                                          \
1479   s32 source_x, source_y;                                                     \
1480   s32 pixel_x, pixel_y;                                                       \
1481                                                                               \
1482   s32 dx = (s16)io_registers[REG_BG2PA];                                      \
1483   s32 dy = (s16)io_registers[REG_BG2PC];                                      \
1484                                                                               \
1485   u32 i;                                                                      \
1486                                                                               \
1487   render_scanline_dest_##alpha_op *dest_ptr =                                 \
1488    ((render_scanline_dest_##alpha_op *)scanline) + start;                     \
1489   render_scanline_vram_setup_##type();                                        \
1490                                                                               \
1491   end -= start;                                                               \
1492                                                                               \
1493   source_x = affine_reference_x[0] + (start * dx);                            \
1494   source_y = affine_reference_y[0] + (start * dy);                            \
1495                                                                               \
1496   if(dy == 0)                                                                 \
1497   {                                                                           \
1498     bitmap_render_scale(type, alpha_op, width, height);                       \
1499   }                                                                           \
1500   else                                                                        \
1501   {                                                                           \
1502     bitmap_render_rotate(type, alpha_op, width, height);                      \
1503   }                                                                           \
1504 }                                                                             \
1505
1506 render_scanline_bitmap_builder(mode3, normal, 240, 160);
1507 render_scanline_bitmap_builder(mode4, normal, 240, 160);
1508 render_scanline_bitmap_builder(mode5, normal, 160, 128);
1509
1510
1511 // Fill in the renderers for a layer based on the mode type,
1512
1513 #define tile_layer_render_functions(type)                                     \
1514 {                                                                             \
1515   render_scanline_##type##_base_normal,                                       \
1516   render_scanline_##type##_transparent_normal,                                \
1517   render_scanline_##type##_base_alpha,                                        \
1518   render_scanline_##type##_transparent_alpha,                                 \
1519   render_scanline_##type##_base_color16,                                      \
1520   render_scanline_##type##_transparent_color16,                               \
1521   render_scanline_##type##_base_color32,                                      \
1522   render_scanline_##type##_transparent_color32                                \
1523 }                                                                             \
1524
1525
1526 // Use if a layer is unsupported for that mode.
1527
1528 #define tile_layer_render_null()                                              \
1529 {                                                                             \
1530   NULL, NULL, NULL, NULL                                                      \
1531 }                                                                             \
1532
1533 #define bitmap_layer_render_functions(type)                                   \
1534 {                                                                             \
1535   render_scanline_bitmap_##type##_normal                                      \
1536 }                                                                             \
1537
1538 // Structs containing functions to render the layers for each mode, for
1539 // each render type.
1540 static const tile_layer_render_struct tile_mode_renderers[3][4] =
1541 {
1542   {
1543     tile_layer_render_functions(text), tile_layer_render_functions(text),
1544     tile_layer_render_functions(text), tile_layer_render_functions(text)
1545   },
1546   {
1547     tile_layer_render_functions(text), tile_layer_render_functions(text),
1548     tile_layer_render_functions(affine), tile_layer_render_functions(text)
1549   },
1550   {
1551     tile_layer_render_functions(text), tile_layer_render_functions(text),
1552     tile_layer_render_functions(affine), tile_layer_render_functions(affine)
1553   }
1554 };
1555
1556 static const bitmap_layer_render_struct bitmap_mode_renderers[3] =
1557 {
1558   bitmap_layer_render_functions(mode3),
1559   bitmap_layer_render_functions(mode4),
1560   bitmap_layer_render_functions(mode5)
1561 };
1562
1563
1564 #define render_scanline_layer_functions_tile()                                \
1565   const tile_layer_render_struct *layer_renderers =                           \
1566    tile_mode_renderers[dispcnt & 0x07]                                        \
1567
1568 #define render_scanline_layer_functions_bitmap()                              \
1569   const bitmap_layer_render_struct *layer_renderers =                         \
1570    bitmap_mode_renderers + ((dispcnt & 0x07) - 3)                             \
1571
1572
1573 // Adjust a flipped obj's starting position
1574
1575 #define obj_tile_offset_noflip(color_depth)                                   \
1576
1577 #define obj_tile_offset_flip(color_depth)                                     \
1578   + (tile_size_##color_depth * ((obj_width - 8) / 8))                         \
1579
1580
1581 // Adjust the obj's starting point if it goes too far off the left edge of
1582 // the screen.
1583
1584 #define obj_tile_right_offset_noflip(color_depth)                             \
1585   tile_ptr += (partial_tile_offset / 8) * tile_size_##color_depth             \
1586
1587 #define obj_tile_right_offset_flip(color_depth)                               \
1588   tile_ptr -= (partial_tile_offset / 8) * tile_size_##color_depth             \
1589
1590 // Get the current row offset into an obj in 1D map space
1591
1592 #define obj_tile_offset_1D(color_depth, flip_op)                              \
1593   tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32)                     \
1594    + ((vertical_offset / 8) * (obj_width / 8) * tile_size_##color_depth)      \
1595    + ((vertical_offset % 8) * tile_width_##color_depth)                       \
1596    obj_tile_offset_##flip_op(color_depth)                                     \
1597
1598 // Get the current row offset into an obj in 2D map space
1599
1600 #define obj_tile_offset_2D(color_depth, flip_op)                              \
1601   tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32)                     \
1602    + ((vertical_offset / 8) * 1024)                                           \
1603    + ((vertical_offset % 8) * tile_width_##color_depth)                       \
1604    obj_tile_offset_##flip_op(color_depth)                                     \
1605
1606
1607 // Get the palette for 4bpp obj.
1608
1609 #define obj_get_palette_4bpp()                                                \
1610   current_palette = (obj_attribute_2 >> 8) & 0xF0                             \
1611
1612 #define obj_get_palette_8bpp()                                                \
1613
1614
1615 // Render the current row of an obj.
1616
1617 #define obj_render(combine_op, color_depth, alpha_op, map_space, flip_op)     \
1618 {                                                                             \
1619   obj_get_palette_##color_depth();                                            \
1620   obj_tile_offset_##map_space(color_depth, flip_op);                          \
1621                                                                               \
1622   if(obj_x < (s32)start)                                                      \
1623   {                                                                           \
1624     dest_ptr = scanline + start;                                              \
1625     pixel_run = obj_width - (start - obj_x);                                  \
1626     if((s32)pixel_run > 0)                                                    \
1627     {                                                                         \
1628       if((obj_x + obj_width) >= end)                                          \
1629       {                                                                       \
1630         pixel_run = end - start;                                              \
1631         partial_tile_offset = start - obj_x;                                  \
1632         obj_tile_right_offset_##flip_op(color_depth);                         \
1633         partial_tile_offset %= 8;                                             \
1634                                                                               \
1635         if(partial_tile_offset)                                               \
1636         {                                                                     \
1637           partial_tile_run = 8 - partial_tile_offset;                         \
1638           if((s32)pixel_run < (s32)partial_tile_run)                          \
1639           {                                                                   \
1640             if((s32)pixel_run > 0)                                            \
1641             {                                                                 \
1642               partial_tile_run = pixel_run;                                   \
1643               partial_tile_mid_obj(combine_op, color_depth, alpha_op,         \
1644                flip_op);                                                      \
1645             }                                                                 \
1646             continue;                                                         \
1647           }                                                                   \
1648           else                                                                \
1649           {                                                                   \
1650             pixel_run -= partial_tile_run;                                    \
1651             partial_tile_right_obj(combine_op, color_depth, alpha_op,         \
1652              flip_op);                                                        \
1653           }                                                                   \
1654         }                                                                     \
1655         tile_run = pixel_run / 8;                                             \
1656         multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op);        \
1657         partial_tile_run = pixel_run % 8;                                     \
1658         if(partial_tile_run)                                                  \
1659         {                                                                     \
1660           partial_tile_left_obj(combine_op, color_depth, alpha_op,            \
1661            flip_op);                                                          \
1662         }                                                                     \
1663       }                                                                       \
1664       else                                                                    \
1665       {                                                                       \
1666         partial_tile_offset = start - obj_x;                                  \
1667         obj_tile_right_offset_##flip_op(color_depth);                         \
1668         partial_tile_offset %= 8;                                             \
1669         if(partial_tile_offset)                                               \
1670         {                                                                     \
1671           partial_tile_run = 8 - partial_tile_offset;                         \
1672           partial_tile_right_obj(combine_op, color_depth, alpha_op,           \
1673            flip_op);                                                          \
1674         }                                                                     \
1675         tile_run = pixel_run / 8;                                             \
1676         multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op);        \
1677       }                                                                       \
1678     }                                                                         \
1679   }                                                                           \
1680   else                                                                        \
1681                                                                               \
1682   if((obj_x + obj_width) >= end)                                              \
1683   {                                                                           \
1684     pixel_run = end - obj_x;                                                  \
1685     if((s32)pixel_run > 0)                                                    \
1686     {                                                                         \
1687       dest_ptr = scanline + obj_x;                                            \
1688       tile_run = pixel_run / 8;                                               \
1689       multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op);          \
1690       partial_tile_run = pixel_run % 8;                                       \
1691       if(partial_tile_run)                                                    \
1692       {                                                                       \
1693         partial_tile_left_obj(combine_op, color_depth, alpha_op, flip_op);    \
1694       }                                                                       \
1695     }                                                                         \
1696   }                                                                           \
1697   else                                                                        \
1698   {                                                                           \
1699     dest_ptr = scanline + obj_x;                                              \
1700     tile_run = obj_width / 8;                                                 \
1701     multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op);            \
1702   }                                                                           \
1703 }                                                                             \
1704
1705 #define obj_scale_offset_1D(color_depth)                                      \
1706   tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32)                     \
1707    + ((vertical_offset / 8) * (max_x / 8) * tile_size_##color_depth)          \
1708    + ((vertical_offset % 8) * tile_width_##color_depth)                       \
1709
1710 // Get the current row offset into an obj in 2D map space
1711
1712 #define obj_scale_offset_2D(color_depth)                                      \
1713   tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32)                     \
1714    + ((vertical_offset / 8) * 1024)                                           \
1715    + ((vertical_offset % 8) * tile_width_##color_depth)                       \
1716
1717 #define obj_render_scale_pixel_4bpp(combine_op, alpha_op)                     \
1718   if(tile_x & 0x01)                                                           \
1719   {                                                                           \
1720     current_pixel = tile_ptr[tile_map_offset + ((tile_x >> 1) & 0x03)] >> 4;  \
1721   }                                                                           \
1722   else                                                                        \
1723   {                                                                           \
1724     current_pixel =                                                           \
1725      tile_ptr[tile_map_offset + ((tile_x >> 1) & 0x03)] & 0x0F;               \
1726   }                                                                           \
1727                                                                               \
1728   tile_4bpp_draw_##combine_op(0, none, 0, alpha_op)                           \
1729
1730
1731 #define obj_render_scale_pixel_8bpp(combine_op, alpha_op)                     \
1732   current_pixel = tile_ptr[tile_map_offset + (tile_x & 0x07)];                \
1733   tile_8bpp_draw_##combine_op(0, none, 0, alpha_op);                          \
1734
1735 #define obj_render_scale(combine_op, color_depth, alpha_op, map_space)        \
1736 {                                                                             \
1737   u32 vertical_offset;                                                        \
1738   source_y += (y_delta * dmy);                                                \
1739   vertical_offset = (source_y >> 8);                                          \
1740   if((u32)vertical_offset < (u32)max_y)                                       \
1741   {                                                                           \
1742     obj_scale_offset_##map_space(color_depth);                                \
1743     source_x += (y_delta * dmx) - (middle_x * dx);                            \
1744                                                                               \
1745     for(i = 0; i < obj_width; i++)                                            \
1746     {                                                                         \
1747       tile_x = (source_x >> 8);                                               \
1748                                                                               \
1749       if((u32)tile_x < (u32)max_x)                                            \
1750         break;                                                                \
1751                                                                               \
1752       source_x += dx;                                                         \
1753       advance_dest_ptr_##combine_op(1);                                       \
1754     }                                                                         \
1755                                                                               \
1756     for(; i < obj_width; i++)                                                 \
1757     {                                                                         \
1758       tile_x = (source_x >> 8);                                               \
1759                                                                               \
1760       if((u32)tile_x >= (u32)max_x)                                           \
1761         break;                                                                \
1762                                                                               \
1763       tile_map_offset = (tile_x >> 3) * tile_size_##color_depth;              \
1764       obj_render_scale_pixel_##color_depth(combine_op, alpha_op);             \
1765                                                                               \
1766       source_x += dx;                                                         \
1767       advance_dest_ptr_##combine_op(1);                                       \
1768     }                                                                         \
1769   }                                                                           \
1770 }                                                                             \
1771
1772
1773 #define obj_rotate_offset_1D(color_depth)                                     \
1774   obj_tile_pitch = (max_x / 8) * tile_size_##color_depth                      \
1775
1776 #define obj_rotate_offset_2D(color_depth)                                     \
1777   obj_tile_pitch = 1024                                                       \
1778
1779 #define obj_render_rotate_pixel_4bpp(combine_op, alpha_op)                    \
1780   if(tile_x & 0x01)                                                           \
1781   {                                                                           \
1782     current_pixel = tile_ptr[tile_map_offset +                                \
1783      ((tile_x >> 1) & 0x03) + ((tile_y & 0x07) * obj_pitch)] >> 4;            \
1784   }                                                                           \
1785   else                                                                        \
1786   {                                                                           \
1787     current_pixel = tile_ptr[tile_map_offset +                                \
1788      ((tile_x >> 1) & 0x03) + ((tile_y & 0x07) * obj_pitch)] & 0x0F;          \
1789   }                                                                           \
1790                                                                               \
1791   tile_4bpp_draw_##combine_op(0, none, 0, alpha_op)                           \
1792
1793 #define obj_render_rotate_pixel_8bpp(combine_op, alpha_op)                    \
1794   current_pixel = tile_ptr[tile_map_offset +                                  \
1795    (tile_x & 0x07) + ((tile_y & 0x07) * obj_pitch)];                          \
1796                                                                               \
1797   tile_8bpp_draw_##combine_op(0, none, 0, alpha_op)                           \
1798
1799 #define obj_render_rotate(combine_op, color_depth, alpha_op, map_space)       \
1800 {                                                                             \
1801   tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32);                    \
1802   obj_rotate_offset_##map_space(color_depth);                                 \
1803                                                                               \
1804   source_x += (y_delta * dmx) - (middle_x * dx);                              \
1805   source_y += (y_delta * dmy) - (middle_x * dy);                              \
1806                                                                               \
1807   for(i = 0; i < obj_width; i++)                                              \
1808   {                                                                           \
1809     tile_x = (source_x >> 8);                                                 \
1810     tile_y = (source_y >> 8);                                                 \
1811                                                                               \
1812     if(((u32)tile_x < (u32)max_x) && ((u32)tile_y < (u32)max_y))              \
1813       break;                                                                  \
1814                                                                               \
1815     source_x += dx;                                                           \
1816     source_y += dy;                                                           \
1817     advance_dest_ptr_##combine_op(1);                                         \
1818   }                                                                           \
1819                                                                               \
1820   for(; i < obj_width; i++)                                                   \
1821   {                                                                           \
1822     tile_x = (source_x >> 8);                                                 \
1823     tile_y = (source_y >> 8);                                                 \
1824                                                                               \
1825     if(((u32)tile_x >= (u32)max_x) || ((u32)tile_y >= (u32)max_y))            \
1826       break;                                                                  \
1827                                                                               \
1828     tile_map_offset = ((tile_x >> 3) * tile_size_##color_depth) +             \
1829     ((tile_y >> 3) * obj_tile_pitch);                                         \
1830     obj_render_rotate_pixel_##color_depth(combine_op, alpha_op);              \
1831                                                                               \
1832     source_x += dx;                                                           \
1833     source_y += dy;                                                           \
1834     advance_dest_ptr_##combine_op(1);                                         \
1835   }                                                                           \
1836 }                                                                             \
1837
1838 // Render the current row of an affine transformed OBJ.
1839
1840 #define obj_render_affine(combine_op, color_depth, alpha_op, map_space)       \
1841 {                                                                             \
1842   s16 *params = (s16 *)oam_ram + (((obj_attribute_1 >> 9) & 0x1F) * 16);      \
1843   s32 dx = params[3];                                                         \
1844   s32 dmx = params[7];                                                        \
1845   s32 dy = params[11];                                                        \
1846   s32 dmy = params[15];                                                       \
1847   s32 source_x, source_y;                                                     \
1848   s32 tile_x, tile_y;                                                         \
1849   u32 tile_map_offset;                                                        \
1850   s32 middle_x;                                                               \
1851   s32 middle_y;                                                               \
1852   s32 max_x = obj_width;                                                      \
1853   s32 max_y = obj_height;                                                     \
1854   s32 y_delta;                                                                \
1855   u32 obj_pitch = tile_width_##color_depth;                                   \
1856   u32 obj_tile_pitch;                                                         \
1857                                                                               \
1858   middle_x = (obj_width / 2);                                                 \
1859   middle_y = (obj_height / 2);                                                \
1860                                                                               \
1861   source_x = (middle_x << 8);                                                 \
1862   source_y = (middle_y << 8);                                                 \
1863                                                                               \
1864                                                                               \
1865   if(obj_attribute_0 & 0x200)                                                 \
1866   {                                                                           \
1867     obj_width *= 2;                                                           \
1868     obj_height *= 2;                                                          \
1869     middle_x *= 2;                                                            \
1870     middle_y *= 2;                                                            \
1871   }                                                                           \
1872                                                                               \
1873   if((s32)obj_x < (s32)start)                                                 \
1874   {                                                                           \
1875     u32 x_delta = start - obj_x;                                              \
1876     middle_x -= x_delta;                                                      \
1877     obj_width -= x_delta;                                                     \
1878     obj_x = start;                                                            \
1879                                                                               \
1880     if((s32)obj_width <= 0)                                                   \
1881       continue;                                                               \
1882   }                                                                           \
1883                                                                               \
1884   if((s32)(obj_x + obj_width) >= (s32)end)                                    \
1885   {                                                                           \
1886     obj_width = end - obj_x;                                                  \
1887                                                                               \
1888     if((s32)obj_width <= 0)                                                   \
1889       continue;                                                               \
1890   }                                                                           \
1891   dest_ptr = scanline + obj_x;                                                \
1892                                                                               \
1893   y_delta = vcount - (obj_y + middle_y);                                      \
1894                                                                               \
1895   obj_get_palette_##color_depth();                                            \
1896                                                                               \
1897   if(dy == 0)                                                                 \
1898   {                                                                           \
1899     obj_render_scale(combine_op, color_depth, alpha_op, map_space);           \
1900   }                                                                           \
1901   else                                                                        \
1902   {                                                                           \
1903     obj_render_rotate(combine_op, color_depth, alpha_op, map_space);          \
1904   }                                                                           \
1905 }                                                                             \
1906
1907 static const u32 obj_width_table[] =
1908   { 8, 16, 32, 64, 16, 32, 32, 64, 8, 8, 16, 32 };
1909 static const u32 obj_height_table[] =
1910   { 8, 16, 32, 64, 8, 8, 16, 32, 16, 32, 32, 64 };
1911
1912 static u8 obj_priority_list[5][160][128];
1913 static u32 obj_priority_count[5][160];
1914 static u32 obj_alpha_count[160];
1915
1916
1917 // Build obj rendering functions
1918
1919 #ifdef RENDER_COLOR16_NORMAL
1920
1921 #define render_scanline_obj_extra_variables_normal(bg_type)                   \
1922   const u32 pixel_combine = (1 << 8)                                          \
1923
1924 #else
1925
1926 #define render_scanline_obj_extra_variables_normal(bg_type)                   \
1927   u16 *palette = palette_ram_converted + 256                                  \
1928
1929 #endif
1930
1931
1932 #define render_scanline_obj_extra_variables_color()                           \
1933   u32 pixel_combine = color_combine_mask(4) | (1 << 8)                        \
1934
1935 #define render_scanline_obj_extra_variables_alpha_obj(map_space)              \
1936   render_scanline_obj_extra_variables_color();                                \
1937   u32 dest;                                                                   \
1938   if((pixel_combine & 0x00000200) == 0)                                       \
1939   {                                                                           \
1940     render_scanline_obj_color32_##map_space(priority, start, end, scanline);  \
1941     return;                                                                   \
1942   }                                                                           \
1943
1944 #define render_scanline_obj_extra_variables_color16(map_space)                \
1945   render_scanline_obj_extra_variables_color()                                 \
1946
1947 #define render_scanline_obj_extra_variables_color32(map_space)                \
1948   render_scanline_obj_extra_variables_color()                                 \
1949
1950 #define render_scanline_obj_extra_variables_partial_alpha(map_space)          \
1951   render_scanline_obj_extra_variables_color();                                \
1952   u32 base_pixel_combine = pixel_combine;                                     \
1953   u32 dest                                                                    \
1954
1955 #define render_scanline_obj_extra_variables_copy(type)                        \
1956   u32 bldcnt = io_registers[REG_BLDCNT];                                      \
1957   u32 dispcnt = io_registers[REG_DISPCNT];                                    \
1958   u32 obj_enable = io_registers[REG_WINOUT] >> 8;                             \
1959   render_scanline_layer_functions_##type();                                   \
1960   u32 copy_start, copy_end;                                                   \
1961   u16 copy_buffer[240];                                                       \
1962   u16 *copy_ptr                                                               \
1963
1964 #define render_scanline_obj_extra_variables_copy_tile(map_space)              \
1965   render_scanline_obj_extra_variables_copy(tile)                              \
1966
1967 #define render_scanline_obj_extra_variables_copy_bitmap(map_space)            \
1968   render_scanline_obj_extra_variables_copy(bitmap)                            \
1969
1970
1971 #define render_scanline_obj_main(combine_op, alpha_op, map_space)             \
1972   if(obj_attribute_0 & 0x100)                                                 \
1973   {                                                                           \
1974     if((obj_attribute_0 >> 13) & 0x01)                                        \
1975     {                                                                         \
1976       obj_render_affine(combine_op, 8bpp, alpha_op, map_space);               \
1977     }                                                                         \
1978     else                                                                      \
1979     {                                                                         \
1980       obj_render_affine(combine_op, 4bpp, alpha_op, map_space);               \
1981     }                                                                         \
1982   }                                                                           \
1983   else                                                                        \
1984   {                                                                           \
1985     vertical_offset = vcount - obj_y;                                         \
1986                                                                               \
1987     if((obj_attribute_1 >> 13) & 0x01)                                        \
1988       vertical_offset = obj_height - vertical_offset - 1;                     \
1989                                                                               \
1990     switch(((obj_attribute_0 >> 12) & 0x02) |                                 \
1991      ((obj_attribute_1 >> 12) & 0x01))                                        \
1992     {                                                                         \
1993       case 0x0:                                                               \
1994         obj_render(combine_op, 4bpp, alpha_op, map_space, noflip);            \
1995         break;                                                                \
1996                                                                               \
1997       case 0x1:                                                               \
1998         obj_render(combine_op, 4bpp, alpha_op, map_space, flip);              \
1999         break;                                                                \
2000                                                                               \
2001       case 0x2:                                                               \
2002         obj_render(combine_op, 8bpp, alpha_op, map_space, noflip);            \
2003         break;                                                                \
2004                                                                               \
2005       case 0x3:                                                               \
2006         obj_render(combine_op, 8bpp, alpha_op, map_space, flip);              \
2007         break;                                                                \
2008     }                                                                         \
2009   }                                                                           \
2010
2011 #define render_scanline_obj_no_partial_alpha(combine_op, alpha_op, map_space) \
2012   render_scanline_obj_main(combine_op, alpha_op, map_space)                   \
2013
2014 #define render_scanline_obj_partial_alpha(combine_op, alpha_op, map_space)    \
2015   if((obj_attribute_0 >> 10) & 0x03)                                          \
2016   {                                                                           \
2017     pixel_combine = 0x00000300;                                               \
2018     render_scanline_obj_main(combine_op, alpha_obj, map_space);               \
2019   }                                                                           \
2020   else                                                                        \
2021   {                                                                           \
2022     pixel_combine = base_pixel_combine;                                       \
2023     render_scanline_obj_main(combine_op, color32, map_space);                 \
2024   }                                                                           \
2025
2026 #define render_scanline_obj_prologue_transparent(alpha_op)                    \
2027
2028 #define render_scanline_obj_prologue_copy_body(type)                          \
2029   copy_start = obj_x;                                                         \
2030   if(obj_attribute_0 & 0x200)                                                 \
2031     copy_end = obj_x + (obj_width * 2);                                       \
2032   else                                                                        \
2033     copy_end = obj_x + obj_width;                                             \
2034                                                                               \
2035   if(copy_start < start)                                                      \
2036     copy_start = start;                                                       \
2037   if(copy_end > end)                                                          \
2038     copy_end = end;                                                           \
2039                                                                               \
2040   if((copy_start < end) && (copy_end > start))                                \
2041   {                                                                           \
2042     render_scanline_conditional_##type(copy_start, copy_end, copy_buffer,     \
2043      obj_enable, dispcnt, bldcnt, layer_renderers);                           \
2044     copy_ptr = copy_buffer + copy_start;                                      \
2045   }                                                                           \
2046   else                                                                        \
2047   {                                                                           \
2048     continue;                                                                 \
2049   }                                                                           \
2050
2051 #define render_scanline_obj_prologue_copy_tile()                              \
2052   render_scanline_obj_prologue_copy_body(tile)                                \
2053
2054 #define render_scanline_obj_prologue_copy_bitmap()                            \
2055   render_scanline_obj_prologue_copy_body(bitmap)                              \
2056
2057 #define render_scanline_obj_prologue_copy(alpha_op)                           \
2058   render_scanline_obj_prologue_##alpha_op()                                   \
2059
2060
2061 #define render_scanline_obj_builder(combine_op, alpha_op, map_space,          \
2062  partial_alpha_op)                                                            \
2063 static void render_scanline_obj_##alpha_op##_##map_space(u32 priority,        \
2064  u32 start, u32 end, render_scanline_dest_##alpha_op *scanline)               \
2065 {                                                                             \
2066   render_scanline_obj_extra_variables_##alpha_op(map_space);                  \
2067   s32 obj_num, i;                                                             \
2068   s32 obj_x, obj_y;                                                           \
2069   s32 obj_size;                                                               \
2070   s32 obj_width, obj_height;                                                  \
2071   u32 obj_attribute_0, obj_attribute_1, obj_attribute_2;                      \
2072   s32 vcount = io_registers[REG_VCOUNT];                                      \
2073   u32 tile_run;                                                               \
2074   u32 current_pixels;                                                         \
2075   u32 current_pixel;                                                          \
2076   u32 current_palette;                                                        \
2077   u32 vertical_offset;                                                        \
2078   u32 partial_tile_run, partial_tile_offset;                                  \
2079   u32 pixel_run;                                                              \
2080   u16 *oam_ptr;                                                               \
2081   render_scanline_dest_##alpha_op *dest_ptr;                                  \
2082   u8 *tile_base = vram + 0x10000;                                             \
2083   u8 *tile_ptr;                                                               \
2084   u32 obj_count = obj_priority_count[priority][vcount];                       \
2085   u8 *obj_list = obj_priority_list[priority][vcount];                         \
2086                                                                               \
2087   for(obj_num = 0; obj_num < obj_count; obj_num++)                            \
2088   {                                                                           \
2089     oam_ptr = oam_ram + (obj_list[obj_num] * 4);                              \
2090     obj_attribute_0 = oam_ptr[0];                                             \
2091     obj_attribute_1 = oam_ptr[1];                                             \
2092     obj_attribute_2 = oam_ptr[2];                                             \
2093     obj_size = ((obj_attribute_0 >> 12) & 0x0C) | (obj_attribute_1 >> 14);    \
2094                                                                               \
2095     obj_x = (s32)(obj_attribute_1 << 23) >> 23;                               \
2096     obj_width = obj_width_table[obj_size];                                    \
2097                                                                               \
2098     render_scanline_obj_prologue_##combine_op(alpha_op);                      \
2099                                                                               \
2100     obj_y = obj_attribute_0 & 0xFF;                                           \
2101                                                                               \
2102     if(obj_y > 160)                                                           \
2103       obj_y -= 256;                                                           \
2104                                                                               \
2105     obj_height = obj_height_table[obj_size];                                  \
2106     render_scanline_obj_##partial_alpha_op(combine_op, alpha_op, map_space);  \
2107   }                                                                           \
2108 }                                                                             \
2109
2110 render_scanline_obj_builder(transparent, normal, 1D, no_partial_alpha);
2111 render_scanline_obj_builder(transparent, normal, 2D, no_partial_alpha);
2112 render_scanline_obj_builder(transparent, color16, 1D, no_partial_alpha);
2113 render_scanline_obj_builder(transparent, color16, 2D, no_partial_alpha);
2114 render_scanline_obj_builder(transparent, color32, 1D, no_partial_alpha);
2115 render_scanline_obj_builder(transparent, color32, 2D, no_partial_alpha);
2116 render_scanline_obj_builder(transparent, alpha_obj, 1D, no_partial_alpha);
2117 render_scanline_obj_builder(transparent, alpha_obj, 2D, no_partial_alpha);
2118 render_scanline_obj_builder(transparent, partial_alpha, 1D, partial_alpha);
2119 render_scanline_obj_builder(transparent, partial_alpha, 2D, partial_alpha);
2120 render_scanline_obj_builder(copy, copy_tile, 1D, no_partial_alpha);
2121 render_scanline_obj_builder(copy, copy_tile, 2D, no_partial_alpha);
2122 render_scanline_obj_builder(copy, copy_bitmap, 1D, no_partial_alpha);
2123 render_scanline_obj_builder(copy, copy_bitmap, 2D, no_partial_alpha);
2124
2125
2126
2127 static void order_obj(u32 video_mode)
2128 {
2129   s32 obj_num, priority, row;
2130   s32 obj_x, obj_y;
2131   s32 obj_size, obj_mode;
2132   s32 obj_width, obj_height;
2133   u32 obj_priority;
2134   u32 obj_attribute_0, obj_attribute_1, obj_attribute_2;
2135   u32 current_count;
2136   u16 *oam_ptr = oam_ram + 508;
2137
2138   for(priority = 0; priority < 5; priority++)
2139   {
2140     for(row = 0; row < 160; row++)
2141     {
2142       obj_priority_count[priority][row] = 0;
2143     }
2144   }
2145
2146   for(row = 0; row < 160; row++)
2147   {
2148     obj_alpha_count[row] = 0;
2149   }
2150
2151   for(obj_num = 127; obj_num >= 0; obj_num--, oam_ptr -= 4)
2152   {
2153     obj_attribute_0 = oam_ptr[0];
2154     obj_attribute_2 = oam_ptr[2];
2155     obj_size = obj_attribute_0 & 0xC000;
2156     obj_priority = (obj_attribute_2 >> 10) & 0x03;
2157     obj_mode = (obj_attribute_0 >> 10) & 0x03;
2158
2159     if(((obj_attribute_0 & 0x0300) != 0x0200) && (obj_size != 0xC000) &&
2160      (obj_mode != 3) && ((video_mode < 3) ||
2161      ((obj_attribute_2 & 0x3FF) >= 512)))
2162     {
2163       obj_y = obj_attribute_0 & 0xFF;
2164       if(obj_y > 160)
2165         obj_y -= 256;
2166
2167       obj_attribute_1 = oam_ptr[1];
2168       obj_size = ((obj_size >> 12) & 0x0C) | (obj_attribute_1 >> 14);
2169       obj_height = obj_height_table[obj_size];
2170       obj_width = obj_width_table[obj_size];
2171
2172       if(obj_attribute_0 & 0x200)
2173       {
2174         obj_height *= 2;
2175         obj_width *= 2;
2176       }
2177
2178       if(((obj_y + obj_height) > 0) && (obj_y < 160))
2179       {
2180         obj_x = (s32)(obj_attribute_1 << 23) >> 23;
2181
2182         if(((obj_x + obj_width) > 0) && (obj_x < 240))
2183         {
2184           if(obj_y < 0)
2185           {
2186             obj_height += obj_y;
2187             obj_y = 0;
2188           }
2189
2190           if((obj_y + obj_height) >= 160)
2191           {
2192             obj_height = 160 - obj_y;
2193           }
2194
2195           if(obj_mode == 1)
2196           {
2197             for(row = obj_y; row < obj_y + obj_height; row++)
2198             {
2199               current_count = obj_priority_count[obj_priority][row];
2200               obj_priority_list[obj_priority][row][current_count] = obj_num;
2201               obj_priority_count[obj_priority][row] = current_count + 1;
2202               obj_alpha_count[row]++;
2203             }
2204           }
2205           else
2206           {
2207             if(obj_mode == 2)
2208             {
2209               obj_priority = 4;
2210             }
2211
2212             for(row = obj_y; row < obj_y + obj_height; row++)
2213             {
2214               current_count = obj_priority_count[obj_priority][row];
2215               obj_priority_list[obj_priority][row][current_count] = obj_num;
2216               obj_priority_count[obj_priority][row] = current_count + 1;
2217             }
2218           }
2219         }
2220       }
2221     }
2222   }
2223 }
2224
2225 u32 layer_order[16];
2226 u32 layer_count;
2227
2228 static void order_layers(u32 layer_flags)
2229 {
2230   s32 priority, layer_number;
2231   layer_count = 0;
2232
2233   for(priority = 3; priority >= 0; priority--)
2234   {
2235     for(layer_number = 3; layer_number >= 0; layer_number--)
2236     {
2237       if(((layer_flags >> layer_number) & 1) &&
2238        ((io_registers[REG_BG0CNT + layer_number] & 0x03) == priority))
2239       {
2240         layer_order[layer_count] = layer_number;
2241         layer_count++;
2242       }
2243     }
2244
2245     if((obj_priority_count[priority][io_registers[REG_VCOUNT]] > 0)
2246      && (layer_flags & 0x10))
2247     {
2248       layer_order[layer_count] = priority | 0x04;
2249       layer_count++;
2250     }
2251   }
2252 }
2253
2254 #define fill_line(_start, _end)                                               \
2255   u32 i;                                                                      \
2256                                                                               \
2257   for(i = _start; i < _end; i++)                                              \
2258   {                                                                           \
2259     dest_ptr[i] = color;                                                      \
2260   }                                                                           \
2261
2262
2263 #define fill_line_color_normal()                                              \
2264   color = palette_ram_converted[color]                                        \
2265
2266 #define fill_line_color_alpha()                                               \
2267
2268 #define fill_line_color_color16()                                             \
2269
2270 #define fill_line_color_color32()                                             \
2271
2272 #define fill_line_builder(type)                                               \
2273 static void fill_line_##type(u16 color, render_scanline_dest_##type *dest_ptr,\
2274  u32 start, u32 end)                                                          \
2275 {                                                                             \
2276   fill_line_color_##type();                                                   \
2277   fill_line(start, end);                                                      \
2278 }                                                                             \
2279
2280 fill_line_builder(normal);
2281 fill_line_builder(alpha);
2282 fill_line_builder(color16);
2283 fill_line_builder(color32);
2284
2285
2286 // Alpha blend two pixels (pixel_top and pixel_bottom).
2287
2288 #define blend_pixel()                                                         \
2289   pixel_bottom = palette_ram_converted[(pixel_pair >> 16) & 0x1FF];           \
2290   pixel_bottom = (pixel_bottom | (pixel_bottom << 16)) & 0x07E0F81F;          \
2291   pixel_top = ((pixel_top * blend_a) + (pixel_bottom * blend_b)) >> 4         \
2292
2293
2294 // Alpha blend two pixels, allowing for saturation (individual channels > 31).
2295 // The operation is optimized towards saturation not occuring.
2296
2297 #define blend_saturate_pixel()                                                \
2298   pixel_bottom = palette_ram_converted[(pixel_pair >> 16) & 0x1FF];           \
2299   pixel_bottom = (pixel_bottom | (pixel_bottom << 16)) & 0x07E0F81F;          \
2300   pixel_top = ((pixel_top * blend_a) + (pixel_bottom * blend_b)) >> 4;        \
2301   if(pixel_top & 0x08010020)                                                  \
2302   {                                                                           \
2303     if(pixel_top & 0x08000000)                                                \
2304       pixel_top |= 0x07E00000;                                                \
2305                                                                               \
2306     if(pixel_top & 0x00010000)                                                \
2307       pixel_top |= 0x0000F800;                                                \
2308                                                                               \
2309     if(pixel_top & 0x00000020)                                                \
2310       pixel_top |= 0x0000001F;                                                \
2311   }                                                                           \
2312
2313 #define brighten_pixel()                                                      \
2314   pixel_top = upper + ((pixel_top * blend) >> 4);                             \
2315
2316 #define darken_pixel()                                                        \
2317   pixel_top = (pixel_top * blend) >> 4;                                       \
2318
2319 #define effect_condition_alpha                                                \
2320   ((pixel_pair & 0x04000200) == 0x04000200)                                   \
2321
2322 #define effect_condition_fade(pixel_source)                                   \
2323   ((pixel_source & 0x00000200) == 0x00000200)                                 \
2324
2325 #define expand_pixel_no_dest(expand_type, pixel_source)                       \
2326   pixel_top = (pixel_top | (pixel_top << 16)) & 0x07E0F81F;                   \
2327   expand_type##_pixel();                                                      \
2328   pixel_top &= 0x07E0F81F;                                                    \
2329   pixel_top = (pixel_top >> 16) | pixel_top                                   \
2330
2331 #define expand_pixel(expand_type, pixel_source)                               \
2332   pixel_top = palette_ram_converted[pixel_source & 0x1FF];                    \
2333   expand_pixel_no_dest(expand_type, pixel_source);                            \
2334   *screen_dest_ptr = pixel_top                                                \
2335
2336 #define expand_loop(expand_type, effect_condition, pixel_source)              \
2337   screen_src_ptr += start;                                                    \
2338   screen_dest_ptr += start;                                                   \
2339                                                                               \
2340   end -= start;                                                               \
2341                                                                               \
2342   for(i = 0; i < end; i++)                                                    \
2343   {                                                                           \
2344     pixel_source = *screen_src_ptr;                                           \
2345     if(effect_condition)                                                      \
2346     {                                                                         \
2347       expand_pixel(expand_type, pixel_source);                                \
2348     }                                                                         \
2349     else                                                                      \
2350     {                                                                         \
2351       *screen_dest_ptr =                                                      \
2352        palette_ram_converted[pixel_source & 0x1FF];                           \
2353     }                                                                         \
2354                                                                               \
2355     screen_src_ptr++;                                                         \
2356     screen_dest_ptr++;                                                        \
2357   }                                                                           \
2358
2359
2360 #define expand_loop_partial_alpha(alpha_expand, expand_type)                  \
2361   screen_src_ptr += start;                                                    \
2362   screen_dest_ptr += start;                                                   \
2363                                                                               \
2364   end -= start;                                                               \
2365                                                                               \
2366   for(i = 0; i < end; i++)                                                    \
2367   {                                                                           \
2368     pixel_pair = *screen_src_ptr;                                             \
2369     if(effect_condition_fade(pixel_pair))                                     \
2370     {                                                                         \
2371       if(effect_condition_alpha)                                              \
2372       {                                                                       \
2373         expand_pixel(alpha_expand, pixel_pair);                               \
2374       }                                                                       \
2375       else                                                                    \
2376       {                                                                       \
2377         expand_pixel(expand_type, pixel_pair);                                \
2378       }                                                                       \
2379     }                                                                         \
2380     else                                                                      \
2381     {                                                                         \
2382       *screen_dest_ptr =                                                      \
2383        palette_ram_converted[pixel_pair & 0x1FF];                             \
2384     }                                                                         \
2385                                                                               \
2386     screen_src_ptr++;                                                         \
2387     screen_dest_ptr++;                                                        \
2388   }                                                                           \
2389
2390
2391 #define expand_partial_alpha(expand_type)                                     \
2392   if((blend_a + blend_b) > 16)                                                \
2393   {                                                                           \
2394     expand_loop_partial_alpha(blend_saturate, expand_type);                   \
2395   }                                                                           \
2396   else                                                                        \
2397   {                                                                           \
2398     expand_loop_partial_alpha(blend, expand_type);                            \
2399   }                                                                           \
2400
2401
2402
2403 // Blend top two pixels of scanline with each other.
2404
2405 #ifdef RENDER_COLOR16_NORMAL
2406
2407 #ifndef ARM_ARCH
2408
2409 void expand_normal(u16 *screen_ptr, u32 start, u32 end)
2410 {
2411   u32 i, pixel_source;
2412   screen_ptr += start;
2413
2414   return;
2415
2416   end -= start;
2417
2418   for(i = 0; i < end; i++)
2419   {
2420     pixel_source = *screen_ptr;
2421     *screen_ptr = palette_ram_converted[pixel_source];
2422
2423     screen_ptr++;
2424   }
2425 }
2426
2427 #endif
2428
2429 #else
2430
2431 #define expand_normal(screen_ptr, start, end)
2432
2433 #endif
2434
2435
2436 void expand_blend(u32 *screen_src_ptr, u16 *screen_dest_ptr,
2437  u32 start, u32 end);
2438
2439 #ifndef ARM_ARCH
2440
2441 void expand_blend(u32 *screen_src_ptr, u16 *screen_dest_ptr,
2442  u32 start, u32 end)
2443 {
2444   u32 pixel_pair;
2445   u32 pixel_top, pixel_bottom;
2446   u32 bldalpha = io_registers[REG_BLDALPHA];
2447   u32 blend_a = bldalpha & 0x1F;
2448   u32 blend_b = (bldalpha >> 8) & 0x1F;
2449   u32 i;
2450
2451   if(blend_a > 16)
2452     blend_a = 16;
2453
2454   if(blend_b > 16)
2455     blend_b = 16;
2456
2457   // The individual colors can saturate over 31, this should be taken
2458   // care of in an alternate pass as it incurs a huge additional speedhit.
2459   if((blend_a + blend_b) > 16)
2460   {
2461     expand_loop(blend_saturate, effect_condition_alpha, pixel_pair);
2462   }
2463   else
2464   {
2465     expand_loop(blend, effect_condition_alpha, pixel_pair);
2466   }
2467 }
2468
2469 #endif
2470
2471 // Blend scanline with white.
2472
2473 static void expand_darken(u16 *screen_src_ptr, u16 *screen_dest_ptr,
2474  u32 start, u32 end)
2475 {
2476   u32 pixel_top;
2477   s32 blend = 16 - (io_registers[REG_BLDY] & 0x1F);
2478   u32 i;
2479
2480   if(blend < 0)
2481     blend = 0;
2482
2483   expand_loop(darken, effect_condition_fade(pixel_top), pixel_top);
2484 }
2485
2486
2487 // Blend scanline with black.
2488
2489 static void expand_brighten(u16 *screen_src_ptr, u16 *screen_dest_ptr,
2490  u32 start, u32 end)
2491 {
2492   u32 pixel_top;
2493   u32 blend = io_registers[REG_BLDY] & 0x1F;
2494   u32 upper;
2495   u32 i;
2496
2497   if(blend > 16)
2498     blend = 16;
2499
2500   upper = ((0x07E0F81F * blend) >> 4) & 0x07E0F81F;
2501   blend = 16 - blend;
2502
2503   expand_loop(brighten, effect_condition_fade(pixel_top), pixel_top);
2504
2505 }
2506
2507
2508 // Expand scanline such that if both top and bottom pass it's alpha,
2509 // if only top passes it's as specified, and if neither pass it's normal.
2510
2511 static void expand_darken_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ptr,
2512  u32 start, u32 end)
2513 {
2514   s32 blend = 16 - (io_registers[REG_BLDY] & 0x1F);
2515   u32 pixel_pair;
2516   u32 pixel_top, pixel_bottom;
2517   u32 bldalpha = io_registers[REG_BLDALPHA];
2518   u32 blend_a = bldalpha & 0x1F;
2519   u32 blend_b = (bldalpha >> 8) & 0x1F;
2520   u32 i;
2521
2522   if(blend < 0)
2523     blend = 0;
2524
2525   if(blend_a > 16)
2526     blend_a = 16;
2527
2528   if(blend_b > 16)
2529     blend_b = 16;
2530
2531   expand_partial_alpha(darken);
2532 }
2533
2534
2535 static void expand_brighten_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ptr,
2536  u32 start, u32 end)
2537 {
2538   s32 blend = io_registers[REG_BLDY] & 0x1F;
2539   u32 pixel_pair;
2540   u32 pixel_top, pixel_bottom;
2541   u32 bldalpha = io_registers[REG_BLDALPHA];
2542   u32 blend_a = bldalpha & 0x1F;
2543   u32 blend_b = (bldalpha >> 8) & 0x1F;
2544   u32 upper;
2545   u32 i;
2546
2547   if(blend > 16)
2548     blend = 16;
2549
2550   upper = ((0x07E0F81F * blend) >> 4) & 0x07E0F81F;
2551   blend = 16 - blend;
2552
2553   if(blend_a > 16)
2554     blend_a = 16;
2555
2556   if(blend_b > 16)
2557     blend_b = 16;
2558
2559   expand_partial_alpha(brighten);
2560 }
2561
2562
2563 // Render an OBJ layer from start to end, depending on the type (1D or 2D)
2564 // stored in dispcnt.
2565
2566 #define render_obj_layer(type, dest, _start, _end)                            \
2567   current_layer &= ~0x04;                                                     \
2568   if(dispcnt & 0x40)                                                          \
2569     render_scanline_obj_##type##_1D(current_layer, _start, _end, dest);       \
2570   else                                                                        \
2571     render_scanline_obj_##type##_2D(current_layer, _start, _end, dest)        \
2572
2573
2574 // Render a target all the way with the background color as taken from the
2575 // palette.
2576
2577 #define fill_line_bg(type, dest, _start, _end)                                \
2578   fill_line_##type(0, dest, _start, _end)                                     \
2579
2580
2581 // Render all layers as they appear in the layer order.
2582
2583 #define render_layers(tile_alpha, obj_alpha, dest)                            \
2584 {                                                                             \
2585   current_layer = layer_order[0];                                             \
2586   if(current_layer & 0x04)                                                    \
2587   {                                                                           \
2588     /* If the first one is OBJ render the background then render it. */       \
2589     fill_line_bg(tile_alpha, dest, 0, 240);                                   \
2590     render_obj_layer(obj_alpha, dest, 0, 240);                                \
2591   }                                                                           \
2592   else                                                                        \
2593   {                                                                           \
2594     /* Otherwise render a base layer. */                                      \
2595     layer_renderers[current_layer].tile_alpha##_render_base(current_layer,    \
2596      0, 240, dest);                                                           \
2597   }                                                                           \
2598                                                                               \
2599   /* Render the rest of the layers. */                                        \
2600   for(layer_order_pos = 1; layer_order_pos < layer_count; layer_order_pos++)  \
2601   {                                                                           \
2602     current_layer = layer_order[layer_order_pos];                             \
2603     if(current_layer & 0x04)                                                  \
2604     {                                                                         \
2605       render_obj_layer(obj_alpha, dest, 0, 240);                              \
2606     }                                                                         \
2607     else                                                                      \
2608     {                                                                         \
2609       layer_renderers[current_layer].                                         \
2610        tile_alpha##_render_transparent(current_layer, 0, 240, dest);          \
2611     }                                                                         \
2612   }                                                                           \
2613 }                                                                             \
2614
2615 #define render_condition_alpha                                                \
2616   (((io_registers[REG_BLDALPHA] & 0x1F1F) != 0x001F) &&                       \
2617    ((io_registers[REG_BLDCNT] & 0x3F) != 0) &&                                \
2618    ((io_registers[REG_BLDCNT] & 0x3F00) != 0))                                \
2619
2620 #define render_condition_fade                                                 \
2621   (((io_registers[REG_BLDY] & 0x1F) != 0) &&                                  \
2622    ((io_registers[REG_BLDCNT] & 0x3F) != 0))                                  \
2623
2624 #define render_layers_color_effect(renderer, layer_condition,                 \
2625  alpha_condition, fade_condition, _start, _end)                               \
2626 {                                                                             \
2627   if(layer_condition)                                                         \
2628   {                                                                           \
2629     if(obj_alpha_count[io_registers[REG_VCOUNT]] > 0)                         \
2630     {                                                                         \
2631       /* Render based on special effects mode. */                             \
2632       u32 screen_buffer[240];                                                 \
2633       switch((bldcnt >> 6) & 0x03)                                            \
2634       {                                                                       \
2635         /* Alpha blend */                                                     \
2636         case 0x01:                                                            \
2637         {                                                                     \
2638           if(alpha_condition)                                                 \
2639           {                                                                   \
2640             renderer(alpha, alpha_obj, screen_buffer);                        \
2641             expand_blend(screen_buffer, scanline, _start, _end);              \
2642             return;                                                           \
2643           }                                                                   \
2644           break;                                                              \
2645         }                                                                     \
2646                                                                               \
2647         /* Fade to white */                                                   \
2648         case 0x02:                                                            \
2649         {                                                                     \
2650           if(fade_condition)                                                  \
2651           {                                                                   \
2652             renderer(color32, partial_alpha, screen_buffer);                  \
2653             expand_brighten_partial_alpha(screen_buffer, scanline,            \
2654              _start, _end);                                                   \
2655             return;                                                           \
2656           }                                                                   \
2657           break;                                                              \
2658         }                                                                     \
2659                                                                               \
2660         /* Fade to black */                                                   \
2661         case 0x03:                                                            \
2662         {                                                                     \
2663           if(fade_condition)                                                  \
2664           {                                                                   \
2665             renderer(color32, partial_alpha, screen_buffer);                  \
2666             expand_darken_partial_alpha(screen_buffer, scanline,              \
2667              _start, _end);                                                   \
2668             return;                                                           \
2669           }                                                                   \
2670           break;                                                              \
2671         }                                                                     \
2672       }                                                                       \
2673                                                                               \
2674       renderer(color32, partial_alpha, screen_buffer);                        \
2675       expand_blend(screen_buffer, scanline, _start, _end);                    \
2676     }                                                                         \
2677     else                                                                      \
2678     {                                                                         \
2679       /* Render based on special effects mode. */                             \
2680       switch((bldcnt >> 6) & 0x03)                                            \
2681       {                                                                       \
2682         /* Alpha blend */                                                     \
2683         case 0x01:                                                            \
2684         {                                                                     \
2685           if(alpha_condition)                                                 \
2686           {                                                                   \
2687             u32 screen_buffer[240];                                           \
2688             renderer(alpha, alpha_obj, screen_buffer);                        \
2689             expand_blend(screen_buffer, scanline, _start, _end);              \
2690             return;                                                           \
2691           }                                                                   \
2692           break;                                                              \
2693         }                                                                     \
2694                                                                               \
2695         /* Fade to white */                                                   \
2696         case 0x02:                                                            \
2697         {                                                                     \
2698           if(fade_condition)                                                  \
2699           {                                                                   \
2700             renderer(color16, color16, scanline);                             \
2701             expand_brighten(scanline, scanline, _start, _end);                \
2702             return;                                                           \
2703           }                                                                   \
2704           break;                                                              \
2705         }                                                                     \
2706                                                                               \
2707         /* Fade to black */                                                   \
2708         case 0x03:                                                            \
2709         {                                                                     \
2710           if(fade_condition)                                                  \
2711           {                                                                   \
2712             renderer(color16, color16, scanline);                             \
2713             expand_darken(scanline, scanline, _start, _end);                  \
2714             return;                                                           \
2715           }                                                                   \
2716           break;                                                              \
2717         }                                                                     \
2718       }                                                                       \
2719                                                                               \
2720       renderer(normal, normal, scanline);                                     \
2721       expand_normal(scanline, _start, _end);                                  \
2722     }                                                                         \
2723   }                                                                           \
2724   else                                                                        \
2725   {                                                                           \
2726     u32 pixel_top = palette_ram_converted[0];                                 \
2727     switch((bldcnt >> 6) & 0x03)                                              \
2728     {                                                                         \
2729       /* Fade to white */                                                     \
2730       case 0x02:                                                              \
2731       {                                                                       \
2732         if(color_combine_mask_a(5))                                           \
2733         {                                                                     \
2734           u32 blend = io_registers[REG_BLDY] & 0x1F;                          \
2735           u32 upper;                                                          \
2736                                                                               \
2737           if(blend > 16)                                                      \
2738             blend = 16;                                                       \
2739                                                                               \
2740           upper = ((0x07E0F81F * blend) >> 4) & 0x07E0F81F;                   \
2741           blend = 16 - blend;                                                 \
2742                                                                               \
2743           expand_pixel_no_dest(brighten, pixel_top);                          \
2744         }                                                                     \
2745         break;                                                                \
2746       }                                                                       \
2747                                                                               \
2748       /* Fade to black */                                                     \
2749       case 0x03:                                                              \
2750       {                                                                       \
2751         if(color_combine_mask_a(5))                                           \
2752         {                                                                     \
2753           s32 blend = 16 - (io_registers[REG_BLDY] & 0x1F);                   \
2754                                                                               \
2755           if(blend < 0)                                                       \
2756             blend = 0;                                                        \
2757                                                                               \
2758           expand_pixel_no_dest(darken, pixel_top);                            \
2759         }                                                                     \
2760         break;                                                                \
2761       }                                                                       \
2762     }                                                                         \
2763     fill_line_color16(pixel_top, scanline, _start, _end);                     \
2764   }                                                                           \
2765 }                                                                             \
2766
2767
2768 // Renders an entire scanline from 0 to 240, based on current color mode.
2769
2770 static void render_scanline_tile(u16 *scanline, u32 dispcnt)
2771 {
2772   u32 current_layer;
2773   u32 layer_order_pos;
2774   u32 bldcnt = io_registers[REG_BLDCNT];
2775   render_scanline_layer_functions_tile();
2776
2777   render_layers_color_effect(render_layers, layer_count,
2778    render_condition_alpha, render_condition_fade, 0, 240);
2779 }
2780
2781 static void render_scanline_bitmap(u16 *scanline, u32 dispcnt)
2782 {
2783   render_scanline_layer_functions_bitmap();
2784   u32 current_layer;
2785   u32 layer_order_pos;
2786
2787   fill_line_bg(normal, scanline, 0, 240);
2788
2789   for(layer_order_pos = 0; layer_order_pos < layer_count; layer_order_pos++)
2790   {
2791     current_layer = layer_order[layer_order_pos];
2792     if(current_layer & 0x04)
2793     {
2794       render_obj_layer(normal, scanline, 0, 240);
2795     }
2796     else
2797     {
2798       layer_renderers->normal_render(0, 240, scanline);
2799     }
2800   }
2801 }
2802
2803 // Render layers from start to end based on if they're allowed in the
2804 // enable flags.
2805
2806 #define render_layers_conditional(tile_alpha, obj_alpha, dest)                \
2807 {                                                                             \
2808   __label__ skip;                                                             \
2809   current_layer = layer_order[layer_order_pos];                               \
2810   /* If OBJ aren't enabled skip to the first non-OBJ layer */                 \
2811   if(!(enable_flags & 0x10))                                                  \
2812   {                                                                           \
2813     while((current_layer & 0x04) || !((1 << current_layer) & enable_flags))   \
2814     {                                                                         \
2815       layer_order_pos++;                                                      \
2816       current_layer = layer_order[layer_order_pos];                           \
2817                                                                               \
2818       /* Oops, ran out of layers, render the background. */                   \
2819       if(layer_order_pos == layer_count)                                      \
2820       {                                                                       \
2821         fill_line_bg(tile_alpha, dest, start, end);                           \
2822         goto skip;                                                            \
2823       }                                                                       \
2824     }                                                                         \
2825                                                                               \
2826     /* Render the first valid layer */                                        \
2827     layer_renderers[current_layer].tile_alpha##_render_base(current_layer,    \
2828      start, end, dest);                                                       \
2829                                                                               \
2830     layer_order_pos++;                                                        \
2831                                                                               \
2832     /* Render the rest of the layers if active, skipping OBJ ones. */         \
2833     for(; layer_order_pos < layer_count; layer_order_pos++)                   \
2834     {                                                                         \
2835       current_layer = layer_order[layer_order_pos];                           \
2836       if(!(current_layer & 0x04) && ((1 << current_layer) & enable_flags))    \
2837       {                                                                       \
2838         layer_renderers[current_layer].                                       \
2839          tile_alpha##_render_transparent(current_layer, start, end, dest);    \
2840       }                                                                       \
2841     }                                                                         \
2842   }                                                                           \
2843   else                                                                        \
2844   {                                                                           \
2845     /* Find the first active layer, skip all of the inactive ones */          \
2846     while(!((current_layer & 0x04) || ((1 << current_layer) & enable_flags))) \
2847     {                                                                         \
2848       layer_order_pos++;                                                      \
2849       current_layer = layer_order[layer_order_pos];                           \
2850                                                                               \
2851       /* Oops, ran out of layers, render the background. */                   \
2852       if(layer_order_pos == layer_count)                                      \
2853       {                                                                       \
2854         fill_line_bg(tile_alpha, dest, start, end);                           \
2855         goto skip;                                                            \
2856       }                                                                       \
2857     }                                                                         \
2858                                                                               \
2859     if(current_layer & 0x04)                                                  \
2860     {                                                                         \
2861       /* If the first one is OBJ render the background then render it. */     \
2862       fill_line_bg(tile_alpha, dest, start, end);                             \
2863       render_obj_layer(obj_alpha, dest, start, end);                          \
2864     }                                                                         \
2865     else                                                                      \
2866     {                                                                         \
2867       /* Otherwise render a base layer. */                                    \
2868       layer_renderers[current_layer].                                         \
2869        tile_alpha##_render_base(current_layer, start, end, dest);             \
2870     }                                                                         \
2871                                                                               \
2872     layer_order_pos++;                                                        \
2873                                                                               \
2874     /* Render the rest of the layers. */                                      \
2875     for(; layer_order_pos < layer_count; layer_order_pos++)                   \
2876     {                                                                         \
2877       current_layer = layer_order[layer_order_pos];                           \
2878       if(current_layer & 0x04)                                                \
2879       {                                                                       \
2880         render_obj_layer(obj_alpha, dest, start, end);                        \
2881       }                                                                       \
2882       else                                                                    \
2883       {                                                                       \
2884         if(enable_flags & (1 << current_layer))                               \
2885         {                                                                     \
2886           layer_renderers[current_layer].                                     \
2887            tile_alpha##_render_transparent(current_layer, start, end, dest);  \
2888         }                                                                     \
2889       }                                                                       \
2890     }                                                                         \
2891   }                                                                           \
2892                                                                               \
2893   skip:                                                                       \
2894     ;                                                                         \
2895 }                                                                             \
2896
2897
2898 // Render all of the BG and OBJ in a tiled scanline from start to end ONLY if
2899 // enable_flag allows that layer/OBJ. Also conditionally render color effects.
2900
2901 static void render_scanline_conditional_tile(u32 start, u32 end, u16 *scanline,
2902  u32 enable_flags, u32 dispcnt, u32 bldcnt, const tile_layer_render_struct
2903  *layer_renderers)
2904 {
2905   u32 current_layer;
2906   u32 layer_order_pos = 0;
2907
2908   render_layers_color_effect(render_layers_conditional,
2909    (layer_count && (enable_flags & 0x1F)),
2910    ((enable_flags & 0x20) && render_condition_alpha),
2911    ((enable_flags & 0x20) && render_condition_fade), start, end);
2912 }
2913
2914
2915 // Render the BG and OBJ in a bitmap scanline from start to end ONLY if
2916 // enable_flag allows that layer/OBJ. Also conditionally render color effects.
2917
2918 static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline,
2919  u32 enable_flags, u32 dispcnt, u32 bldcnt, const bitmap_layer_render_struct
2920  *layer_renderers)
2921 {
2922   u32 current_layer;
2923   u32 layer_order_pos;
2924
2925   fill_line_bg(normal, scanline, start, end);
2926
2927   for(layer_order_pos = 0; layer_order_pos < layer_count; layer_order_pos++)
2928   {
2929     current_layer = layer_order[layer_order_pos];
2930     if(current_layer & 0x04)
2931     {
2932       if(enable_flags & 0x10)
2933       {
2934         render_obj_layer(normal, scanline, start, end);
2935       }
2936     }
2937     else
2938     {
2939       if(enable_flags & 0x04)
2940         layer_renderers->normal_render(start, end, scanline);
2941     }
2942   }
2943 }
2944
2945
2946 #define window_x_coords(window_number)                                        \
2947   window_##window_number##_x1 =                                               \
2948    io_registers[REG_WIN##window_number##H] >> 8;                              \
2949   window_##window_number##_x2 =                                               \
2950    io_registers[REG_WIN##window_number##H] & 0xFF;                            \
2951   window_##window_number##_enable =                                           \
2952    (winin >> (window_number * 8)) & 0x3F;                                     \
2953                                                                               \
2954   if(window_##window_number##_x1 > 240)                                       \
2955     window_##window_number##_x1 = 240;                                        \
2956                                                                               \
2957   if(window_##window_number##_x2 > 240)                                       \
2958     window_##window_number##_x2 = 240                                         \
2959
2960 #define window_coords(window_number)                                          \
2961   u32 window_##window_number##_x1, window_##window_number##_x2;               \
2962   u32 window_##window_number##_y1, window_##window_number##_y2;               \
2963   u32 window_##window_number##_enable = 0;                                    \
2964   window_##window_number##_y1 =                                               \
2965    io_registers[REG_WIN##window_number##V] >> 8;                              \
2966   window_##window_number##_y2 =                                               \
2967    io_registers[REG_WIN##window_number##V] & 0xFF;                            \
2968                                                                               \
2969   if(window_##window_number##_y1 > window_##window_number##_y2)               \
2970   {                                                                           \
2971     if((((vcount <= window_##window_number##_y2) ||                           \
2972      (vcount > window_##window_number##_y1)) ||                               \
2973      (window_##window_number##_y2 > 227)) &&                                  \
2974      (window_##window_number##_y1 <= 227))                                    \
2975     {                                                                         \
2976       window_x_coords(window_number);                                         \
2977     }                                                                         \
2978     else                                                                      \
2979     {                                                                         \
2980       window_##window_number##_x1 = 240;                                      \
2981       window_##window_number##_x2 = 240;                                      \
2982     }                                                                         \
2983   }                                                                           \
2984   else                                                                        \
2985   {                                                                           \
2986     if((((vcount >= window_##window_number##_y1) &&                           \
2987      (vcount < window_##window_number##_y2)) ||                               \
2988      (window_##window_number##_y2 > 227)) &&                                  \
2989      (window_##window_number##_y1 <= 227))                                    \
2990     {                                                                         \
2991       window_x_coords(window_number);                                         \
2992     }                                                                         \
2993     else                                                                      \
2994     {                                                                         \
2995       window_##window_number##_x1 = 240;                                      \
2996       window_##window_number##_x2 = 240;                                      \
2997     }                                                                         \
2998   }                                                                           \
2999
3000 #define render_window_segment(type, start, end, window_type)                  \
3001   if(start != end)                                                            \
3002   {                                                                           \
3003     render_scanline_conditional_##type(start, end, scanline,                  \
3004      window_##window_type##_enable, dispcnt, bldcnt, layer_renderers);        \
3005   }                                                                           \
3006
3007 #define render_window_segment_unequal(type, start, end, window_type)          \
3008   render_scanline_conditional_##type(start, end, scanline,                    \
3009    window_##window_type##_enable, dispcnt, bldcnt, layer_renderers)           \
3010
3011 #define render_window_segment_clip(type, clip_start, clip_end, start, end,    \
3012  window_type)                                                                 \
3013 {                                                                             \
3014   if(start != end)                                                            \
3015   {                                                                           \
3016     if(start < clip_start)                                                    \
3017     {                                                                         \
3018       if(end > clip_start)                                                    \
3019       {                                                                       \
3020         if(end > clip_end)                                                    \
3021         {                                                                     \
3022           render_window_segment_unequal(type, clip_start, clip_end,           \
3023            window_type);                                                      \
3024         }                                                                     \
3025         else                                                                  \
3026         {                                                                     \
3027           render_window_segment_unequal(type, clip_start, end, window_type);  \
3028         }                                                                     \
3029       }                                                                       \
3030     }                                                                         \
3031     else                                                                      \
3032                                                                               \
3033     if(end > clip_end)                                                        \
3034     {                                                                         \
3035       if(start < clip_end)                                                    \
3036         render_window_segment_unequal(type, start, clip_end, window_type);    \
3037     }                                                                         \
3038     else                                                                      \
3039     {                                                                         \
3040       render_window_segment_unequal(type, start, end, window_type);           \
3041     }                                                                         \
3042   }                                                                           \
3043 }                                                                             \
3044
3045 #define render_window_clip_1(type, start, end)                                \
3046   if(window_1_x1 != 240)                                                      \
3047   {                                                                           \
3048     if(window_1_x1 > window_1_x2)                                             \
3049     {                                                                         \
3050       render_window_segment_clip(type, start, end, 0, window_1_x2, 1);        \
3051       render_window_segment_clip(type, start, end, window_1_x2, window_1_x1,  \
3052        out);                                                                  \
3053       render_window_segment_clip(type, start, end, window_1_x1, 240, 1);      \
3054     }                                                                         \
3055     else                                                                      \
3056     {                                                                         \
3057       render_window_segment_clip(type, start, end, 0, window_1_x1, out);      \
3058       render_window_segment_clip(type, start, end, window_1_x1, window_1_x2,  \
3059        1);                                                                    \
3060       render_window_segment_clip(type, start, end, window_1_x2, 240, out);    \
3061     }                                                                         \
3062   }                                                                           \
3063   else                                                                        \
3064   {                                                                           \
3065     render_window_segment(type, start, end, out);                             \
3066   }                                                                           \
3067
3068 #define render_window_clip_obj(type, start, end);                             \
3069   render_window_segment(type, start, end, out);                               \
3070   if(dispcnt & 0x40)                                                          \
3071     render_scanline_obj_copy_##type##_1D(4, start, end, scanline);            \
3072   else                                                                        \
3073     render_scanline_obj_copy_##type##_2D(4, start, end, scanline)             \
3074
3075
3076 #define render_window_segment_clip_obj(type, clip_start, clip_end, start,     \
3077  end)                                                                         \
3078 {                                                                             \
3079   if(start != end)                                                            \
3080   {                                                                           \
3081     if(start < clip_start)                                                    \
3082     {                                                                         \
3083       if(end > clip_start)                                                    \
3084       {                                                                       \
3085         if(end > clip_end)                                                    \
3086         {                                                                     \
3087           render_window_clip_obj(type, clip_start, clip_end);                 \
3088         }                                                                     \
3089         else                                                                  \
3090         {                                                                     \
3091           render_window_clip_obj(type, clip_start, end);                      \
3092         }                                                                     \
3093       }                                                                       \
3094     }                                                                         \
3095     else                                                                      \
3096                                                                               \
3097     if(end > clip_end)                                                        \
3098     {                                                                         \
3099       if(start < clip_end)                                                    \
3100       {                                                                       \
3101         render_window_clip_obj(type, start, clip_end);                        \
3102       }                                                                       \
3103     }                                                                         \
3104     else                                                                      \
3105     {                                                                         \
3106       render_window_clip_obj(type, start, end);                               \
3107     }                                                                         \
3108   }                                                                           \
3109 }                                                                             \
3110
3111
3112 #define render_window_clip_1_obj(type, start, end)                            \
3113   if(window_1_x1 != 240)                                                      \
3114   {                                                                           \
3115     if(window_1_x1 > window_1_x2)                                             \
3116     {                                                                         \
3117       render_window_segment_clip(type, start, end, 0, window_1_x2, 1);        \
3118       render_window_segment_clip_obj(type, start, end, window_1_x2,           \
3119        window_1_x1);                                                          \
3120       render_window_segment_clip(type, start, end, window_1_x1, 240, 1);      \
3121     }                                                                         \
3122     else                                                                      \
3123     {                                                                         \
3124       render_window_segment_clip_obj(type, start, end, 0, window_1_x1);       \
3125       render_window_segment_clip(type, start, end, window_1_x1, window_1_x2,  \
3126        1);                                                                    \
3127       render_window_segment_clip_obj(type, start, end, window_1_x2, 240);     \
3128     }                                                                         \
3129   }                                                                           \
3130   else                                                                        \
3131   {                                                                           \
3132     render_window_clip_obj(type, start, end);                                 \
3133   }                                                                           \
3134
3135
3136
3137 #define render_window_single(type, window_number)                             \
3138   u32 winin = io_registers[REG_WININ];                                        \
3139   window_coords(window_number);                                               \
3140   if(window_##window_number##_x1 > window_##window_number##_x2)               \
3141   {                                                                           \
3142     render_window_segment(type, 0, window_##window_number##_x2,               \
3143      window_number);                                                          \
3144     render_window_segment(type, window_##window_number##_x2,                  \
3145      window_##window_number##_x1, out);                                       \
3146     render_window_segment(type, window_##window_number##_x1, 240,             \
3147      window_number);                                                          \
3148   }                                                                           \
3149   else                                                                        \
3150   {                                                                           \
3151     render_window_segment(type, 0, window_##window_number##_x1, out);         \
3152     render_window_segment(type, window_##window_number##_x1,                  \
3153      window_##window_number##_x2, window_number);                             \
3154     render_window_segment(type, window_##window_number##_x2, 240, out);       \
3155   }                                                                           \
3156
3157 #define render_window_multi(type, front, back)                                \
3158   if(window_##front##_x1 > window_##front##_x2)                               \
3159   {                                                                           \
3160     render_window_segment(type, 0, window_##front##_x2, front);               \
3161     render_window_clip_##back(type, window_##front##_x2,                      \
3162      window_##front##_x1);                                                    \
3163     render_window_segment(type, window_##front##_x1, 240, front);             \
3164   }                                                                           \
3165   else                                                                        \
3166   {                                                                           \
3167     render_window_clip_##back(type, 0, window_##front##_x1);                  \
3168     render_window_segment(type, window_##front##_x1, window_##front##_x2,     \
3169      front);                                                                  \
3170     render_window_clip_##back(type, window_##front##_x2, 240);                \
3171   }                                                                           \
3172
3173 #define render_scanline_window_builder(type)                                  \
3174 static void render_scanline_window_##type(u16 *scanline, u32 dispcnt)         \
3175 {                                                                             \
3176   u32 vcount = io_registers[REG_VCOUNT];                                      \
3177   u32 winout = io_registers[REG_WINOUT];                                      \
3178   u32 bldcnt = io_registers[REG_BLDCNT];                                      \
3179   u32 window_out_enable = winout & 0x3F;                                      \
3180                                                                               \
3181   render_scanline_layer_functions_##type();                                   \
3182                                                                               \
3183   switch(dispcnt >> 13)                                                       \
3184   {                                                                           \
3185     /* Just window 0 */                                                       \
3186     case 0x01:                                                                \
3187     {                                                                         \
3188       render_window_single(type, 0);                                          \
3189       break;                                                                  \
3190     }                                                                         \
3191                                                                               \
3192     /* Just window 1 */                                                       \
3193     case 0x02:                                                                \
3194     {                                                                         \
3195       render_window_single(type, 1);                                          \
3196       break;                                                                  \
3197     }                                                                         \
3198                                                                               \
3199     /* Windows 1 and 2 */                                                     \
3200     case 0x03:                                                                \
3201     {                                                                         \
3202       u32 winin = io_registers[REG_WININ];                                    \
3203       window_coords(0);                                                       \
3204       window_coords(1);                                                       \
3205       render_window_multi(type, 0, 1);                                        \
3206       break;                                                                  \
3207     }                                                                         \
3208                                                                               \
3209     /* Just OBJ windows */                                                    \
3210     case 0x04:                                                                \
3211     {                                                                         \
3212       render_window_clip_obj(type, 0, 240);                                   \
3213       break;                                                                  \
3214     }                                                                         \
3215                                                                               \
3216     /* Window 0 and OBJ window */                                             \
3217     case 0x05:                                                                \
3218     {                                                                         \
3219       u32 winin = io_registers[REG_WININ];                                    \
3220       window_coords(0);                                                       \
3221       render_window_multi(type, 0, obj);                                      \
3222       break;                                                                  \
3223     }                                                                         \
3224                                                                               \
3225     /* Window 1 and OBJ window */                                             \
3226     case 0x06:                                                                \
3227     {                                                                         \
3228       u32 winin = io_registers[REG_WININ];                                    \
3229       window_coords(1);                                                       \
3230       render_window_multi(type, 1, obj);                                      \
3231       break;                                                                  \
3232     }                                                                         \
3233                                                                               \
3234     /* Window 0, 1, and OBJ window */                                         \
3235     case 0x07:                                                                \
3236     {                                                                         \
3237       u32 winin = io_registers[REG_WININ];                                    \
3238       window_coords(0);                                                       \
3239       window_coords(1);                                                       \
3240       render_window_multi(type, 0, 1_obj);                                    \
3241       break;                                                                  \
3242     }                                                                         \
3243   }                                                                           \
3244 }                                                                             \
3245
3246 render_scanline_window_builder(tile);
3247 render_scanline_window_builder(bitmap);
3248
3249 static const u32 active_layers[6] = { 0x1F, 0x17, 0x1C, 0x14, 0x14, 0x14 };
3250
3251 u32 small_resolution_width = 240;
3252 u32 small_resolution_height = 160;
3253 u32 resolution_width, resolution_height;
3254
3255 void update_scanline()
3256 {
3257   u32 pitch = get_screen_pitch();
3258   u32 dispcnt = io_registers[REG_DISPCNT];
3259   u32 vcount = io_registers[REG_VCOUNT];
3260   u16 *screen_offset = get_screen_pixels() + (vcount * pitch);
3261   u32 video_mode = dispcnt & 0x07;
3262
3263   // If OAM has been modified since the last scanline has been updated then
3264   // reorder and reprofile the OBJ lists.
3265   if(oam_update)
3266   {
3267     order_obj(video_mode);
3268     oam_update = 0;
3269   }
3270
3271   order_layers((dispcnt >> 8) & active_layers[video_mode]);
3272
3273   if(skip_next_frame)
3274     return;
3275
3276 #ifdef WIZ_BUILD
3277   if (screen_scale == unscaled_rot || screen_scale == scaled_aspect_rot)
3278   {
3279     if (rot_line_count == rot_lines_total)
3280     {
3281       rot_line_count = 0;
3282       if (vcount - rot_lines_total < FONT_HEIGHT && rot_msg_buff[0])
3283       {
3284         print_string_ext(rot_msg_buff, 0xFFFF, 0x0000, 0, 0,
3285           rot_buffer, 240, 0, vcount - rot_lines_total, rot_lines_total);
3286         if (vcount >= FONT_HEIGHT)
3287           rot_msg_buff[0] = 0;
3288       }
3289       if (screen_scale == unscaled_rot)
3290         do_rotated_blit(gpsp_gp2x_screen, rot_buffer, vcount);
3291       else
3292         upscale_aspect_row(gpsp_gp2x_screen, rot_buffer, vcount/3);
3293     }
3294     screen_offset = &rot_buffer[rot_line_count++ * 240];
3295   }
3296 #endif
3297
3298   // If the screen is in in forced blank draw pure white.
3299   if(dispcnt & 0x80)
3300   {
3301     fill_line_color16(0xFFFF, screen_offset, 0, 240);
3302   }
3303   else
3304   {
3305     if(video_mode < 3)
3306     {
3307       if(dispcnt >> 13)
3308       {
3309         render_scanline_window_tile(screen_offset, dispcnt);
3310       }
3311       else
3312       {
3313         render_scanline_tile(screen_offset, dispcnt);
3314       }
3315     }
3316     else
3317     {
3318       if(dispcnt >> 13)
3319         render_scanline_window_bitmap(screen_offset, dispcnt);
3320       else
3321         render_scanline_bitmap(screen_offset, dispcnt);
3322     }
3323   }
3324
3325   affine_reference_x[0] += (s16)io_registers[REG_BG2PB];
3326   affine_reference_y[0] += (s16)io_registers[REG_BG2PD];
3327   affine_reference_x[1] += (s16)io_registers[REG_BG3PB];
3328   affine_reference_y[1] += (s16)io_registers[REG_BG3PD];
3329 }
3330
3331 #ifdef PSP_BUILD
3332
3333 u32 screen_flip = 0;
3334
3335 void flip_screen()
3336 {
3337   if(video_direct == 0)
3338   {
3339     u32 *old_ge_cmd_ptr = ge_cmd_ptr;
3340     sceKernelDcacheWritebackAll();
3341
3342     // Render the current screen
3343     ge_cmd_ptr = ge_cmd + 2;
3344     GE_CMD(TBP0, ((u32)screen_pixels & 0x00FFFFFF));
3345     GE_CMD(TBW0, (((u32)screen_pixels & 0xFF000000) >> 8) |
3346      GBA_SCREEN_WIDTH);
3347     ge_cmd_ptr = old_ge_cmd_ptr;
3348
3349     sceGeListEnQueue(ge_cmd, ge_cmd_ptr, gecbid, NULL);
3350
3351     // Flip to the next screen
3352     screen_flip ^= 1;
3353
3354     if(screen_flip)
3355       screen_pixels = screen_texture + (240 * 160 * 2);
3356     else
3357       screen_pixels = screen_texture;
3358   }
3359 }
3360
3361 #elif defined(POLLUX_BUILD)
3362
3363 void flip_screen()
3364 {
3365   if((resolution_width == small_resolution_width) &&
3366    (resolution_height == small_resolution_height))
3367   {
3368     switch(screen_scale)
3369     {
3370       case unscaled:
3371         break;
3372       case scaled_aspect:
3373         upscale_aspect(gpsp_gp2x_screen, screen_pixels);
3374         break;
3375       case unscaled_rot:
3376         do_rotated_blit(gpsp_gp2x_screen, rot_buffer, 160);
3377         rot_line_count = 0;
3378         goto no_clean;
3379       case scaled_aspect_rot:
3380         rot_line_count = 0;
3381         goto no_clean;
3382     }
3383   }
3384   warm_cache_op_all(WOP_D_CLEAN);
3385
3386 no_clean:
3387   pollux_video_flip();
3388   screen_pixels = (u16 *)gpsp_gp2x_screen + screen_offset;
3389 }
3390
3391 #elif defined(PND_BUILD)
3392
3393 void flip_screen()
3394 {
3395   screen_pixels = fb_flip_screen();
3396 }
3397
3398 #else
3399
3400 #define integer_scale_copy_2()                                                \
3401   current_scanline_ptr[x2] = current_pixel;                                   \
3402   current_scanline_ptr[x2 - 1] = current_pixel;                               \
3403   x2 -= 2                                                                     \
3404
3405 #define integer_scale_copy_3()                                                \
3406   current_scanline_ptr[x2] = current_pixel;                                   \
3407   current_scanline_ptr[x2 - 1] = current_pixel;                               \
3408   current_scanline_ptr[x2 - 2] = current_pixel;                               \
3409   x2 -= 3                                                                     \
3410
3411 #define integer_scale_copy_4()                                                \
3412   current_scanline_ptr[x2] = current_pixel;                                   \
3413   current_scanline_ptr[x2 - 1] = current_pixel;                               \
3414   current_scanline_ptr[x2 - 2] = current_pixel;                               \
3415   current_scanline_ptr[x2 - 3] = current_pixel;                               \
3416   x2 -= 4                                                                     \
3417
3418 #define integer_scale_horizontal(scale_factor)                                \
3419   for(y = 0; y < 160; y++)                                                    \
3420   {                                                                           \
3421     for(x = 239, x2 = (240 * video_scale) - 1; x >= 0; x--)                   \
3422     {                                                                         \
3423       current_pixel = current_scanline_ptr[x];                                \
3424       integer_scale_copy_##scale_factor();                                    \
3425       current_scanline_ptr[x2] = current_scanline_ptr[x];                     \
3426       current_scanline_ptr[x2 - 1] = current_scanline_ptr[x];                 \
3427       current_scanline_ptr[x2 - 2] = current_scanline_ptr[x];                 \
3428     }                                                                         \
3429     current_scanline_ptr += pitch;                                            \
3430   }                                                                           \
3431
3432 void flip_screen()
3433 {
3434   if((video_scale != 1) && (current_scale != unscaled))
3435   {
3436     s32 x, y;
3437     s32 x2, y2;
3438     u16 *screen_ptr = get_screen_pixels();
3439     u16 *current_scanline_ptr = screen_ptr;
3440     u32 pitch = get_screen_pitch();
3441     u16 current_pixel;
3442     u32 i;
3443
3444     switch(video_scale)
3445     {
3446       case 2:
3447         integer_scale_horizontal(2);
3448         break;
3449
3450       case 3:
3451         integer_scale_horizontal(3);
3452         break;
3453
3454       default:
3455       case 4:
3456         integer_scale_horizontal(4);
3457         break;
3458
3459     }
3460
3461     for(y = 159, y2 = (160 * video_scale) - 1; y >= 0; y--)
3462     {
3463       for(i = 0; i < video_scale; i++)
3464       {
3465         memcpy(screen_ptr + (y2 * pitch),
3466          screen_ptr + (y * pitch), 480 * video_scale);
3467         y2--;
3468       }
3469     }
3470   }
3471 #ifdef GP2X_BUILD
3472   {
3473     if((resolution_width == small_resolution_width) &&
3474      (resolution_height == small_resolution_height))
3475     {
3476       switch (screen_scale)
3477       {
3478         case unscaled:
3479         {
3480           SDL_Rect srect = {0, 0, 240, 160};
3481           SDL_Rect drect = {40, 40, 240, 160};
3482           warm_cache_op_all(WOP_D_CLEAN);
3483           SDL_BlitSurface(screen, &srect, hw_screen, &drect);
3484           return;
3485         }
3486         case scaled_aspect:
3487         {
3488           SDL_Rect drect = {0, 10, 0, 0};
3489           warm_cache_op_all(WOP_D_CLEAN);
3490           SDL_BlitSurface(screen, NULL, hw_screen, &drect);
3491           return;
3492         }
3493         case scaled_aspect_sw:
3494         {
3495           upscale_aspect(hw_screen->pixels, get_screen_pixels());
3496           return;
3497         }
3498         case fullscreen:
3499           break;
3500       }
3501     }
3502     warm_cache_op_all(WOP_D_CLEAN);
3503     SDL_BlitSurface(screen, NULL, hw_screen, NULL);
3504   }
3505 #else
3506   SDL_Flip(screen);
3507 #endif
3508 }
3509
3510 #endif
3511
3512 u32 frame_to_render;
3513
3514 void update_screen()
3515 {
3516   if(!skip_next_frame)
3517     flip_screen();
3518 }
3519
3520 #ifdef PSP_BUILD
3521
3522 void init_video()
3523 {
3524   sceDisplaySetMode(0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
3525
3526   sceDisplayWaitVblankStart();
3527   sceDisplaySetFrameBuf((void*)psp_gu_vram_base, PSP_LINE_SIZE,
3528    PSP_DISPLAY_PIXEL_FORMAT_565, PSP_DISPLAY_SETBUF_NEXTFRAME);
3529
3530   sceGuInit();
3531
3532   sceGuStart(GU_DIRECT, display_list);
3533   sceGuDrawBuffer(GU_PSM_5650, (void*)0, PSP_LINE_SIZE);
3534   sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
3535    (void*)0, PSP_LINE_SIZE);
3536   sceGuClear(GU_COLOR_BUFFER_BIT);
3537
3538   sceGuOffset(2048 - (PSP_SCREEN_WIDTH / 2), 2048 - (PSP_SCREEN_HEIGHT / 2));
3539   sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
3540
3541   sceGuScissor(0, 0, PSP_SCREEN_WIDTH + 1, PSP_SCREEN_HEIGHT + 1);
3542   sceGuEnable(GU_SCISSOR_TEST);
3543   sceGuTexMode(GU_PSM_5650, 0, 0, GU_FALSE);
3544   sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
3545   sceGuTexFilter(GU_LINEAR, GU_LINEAR);
3546   sceGuEnable(GU_TEXTURE_2D);
3547
3548   sceGuFrontFace(GU_CW);
3549   sceGuDisable(GU_BLEND);
3550
3551   sceGuFinish();
3552   sceGuSync(0, 0);
3553
3554   sceDisplayWaitVblankStart();
3555   sceGuDisplay(GU_TRUE);
3556
3557   PspGeCallbackData gecb;
3558   gecb.signal_func = NULL;
3559   gecb.signal_arg = NULL;
3560   gecb.finish_func = Ge_Finish_Callback;
3561   gecb.finish_arg = NULL;
3562   gecbid = sceGeSetCallback(&gecb);
3563
3564   screen_vertex[0] = 0 + 0.5;
3565   screen_vertex[1] = 0 + 0.5;
3566   screen_vertex[2] = 0 + 0.5;
3567   screen_vertex[3] = 0 + 0.5;
3568   screen_vertex[4] = 0;
3569   screen_vertex[5] = GBA_SCREEN_WIDTH - 0.5;
3570   screen_vertex[6] = GBA_SCREEN_HEIGHT - 0.5;
3571   screen_vertex[7] = PSP_SCREEN_WIDTH - 0.5;
3572   screen_vertex[8] = PSP_SCREEN_HEIGHT - 0.5;
3573   screen_vertex[9] = 0;
3574
3575   // Set framebuffer to PSP VRAM
3576   GE_CMD(FBP, ((u32)psp_gu_vram_base & 0x00FFFFFF));
3577   GE_CMD(FBW, (((u32)psp_gu_vram_base & 0xFF000000) >> 8) | PSP_LINE_SIZE);
3578   // Set texture 0 to the screen texture
3579   GE_CMD(TBP0, ((u32)screen_texture & 0x00FFFFFF));
3580   GE_CMD(TBW0, (((u32)screen_texture & 0xFF000000) >> 8) | GBA_SCREEN_WIDTH);
3581   // Set the texture size to 256 by 256 (2^8 by 2^8)
3582   GE_CMD(TSIZE0, (8 << 8) | 8);
3583   // Flush the texture cache
3584   GE_CMD(TFLUSH, 0);
3585   // Use 2D coordinates, no indeces, no weights, 32bit float positions,
3586   // 32bit float texture coordinates
3587   GE_CMD(VTYPE, (1 << 23) | (0 << 11) | (0 << 9) |
3588    (3 << 7) | (0 << 5) | (0 << 2) | 3);
3589   // Set the base of the index list pointer to 0
3590   GE_CMD(BASE, 0);
3591   // Set the rest of index list pointer to 0 (not being used)
3592   GE_CMD(IADDR, 0);
3593   // Set the base of the screen vertex list pointer
3594   GE_CMD(BASE, ((u32)screen_vertex & 0xFF000000) >> 8);
3595   // Set the rest of the screen vertex list pointer
3596   GE_CMD(VADDR, ((u32)screen_vertex & 0x00FFFFFF));
3597   // Primitive kick: render sprite (primitive 6), 2 vertices
3598   GE_CMD(PRIM, (6 << 16) | 2);
3599   // Done with commands
3600   GE_CMD(FINISH, 0);
3601   // Raise signal interrupt
3602   GE_CMD(SIGNAL, 0);
3603   GE_CMD(NOP, 0);
3604   GE_CMD(NOP, 0);
3605 }
3606
3607 #elif defined(POLLUX_BUILD) || defined(PND_BUILD)
3608
3609 void init_video()
3610 {
3611 }
3612
3613 #else
3614
3615 void init_video()
3616 {
3617   SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE);
3618
3619 #ifdef GP2X_BUILD
3620   SDL_GP2X_AllowGfxMemory(NULL, 0);
3621
3622   hw_screen = SDL_SetVideoMode(320 * video_scale, 240 * video_scale,
3623    16, SDL_HWSURFACE);
3624
3625   screen = SDL_CreateRGBSurface(SDL_HWSURFACE, 240 * video_scale,
3626    160 * video_scale, 16, 0xFFFF, 0xFFFF, 0xFFFF, 0);
3627
3628   warm_change_cb_upper(WCB_C_BIT|WCB_B_BIT, 1);
3629 #else
3630   screen = SDL_SetVideoMode(240 * video_scale, 160 * video_scale, 16, 0);
3631 #endif
3632   SDL_ShowCursor(0);
3633 }
3634
3635 #endif
3636
3637 video_scale_type screen_scale = scaled_aspect;
3638 video_scale_type current_scale = scaled_aspect;
3639 video_filter_type screen_filter = filter_bilinear;
3640 video_filter_type2 screen_filter2 = filter2_none;
3641
3642
3643 #ifdef PSP_BUILD
3644
3645 void video_resolution_large()
3646 {
3647   if(video_direct != 1)
3648   {
3649     video_direct = 1;
3650     screen_pixels = psp_gu_vram_base;
3651     screen_pitch = 512;
3652     sceGuStart(GU_DIRECT, display_list);
3653     sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
3654      (void*)0, PSP_LINE_SIZE);
3655     sceGuFinish();
3656   }
3657 }
3658
3659 void set_gba_resolution(video_scale_type scale)
3660 {
3661   u32 filter_linear = 0;
3662   screen_scale = scale;
3663   switch(scale)
3664   {
3665     case unscaled:
3666       screen_vertex[2] = 120 + 0.5;
3667       screen_vertex[3] = 56 + 0.5;
3668       screen_vertex[7] = GBA_SCREEN_WIDTH + 120 - 0.5;
3669       screen_vertex[8] = GBA_SCREEN_HEIGHT + 56 - 0.5;
3670       break;
3671
3672     case scaled_aspect:
3673       screen_vertex[2] = 36 + 0.5;
3674       screen_vertex[3] = 0 + 0.5;
3675       screen_vertex[7] = 408 + 36 - 0.5;
3676       screen_vertex[8] = PSP_SCREEN_HEIGHT - 0.5;
3677       break;
3678
3679     case fullscreen:
3680       screen_vertex[2] = 0;
3681       screen_vertex[3] = 0;
3682       screen_vertex[7] = PSP_SCREEN_WIDTH;
3683       screen_vertex[8] = PSP_SCREEN_HEIGHT;
3684       break;
3685   }
3686
3687   sceGuStart(GU_DIRECT, display_list);
3688   if(screen_filter == filter_bilinear)
3689     sceGuTexFilter(GU_LINEAR, GU_LINEAR);
3690   else
3691     sceGuTexFilter(GU_NEAREST, GU_NEAREST);
3692
3693   sceGuFinish();
3694   sceGuSync(0, 0);
3695
3696   clear_screen(0x0000);
3697 }
3698
3699 void video_resolution_small()
3700 {
3701   if(video_direct != 0)
3702   {
3703     set_gba_resolution(screen_scale);
3704     video_direct = 0;
3705     screen_pixels = screen_texture;
3706     screen_flip = 0;
3707     screen_pitch = 240;
3708     sceGuStart(GU_DIRECT, display_list);
3709     sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
3710      (void*)0, PSP_LINE_SIZE);
3711     sceGuFinish();
3712   }
3713 }
3714
3715 void clear_screen(u16 color)
3716 {
3717   u32 i;
3718   u16 *src_ptr = get_screen_pixels();
3719
3720   sceGuSync(0, 0);
3721
3722   for(i = 0; i < (512 * 272); i++, src_ptr++)
3723   {
3724     *src_ptr = color;
3725   }
3726
3727   // I don't know why this doesn't work.
3728 /*  color = (((color & 0x1F) * 255 / 31) << 0) |
3729    ((((color >> 5) & 0x3F) * 255 / 63) << 8) |
3730    ((((color >> 11) & 0x1F) * 255 / 31) << 16) | (0xFF << 24);
3731
3732   sceGuStart(GU_DIRECT, display_list);
3733   sceGuDrawBuffer(GU_PSM_5650, (void*)0, PSP_LINE_SIZE);
3734   //sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
3735   // (void*)0, PSP_LINE_SIZE);
3736   sceGuClearColor(color);
3737   sceGuClear(GU_COLOR_BUFFER_BIT);
3738   sceGuFinish();
3739   sceGuSync(0, 0); */
3740 }
3741
3742 #elif defined(POLLUX_BUILD)
3743
3744 void video_resolution_large()
3745 {
3746   screen_offset = 0;
3747   resolution_width = 320;
3748   resolution_height = 240;
3749
3750   fb_use_buffers(1);
3751   flip_screen();
3752   clear_screen(0);
3753   wiz_lcd_set_portrait(0);
3754 }
3755
3756 void video_resolution_small()
3757 {
3758   fb_use_buffers(4);
3759
3760   switch (screen_scale)
3761   {
3762     case unscaled:
3763       screen_offset = 320*40 + 40;
3764       wiz_lcd_set_portrait(0);
3765       break;
3766     case scaled_aspect:
3767       screen_offset = 320*(80 - 14) + 80;
3768       wiz_lcd_set_portrait(0);
3769       break;
3770     case unscaled_rot:
3771       wiz_lcd_set_portrait(1);
3772       rot_lines_total = 4;
3773       rot_line_count = 0;
3774       break;
3775     case scaled_aspect_rot:
3776       wiz_lcd_set_portrait(1);
3777       rot_lines_total = 3;
3778       rot_line_count = 0;
3779       break;
3780   }
3781
3782   flip_screen();
3783   clear_screen(0);
3784
3785   resolution_width = 240;
3786   resolution_height = 160;
3787 }
3788
3789 void set_gba_resolution(video_scale_type scale)
3790 {
3791   screen_scale = scale;
3792 }
3793
3794 void clear_screen(u16 color)
3795 {
3796   u32 col = ((u32)color << 16) | color;
3797   u32 *p = gpsp_gp2x_screen;
3798   int c = 320*240/2;
3799   while (c-- > 0)
3800     *p++ = col;
3801 }
3802
3803 #elif defined(PND_BUILD)
3804
3805 void video_resolution_large()
3806 {
3807   resolution_width = 400;
3808   resolution_height = 272;
3809
3810   fb_set_mode(400, 272, 1, 15, screen_filter, screen_filter2);
3811   flip_screen();
3812   clear_screen(0);
3813 }
3814
3815 void video_resolution_small()
3816 {
3817   resolution_width = 240;
3818   resolution_height = 160;
3819
3820   fb_set_mode(240, 160, 3, screen_scale, screen_filter, screen_filter2);
3821   flip_screen();
3822   clear_screen(0);
3823 }
3824
3825 void set_gba_resolution(video_scale_type scale)
3826 {
3827   screen_scale = scale;
3828 }
3829
3830 void clear_screen(u16 color)
3831 {
3832   u32 col = ((u32)color << 16) | color;
3833   u32 *p = (u32 *)get_screen_pixels();
3834   int c = resolution_width * resolution_height / 2;
3835   while (c-- > 0)
3836     *p++ = col;
3837 }
3838
3839 #else
3840
3841 void video_resolution_large()
3842 {
3843   current_scale = unscaled;
3844
3845 #ifdef GP2X_BUILD
3846   SDL_FreeSurface(screen);
3847   SDL_GP2X_AllowGfxMemory(NULL, 0);
3848     hw_screen = SDL_SetVideoMode(320, 240, 16, SDL_HWSURFACE);
3849   screen = SDL_CreateRGBSurface(SDL_HWSURFACE, 320, 240, 16, 0xFFFF,
3850    0xFFFF, 0xFFFF, 0);
3851   resolution_width = 320;
3852     resolution_height = 240;
3853   SDL_ShowCursor(0);
3854
3855   warm_change_cb_upper(WCB_C_BIT|WCB_B_BIT, 1);
3856 #else
3857   screen = SDL_SetVideoMode(480, 272, 16, 0);
3858   resolution_width = 480;
3859   resolution_height = 272;
3860 #endif
3861 }
3862
3863 void video_resolution_small()
3864 {
3865   current_scale = screen_scale;
3866
3867 #ifdef GP2X_BUILD
3868   int w, h;
3869   SDL_FreeSurface(screen);
3870   SDL_GP2X_AllowGfxMemory(NULL, 0);
3871
3872   w = 320; h = 240;
3873   if (screen_scale == scaled_aspect || screen_scale == fullscreen)
3874   {
3875     w = small_resolution_width * video_scale;
3876     h = small_resolution_height * video_scale;
3877   }
3878   if (screen_scale == scaled_aspect) h += 20;
3879   hw_screen = SDL_SetVideoMode(w, h, 16, SDL_HWSURFACE);
3880
3881   w = small_resolution_width * video_scale;
3882   if (screen_scale == scaled_aspect_sw)
3883     w = 320;
3884   screen = SDL_CreateRGBSurface(SDL_HWSURFACE,
3885    w, small_resolution_height * video_scale,
3886    16, 0xFFFF, 0xFFFF, 0xFFFF, 0);
3887
3888   SDL_ShowCursor(0);
3889
3890   warm_change_cb_upper(WCB_C_BIT|WCB_B_BIT, 1);
3891 #else
3892   screen = SDL_SetVideoMode(small_resolution_width * video_scale,
3893    small_resolution_height * video_scale, 16, 0);
3894 #endif
3895   resolution_width = small_resolution_width;
3896   resolution_height = small_resolution_height;
3897 }
3898
3899 void set_gba_resolution(video_scale_type scale)
3900 {
3901   if(screen_scale != scale)
3902   {
3903     screen_scale = scale;
3904     small_resolution_width = 240 * video_scale;
3905     small_resolution_height = 160 * video_scale;
3906   }
3907 }
3908
3909 void clear_screen(u16 color)
3910 {
3911   u16 *dest_ptr = get_screen_pixels();
3912   u32 line_skip = get_screen_pitch() - screen->w;
3913   u32 x, y;
3914
3915   for(y = 0; y < screen->h; y++)
3916   {
3917     for(x = 0; x < screen->w; x++, dest_ptr++)
3918     {
3919       *dest_ptr = color;
3920     }
3921     dest_ptr += line_skip;
3922   }
3923 }
3924
3925 #endif
3926
3927 u16 *copy_screen()
3928 {
3929   u16 *copy = malloc(240 * 160 * 2);
3930   memcpy(copy, get_screen_pixels(), 240 * 160 * 2);
3931   return copy;
3932 }
3933
3934 void blit_to_screen(u16 *src, u32 w, u32 h, u32 dest_x, u32 dest_y)
3935 {
3936   u32 pitch = get_screen_pitch();
3937   u16 *dest_ptr = get_screen_pixels() + dest_x + (dest_y * pitch);
3938
3939   s32 w1 = dest_x + w > pitch ? pitch - dest_x : w;
3940   u16 *src_ptr = src;
3941   s32 x, y;
3942
3943   for(y = 0; y < h; y++)
3944   {
3945     for(x = 0; x < w1; x++)
3946     {
3947       dest_ptr[x] = src_ptr[x];
3948     }
3949     src_ptr += w;
3950     dest_ptr += pitch;
3951   }
3952 }
3953
3954 void print_string_ext(const char *str, u16 fg_color, u16 bg_color,
3955  u32 x, u32 y, void *_dest_ptr, u32 pitch, u32 pad, u32 h_offset, u32 height)
3956 {
3957   u16 *dest_ptr = (u16 *)_dest_ptr + (y * pitch) + x;
3958   u8 current_char = str[0];
3959   u32 current_row;
3960   u32 glyph_offset;
3961   u32 i = 0, i2, i3, h;
3962   u32 str_index = 1;
3963   u32 current_x = x;
3964
3965   if(y + height > resolution_height)
3966       return;
3967
3968   while(current_char)
3969   {
3970     if(current_char == '\n')
3971     {
3972       y += FONT_HEIGHT;
3973       current_x = x;
3974       dest_ptr = get_screen_pixels() + (y * pitch) + x;
3975     }
3976     else
3977     {
3978       glyph_offset = _font_offset[current_char];
3979       current_x += FONT_WIDTH;
3980       glyph_offset += h_offset;
3981       for(i2 = h_offset, h = 0; i2 < FONT_HEIGHT && h < height; i2++, h++, glyph_offset++)
3982       {
3983         current_row = _font_bits[glyph_offset];
3984         for(i3 = 0; i3 < FONT_WIDTH; i3++)
3985         {
3986           if((current_row >> (15 - i3)) & 0x01)
3987             *dest_ptr = fg_color;
3988           else
3989             *dest_ptr = bg_color;
3990           dest_ptr++;
3991         }
3992         dest_ptr += (pitch - FONT_WIDTH);
3993       }
3994       dest_ptr = dest_ptr - (pitch * h) + FONT_WIDTH;
3995     }
3996
3997     i++;
3998
3999     current_char = str[str_index];
4000
4001     if((i < pad) && (current_char == 0))
4002     {
4003       current_char = ' ';
4004     }
4005     else
4006     {
4007       str_index++;
4008     }
4009
4010     if(current_x + FONT_WIDTH > resolution_width /* EDIT */)
4011     {
4012       while (current_char && current_char != '\n')
4013       {
4014         current_char = str[str_index++];
4015       }
4016     }
4017   }
4018 }
4019
4020 void print_string(const char *str, u16 fg_color, u16 bg_color,
4021  u32 x, u32 y)
4022 {
4023 #ifdef WIZ_BUILD
4024   if ((screen_scale == unscaled_rot || screen_scale == scaled_aspect_rot) &&
4025    (resolution_width == small_resolution_width) &&
4026    (resolution_height == small_resolution_height))
4027   {
4028     snprintf(rot_msg_buff, sizeof(rot_msg_buff), "%s", str);
4029     return;
4030   }
4031 #endif
4032   print_string_ext(str, fg_color, bg_color, x, y, get_screen_pixels(),
4033    get_screen_pitch(), 0, 0, FONT_HEIGHT);
4034 }
4035
4036 void print_string_pad(const char *str, u16 fg_color, u16 bg_color,
4037  u32 x, u32 y, u32 pad)
4038 {
4039   print_string_ext(str, fg_color, bg_color, x, y, get_screen_pixels(),
4040    get_screen_pitch(), pad, 0, FONT_HEIGHT);
4041 }
4042
4043 u32 debug_cursor_x = 0;
4044 u32 debug_cursor_y = 0;
4045
4046 #ifdef STDIO_DEBUG
4047
4048 void debug_screen_clear()
4049 {
4050 }
4051
4052 void debug_screen_start()
4053 {
4054 }
4055
4056 void debug_screen_end()
4057 {
4058 }
4059
4060 void debug_screen_update()
4061 {
4062 }
4063
4064 void debug_screen_printf(const char *format, ...)
4065 {
4066   va_list ap;
4067
4068   va_start(ap, format);
4069   vprintf(format, ap);
4070   va_end(ap);
4071 }
4072
4073 void debug_screen_newline(u32 count)
4074 {
4075   printf("\n");
4076 }
4077
4078
4079 #else
4080
4081 void debug_screen_clear()
4082 {
4083   debug_cursor_x = 0;
4084   debug_cursor_y = 0;
4085   clear_screen(0x0000);
4086 }
4087
4088 void debug_screen_start()
4089 {
4090   video_resolution_large();
4091   debug_screen_clear();
4092 }
4093
4094 void debug_screen_end()
4095 {
4096   video_resolution_small();
4097 }
4098
4099 void debug_screen_update()
4100 {
4101   flip_screen();
4102 }
4103
4104 void debug_screen_printf(const char *format, ...)
4105 {
4106   char str_buffer[512];
4107   u32 str_buffer_length;
4108   va_list ap;
4109
4110   va_start(ap, format);
4111   str_buffer_length = vsnprintf(str_buffer, 512, format, ap);
4112   va_end(ap);
4113
4114   printf("printing debug string %s at %d %d\n", str_buffer,
4115    debug_cursor_x, debug_cursor_y);
4116
4117   print_string(str_buffer, 0xFFFF, 0x0000, debug_cursor_x, debug_cursor_y);
4118   debug_cursor_x += FONT_WIDTH * str_buffer_length;
4119 }
4120
4121 void debug_screen_newline(u32 count)
4122 {
4123   debug_cursor_x = 0;
4124   debug_cursor_y += FONT_HEIGHT * count;
4125 }
4126
4127 #endif
4128
4129 void debug_screen_printl(const char *format, ...)
4130 {
4131   va_list ap;
4132
4133   va_start(ap, format);
4134   debug_screen_printf(format, ap);
4135   debug_screen_newline(1);
4136 //  debug_screen_printf("\n");
4137   va_end(ap);
4138 }
4139
4140
4141 #define video_savestate_builder(type)                                         \
4142 void video_##type##_savestate(file_tag_type savestate_file)                   \
4143 {                                                                             \
4144   file_##type##_array(savestate_file, affine_reference_x);                    \
4145   file_##type##_array(savestate_file, affine_reference_y);                    \
4146 }                                                                             \
4147
4148 video_savestate_builder(read);
4149 video_savestate_builder(write_mem);
4150
4151