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