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