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