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