3 * Copyright (C) 2006 Exophase <exophase@gmail.com>
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.
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.
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
27 #include <pspkernel.h>
29 #include <pspdisplay.h>
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;
40 static u32 video_direct = 0;
42 static u32 __attribute__((aligned(16))) display_list[32];
44 #define GBA_SCREEN_WIDTH 240
45 #define GBA_SCREEN_HEIGHT 160
47 #define PSP_SCREEN_WIDTH 480
48 #define PSP_SCREEN_HEIGHT 272
49 #define PSP_LINE_SIZE 512
51 #define PSP_ALL_BUTTON_MASK 0xFFFF
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
69 #define GE_CMD(cmd, operand) \
70 *ge_cmd_ptr = (((GE_CMD_##cmd) << 24) | (operand)); \
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;
78 static void Ge_Finish_Callback(int id, void *arg)
82 #define get_screen_pixels() \
85 #define get_screen_pitch() \
88 #elif defined(WIZ_BUILD)
90 static u16 rot_buffer[240*4];
91 static u32 rot_lines_total = 4;
92 static u32 rot_line_count = 0;
93 static char rot_msg_buff[64];
95 static u32 screen_offset = 0;
96 static u16 *screen_pixels = NULL;
97 const u32 screen_pitch = 320;
99 #define get_screen_pixels() \
102 #define get_screen_pitch() \
105 #elif defined(PND_BUILD)
107 static u16 *screen_pixels = NULL;
109 #define get_screen_pixels() \
112 #define get_screen_pitch() \
118 #include "SDL_gp2x.h"
119 SDL_Surface *hw_screen;
122 const u32 video_scale = 1;
124 #define get_screen_pixels() \
125 ((u16 *)screen->pixels) \
127 #define get_screen_pitch() \
128 (screen->pitch / 2) \
132 void render_scanline_conditional_tile(u32 start, u32 end, u16 *scanline,
133 u32 enable_flags, u32 dispcnt, u32 bldcnt, tile_layer_render_struct
135 void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline,
136 u32 enable_flags, u32 dispcnt, u32 bldcnt, bitmap_layer_render_struct
141 // This old version is not necessary if the palette is either being converted
142 // transparently or the ABGR 1555 format is being used natively. The direct
143 // version (without conversion) is much faster.
145 #define tile_lookup_palette_full(palette, source) \
146 current_pixel = palette[source]; \
147 convert_palette(current_pixel) \
149 #define tile_lookup_palette(palette, source) \
150 current_pixel = palette[source]; \
153 #ifdef RENDER_COLOR16_NORMAL
155 #define tile_expand_base_normal(index) \
156 tile_expand_base_color16(index) \
160 #define tile_expand_base_normal(index) \
161 tile_lookup_palette(palette, current_pixel); \
162 dest_ptr[index] = current_pixel \
166 #define tile_expand_transparent_normal(index) \
167 tile_expand_base_normal(index) \
169 #define tile_expand_copy(index) \
170 dest_ptr[index] = copy_ptr[index] \
173 #define advance_dest_ptr_base(delta) \
176 #define advance_dest_ptr_transparent(delta) \
177 advance_dest_ptr_base(delta) \
179 #define advance_dest_ptr_copy(delta) \
180 advance_dest_ptr_base(delta); \
184 #define color_combine_mask_a(layer) \
185 ((io_registers[REG_BLDCNT] >> layer) & 0x01) \
187 // For color blending operations, will create a mask that has in bit
188 // 10 if the layer is target B, and bit 9 if the layer is target A.
190 #define color_combine_mask(layer) \
191 (color_combine_mask_a(layer) | \
192 ((io_registers[REG_BLDCNT] >> (layer + 7)) & 0x02)) << 9 \
194 // For alpha blending renderers, draw the palette index (9bpp) and
195 // layer bits rather than the raw RGB. For the base this should write to
196 // the 32bit location directly.
198 #define tile_expand_base_alpha(index) \
199 dest_ptr[index] = current_pixel | pixel_combine \
201 #define tile_expand_base_bg(index) \
202 dest_ptr[index] = bg_combine \
205 // For layered (transparent) writes this should shift the "stack" and write
206 // to the bottom. This will preserve the topmost pixel and the most recent
209 #define tile_expand_transparent_alpha(index) \
210 dest_ptr[index] = (dest_ptr[index] << 16) | current_pixel | pixel_combine \
213 // OBJ should only shift if the top isn't already OBJ
214 #define tile_expand_transparent_alpha_obj(index) \
215 dest = dest_ptr[index]; \
216 if(dest & 0x00000100) \
218 dest_ptr[index] = (dest & 0xFFFF0000) | current_pixel | pixel_combine; \
222 dest_ptr[index] = (dest << 16) | current_pixel | pixel_combine; \
226 // For color effects that don't need to preserve the previous layer.
227 // The color32 version should be used with 32bit wide dest_ptr so as to be
228 // compatible with alpha combine on top of it.
230 #define tile_expand_base_color16(index) \
231 dest_ptr[index] = current_pixel | pixel_combine \
233 #define tile_expand_transparent_color16(index) \
234 tile_expand_base_color16(index) \
236 #define tile_expand_base_color32(index) \
237 tile_expand_base_color16(index) \
239 #define tile_expand_transparent_color32(index) \
240 tile_expand_base_color16(index) \
243 // Operations for isolation 8bpp pixels within 32bpp pixel blocks.
245 #define tile_8bpp_pixel_op_mask(op_param) \
246 current_pixel = current_pixels & 0xFF \
248 #define tile_8bpp_pixel_op_shift_mask(shift) \
249 current_pixel = (current_pixels >> shift) & 0xFF \
251 #define tile_8bpp_pixel_op_shift(shift) \
252 current_pixel = current_pixels >> shift \
254 #define tile_8bpp_pixel_op_none(shift) \
256 // Base should always draw raw in 8bpp mode; color 0 will be drawn where
259 #define tile_8bpp_draw_base_normal(index) \
260 tile_expand_base_normal(index) \
262 #define tile_8bpp_draw_base_alpha(index) \
265 tile_expand_base_alpha(index); \
269 tile_expand_base_bg(index); \
273 #define tile_8bpp_draw_base_color16(index) \
274 tile_8bpp_draw_base_alpha(index) \
276 #define tile_8bpp_draw_base_color32(index) \
277 tile_8bpp_draw_base_alpha(index) \
280 #define tile_8bpp_draw_base(index, op, op_param, alpha_op) \
281 tile_8bpp_pixel_op_##op(op_param); \
282 tile_8bpp_draw_base_##alpha_op(index) \
284 // Transparent (layered) writes should only replace what is there if the
285 // pixel is not transparent (zero)
287 #define tile_8bpp_draw_transparent(index, op, op_param, alpha_op) \
288 tile_8bpp_pixel_op_##op(op_param); \
291 tile_expand_transparent_##alpha_op(index); \
294 #define tile_8bpp_draw_copy(index, op, op_param, alpha_op) \
295 tile_8bpp_pixel_op_##op(op_param); \
298 tile_expand_copy(index); \
301 // Get the current tile from the map in 8bpp mode
303 #define get_tile_8bpp() \
304 current_tile = *map_ptr; \
305 tile_ptr = tile_base + ((current_tile & 0x3FF) * 64) \
308 // Draw half of a tile in 8bpp mode, for base renderer
310 #define tile_8bpp_draw_four_noflip(index, combine_op, alpha_op) \
311 tile_8bpp_draw_##combine_op(index + 0, mask, 0, alpha_op); \
312 tile_8bpp_draw_##combine_op(index + 1, shift_mask, 8, alpha_op); \
313 tile_8bpp_draw_##combine_op(index + 2, shift_mask, 16, alpha_op); \
314 tile_8bpp_draw_##combine_op(index + 3, shift, 24, alpha_op) \
317 // Like the above, but draws the half-tile horizontally flipped
319 #define tile_8bpp_draw_four_flip(index, combine_op, alpha_op) \
320 tile_8bpp_draw_##combine_op(index + 3, mask, 0, alpha_op); \
321 tile_8bpp_draw_##combine_op(index + 2, shift_mask, 8, alpha_op); \
322 tile_8bpp_draw_##combine_op(index + 1, shift_mask, 16, alpha_op); \
323 tile_8bpp_draw_##combine_op(index + 0, shift, 24, alpha_op) \
325 #define tile_8bpp_draw_four_base(index, alpha_op, flip_op) \
326 tile_8bpp_draw_four_##flip_op(index, base, alpha_op) \
329 // Draw half of a tile in 8bpp mode, for transparent renderer; as an
330 // optimization the entire thing is checked against zero (in transparent
331 // capable renders it is more likely for the pixels to be transparent than
334 #define tile_8bpp_draw_four_transparent(index, alpha_op, flip_op) \
335 if(current_pixels != 0) \
337 tile_8bpp_draw_four_##flip_op(index, transparent, alpha_op); \
340 #define tile_8bpp_draw_four_copy(index, alpha_op, flip_op) \
341 if(current_pixels != 0) \
343 tile_8bpp_draw_four_##flip_op(index, copy, alpha_op); \
346 // Helper macro for drawing 8bpp tiles clipped against the edge of the screen
348 #define partial_tile_8bpp(combine_op, alpha_op) \
349 for(i = 0; i < partial_tile_run; i++) \
351 tile_8bpp_draw_##combine_op(0, mask, 0, alpha_op); \
352 current_pixels >>= 8; \
353 advance_dest_ptr_##combine_op(1); \
357 // Draws 8bpp tiles clipped against the left side of the screen,
358 // partial_tile_offset indicates how much clipped in it is, partial_tile_run
359 // indicates how much it should draw.
361 #define partial_tile_right_noflip_8bpp(combine_op, alpha_op) \
362 if(partial_tile_offset >= 4) \
364 current_pixels = *((u32 *)(tile_ptr + 4)) >> \
365 ((partial_tile_offset - 4) * 8); \
366 partial_tile_8bpp(combine_op, alpha_op); \
370 partial_tile_run -= 4; \
371 current_pixels = *((u32 *)tile_ptr) >> (partial_tile_offset * 8); \
372 partial_tile_8bpp(combine_op, alpha_op); \
373 current_pixels = *((u32 *)(tile_ptr + 4)); \
374 tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \
375 advance_dest_ptr_##combine_op(4); \
379 // Draws 8bpp tiles clipped against both the left and right side of the
380 // screen, IE, runs of less than 8 - partial_tile_offset.
382 #define partial_tile_mid_noflip_8bpp(combine_op, alpha_op) \
383 if(partial_tile_offset >= 4) \
385 current_pixels = *((u32 *)(tile_ptr + 4)) >> \
386 ((partial_tile_offset - 4) * 8); \
387 partial_tile_8bpp(combine_op, alpha_op); \
391 current_pixels = *((u32 *)tile_ptr) >> (partial_tile_offset * 8); \
392 if((partial_tile_offset + partial_tile_run) > 4) \
394 u32 old_run = partial_tile_run; \
395 partial_tile_run = 4 - partial_tile_offset; \
396 partial_tile_8bpp(combine_op, alpha_op); \
397 partial_tile_run = old_run - partial_tile_run; \
398 current_pixels = *((u32 *)(tile_ptr + 4)); \
399 partial_tile_8bpp(combine_op, alpha_op); \
403 partial_tile_8bpp(combine_op, alpha_op); \
408 // Draws 8bpp tiles clipped against the right side of the screen,
409 // partial_tile_run indicates how much there is to draw.
411 #define partial_tile_left_noflip_8bpp(combine_op, alpha_op) \
412 if(partial_tile_run >= 4) \
414 current_pixels = *((u32 *)tile_ptr); \
415 tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \
416 advance_dest_ptr_##combine_op(4); \
418 partial_tile_run -= 4; \
421 current_pixels = *((u32 *)(tile_ptr)); \
422 partial_tile_8bpp(combine_op, alpha_op) \
425 // Draws a non-clipped (complete) 8bpp tile.
427 #define tile_noflip_8bpp(combine_op, alpha_op) \
428 current_pixels = *((u32 *)tile_ptr); \
429 tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \
430 current_pixels = *((u32 *)(tile_ptr + 4)); \
431 tile_8bpp_draw_four_##combine_op(4, alpha_op, noflip) \
434 // Like the above versions but draws flipped tiles.
436 #define partial_tile_flip_8bpp(combine_op, alpha_op) \
437 for(i = 0; i < partial_tile_run; i++) \
439 tile_8bpp_draw_##combine_op(0, shift, 24, alpha_op); \
440 current_pixels <<= 8; \
441 advance_dest_ptr_##combine_op(1); \
444 #define partial_tile_right_flip_8bpp(combine_op, alpha_op) \
445 if(partial_tile_offset >= 4) \
447 current_pixels = *((u32 *)tile_ptr) << ((partial_tile_offset - 4) * 8); \
448 partial_tile_flip_8bpp(combine_op, alpha_op); \
452 partial_tile_run -= 4; \
453 current_pixels = *((u32 *)(tile_ptr + 4)) << \
454 ((partial_tile_offset - 4) * 8); \
455 partial_tile_flip_8bpp(combine_op, alpha_op); \
456 current_pixels = *((u32 *)tile_ptr); \
457 tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \
458 advance_dest_ptr_##combine_op(4); \
461 #define partial_tile_mid_flip_8bpp(combine_op, alpha_op) \
462 if(partial_tile_offset >= 4) \
464 current_pixels = *((u32 *)tile_ptr) << ((partial_tile_offset - 4) * 8); \
465 partial_tile_flip_8bpp(combine_op, alpha_op); \
469 current_pixels = *((u32 *)(tile_ptr + 4)) << \
470 ((partial_tile_offset - 4) * 8); \
472 if((partial_tile_offset + partial_tile_run) > 4) \
474 u32 old_run = partial_tile_run; \
475 partial_tile_run = 4 - partial_tile_offset; \
476 partial_tile_flip_8bpp(combine_op, alpha_op); \
477 partial_tile_run = old_run - partial_tile_run; \
478 current_pixels = *((u32 *)(tile_ptr)); \
479 partial_tile_flip_8bpp(combine_op, alpha_op); \
483 partial_tile_flip_8bpp(combine_op, alpha_op); \
487 #define partial_tile_left_flip_8bpp(combine_op, alpha_op) \
488 if(partial_tile_run >= 4) \
490 current_pixels = *((u32 *)(tile_ptr + 4)); \
491 tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \
492 advance_dest_ptr_##combine_op(4); \
494 partial_tile_run -= 4; \
497 current_pixels = *((u32 *)(tile_ptr + 4)); \
498 partial_tile_flip_8bpp(combine_op, alpha_op) \
500 #define tile_flip_8bpp(combine_op, alpha_op) \
501 current_pixels = *((u32 *)(tile_ptr + 4)); \
502 tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \
503 current_pixels = *((u32 *)tile_ptr); \
504 tile_8bpp_draw_four_##combine_op(4, alpha_op, flip) \
507 // Operations for isolating 4bpp tiles in a 32bit block
509 #define tile_4bpp_pixel_op_mask(op_param) \
510 current_pixel = current_pixels & 0x0F \
512 #define tile_4bpp_pixel_op_shift_mask(shift) \
513 current_pixel = (current_pixels >> shift) & 0x0F \
515 #define tile_4bpp_pixel_op_shift(shift) \
516 current_pixel = current_pixels >> shift \
518 #define tile_4bpp_pixel_op_none(op_param) \
520 // Draws a single 4bpp pixel as base, normal renderer; checks to see if the
521 // pixel is zero because if so the current palette should not be applied.
522 // These ifs can be replaced with a lookup table, may or may not be superior
523 // this way, should be benchmarked. The lookup table would be from 0-255
524 // identity map except for multiples of 16, which would map to 0.
526 #define tile_4bpp_draw_base_normal(index) \
529 current_pixel |= current_palette; \
530 tile_expand_base_normal(index); \
534 tile_expand_base_normal(index); \
538 #define tile_4bpp_draw_base_alpha(index) \
541 current_pixel |= current_palette; \
542 tile_expand_base_alpha(index); \
546 tile_expand_base_bg(index); \
549 #define tile_4bpp_draw_base_color16(index) \
550 tile_4bpp_draw_base_alpha(index) \
552 #define tile_4bpp_draw_base_color32(index) \
553 tile_4bpp_draw_base_alpha(index) \
556 #define tile_4bpp_draw_base(index, op, op_param, alpha_op) \
557 tile_4bpp_pixel_op_##op(op_param); \
558 tile_4bpp_draw_base_##alpha_op(index) \
561 // Draws a single 4bpp pixel as layered, if not transparent.
563 #define tile_4bpp_draw_transparent(index, op, op_param, alpha_op) \
564 tile_4bpp_pixel_op_##op(op_param); \
567 current_pixel |= current_palette; \
568 tile_expand_transparent_##alpha_op(index); \
571 #define tile_4bpp_draw_copy(index, op, op_param, alpha_op) \
572 tile_4bpp_pixel_op_##op(op_param); \
575 current_pixel |= current_palette; \
576 tile_expand_copy(index); \
580 // Draws eight background pixels in transparent mode, for alpha or normal
583 #define tile_4bpp_draw_eight_base_zero(value) \
584 dest_ptr[0] = value; \
585 dest_ptr[1] = value; \
586 dest_ptr[2] = value; \
587 dest_ptr[3] = value; \
588 dest_ptr[4] = value; \
589 dest_ptr[5] = value; \
590 dest_ptr[6] = value; \
591 dest_ptr[7] = value \
594 // Draws eight background pixels for the alpha renderer, basically color zero
595 // with the background flag high.
597 #define tile_4bpp_draw_eight_base_zero_alpha() \
598 tile_4bpp_draw_eight_base_zero(bg_combine) \
600 #define tile_4bpp_draw_eight_base_zero_color16() \
601 tile_4bpp_draw_eight_base_zero_alpha() \
603 #define tile_4bpp_draw_eight_base_zero_color32() \
604 tile_4bpp_draw_eight_base_zero_alpha() \
607 // Draws eight background pixels for the normal renderer, just a bunch of
610 #ifdef RENDER_COLOR16_NORMAL
612 #define tile_4bpp_draw_eight_base_zero_normal() \
614 tile_4bpp_draw_eight_base_zero(current_pixel) \
618 #define tile_4bpp_draw_eight_base_zero_normal() \
619 current_pixel = palette[0]; \
620 tile_4bpp_draw_eight_base_zero(current_pixel) \
625 // Draws eight 4bpp pixels.
627 #define tile_4bpp_draw_eight_noflip(combine_op, alpha_op) \
628 tile_4bpp_draw_##combine_op(0, mask, 0, alpha_op); \
629 tile_4bpp_draw_##combine_op(1, shift_mask, 4, alpha_op); \
630 tile_4bpp_draw_##combine_op(2, shift_mask, 8, alpha_op); \
631 tile_4bpp_draw_##combine_op(3, shift_mask, 12, alpha_op); \
632 tile_4bpp_draw_##combine_op(4, shift_mask, 16, alpha_op); \
633 tile_4bpp_draw_##combine_op(5, shift_mask, 20, alpha_op); \
634 tile_4bpp_draw_##combine_op(6, shift_mask, 24, alpha_op); \
635 tile_4bpp_draw_##combine_op(7, shift, 28, alpha_op) \
638 // Draws eight 4bpp pixels in reverse order (for hflip).
640 #define tile_4bpp_draw_eight_flip(combine_op, alpha_op) \
641 tile_4bpp_draw_##combine_op(7, mask, 0, alpha_op); \
642 tile_4bpp_draw_##combine_op(6, shift_mask, 4, alpha_op); \
643 tile_4bpp_draw_##combine_op(5, shift_mask, 8, alpha_op); \
644 tile_4bpp_draw_##combine_op(4, shift_mask, 12, alpha_op); \
645 tile_4bpp_draw_##combine_op(3, shift_mask, 16, alpha_op); \
646 tile_4bpp_draw_##combine_op(2, shift_mask, 20, alpha_op); \
647 tile_4bpp_draw_##combine_op(1, shift_mask, 24, alpha_op); \
648 tile_4bpp_draw_##combine_op(0, shift, 28, alpha_op) \
651 // Draws eight 4bpp pixels in base mode, checks if all are zero, if so draws
652 // the appropriate background pixels.
654 #define tile_4bpp_draw_eight_base(alpha_op, flip_op) \
655 if(current_pixels != 0) \
657 tile_4bpp_draw_eight_##flip_op(base, alpha_op); \
661 tile_4bpp_draw_eight_base_zero_##alpha_op(); \
665 // Draws eight 4bpp pixels in transparent (layered) mode, checks if all are
666 // zero and if so draws nothing.
668 #define tile_4bpp_draw_eight_transparent(alpha_op, flip_op) \
669 if(current_pixels != 0) \
671 tile_4bpp_draw_eight_##flip_op(transparent, alpha_op); \
675 #define tile_4bpp_draw_eight_copy(alpha_op, flip_op) \
676 if(current_pixels != 0) \
678 tile_4bpp_draw_eight_##flip_op(copy, alpha_op); \
681 // Gets the current tile in 4bpp mode, also getting the current palette and
684 #define get_tile_4bpp() \
685 current_tile = *map_ptr; \
686 current_palette = (current_tile >> 12) << 4; \
687 tile_ptr = tile_base + ((current_tile & 0x3FF) * 32); \
690 // Helper macro for drawing clipped 4bpp tiles.
692 #define partial_tile_4bpp(combine_op, alpha_op) \
693 for(i = 0; i < partial_tile_run; i++) \
695 tile_4bpp_draw_##combine_op(0, mask, 0, alpha_op); \
696 current_pixels >>= 4; \
697 advance_dest_ptr_##combine_op(1); \
701 // Draws a 4bpp tile clipped against the left edge of the screen.
702 // partial_tile_offset is how far in it's clipped, partial_tile_run is
705 #define partial_tile_right_noflip_4bpp(combine_op, alpha_op) \
706 current_pixels = *((u32 *)tile_ptr) >> (partial_tile_offset * 4); \
707 partial_tile_4bpp(combine_op, alpha_op) \
710 // Draws a 4bpp tile clipped against both edges of the screen, same as right.
712 #define partial_tile_mid_noflip_4bpp(combine_op, alpha_op) \
713 partial_tile_right_noflip_4bpp(combine_op, alpha_op) \
716 // Draws a 4bpp tile clipped against the right edge of the screen.
717 // partial_tile_offset is how many to draw.
719 #define partial_tile_left_noflip_4bpp(combine_op, alpha_op) \
720 current_pixels = *((u32 *)tile_ptr); \
721 partial_tile_4bpp(combine_op, alpha_op) \
724 // Draws a complete 4bpp tile row (not clipped)
725 #define tile_noflip_4bpp(combine_op, alpha_op) \
726 current_pixels = *((u32 *)tile_ptr); \
727 tile_4bpp_draw_eight_##combine_op(alpha_op, noflip) \
730 // Like the above, but draws flipped tiles.
732 #define partial_tile_flip_4bpp(combine_op, alpha_op) \
733 for(i = 0; i < partial_tile_run; i++) \
735 tile_4bpp_draw_##combine_op(0, shift, 28, alpha_op); \
736 current_pixels <<= 4; \
737 advance_dest_ptr_##combine_op(1); \
740 #define partial_tile_right_flip_4bpp(combine_op, alpha_op) \
741 current_pixels = *((u32 *)tile_ptr) << (partial_tile_offset * 4); \
742 partial_tile_flip_4bpp(combine_op, alpha_op) \
744 #define partial_tile_mid_flip_4bpp(combine_op, alpha_op) \
745 partial_tile_right_flip_4bpp(combine_op, alpha_op) \
747 #define partial_tile_left_flip_4bpp(combine_op, alpha_op) \
748 current_pixels = *((u32 *)tile_ptr); \
749 partial_tile_flip_4bpp(combine_op, alpha_op) \
751 #define tile_flip_4bpp(combine_op, alpha_op) \
752 current_pixels = *((u32 *)tile_ptr); \
753 tile_4bpp_draw_eight_##combine_op(alpha_op, flip) \
756 // Draws a single (partial or complete) tile from the tilemap, flipping
759 #define single_tile_map(tile_type, combine_op, color_depth, alpha_op) \
760 get_tile_##color_depth(); \
761 if(current_tile & 0x800) \
762 tile_ptr += vertical_pixel_flip; \
764 if(current_tile & 0x400) \
766 tile_type##_flip_##color_depth(combine_op, alpha_op); \
770 tile_type##_noflip_##color_depth(combine_op, alpha_op); \
774 // Draws multiple sequential tiles from the tilemap, hflips and vflips as
777 #define multiple_tile_map(combine_op, color_depth, alpha_op) \
778 for(i = 0; i < tile_run; i++) \
780 single_tile_map(tile, combine_op, color_depth, alpha_op); \
781 advance_dest_ptr_##combine_op(8); \
785 // Draws a partial tile from a tilemap clipped against the left edge of the
788 #define partial_tile_right_map(combine_op, color_depth, alpha_op) \
789 single_tile_map(partial_tile_right, combine_op, color_depth, alpha_op); \
792 // Draws a partial tile from a tilemap clipped against both edges of the
795 #define partial_tile_mid_map(combine_op, color_depth, alpha_op) \
796 single_tile_map(partial_tile_mid, combine_op, color_depth, alpha_op) \
798 // Draws a partial tile from a tilemap clipped against the right edge of the
801 #define partial_tile_left_map(combine_op, color_depth, alpha_op) \
802 single_tile_map(partial_tile_left, combine_op, color_depth, alpha_op) \
805 // Advances a non-flipped 4bpp obj to the next tile.
807 #define obj_advance_noflip_4bpp() \
811 // Advances a non-flipped 8bpp obj to the next tile.
813 #define obj_advance_noflip_8bpp() \
817 // Advances a flipped 4bpp obj to the next tile.
819 #define obj_advance_flip_4bpp() \
823 // Advances a flipped 8bpp obj to the next tile.
825 #define obj_advance_flip_8bpp() \
830 // Draws multiple sequential tiles from an obj, flip_op determines if it should
831 // be flipped or not (set to flip or noflip)
833 #define multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op) \
834 for(i = 0; i < tile_run; i++) \
836 tile_##flip_op##_##color_depth(combine_op, alpha_op); \
837 obj_advance_##flip_op##_##color_depth(); \
838 advance_dest_ptr_##combine_op(8); \
842 // Draws an obj's tile clipped against the left side of the screen
844 #define partial_tile_right_obj(combine_op, color_depth, alpha_op, flip_op) \
845 partial_tile_right_##flip_op##_##color_depth(combine_op, alpha_op); \
846 obj_advance_##flip_op##_##color_depth() \
848 // Draws an obj's tile clipped against both sides of the screen
850 #define partial_tile_mid_obj(combine_op, color_depth, alpha_op, flip_op) \
851 partial_tile_mid_##flip_op##_##color_depth(combine_op, alpha_op) \
853 // Draws an obj's tile clipped against the right side of the screen
855 #define partial_tile_left_obj(combine_op, color_depth, alpha_op, flip_op) \
856 partial_tile_left_##flip_op##_##color_depth(combine_op, alpha_op) \
859 // Extra variables specific for 8bpp/4bpp tile renderers.
861 #define tile_extra_variables_8bpp() \
863 #define tile_extra_variables_4bpp() \
864 u32 current_palette \
867 // Byte lengths of complete tiles and tile rows in 4bpp and 8bpp.
869 #define tile_width_4bpp 4
870 #define tile_size_4bpp 32
871 #define tile_width_8bpp 8
872 #define tile_size_8bpp 64
875 // Render a single scanline of text tiles
877 #define tile_render(color_depth, combine_op, alpha_op) \
879 u32 vertical_pixel_offset = (vertical_offset % 8) * \
880 tile_width_##color_depth; \
881 u32 vertical_pixel_flip = \
882 ((tile_size_##color_depth - tile_width_##color_depth) - \
883 vertical_pixel_offset) - vertical_pixel_offset; \
884 tile_extra_variables_##color_depth(); \
885 u8 *tile_base = vram + (((bg_control >> 2) & 0x03) * (1024 * 16)) + \
886 vertical_pixel_offset; \
887 u32 pixel_run = 256 - (horizontal_offset % 256); \
890 map_base += ((vertical_offset % 256) / 8) * 32; \
891 partial_tile_offset = (horizontal_offset % 8); \
893 if(pixel_run >= end) \
895 if(partial_tile_offset) \
897 partial_tile_run = 8 - partial_tile_offset; \
898 if(end < partial_tile_run) \
900 partial_tile_run = end; \
901 partial_tile_mid_map(combine_op, color_depth, alpha_op); \
906 end -= partial_tile_run; \
907 partial_tile_right_map(combine_op, color_depth, alpha_op); \
911 tile_run = end / 8; \
912 multiple_tile_map(combine_op, color_depth, alpha_op); \
914 partial_tile_run = end % 8; \
916 if(partial_tile_run) \
918 partial_tile_left_map(combine_op, color_depth, alpha_op); \
923 if(partial_tile_offset) \
925 partial_tile_run = 8 - partial_tile_offset; \
926 partial_tile_right_map(combine_op, color_depth, alpha_op); \
929 tile_run = (pixel_run - partial_tile_run) / 8; \
930 multiple_tile_map(combine_op, color_depth, alpha_op); \
931 map_ptr = second_ptr; \
933 tile_run = end / 8; \
934 multiple_tile_map(combine_op, color_depth, alpha_op); \
936 partial_tile_run = end % 8; \
937 if(partial_tile_run) \
939 partial_tile_left_map(combine_op, color_depth, alpha_op); \
944 #define render_scanline_dest_normal u16
945 #define render_scanline_dest_alpha u32
946 #define render_scanline_dest_alpha_obj u32
947 #define render_scanline_dest_color16 u16
948 #define render_scanline_dest_color32 u32
949 #define render_scanline_dest_partial_alpha u32
950 #define render_scanline_dest_copy_tile u16
951 #define render_scanline_dest_copy_bitmap u16
954 // If rendering a scanline that is not a target A then there's no point in
955 // keeping what's underneath it because it can't blend with it.
957 #define render_scanline_skip_alpha(bg_type, combine_op) \
958 if((pixel_combine & 0x00000200) == 0) \
960 render_scanline_##bg_type##_##combine_op##_color32(layer, \
961 start, end, scanline); \
966 #ifdef RENDER_COLOR16_NORMAL
968 #define render_scanline_extra_variables_base_normal(bg_type) \
969 const u32 pixel_combine = 0 \
973 #define render_scanline_extra_variables_base_normal(bg_type) \
974 u16 *palette = palette_ram_converted \
979 #define render_scanline_extra_variables_base_alpha(bg_type) \
980 u32 bg_combine = color_combine_mask(5); \
981 u32 pixel_combine = color_combine_mask(layer) | (bg_combine << 16); \
982 render_scanline_skip_alpha(bg_type, base) \
984 #define render_scanline_extra_variables_base_color() \
985 u32 bg_combine = color_combine_mask(5); \
986 u32 pixel_combine = color_combine_mask(layer) \
988 #define render_scanline_extra_variables_base_color16(bg_type) \
989 render_scanline_extra_variables_base_color() \
991 #define render_scanline_extra_variables_base_color32(bg_type) \
992 render_scanline_extra_variables_base_color() \
995 #define render_scanline_extra_variables_transparent_normal(bg_type) \
996 render_scanline_extra_variables_base_normal(bg_type) \
998 #define render_scanline_extra_variables_transparent_alpha(bg_type) \
999 u32 pixel_combine = color_combine_mask(layer); \
1000 render_scanline_skip_alpha(bg_type, transparent) \
1002 #define render_scanline_extra_variables_transparent_color() \
1003 u32 pixel_combine = color_combine_mask(layer) \
1005 #define render_scanline_extra_variables_transparent_color16(bg_type) \
1006 render_scanline_extra_variables_transparent_color() \
1008 #define render_scanline_extra_variables_transparent_color32(bg_type) \
1009 render_scanline_extra_variables_transparent_color() \
1015 // Map widths and heights
1017 u32 map_widths[] = { 256, 512, 256, 512 };
1018 u32 map_heights[] = { 256, 256, 512, 512 };
1020 // Build text scanline rendering functions.
1022 #define render_scanline_text_builder(combine_op, alpha_op) \
1023 void render_scanline_text_##combine_op##_##alpha_op(u32 layer, \
1024 u32 start, u32 end, void *scanline) \
1026 render_scanline_extra_variables_##combine_op##_##alpha_op(text); \
1027 u32 bg_control = io_registers[REG_BG0CNT + layer]; \
1028 u32 map_size = (bg_control >> 14) & 0x03; \
1029 u32 map_width = map_widths[map_size]; \
1030 u32 map_height = map_heights[map_size]; \
1031 u32 horizontal_offset = \
1032 (io_registers[REG_BG0HOFS + (layer * 2)] + start) % 512; \
1033 u32 vertical_offset = (io_registers[REG_VCOUNT] + \
1034 io_registers[REG_BG0VOFS + (layer * 2)]) % 512; \
1035 u32 current_pixel; \
1036 u32 current_pixels; \
1037 u32 partial_tile_run = 0; \
1038 u32 partial_tile_offset; \
1041 render_scanline_dest_##alpha_op *dest_ptr = \
1042 ((render_scanline_dest_##alpha_op *)scanline) + start; \
1044 u16 *map_base = (u16 *)(vram + ((bg_control >> 8) & 0x1F) * (1024 * 2)); \
1045 u16 *map_ptr, *second_ptr; \
1050 if((map_size & 0x02) && (vertical_offset >= 256)) \
1052 map_base += ((map_width / 8) * 32) + \
1053 (((vertical_offset - 256) / 8) * 32); \
1057 map_base += (((vertical_offset % 256) / 8) * 32); \
1060 if(map_size & 0x01) \
1062 if(horizontal_offset >= 256) \
1064 horizontal_offset -= 256; \
1065 map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); \
1066 second_ptr = map_base; \
1070 map_ptr = map_base + (horizontal_offset / 8); \
1071 second_ptr = map_base + (32 * 32); \
1076 horizontal_offset %= 256; \
1077 map_ptr = map_base + (horizontal_offset / 8); \
1078 second_ptr = map_base; \
1081 if(bg_control & 0x80) \
1083 tile_render(8bpp, combine_op, alpha_op); \
1087 tile_render(4bpp, combine_op, alpha_op); \
1091 render_scanline_text_builder(base, normal);
1092 render_scanline_text_builder(transparent, normal);
1093 render_scanline_text_builder(base, color16);
1094 render_scanline_text_builder(transparent, color16);
1095 render_scanline_text_builder(base, color32);
1096 render_scanline_text_builder(transparent, color32);
1097 render_scanline_text_builder(base, alpha);
1098 render_scanline_text_builder(transparent, alpha);
1101 s32 affine_reference_x[2];
1102 s32 affine_reference_y[2];
1104 #define affine_render_bg_pixel_normal() \
1105 current_pixel = palette_ram_converted[0] \
1107 #define affine_render_bg_pixel_alpha() \
1108 current_pixel = bg_combine \
1110 #define affine_render_bg_pixel_color16() \
1111 affine_render_bg_pixel_alpha() \
1113 #define affine_render_bg_pixel_color32() \
1114 affine_render_bg_pixel_alpha() \
1116 #define affine_render_bg_pixel_base(alpha_op) \
1117 affine_render_bg_pixel_##alpha_op() \
1119 #define affine_render_bg_pixel_transparent(alpha_op) \
1121 #define affine_render_bg_pixel_copy(alpha_op) \
1123 #define affine_render_bg_base(alpha_op) \
1124 dest_ptr[0] = current_pixel
1126 #define affine_render_bg_transparent(alpha_op) \
1128 #define affine_render_bg_copy(alpha_op) \
1130 #define affine_render_bg_remainder_base(alpha_op) \
1131 affine_render_bg_pixel_##alpha_op(); \
1132 for(; i < end; i++) \
1134 affine_render_bg_base(alpha_op); \
1135 advance_dest_ptr_base(1); \
1138 #define affine_render_bg_remainder_transparent(alpha_op) \
1140 #define affine_render_bg_remainder_copy(alpha_op) \
1142 #define affine_render_next(combine_op) \
1145 advance_dest_ptr_##combine_op(1) \
1147 #define affine_render_scale_offset() \
1148 tile_base += ((pixel_y % 8) * 8); \
1149 map_base += (pixel_y / 8) << map_pitch \
1151 #define affine_render_scale_pixel(combine_op, alpha_op) \
1152 map_offset = (pixel_x / 8); \
1153 if(map_offset != last_map_offset) \
1155 tile_ptr = tile_base + (map_base[map_offset] * 64); \
1156 last_map_offset = map_offset; \
1158 tile_ptr = tile_base + (map_base[(pixel_x / 8)] * 64); \
1159 current_pixel = tile_ptr[(pixel_x % 8)]; \
1160 tile_8bpp_draw_##combine_op(0, none, 0, alpha_op); \
1161 affine_render_next(combine_op) \
1163 #define affine_render_scale(combine_op, alpha_op) \
1165 pixel_y = source_y >> 8; \
1167 affine_render_bg_pixel_##combine_op(alpha_op); \
1168 if((u32)pixel_y < (u32)width_height) \
1170 affine_render_scale_offset(); \
1171 for(; i < end; i++) \
1173 pixel_x = source_x >> 8; \
1175 if((u32)pixel_x < (u32)width_height) \
1180 affine_render_bg_##combine_op(alpha_op); \
1181 affine_render_next(combine_op); \
1184 for(; i < end; i++) \
1186 pixel_x = source_x >> 8; \
1188 if((u32)pixel_x >= (u32)width_height) \
1191 affine_render_scale_pixel(combine_op, alpha_op); \
1194 affine_render_bg_remainder_##combine_op(alpha_op); \
1197 #define affine_render_scale_wrap(combine_op, alpha_op) \
1199 u32 wrap_mask = width_height - 1; \
1200 pixel_y = (source_y >> 8) & wrap_mask; \
1201 if((u32)pixel_y < (u32)width_height) \
1203 affine_render_scale_offset(); \
1204 for(i = 0; i < end; i++) \
1206 pixel_x = (source_x >> 8) & wrap_mask; \
1207 affine_render_scale_pixel(combine_op, alpha_op); \
1213 #define affine_render_rotate_pixel(combine_op, alpha_op) \
1214 map_offset = (pixel_x / 8) + ((pixel_y / 8) << map_pitch); \
1215 if(map_offset != last_map_offset) \
1217 tile_ptr = tile_base + (map_base[map_offset] * 64); \
1218 last_map_offset = map_offset; \
1221 current_pixel = tile_ptr[(pixel_x % 8) + ((pixel_y % 8) * 8)]; \
1222 tile_8bpp_draw_##combine_op(0, none, 0, alpha_op); \
1223 affine_render_next(combine_op) \
1225 #define affine_render_rotate(combine_op, alpha_op) \
1227 affine_render_bg_pixel_##combine_op(alpha_op); \
1228 for(i = 0; i < end; i++) \
1230 pixel_x = source_x >> 8; \
1231 pixel_y = source_y >> 8; \
1233 if(((u32)pixel_x < (u32)width_height) && \
1234 ((u32)pixel_y < (u32)width_height)) \
1238 affine_render_bg_##combine_op(alpha_op); \
1239 affine_render_next(combine_op); \
1242 for(; i < end; i++) \
1244 pixel_x = source_x >> 8; \
1245 pixel_y = source_y >> 8; \
1247 if(((u32)pixel_x >= (u32)width_height) || \
1248 ((u32)pixel_y >= (u32)width_height)) \
1250 affine_render_bg_remainder_##combine_op(alpha_op); \
1254 affine_render_rotate_pixel(combine_op, alpha_op); \
1258 #define affine_render_rotate_wrap(combine_op, alpha_op) \
1260 u32 wrap_mask = width_height - 1; \
1261 for(i = 0; i < end; i++) \
1263 pixel_x = (source_x >> 8) & wrap_mask; \
1264 pixel_y = (source_y >> 8) & wrap_mask; \
1266 affine_render_rotate_pixel(combine_op, alpha_op); \
1271 // Build affine background renderers.
1273 #define render_scanline_affine_builder(combine_op, alpha_op) \
1274 void render_scanline_affine_##combine_op##_##alpha_op(u32 layer, \
1275 u32 start, u32 end, void *scanline) \
1277 render_scanline_extra_variables_##combine_op##_##alpha_op(affine); \
1278 u32 bg_control = io_registers[REG_BG0CNT + layer]; \
1279 u32 current_pixel; \
1280 s32 source_x, source_y; \
1281 u32 vcount = io_registers[REG_VCOUNT]; \
1282 u32 pixel_x, pixel_y; \
1283 u32 layer_offset = (layer - 2) * 8; \
1285 u32 map_size = (bg_control >> 14) & 0x03; \
1286 u32 width_height = 1 << (7 + map_size); \
1287 u32 map_pitch = map_size + 4; \
1288 u8 *map_base = vram + (((bg_control >> 8) & 0x1F) * (1024 * 2)); \
1289 u8 *tile_base = vram + (((bg_control >> 2) & 0x03) * (1024 * 16)); \
1291 u32 map_offset, last_map_offset = (u32)-1; \
1293 render_scanline_dest_##alpha_op *dest_ptr = \
1294 ((render_scanline_dest_##alpha_op *)scanline) + start; \
1296 dx = (s16)io_registers[REG_BG2PA + layer_offset]; \
1297 dy = (s16)io_registers[REG_BG2PC + layer_offset]; \
1298 source_x = affine_reference_x[layer - 2] + (start * dx); \
1299 source_y = affine_reference_y[layer - 2] + (start * dy); \
1303 switch(((bg_control >> 12) & 0x02) | (dy != 0)) \
1306 affine_render_scale(combine_op, alpha_op); \
1310 affine_render_rotate(combine_op, alpha_op); \
1314 affine_render_scale_wrap(combine_op, alpha_op); \
1318 affine_render_rotate_wrap(combine_op, alpha_op); \
1323 render_scanline_affine_builder(base, normal);
1324 render_scanline_affine_builder(transparent, normal);
1325 render_scanline_affine_builder(base, color16);
1326 render_scanline_affine_builder(transparent, color16);
1327 render_scanline_affine_builder(base, color32);
1328 render_scanline_affine_builder(transparent, color32);
1329 render_scanline_affine_builder(base, alpha);
1330 render_scanline_affine_builder(transparent, alpha);
1333 #define bitmap_render_pixel_mode3(alpha_op) \
1334 convert_palette(current_pixel); \
1335 *dest_ptr = current_pixel \
1337 #define bitmap_render_pixel_mode4(alpha_op) \
1338 tile_expand_base_##alpha_op(0) \
1340 #define bitmap_render_pixel_mode5(alpha_op) \
1341 bitmap_render_pixel_mode3(alpha_op) \
1344 #define bitmap_render_scale(type, alpha_op, width, height) \
1345 pixel_y = (source_y >> 8); \
1346 if((u32)pixel_y < (u32)height) \
1348 pixel_x = (source_x >> 8); \
1349 src_ptr += (pixel_y * width); \
1355 dest_ptr -= pixel_x; \
1362 src_ptr += pixel_x; \
1365 if((pixel_x + end) >= width) \
1366 end = (width - pixel_x); \
1368 for(i = 0; (s32)i < (s32)end; i++) \
1370 current_pixel = *src_ptr; \
1371 bitmap_render_pixel_##type(alpha_op); \
1378 if((u32)(source_y >> 8) < (u32)height) \
1380 for(i = 0; i < end; i++) \
1382 pixel_x = (source_x >> 8); \
1384 if((u32)pixel_x < (u32)width) \
1391 for(; i < end; i++) \
1393 pixel_x = (source_x >> 8); \
1395 if((u32)pixel_x >= (u32)width) \
1398 current_pixel = src_ptr[pixel_x]; \
1399 bitmap_render_pixel_##type(alpha_op); \
1408 #define bitmap_render_rotate(type, alpha_op, width, height) \
1409 for(i = 0; i < end; i++) \
1411 pixel_x = source_x >> 8; \
1412 pixel_y = source_y >> 8; \
1414 if(((u32)pixel_x < (u32)width) && ((u32)pixel_y < (u32)height)) \
1422 for(; i < end; i++) \
1424 pixel_x = (source_x >> 8); \
1425 pixel_y = (source_y >> 8); \
1427 if(((u32)pixel_x >= (u32)width) || ((u32)pixel_y >= (u32)height)) \
1430 current_pixel = src_ptr[pixel_x + (pixel_y * width)]; \
1431 bitmap_render_pixel_##type(alpha_op); \
1439 #define render_scanline_vram_setup_mode3() \
1440 u16 *src_ptr = (u16 *)vram \
1442 #define render_scanline_vram_setup_mode5() \
1444 if(io_registers[REG_DISPCNT] & 0x10) \
1445 src_ptr = (u16 *)(vram + 0xA000); \
1447 src_ptr = (u16 *)vram \
1450 #ifdef RENDER_COLOR16_NORMAL
1452 #define render_scanline_vram_setup_mode4() \
1453 const u32 pixel_combine = 0; \
1455 if(io_registers[REG_DISPCNT] & 0x10) \
1456 src_ptr = vram + 0xA000; \
1463 #define render_scanline_vram_setup_mode4() \
1464 u16 *palette = palette_ram_converted; \
1466 if(io_registers[REG_DISPCNT] & 0x10) \
1467 src_ptr = vram + 0xA000; \
1475 // Build bitmap scanline rendering functions.
1477 #define render_scanline_bitmap_builder(type, alpha_op, width, height) \
1478 void render_scanline_bitmap_##type##_##alpha_op(u32 start, u32 end, \
1481 u32 bg_control = io_registers[REG_BG2CNT]; \
1482 u32 current_pixel; \
1483 s32 source_x, source_y; \
1484 u32 vcount = io_registers[REG_VCOUNT]; \
1485 s32 pixel_x, pixel_y; \
1487 s32 dx = (s16)io_registers[REG_BG2PA]; \
1488 s32 dy = (s16)io_registers[REG_BG2PC]; \
1492 render_scanline_dest_##alpha_op *dest_ptr = \
1493 ((render_scanline_dest_##alpha_op *)scanline) + start; \
1494 render_scanline_vram_setup_##type(); \
1498 source_x = affine_reference_x[0] + (start * dx); \
1499 source_y = affine_reference_y[0] + (start * dy); \
1503 bitmap_render_scale(type, alpha_op, width, height); \
1507 bitmap_render_rotate(type, alpha_op, width, height); \
1511 render_scanline_bitmap_builder(mode3, normal, 240, 160);
1512 render_scanline_bitmap_builder(mode4, normal, 240, 160);
1513 render_scanline_bitmap_builder(mode5, normal, 160, 128);
1516 // Fill in the renderers for a layer based on the mode type,
1518 #define tile_layer_render_functions(type) \
1520 render_scanline_##type##_base_normal, \
1521 render_scanline_##type##_transparent_normal, \
1522 render_scanline_##type##_base_alpha, \
1523 render_scanline_##type##_transparent_alpha, \
1524 render_scanline_##type##_base_color16, \
1525 render_scanline_##type##_transparent_color16, \
1526 render_scanline_##type##_base_color32, \
1527 render_scanline_##type##_transparent_color32 \
1531 // Use if a layer is unsupported for that mode.
1533 #define tile_layer_render_null() \
1535 NULL, NULL, NULL, NULL \
1538 #define bitmap_layer_render_functions(type) \
1540 render_scanline_bitmap_##type##_normal \
1543 // Structs containing functions to render the layers for each mode, for
1544 // each render type.
1545 tile_layer_render_struct tile_mode_renderers[3][4] =
1548 tile_layer_render_functions(text), tile_layer_render_functions(text),
1549 tile_layer_render_functions(text), tile_layer_render_functions(text)
1552 tile_layer_render_functions(text), tile_layer_render_functions(text),
1553 tile_layer_render_functions(affine), tile_layer_render_functions(text)
1556 tile_layer_render_functions(text), tile_layer_render_functions(text),
1557 tile_layer_render_functions(affine), tile_layer_render_functions(affine)
1561 bitmap_layer_render_struct bitmap_mode_renderers[3] =
1563 bitmap_layer_render_functions(mode3),
1564 bitmap_layer_render_functions(mode4),
1565 bitmap_layer_render_functions(mode5)
1569 #define render_scanline_layer_functions_tile() \
1570 tile_layer_render_struct *layer_renderers = \
1571 tile_mode_renderers[dispcnt & 0x07] \
1573 #define render_scanline_layer_functions_bitmap() \
1574 bitmap_layer_render_struct *layer_renderers = \
1575 bitmap_mode_renderers + ((dispcnt & 0x07) - 3) \
1578 // Adjust a flipped obj's starting position
1580 #define obj_tile_offset_noflip(color_depth) \
1582 #define obj_tile_offset_flip(color_depth) \
1583 + (tile_size_##color_depth * ((obj_width - 8) / 8)) \
1586 // Adjust the obj's starting point if it goes too far off the left edge of \
1589 #define obj_tile_right_offset_noflip(color_depth) \
1590 tile_ptr += (partial_tile_offset / 8) * tile_size_##color_depth \
1592 #define obj_tile_right_offset_flip(color_depth) \
1593 tile_ptr -= (partial_tile_offset / 8) * tile_size_##color_depth \
1595 // Get the current row offset into an obj in 1D map space
1597 #define obj_tile_offset_1D(color_depth, flip_op) \
1598 tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) \
1599 + ((vertical_offset / 8) * (obj_width / 8) * tile_size_##color_depth) \
1600 + ((vertical_offset % 8) * tile_width_##color_depth) \
1601 obj_tile_offset_##flip_op(color_depth) \
1603 // Get the current row offset into an obj in 2D map space
1605 #define obj_tile_offset_2D(color_depth, flip_op) \
1606 tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) \
1607 + ((vertical_offset / 8) * 1024) \
1608 + ((vertical_offset % 8) * tile_width_##color_depth) \
1609 obj_tile_offset_##flip_op(color_depth) \
1612 // Get the palette for 4bpp obj.
1614 #define obj_get_palette_4bpp() \
1615 current_palette = (obj_attribute_2 >> 8) & 0xF0 \
1617 #define obj_get_palette_8bpp() \
1620 // Render the current row of an obj.
1622 #define obj_render(combine_op, color_depth, alpha_op, map_space, flip_op) \
1624 obj_get_palette_##color_depth(); \
1625 obj_tile_offset_##map_space(color_depth, flip_op); \
1627 if(obj_x < (s32)start) \
1629 dest_ptr = scanline + start; \
1630 pixel_run = obj_width - (start - obj_x); \
1631 if((s32)pixel_run > 0) \
1633 if((obj_x + obj_width) >= end) \
1635 pixel_run = end - start; \
1636 partial_tile_offset = start - obj_x; \
1637 obj_tile_right_offset_##flip_op(color_depth); \
1638 partial_tile_offset %= 8; \
1640 if(partial_tile_offset) \
1642 partial_tile_run = 8 - partial_tile_offset; \
1643 if((s32)pixel_run < (s32)partial_tile_run) \
1645 if((s32)pixel_run > 0) \
1647 partial_tile_run = pixel_run; \
1648 partial_tile_mid_obj(combine_op, color_depth, alpha_op, \
1655 pixel_run -= partial_tile_run; \
1656 partial_tile_right_obj(combine_op, color_depth, alpha_op, \
1660 tile_run = pixel_run / 8; \
1661 multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \
1662 partial_tile_run = pixel_run % 8; \
1663 if(partial_tile_run) \
1665 partial_tile_left_obj(combine_op, color_depth, alpha_op, \
1671 partial_tile_offset = start - obj_x; \
1672 obj_tile_right_offset_##flip_op(color_depth); \
1673 partial_tile_offset %= 8; \
1674 if(partial_tile_offset) \
1676 partial_tile_run = 8 - partial_tile_offset; \
1677 partial_tile_right_obj(combine_op, color_depth, alpha_op, \
1680 tile_run = pixel_run / 8; \
1681 multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \
1687 if((obj_x + obj_width) >= end) \
1689 pixel_run = end - obj_x; \
1690 if((s32)pixel_run > 0) \
1692 dest_ptr = scanline + obj_x; \
1693 tile_run = pixel_run / 8; \
1694 multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \
1695 partial_tile_run = pixel_run % 8; \
1696 if(partial_tile_run) \
1698 partial_tile_left_obj(combine_op, color_depth, alpha_op, flip_op); \
1704 dest_ptr = scanline + obj_x; \
1705 tile_run = obj_width / 8; \
1706 multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \
1710 #define obj_scale_offset_1D(color_depth) \
1711 tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) \
1712 + ((vertical_offset / 8) * (max_x / 8) * tile_size_##color_depth) \
1713 + ((vertical_offset % 8) * tile_width_##color_depth) \
1715 // Get the current row offset into an obj in 2D map space
1717 #define obj_scale_offset_2D(color_depth) \
1718 tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) \
1719 + ((vertical_offset / 8) * 1024) \
1720 + ((vertical_offset % 8) * tile_width_##color_depth) \
1722 #define obj_render_scale_pixel_4bpp(combine_op, alpha_op) \
1725 current_pixel = tile_ptr[tile_map_offset + ((tile_x >> 1) & 0x03)] >> 4; \
1730 tile_ptr[tile_map_offset + ((tile_x >> 1) & 0x03)] & 0x0F; \
1733 tile_4bpp_draw_##combine_op(0, none, 0, alpha_op) \
1736 #define obj_render_scale_pixel_8bpp(combine_op, alpha_op) \
1737 current_pixel = tile_ptr[tile_map_offset + (tile_x & 0x07)]; \
1738 tile_8bpp_draw_##combine_op(0, none, 0, alpha_op); \
1740 #define obj_render_scale(combine_op, color_depth, alpha_op, map_space) \
1742 u32 vertical_offset; \
1743 source_y += (y_delta * dmy); \
1744 vertical_offset = (source_y >> 8); \
1745 if((u32)vertical_offset < (u32)max_y) \
1747 obj_scale_offset_##map_space(color_depth); \
1748 source_x += (y_delta * dmx) - (middle_x * dx); \
1750 for(i = 0; i < obj_width; i++) \
1752 tile_x = (source_x >> 8); \
1754 if((u32)tile_x < (u32)max_x) \
1758 advance_dest_ptr_##combine_op(1); \
1761 for(; i < obj_width; i++) \
1763 tile_x = (source_x >> 8); \
1765 if((u32)tile_x >= (u32)max_x) \
1768 tile_map_offset = (tile_x >> 3) * tile_size_##color_depth; \
1769 obj_render_scale_pixel_##color_depth(combine_op, alpha_op); \
1772 advance_dest_ptr_##combine_op(1); \
1778 #define obj_rotate_offset_1D(color_depth) \
1779 obj_tile_pitch = (max_x / 8) * tile_size_##color_depth \
1781 #define obj_rotate_offset_2D(color_depth) \
1782 obj_tile_pitch = 1024 \
1784 #define obj_render_rotate_pixel_4bpp(combine_op, alpha_op) \
1787 current_pixel = tile_ptr[tile_map_offset + \
1788 ((tile_x >> 1) & 0x03) + ((tile_y & 0x07) * obj_pitch)] >> 4; \
1792 current_pixel = tile_ptr[tile_map_offset + \
1793 ((tile_x >> 1) & 0x03) + ((tile_y & 0x07) * obj_pitch)] & 0x0F; \
1796 tile_4bpp_draw_##combine_op(0, none, 0, alpha_op) \
1798 #define obj_render_rotate_pixel_8bpp(combine_op, alpha_op) \
1799 current_pixel = tile_ptr[tile_map_offset + \
1800 (tile_x & 0x07) + ((tile_y & 0x07) * obj_pitch)]; \
1802 tile_8bpp_draw_##combine_op(0, none, 0, alpha_op) \
1804 #define obj_render_rotate(combine_op, color_depth, alpha_op, map_space) \
1806 tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32); \
1807 obj_rotate_offset_##map_space(color_depth); \
1809 source_x += (y_delta * dmx) - (middle_x * dx); \
1810 source_y += (y_delta * dmy) - (middle_x * dy); \
1812 for(i = 0; i < obj_width; i++) \
1814 tile_x = (source_x >> 8); \
1815 tile_y = (source_y >> 8); \
1817 if(((u32)tile_x < (u32)max_x) && ((u32)tile_y < (u32)max_y)) \
1822 advance_dest_ptr_##combine_op(1); \
1825 for(; i < obj_width; i++) \
1827 tile_x = (source_x >> 8); \
1828 tile_y = (source_y >> 8); \
1830 if(((u32)tile_x >= (u32)max_x) || ((u32)tile_y >= (u32)max_y)) \
1833 tile_map_offset = ((tile_x >> 3) * tile_size_##color_depth) + \
1834 ((tile_y >> 3) * obj_tile_pitch); \
1835 obj_render_rotate_pixel_##color_depth(combine_op, alpha_op); \
1839 advance_dest_ptr_##combine_op(1); \
1843 // Render the current row of an affine transformed OBJ.
1845 #define obj_render_affine(combine_op, color_depth, alpha_op, map_space) \
1847 s16 *params = oam_ram + (((obj_attribute_1 >> 9) & 0x1F) * 16); \
1848 s32 dx = params[3]; \
1849 s32 dmx = params[7]; \
1850 s32 dy = params[11]; \
1851 s32 dmy = params[15]; \
1852 s32 source_x, source_y; \
1853 s32 tile_x, tile_y; \
1855 u32 tile_map_offset; \
1858 s32 max_x = obj_width; \
1859 s32 max_y = obj_height; \
1861 u32 obj_pitch = tile_width_##color_depth; \
1862 u32 obj_tile_pitch; \
1864 middle_x = (obj_width / 2); \
1865 middle_y = (obj_height / 2); \
1867 source_x = (middle_x << 8); \
1868 source_y = (middle_y << 8); \
1871 if(obj_attribute_0 & 0x200) \
1879 if((s32)obj_x < (s32)start) \
1881 u32 x_delta = start - obj_x; \
1882 middle_x -= x_delta; \
1883 obj_width -= x_delta; \
1886 if((s32)obj_width <= 0) \
1890 if((s32)(obj_x + obj_width) >= (s32)end) \
1892 obj_width = end - obj_x; \
1894 if((s32)obj_width <= 0) \
1897 dest_ptr = scanline + obj_x; \
1899 y_delta = vcount - (obj_y + middle_y); \
1901 obj_get_palette_##color_depth(); \
1905 obj_render_scale(combine_op, color_depth, alpha_op, map_space); \
1909 obj_render_rotate(combine_op, color_depth, alpha_op, map_space); \
1913 u32 obj_width_table[] = { 8, 16, 32, 64, 16, 32, 32, 64, 8, 8, 16, 32 };
1914 u32 obj_height_table[] = { 8, 16, 32, 64, 8, 8, 16, 32, 16, 32, 32, 64 };
1916 u8 obj_priority_list[5][160][128];
1917 u32 obj_priority_count[5][160];
1918 u32 obj_alpha_count[160];
1921 // Build obj rendering functions
1923 #ifdef RENDER_COLOR16_NORMAL
1925 #define render_scanline_obj_extra_variables_normal(bg_type) \
1926 const u32 pixel_combine = (1 << 8) \
1930 #define render_scanline_obj_extra_variables_normal(bg_type) \
1931 u16 *palette = palette_ram_converted + 256 \
1936 #define render_scanline_obj_extra_variables_color() \
1938 u32 pixel_combine = color_combine_mask(4) | (1 << 8) \
1940 #define render_scanline_obj_extra_variables_alpha_obj(map_space) \
1941 render_scanline_obj_extra_variables_color(); \
1942 if((pixel_combine & 0x00000200) == 0) \
1944 render_scanline_obj_color32_##map_space(priority, start, end, scanline); \
1948 #define render_scanline_obj_extra_variables_color16(map_space) \
1949 render_scanline_obj_extra_variables_color() \
1951 #define render_scanline_obj_extra_variables_color32(map_space) \
1952 render_scanline_obj_extra_variables_color() \
1954 #define render_scanline_obj_extra_variables_partial_alpha(map_space) \
1955 render_scanline_obj_extra_variables_color(); \
1956 u32 base_pixel_combine = pixel_combine \
1958 #define render_scanline_obj_extra_variables_copy(type) \
1959 u32 bldcnt = io_registers[REG_BLDCNT]; \
1960 u32 dispcnt = io_registers[REG_DISPCNT]; \
1961 u32 obj_enable = io_registers[REG_WINOUT] >> 8; \
1962 render_scanline_layer_functions_##type(); \
1963 u32 copy_start, copy_end; \
1964 u16 copy_buffer[240]; \
1967 #define render_scanline_obj_extra_variables_copy_tile(map_space) \
1968 render_scanline_obj_extra_variables_copy(tile) \
1970 #define render_scanline_obj_extra_variables_copy_bitmap(map_space) \
1971 render_scanline_obj_extra_variables_copy(bitmap) \
1974 #define render_scanline_obj_main(combine_op, alpha_op, map_space) \
1975 if(obj_attribute_0 & 0x100) \
1977 if((obj_attribute_0 >> 13) & 0x01) \
1979 obj_render_affine(combine_op, 8bpp, alpha_op, map_space); \
1983 obj_render_affine(combine_op, 4bpp, alpha_op, map_space); \
1988 vertical_offset = vcount - obj_y; \
1990 if((obj_attribute_1 >> 13) & 0x01) \
1991 vertical_offset = obj_height - vertical_offset - 1; \
1993 switch(((obj_attribute_0 >> 12) & 0x02) | \
1994 ((obj_attribute_1 >> 12) & 0x01)) \
1997 obj_render(combine_op, 4bpp, alpha_op, map_space, noflip); \
2001 obj_render(combine_op, 4bpp, alpha_op, map_space, flip); \
2005 obj_render(combine_op, 8bpp, alpha_op, map_space, noflip); \
2009 obj_render(combine_op, 8bpp, alpha_op, map_space, flip); \
2014 #define render_scanline_obj_no_partial_alpha(combine_op, alpha_op, map_space) \
2015 render_scanline_obj_main(combine_op, alpha_op, map_space) \
2017 #define render_scanline_obj_partial_alpha(combine_op, alpha_op, map_space) \
2018 if((obj_attribute_0 >> 10) & 0x03) \
2020 pixel_combine = 0x00000300; \
2021 render_scanline_obj_main(combine_op, alpha_obj, map_space); \
2025 pixel_combine = base_pixel_combine; \
2026 render_scanline_obj_main(combine_op, color32, map_space); \
2029 #define render_scanline_obj_prologue_transparent(alpha_op) \
2031 #define render_scanline_obj_prologue_copy_body(type) \
2032 copy_start = obj_x; \
2033 if(obj_attribute_0 & 0x200) \
2034 copy_end = obj_x + (obj_width * 2); \
2036 copy_end = obj_x + obj_width; \
2038 if(copy_start < start) \
2039 copy_start = start; \
2040 if(copy_end > end) \
2043 if((copy_start < end) && (copy_end > start)) \
2045 render_scanline_conditional_##type(copy_start, copy_end, copy_buffer, \
2046 obj_enable, dispcnt, bldcnt, layer_renderers); \
2047 copy_ptr = copy_buffer + copy_start; \
2054 #define render_scanline_obj_prologue_copy_tile() \
2055 render_scanline_obj_prologue_copy_body(tile) \
2057 #define render_scanline_obj_prologue_copy_bitmap() \
2058 render_scanline_obj_prologue_copy_body(bitmap) \
2060 #define render_scanline_obj_prologue_copy(alpha_op) \
2061 render_scanline_obj_prologue_##alpha_op() \
2064 #define render_scanline_obj_builder(combine_op, alpha_op, map_space, \
2066 void render_scanline_obj_##alpha_op##_##map_space(u32 priority, \
2067 u32 start, u32 end, render_scanline_dest_##alpha_op *scanline) \
2069 render_scanline_obj_extra_variables_##alpha_op(map_space); \
2073 s32 obj_width, obj_height; \
2074 u32 obj_attribute_0, obj_attribute_1, obj_attribute_2; \
2075 s32 vcount = io_registers[REG_VCOUNT]; \
2077 u32 current_pixels; \
2078 u32 current_pixel; \
2079 u32 current_palette; \
2080 u32 vertical_offset; \
2081 u32 partial_tile_run, partial_tile_offset; \
2084 render_scanline_dest_##alpha_op *dest_ptr; \
2085 u8 *tile_base = vram + 0x10000; \
2087 u32 obj_count = obj_priority_count[priority][vcount]; \
2088 u8 *obj_list = obj_priority_list[priority][vcount]; \
2090 for(obj_num = 0; obj_num < obj_count; obj_num++) \
2092 oam_ptr = oam_ram + (obj_list[obj_num] * 4); \
2093 obj_attribute_0 = oam_ptr[0]; \
2094 obj_attribute_1 = oam_ptr[1]; \
2095 obj_attribute_2 = oam_ptr[2]; \
2096 obj_size = ((obj_attribute_0 >> 12) & 0x0C) | (obj_attribute_1 >> 14); \
2098 obj_x = (s32)(obj_attribute_1 << 23) >> 23; \
2099 obj_width = obj_width_table[obj_size]; \
2101 render_scanline_obj_prologue_##combine_op(alpha_op); \
2103 obj_y = obj_attribute_0 & 0xFF; \
2108 obj_height = obj_height_table[obj_size]; \
2109 render_scanline_obj_##partial_alpha_op(combine_op, alpha_op, map_space); \
2113 render_scanline_obj_builder(transparent, normal, 1D, no_partial_alpha);
2114 render_scanline_obj_builder(transparent, normal, 2D, no_partial_alpha);
2115 render_scanline_obj_builder(transparent, color16, 1D, no_partial_alpha);
2116 render_scanline_obj_builder(transparent, color16, 2D, no_partial_alpha);
2117 render_scanline_obj_builder(transparent, color32, 1D, no_partial_alpha);
2118 render_scanline_obj_builder(transparent, color32, 2D, no_partial_alpha);
2119 render_scanline_obj_builder(transparent, alpha_obj, 1D, no_partial_alpha);
2120 render_scanline_obj_builder(transparent, alpha_obj, 2D, no_partial_alpha);
2121 render_scanline_obj_builder(transparent, partial_alpha, 1D, partial_alpha);
2122 render_scanline_obj_builder(transparent, partial_alpha, 2D, partial_alpha);
2123 render_scanline_obj_builder(copy, copy_tile, 1D, no_partial_alpha);
2124 render_scanline_obj_builder(copy, copy_tile, 2D, no_partial_alpha);
2125 render_scanline_obj_builder(copy, copy_bitmap, 1D, no_partial_alpha);
2126 render_scanline_obj_builder(copy, copy_bitmap, 2D, no_partial_alpha);
2130 void order_obj(u32 video_mode)
2132 s32 obj_num, priority, row;
2134 s32 obj_size, obj_mode;
2135 s32 obj_width, obj_height;
2137 u32 obj_attribute_0, obj_attribute_1, obj_attribute_2;
2138 s32 vcount = io_registers[REG_VCOUNT];
2139 u32 partial_tile_run, partial_tile_offset;
2142 u16 *oam_ptr = oam_ram + 508;
2144 u8 *tile_base = vram + 0x10000;
2147 for(priority = 0; priority < 5; priority++)
2149 for(row = 0; row < 160; row++)
2151 obj_priority_count[priority][row] = 0;
2155 for(row = 0; row < 160; row++)
2157 obj_alpha_count[row] = 0;
2160 for(obj_num = 127; obj_num >= 0; obj_num--, oam_ptr -= 4)
2162 obj_attribute_0 = oam_ptr[0];
2163 obj_attribute_2 = oam_ptr[2];
2164 obj_size = obj_attribute_0 & 0xC000;
2165 obj_priority = (obj_attribute_2 >> 10) & 0x03;
2166 obj_mode = (obj_attribute_0 >> 10) & 0x03;
2168 if(((obj_attribute_0 & 0x0300) != 0x0200) && (obj_size != 0xC000) &&
2169 (obj_mode != 3) && ((video_mode < 3) ||
2170 ((obj_attribute_2 & 0x3FF) >= 512)))
2172 obj_y = obj_attribute_0 & 0xFF;
2176 obj_attribute_1 = oam_ptr[1];
2177 obj_size = ((obj_size >> 12) & 0x0C) | (obj_attribute_1 >> 14);
2178 obj_height = obj_height_table[obj_size];
2179 obj_width = obj_width_table[obj_size];
2181 if(obj_attribute_0 & 0x200)
2187 if(((obj_y + obj_height) > 0) && (obj_y < 160))
2189 obj_x = (s32)(obj_attribute_1 << 23) >> 23;
2191 if(((obj_x + obj_width) > 0) && (obj_x < 240))
2195 obj_height += obj_y;
2199 if((obj_y + obj_height) >= 160)
2201 obj_height = 160 - obj_y;
2206 for(row = obj_y; row < obj_y + obj_height; row++)
2208 current_count = obj_priority_count[obj_priority][row];
2209 obj_priority_list[obj_priority][row][current_count] = obj_num;
2210 obj_priority_count[obj_priority][row] = current_count + 1;
2211 obj_alpha_count[row]++;
2221 for(row = obj_y; row < obj_y + obj_height; row++)
2223 current_count = obj_priority_count[obj_priority][row];
2224 obj_priority_list[obj_priority][row][current_count] = obj_num;
2225 obj_priority_count[obj_priority][row] = current_count + 1;
2234 u32 layer_order[16];
2237 u32 order_layers(u32 layer_flags)
2239 s32 priority, layer_number;
2242 for(priority = 3; priority >= 0; priority--)
2244 for(layer_number = 3; layer_number >= 0; layer_number--)
2246 if(((layer_flags >> layer_number) & 1) &&
2247 ((io_registers[REG_BG0CNT + layer_number] & 0x03) == priority))
2249 layer_order[layer_count] = layer_number;
2254 if((obj_priority_count[priority][io_registers[REG_VCOUNT]] > 0)
2255 && (layer_flags & 0x10))
2257 layer_order[layer_count] = priority | 0x04;
2263 #define fill_line(_start, _end) \
2266 for(i = _start; i < _end; i++) \
2268 dest_ptr[i] = color; \
2272 #define fill_line_color_normal() \
2273 color = palette_ram_converted[color] \
2275 #define fill_line_color_alpha() \
2277 #define fill_line_color_color16() \
2279 #define fill_line_color_color32() \
2281 #define fill_line_builder(type) \
2282 void fill_line_##type(u16 color, render_scanline_dest_##type *dest_ptr, \
2283 u32 start, u32 end) \
2285 fill_line_color_##type(); \
2286 fill_line(start, end); \
2289 fill_line_builder(normal);
2290 fill_line_builder(alpha);
2291 fill_line_builder(color16);
2292 fill_line_builder(color32);
2295 // Alpha blend two pixels (pixel_top and pixel_bottom).
2297 #define blend_pixel() \
2298 pixel_bottom = palette_ram_converted[(pixel_pair >> 16) & 0x1FF]; \
2299 pixel_bottom = (pixel_bottom | (pixel_bottom << 16)) & 0x07E0F81F; \
2300 pixel_top = ((pixel_top * blend_a) + (pixel_bottom * blend_b)) >> 4 \
2303 // Alpha blend two pixels, allowing for saturation (individual channels > 31).
2304 // The operation is optimized towards saturation not occuring.
2306 #define blend_saturate_pixel() \
2307 pixel_bottom = palette_ram_converted[(pixel_pair >> 16) & 0x1FF]; \
2308 pixel_bottom = (pixel_bottom | (pixel_bottom << 16)) & 0x07E0F81F; \
2309 pixel_top = ((pixel_top * blend_a) + (pixel_bottom * blend_b)) >> 4; \
2310 if(pixel_top & 0x08010020) \
2312 if(pixel_top & 0x08000000) \
2313 pixel_top |= 0x07E00000; \
2315 if(pixel_top & 0x00010000) \
2316 pixel_top |= 0x0000F800; \
2318 if(pixel_top & 0x00000020) \
2319 pixel_top |= 0x0000001F; \
2322 #define brighten_pixel() \
2323 pixel_top = upper + ((pixel_top * blend) >> 4); \
2325 #define darken_pixel() \
2326 pixel_top = (pixel_top * blend) >> 4; \
2328 #define effect_condition_alpha \
2329 ((pixel_pair & 0x04000200) == 0x04000200) \
2331 #define effect_condition_fade(pixel_source) \
2332 ((pixel_source & 0x00000200) == 0x00000200) \
2334 #define expand_pixel_no_dest(expand_type, pixel_source) \
2335 pixel_top = (pixel_top | (pixel_top << 16)) & 0x07E0F81F; \
2336 expand_type##_pixel(); \
2337 pixel_top &= 0x07E0F81F; \
2338 pixel_top = (pixel_top >> 16) | pixel_top \
2340 #define expand_pixel(expand_type, pixel_source) \
2341 pixel_top = palette_ram_converted[pixel_source & 0x1FF]; \
2342 expand_pixel_no_dest(expand_type, pixel_source); \
2343 *screen_dest_ptr = pixel_top \
2345 #define expand_loop(expand_type, effect_condition, pixel_source) \
2346 screen_src_ptr += start; \
2347 screen_dest_ptr += start; \
2351 for(i = 0; i < end; i++) \
2353 pixel_source = *screen_src_ptr; \
2354 if(effect_condition) \
2356 expand_pixel(expand_type, pixel_source); \
2360 *screen_dest_ptr = \
2361 palette_ram_converted[pixel_source & 0x1FF]; \
2365 screen_dest_ptr++; \
2369 #define expand_loop_partial_alpha(alpha_expand, expand_type) \
2370 screen_src_ptr += start; \
2371 screen_dest_ptr += start; \
2375 for(i = 0; i < end; i++) \
2377 pixel_pair = *screen_src_ptr; \
2378 if(effect_condition_fade(pixel_pair)) \
2380 if(effect_condition_alpha) \
2382 expand_pixel(alpha_expand, pixel_pair); \
2386 expand_pixel(expand_type, pixel_pair); \
2391 *screen_dest_ptr = \
2392 palette_ram_converted[pixel_pair & 0x1FF]; \
2396 screen_dest_ptr++; \
2400 #define expand_partial_alpha(expand_type) \
2401 if((blend_a + blend_b) > 16) \
2403 expand_loop_partial_alpha(blend_saturate, expand_type); \
2407 expand_loop_partial_alpha(blend, expand_type); \
2412 // Blend top two pixels of scanline with each other.
2414 #ifdef RENDER_COLOR16_NORMAL
2418 void expand_normal(u16 *screen_ptr, u32 start, u32 end)
2420 u32 i, pixel_source;
2421 screen_ptr += start;
2427 for(i = 0; i < end; i++)
2429 pixel_source = *screen_ptr;
2430 *screen_ptr = palette_ram_converted[pixel_source];
2440 #define expand_normal(screen_ptr, start, end)
2445 void expand_blend(u32 *screen_src_ptr, u16 *screen_dest_ptr,
2446 u32 start, u32 end);
2450 void expand_blend(u32 *screen_src_ptr, u16 *screen_dest_ptr,
2454 u32 pixel_top, pixel_bottom;
2455 u32 bldalpha = io_registers[REG_BLDALPHA];
2456 u32 blend_a = bldalpha & 0x1F;
2457 u32 blend_b = (bldalpha >> 8) & 0x1F;
2466 // The individual colors can saturate over 31, this should be taken
2467 // care of in an alternate pass as it incurs a huge additional speedhit.
2468 if((blend_a + blend_b) > 16)
2470 expand_loop(blend_saturate, effect_condition_alpha, pixel_pair);
2474 expand_loop(blend, effect_condition_alpha, pixel_pair);
2480 // Blend scanline with white.
2482 void expand_darken(u16 *screen_src_ptr, u16 *screen_dest_ptr,
2486 s32 blend = 16 - (io_registers[REG_BLDY] & 0x1F);
2492 expand_loop(darken, effect_condition_fade(pixel_top), pixel_top);
2496 // Blend scanline with black.
2498 void expand_brighten(u16 *screen_src_ptr, u16 *screen_dest_ptr,
2502 u32 blend = io_registers[REG_BLDY] & 0x1F;
2509 upper = ((0x07E0F81F * blend) >> 4) & 0x07E0F81F;
2512 expand_loop(brighten, effect_condition_fade(pixel_top), pixel_top);
2517 // Expand scanline such that if both top and bottom pass it's alpha,
2518 // if only top passes it's as specified, and if neither pass it's normal.
2520 void expand_darken_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ptr,
2523 s32 blend = 16 - (io_registers[REG_BLDY] & 0x1F);
2525 u32 pixel_top, pixel_bottom;
2526 u32 bldalpha = io_registers[REG_BLDALPHA];
2527 u32 blend_a = bldalpha & 0x1F;
2528 u32 blend_b = (bldalpha >> 8) & 0x1F;
2540 expand_partial_alpha(darken);
2544 void expand_brighten_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ptr,
2547 s32 blend = io_registers[REG_BLDY] & 0x1F;
2549 u32 pixel_top, pixel_bottom;
2550 u32 bldalpha = io_registers[REG_BLDALPHA];
2551 u32 blend_a = bldalpha & 0x1F;
2552 u32 blend_b = (bldalpha >> 8) & 0x1F;
2559 upper = ((0x07E0F81F * blend) >> 4) & 0x07E0F81F;
2568 expand_partial_alpha(brighten);
2572 // Render an OBJ layer from start to end, depending on the type (1D or 2D)
2573 // stored in dispcnt.
2575 #define render_obj_layer(type, dest, _start, _end) \
2576 current_layer &= ~0x04; \
2577 if(dispcnt & 0x40) \
2578 render_scanline_obj_##type##_1D(current_layer, _start, _end, dest); \
2580 render_scanline_obj_##type##_2D(current_layer, _start, _end, dest) \
2583 // Render a target all the way with the background color as taken from the
2586 #define fill_line_bg(type, dest, _start, _end) \
2587 fill_line_##type(0, dest, _start, _end) \
2590 // Render all layers as they appear in the layer order.
2592 #define render_layers(tile_alpha, obj_alpha, dest) \
2594 current_layer = layer_order[0]; \
2595 if(current_layer & 0x04) \
2597 /* If the first one is OBJ render the background then render it. */ \
2598 fill_line_bg(tile_alpha, dest, 0, 240); \
2599 render_obj_layer(obj_alpha, dest, 0, 240); \
2603 /* Otherwise render a base layer. */ \
2604 layer_renderers[current_layer].tile_alpha##_render_base(current_layer, \
2608 /* Render the rest of the layers. */ \
2609 for(layer_order_pos = 1; layer_order_pos < layer_count; layer_order_pos++) \
2611 current_layer = layer_order[layer_order_pos]; \
2612 if(current_layer & 0x04) \
2614 render_obj_layer(obj_alpha, dest, 0, 240); \
2618 layer_renderers[current_layer]. \
2619 tile_alpha##_render_transparent(current_layer, 0, 240, dest); \
2624 #define render_condition_alpha \
2625 (((io_registers[REG_BLDALPHA] & 0x1F1F) != 0x001F) && \
2626 ((io_registers[REG_BLDCNT] & 0x3F) != 0) && \
2627 ((io_registers[REG_BLDCNT] & 0x3F00) != 0)) \
2629 #define render_condition_fade \
2630 (((io_registers[REG_BLDY] & 0x1F) != 0) && \
2631 ((io_registers[REG_BLDCNT] & 0x3F) != 0)) \
2633 #define render_layers_color_effect(renderer, layer_condition, \
2634 alpha_condition, fade_condition, _start, _end) \
2636 if(layer_condition) \
2638 if(obj_alpha_count[io_registers[REG_VCOUNT]] > 0) \
2640 /* Render based on special effects mode. */ \
2641 u32 screen_buffer[240]; \
2642 switch((bldcnt >> 6) & 0x03) \
2647 if(alpha_condition) \
2649 renderer(alpha, alpha_obj, screen_buffer); \
2650 expand_blend(screen_buffer, scanline, _start, _end); \
2656 /* Fade to white */ \
2659 if(fade_condition) \
2661 renderer(color32, partial_alpha, screen_buffer); \
2662 expand_brighten_partial_alpha(screen_buffer, scanline, \
2669 /* Fade to black */ \
2672 if(fade_condition) \
2674 renderer(color32, partial_alpha, screen_buffer); \
2675 expand_darken_partial_alpha(screen_buffer, scanline, \
2683 renderer(color32, partial_alpha, screen_buffer); \
2684 expand_blend(screen_buffer, scanline, _start, _end); \
2688 /* Render based on special effects mode. */ \
2689 switch((bldcnt >> 6) & 0x03) \
2694 if(alpha_condition) \
2696 u32 screen_buffer[240]; \
2697 renderer(alpha, alpha_obj, screen_buffer); \
2698 expand_blend(screen_buffer, scanline, _start, _end); \
2704 /* Fade to white */ \
2707 if(fade_condition) \
2709 renderer(color16, color16, scanline); \
2710 expand_brighten(scanline, scanline, _start, _end); \
2716 /* Fade to black */ \
2719 if(fade_condition) \
2721 renderer(color16, color16, scanline); \
2722 expand_darken(scanline, scanline, _start, _end); \
2729 renderer(normal, normal, scanline); \
2730 expand_normal(scanline, _start, _end); \
2735 u32 pixel_top = palette_ram_converted[0]; \
2736 switch((bldcnt >> 6) & 0x03) \
2738 /* Fade to white */ \
2741 if(color_combine_mask_a(5)) \
2743 u32 blend = io_registers[REG_BLDY] & 0x1F; \
2749 upper = ((0x07E0F81F * blend) >> 4) & 0x07E0F81F; \
2750 blend = 16 - blend; \
2752 expand_pixel_no_dest(brighten, pixel_top); \
2757 /* Fade to black */ \
2760 if(color_combine_mask_a(5)) \
2762 s32 blend = 16 - (io_registers[REG_BLDY] & 0x1F); \
2767 expand_pixel_no_dest(darken, pixel_top); \
2772 fill_line_color16(pixel_top, scanline, _start, _end); \
2777 // Renders an entire scanline from 0 to 240, based on current color mode.
2779 void render_scanline_tile(u16 *scanline, u32 dispcnt)
2782 u32 layer_order_pos;
2783 u32 bldcnt = io_registers[REG_BLDCNT];
2784 render_scanline_layer_functions_tile();
2786 render_layers_color_effect(render_layers, layer_count,
2787 render_condition_alpha, render_condition_fade, 0, 240);
2790 void render_scanline_bitmap(u16 *scanline, u32 dispcnt)
2792 u32 bldcnt = io_registers[REG_BLDCNT];
2793 render_scanline_layer_functions_bitmap();
2795 u32 layer_order_pos;
2797 fill_line_bg(normal, scanline, 0, 240);
2799 for(layer_order_pos = 0; layer_order_pos < layer_count; layer_order_pos++)
2801 current_layer = layer_order[layer_order_pos];
2802 if(current_layer & 0x04)
2804 render_obj_layer(normal, scanline, 0, 240);
2808 layer_renderers->normal_render(0, 240, scanline);
2813 // Render layers from start to end based on if they're allowed in the
2816 #define render_layers_conditional(tile_alpha, obj_alpha, dest) \
2819 current_layer = layer_order[layer_order_pos]; \
2820 /* If OBJ aren't enabled skip to the first non-OBJ layer */ \
2821 if(!(enable_flags & 0x10)) \
2823 while((current_layer & 0x04) || !((1 << current_layer) & enable_flags)) \
2825 layer_order_pos++; \
2826 current_layer = layer_order[layer_order_pos]; \
2828 /* Oops, ran out of layers, render the background. */ \
2829 if(layer_order_pos == layer_count) \
2831 fill_line_bg(tile_alpha, dest, start, end); \
2836 /* Render the first valid layer */ \
2837 layer_renderers[current_layer].tile_alpha##_render_base(current_layer, \
2838 start, end, dest); \
2840 layer_order_pos++; \
2842 /* Render the rest of the layers if active, skipping OBJ ones. */ \
2843 for(; layer_order_pos < layer_count; layer_order_pos++) \
2845 current_layer = layer_order[layer_order_pos]; \
2846 if(!(current_layer & 0x04) && ((1 << current_layer) & enable_flags)) \
2848 layer_renderers[current_layer]. \
2849 tile_alpha##_render_transparent(current_layer, start, end, dest); \
2855 /* Find the first active layer, skip all of the inactive ones */ \
2856 while(!((current_layer & 0x04) || ((1 << current_layer) & enable_flags))) \
2858 layer_order_pos++; \
2859 current_layer = layer_order[layer_order_pos]; \
2861 /* Oops, ran out of layers, render the background. */ \
2862 if(layer_order_pos == layer_count) \
2864 fill_line_bg(tile_alpha, dest, start, end); \
2869 if(current_layer & 0x04) \
2871 /* If the first one is OBJ render the background then render it. */ \
2872 fill_line_bg(tile_alpha, dest, start, end); \
2873 render_obj_layer(obj_alpha, dest, start, end); \
2877 /* Otherwise render a base layer. */ \
2878 layer_renderers[current_layer]. \
2879 tile_alpha##_render_base(current_layer, start, end, dest); \
2882 layer_order_pos++; \
2884 /* Render the rest of the layers. */ \
2885 for(; layer_order_pos < layer_count; layer_order_pos++) \
2887 current_layer = layer_order[layer_order_pos]; \
2888 if(current_layer & 0x04) \
2890 render_obj_layer(obj_alpha, dest, start, end); \
2894 if(enable_flags & (1 << current_layer)) \
2896 layer_renderers[current_layer]. \
2897 tile_alpha##_render_transparent(current_layer, start, end, dest); \
2908 // Render all of the BG and OBJ in a tiled scanline from start to end ONLY if
2909 // enable_flag allows that layer/OBJ. Also conditionally render color effects.
2911 void render_scanline_conditional_tile(u32 start, u32 end, u16 *scanline,
2912 u32 enable_flags, u32 dispcnt, u32 bldcnt, tile_layer_render_struct
2916 u32 layer_order_pos = 0;
2918 render_layers_color_effect(render_layers_conditional,
2919 (layer_count && (enable_flags & 0x1F)),
2920 ((enable_flags & 0x20) && render_condition_alpha),
2921 ((enable_flags & 0x20) && render_condition_fade), start, end);
2925 // Render the BG and OBJ in a bitmap scanline from start to end ONLY if
2926 // enable_flag allows that layer/OBJ. Also conditionally render color effects.
2928 void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline,
2929 u32 enable_flags, u32 dispcnt, u32 bldcnt, bitmap_layer_render_struct
2933 u32 layer_order_pos;
2935 fill_line_bg(normal, scanline, start, end);
2937 for(layer_order_pos = 0; layer_order_pos < layer_count; layer_order_pos++)
2939 current_layer = layer_order[layer_order_pos];
2940 if(current_layer & 0x04)
2942 if(enable_flags & 0x10)
2944 render_obj_layer(normal, scanline, start, end);
2949 if(enable_flags & 0x04)
2950 layer_renderers->normal_render(start, end, scanline);
2956 #define window_x_coords(window_number) \
2957 window_##window_number##_x1 = \
2958 io_registers[REG_WIN##window_number##H] >> 8; \
2959 window_##window_number##_x2 = \
2960 io_registers[REG_WIN##window_number##H] & 0xFF; \
2961 window_##window_number##_enable = \
2962 (winin >> (window_number * 8)) & 0x3F; \
2964 if(window_##window_number##_x1 > 240) \
2965 window_##window_number##_x1 = 240; \
2967 if(window_##window_number##_x2 > 240) \
2968 window_##window_number##_x2 = 240 \
2970 #define window_coords(window_number) \
2971 u32 window_##window_number##_x1, window_##window_number##_x2; \
2972 u32 window_##window_number##_y1, window_##window_number##_y2; \
2973 u32 window_##window_number##_enable; \
2974 window_##window_number##_y1 = \
2975 io_registers[REG_WIN##window_number##V] >> 8; \
2976 window_##window_number##_y2 = \
2977 io_registers[REG_WIN##window_number##V] & 0xFF; \
2979 if(window_##window_number##_y1 > window_##window_number##_y2) \
2981 if((((vcount <= window_##window_number##_y2) || \
2982 (vcount > window_##window_number##_y1)) || \
2983 (window_##window_number##_y2 > 227)) && \
2984 (window_##window_number##_y1 <= 227)) \
2986 window_x_coords(window_number); \
2990 window_##window_number##_x1 = 240; \
2991 window_##window_number##_x2 = 240; \
2996 if((((vcount >= window_##window_number##_y1) && \
2997 (vcount < window_##window_number##_y2)) || \
2998 (window_##window_number##_y2 > 227)) && \
2999 (window_##window_number##_y1 <= 227)) \
3001 window_x_coords(window_number); \
3005 window_##window_number##_x1 = 240; \
3006 window_##window_number##_x2 = 240; \
3010 #define render_window_segment(type, start, end, window_type) \
3013 render_scanline_conditional_##type(start, end, scanline, \
3014 window_##window_type##_enable, dispcnt, bldcnt, layer_renderers); \
3017 #define render_window_segment_unequal(type, start, end, window_type) \
3018 render_scanline_conditional_##type(start, end, scanline, \
3019 window_##window_type##_enable, dispcnt, bldcnt, layer_renderers) \
3021 #define render_window_segment_clip(type, clip_start, clip_end, start, end, \
3026 if(start < clip_start) \
3028 if(end > clip_start) \
3030 if(end > clip_end) \
3032 render_window_segment_unequal(type, clip_start, clip_end, \
3037 render_window_segment_unequal(type, clip_start, end, window_type); \
3043 if(end > clip_end) \
3045 if(start < clip_end) \
3046 render_window_segment_unequal(type, start, clip_end, window_type); \
3050 render_window_segment_unequal(type, start, end, window_type); \
3055 #define render_window_clip_1(type, start, end) \
3056 if(window_1_x1 != 240) \
3058 if(window_1_x1 > window_1_x2) \
3060 render_window_segment_clip(type, start, end, 0, window_1_x2, 1); \
3061 render_window_segment_clip(type, start, end, window_1_x2, window_1_x1, \
3063 render_window_segment_clip(type, start, end, window_1_x1, 240, 1); \
3067 render_window_segment_clip(type, start, end, 0, window_1_x1, out); \
3068 render_window_segment_clip(type, start, end, window_1_x1, window_1_x2, \
3070 render_window_segment_clip(type, start, end, window_1_x2, 240, out); \
3075 render_window_segment(type, start, end, out); \
3078 #define render_window_clip_obj(type, start, end); \
3079 render_window_segment(type, start, end, out); \
3080 if(dispcnt & 0x40) \
3081 render_scanline_obj_copy_##type##_1D(4, start, end, scanline); \
3083 render_scanline_obj_copy_##type##_2D(4, start, end, scanline) \
3086 #define render_window_segment_clip_obj(type, clip_start, clip_end, start, \
3091 if(start < clip_start) \
3093 if(end > clip_start) \
3095 if(end > clip_end) \
3097 render_window_clip_obj(type, clip_start, clip_end); \
3101 render_window_clip_obj(type, clip_start, end); \
3107 if(end > clip_end) \
3109 if(start < clip_end) \
3111 render_window_clip_obj(type, start, clip_end); \
3116 render_window_clip_obj(type, start, end); \
3122 #define render_window_clip_1_obj(type, start, end) \
3123 if(window_1_x1 != 240) \
3125 if(window_1_x1 > window_1_x2) \
3127 render_window_segment_clip(type, start, end, 0, window_1_x2, 1); \
3128 render_window_segment_clip_obj(type, start, end, window_1_x2, \
3130 render_window_segment_clip(type, start, end, window_1_x1, 240, 1); \
3134 render_window_segment_clip_obj(type, start, end, 0, window_1_x1); \
3135 render_window_segment_clip(type, start, end, window_1_x1, window_1_x2, \
3137 render_window_segment_clip_obj(type, start, end, window_1_x2, 240); \
3142 render_window_clip_obj(type, start, end); \
3147 #define render_window_single(type, window_number) \
3148 u32 winin = io_registers[REG_WININ]; \
3149 window_coords(window_number); \
3150 if(window_##window_number##_x1 > window_##window_number##_x2) \
3152 render_window_segment(type, 0, window_##window_number##_x2, \
3154 render_window_segment(type, window_##window_number##_x2, \
3155 window_##window_number##_x1, out); \
3156 render_window_segment(type, window_##window_number##_x1, 240, \
3161 render_window_segment(type, 0, window_##window_number##_x1, out); \
3162 render_window_segment(type, window_##window_number##_x1, \
3163 window_##window_number##_x2, window_number); \
3164 render_window_segment(type, window_##window_number##_x2, 240, out); \
3167 #define render_window_multi(type, front, back) \
3168 if(window_##front##_x1 > window_##front##_x2) \
3170 render_window_segment(type, 0, window_##front##_x2, front); \
3171 render_window_clip_##back(type, window_##front##_x2, \
3172 window_##front##_x1); \
3173 render_window_segment(type, window_##front##_x1, 240, front); \
3177 render_window_clip_##back(type, 0, window_##front##_x1); \
3178 render_window_segment(type, window_##front##_x1, window_##front##_x2, \
3180 render_window_clip_##back(type, window_##front##_x2, 240); \
3183 #define render_scanline_window_builder(type) \
3184 void render_scanline_window_##type(u16 *scanline, u32 dispcnt) \
3186 u32 vcount = io_registers[REG_VCOUNT]; \
3187 u32 winout = io_registers[REG_WINOUT]; \
3188 u32 bldcnt = io_registers[REG_BLDCNT]; \
3189 u32 window_out_enable = winout & 0x3F; \
3191 render_scanline_layer_functions_##type(); \
3193 switch(dispcnt >> 13) \
3195 /* Just window 0 */ \
3198 render_window_single(type, 0); \
3202 /* Just window 1 */ \
3205 render_window_single(type, 1); \
3209 /* Windows 1 and 2 */ \
3212 u32 winin = io_registers[REG_WININ]; \
3215 render_window_multi(type, 0, 1); \
3219 /* Just OBJ windows */ \
3222 u32 window_obj_enable = winout >> 8; \
3223 render_window_clip_obj(type, 0, 240); \
3227 /* Window 0 and OBJ window */ \
3230 u32 window_obj_enable = winout >> 8; \
3231 u32 winin = io_registers[REG_WININ]; \
3233 render_window_multi(type, 0, obj); \
3237 /* Window 1 and OBJ window */ \
3240 u32 window_obj_enable = winout >> 8; \
3241 u32 winin = io_registers[REG_WININ]; \
3243 render_window_multi(type, 1, obj); \
3247 /* Window 0, 1, and OBJ window */ \
3250 u32 window_obj_enable = winout >> 8; \
3251 u32 winin = io_registers[REG_WININ]; \
3254 render_window_multi(type, 0, 1_obj); \
3260 render_scanline_window_builder(tile);
3261 render_scanline_window_builder(bitmap);
3263 u32 active_layers[6] = { 0x1F, 0x17, 0x1C, 0x14, 0x14, 0x14 };
3265 u32 small_resolution_width = 240;
3266 u32 small_resolution_height = 160;
3267 u32 resolution_width, resolution_height;
3269 void update_scanline()
3271 u32 pitch = get_screen_pitch();
3272 u32 dispcnt = io_registers[REG_DISPCNT];
3273 u32 display_flags = (dispcnt >> 8) & 0x1F;
3274 u32 vcount = io_registers[REG_VCOUNT];
3275 u16 *screen_offset = get_screen_pixels() + (vcount * pitch);
3276 u32 video_mode = dispcnt & 0x07;
3279 // If OAM has been modified since the last scanline has been updated then
3280 // reorder and reprofile the OBJ lists.
3283 order_obj(video_mode);
3287 order_layers((dispcnt >> 8) & active_layers[video_mode]);
3293 if (screen_scale == unscaled_rot || screen_scale == scaled_aspect_rot)
3295 if (rot_line_count == rot_lines_total)
3298 if (vcount - rot_lines_total < FONT_HEIGHT && rot_msg_buff[0])
3300 print_string_ext(rot_msg_buff, 0xFFFF, 0x0000, 0, 0,
3301 rot_buffer, 240, 0, vcount - rot_lines_total, rot_lines_total);
3302 if (vcount >= FONT_HEIGHT)
3303 rot_msg_buff[0] = 0;
3305 if (screen_scale == unscaled_rot)
3306 do_rotated_blit(gpsp_gp2x_screen, rot_buffer, vcount);
3308 upscale_aspect_row(gpsp_gp2x_screen, rot_buffer, vcount/3);
3310 screen_offset = &rot_buffer[rot_line_count++ * 240];
3314 // If the screen is in in forced blank draw pure white.
3317 fill_line_color16(0xFFFF, screen_offset, 0, 240);
3325 render_scanline_window_tile(screen_offset, dispcnt);
3329 render_scanline_tile(screen_offset, dispcnt);
3335 render_scanline_window_bitmap(screen_offset, dispcnt);
3337 render_scanline_bitmap(screen_offset, dispcnt);
3341 affine_reference_x[0] += (s16)io_registers[REG_BG2PB];
3342 affine_reference_y[0] += (s16)io_registers[REG_BG2PD];
3343 affine_reference_x[1] += (s16)io_registers[REG_BG3PB];
3344 affine_reference_y[1] += (s16)io_registers[REG_BG3PD];
3349 u32 screen_flip = 0;
3353 if(video_direct == 0)
3355 u32 *old_ge_cmd_ptr = ge_cmd_ptr;
3356 sceKernelDcacheWritebackAll();
3358 // Render the current screen
3359 ge_cmd_ptr = ge_cmd + 2;
3360 GE_CMD(TBP0, ((u32)screen_pixels & 0x00FFFFFF));
3361 GE_CMD(TBW0, (((u32)screen_pixels & 0xFF000000) >> 8) |
3363 ge_cmd_ptr = old_ge_cmd_ptr;
3365 sceGeListEnQueue(ge_cmd, ge_cmd_ptr, gecbid, NULL);
3367 // Flip to the next screen
3371 screen_pixels = screen_texture + (240 * 160 * 2);
3373 screen_pixels = screen_texture;
3377 #elif defined(WIZ_BUILD)
3381 if((resolution_width == small_resolution_width) &&
3382 (resolution_height == small_resolution_height))
3384 switch(screen_scale)
3387 upscale_aspect(gpsp_gp2x_screen, screen_pixels);
3390 do_rotated_blit(gpsp_gp2x_screen, rot_buffer, 160);
3393 case scaled_aspect_rot:
3398 warm_cache_op_all(WOP_D_CLEAN);
3401 pollux_video_flip();
3402 screen_pixels = (u16 *)gpsp_gp2x_screen + screen_offset;
3405 #elif defined(PND_BUILD)
3409 screen_pixels = fb_flip_screen();
3414 #define integer_scale_copy_2() \
3415 current_scanline_ptr[x2] = current_pixel; \
3416 current_scanline_ptr[x2 - 1] = current_pixel; \
3419 #define integer_scale_copy_3() \
3420 current_scanline_ptr[x2] = current_pixel; \
3421 current_scanline_ptr[x2 - 1] = current_pixel; \
3422 current_scanline_ptr[x2 - 2] = current_pixel; \
3425 #define integer_scale_copy_4() \
3426 current_scanline_ptr[x2] = current_pixel; \
3427 current_scanline_ptr[x2 - 1] = current_pixel; \
3428 current_scanline_ptr[x2 - 2] = current_pixel; \
3429 current_scanline_ptr[x2 - 3] = current_pixel; \
3432 #define integer_scale_horizontal(scale_factor) \
3433 for(y = 0; y < 160; y++) \
3435 for(x = 239, x2 = (240 * video_scale) - 1; x >= 0; x--) \
3437 current_pixel = current_scanline_ptr[x]; \
3438 integer_scale_copy_##scale_factor(); \
3439 current_scanline_ptr[x2] = current_scanline_ptr[x]; \
3440 current_scanline_ptr[x2 - 1] = current_scanline_ptr[x]; \
3441 current_scanline_ptr[x2 - 2] = current_scanline_ptr[x]; \
3443 current_scanline_ptr += pitch; \
3448 if((video_scale != 1) && (current_scale != unscaled))
3452 u16 *screen_ptr = get_screen_pixels();
3453 u16 *current_scanline_ptr = screen_ptr;
3454 u32 pitch = get_screen_pitch();
3461 integer_scale_horizontal(2);
3465 integer_scale_horizontal(3);
3470 integer_scale_horizontal(4);
3475 for(y = 159, y2 = (160 * video_scale) - 1; y >= 0; y--)
3477 for(i = 0; i < video_scale; i++)
3479 memcpy(screen_ptr + (y2 * pitch),
3480 screen_ptr + (y * pitch), 480 * video_scale);
3487 if((resolution_width == small_resolution_width) &&
3488 (resolution_height == small_resolution_height))
3490 switch (screen_scale)
3494 SDL_Rect srect = {0, 0, 240, 160};
3495 SDL_Rect drect = {40, 40, 240, 160};
3496 warm_cache_op_all(WOP_D_CLEAN);
3497 SDL_BlitSurface(screen, &srect, hw_screen, &drect);
3502 SDL_Rect drect = {0, 10, 0, 0};
3503 warm_cache_op_all(WOP_D_CLEAN);
3504 SDL_BlitSurface(screen, NULL, hw_screen, &drect);
3507 case scaled_aspect_sw:
3509 upscale_aspect(hw_screen->pixels, get_screen_pixels());
3516 warm_cache_op_all(WOP_D_CLEAN);
3517 SDL_BlitSurface(screen, NULL, hw_screen, NULL);
3526 u32 frame_to_render;
3528 void update_screen()
3530 if(!skip_next_frame)
3538 sceDisplaySetMode(0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
3540 sceDisplayWaitVblankStart();
3541 sceDisplaySetFrameBuf((void*)psp_gu_vram_base, PSP_LINE_SIZE,
3542 PSP_DISPLAY_PIXEL_FORMAT_565, PSP_DISPLAY_SETBUF_NEXTFRAME);
3546 sceGuStart(GU_DIRECT, display_list);
3547 sceGuDrawBuffer(GU_PSM_5650, (void*)0, PSP_LINE_SIZE);
3548 sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
3549 (void*)0, PSP_LINE_SIZE);
3550 sceGuClear(GU_COLOR_BUFFER_BIT);
3552 sceGuOffset(2048 - (PSP_SCREEN_WIDTH / 2), 2048 - (PSP_SCREEN_HEIGHT / 2));
3553 sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
3555 sceGuScissor(0, 0, PSP_SCREEN_WIDTH + 1, PSP_SCREEN_HEIGHT + 1);
3556 sceGuEnable(GU_SCISSOR_TEST);
3557 sceGuTexMode(GU_PSM_5650, 0, 0, GU_FALSE);
3558 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
3559 sceGuTexFilter(GU_LINEAR, GU_LINEAR);
3560 sceGuEnable(GU_TEXTURE_2D);
3562 sceGuFrontFace(GU_CW);
3563 sceGuDisable(GU_BLEND);
3568 sceDisplayWaitVblankStart();
3569 sceGuDisplay(GU_TRUE);
3571 PspGeCallbackData gecb;
3572 gecb.signal_func = NULL;
3573 gecb.signal_arg = NULL;
3574 gecb.finish_func = Ge_Finish_Callback;
3575 gecb.finish_arg = NULL;
3576 gecbid = sceGeSetCallback(&gecb);
3578 screen_vertex[0] = 0 + 0.5;
3579 screen_vertex[1] = 0 + 0.5;
3580 screen_vertex[2] = 0 + 0.5;
3581 screen_vertex[3] = 0 + 0.5;
3582 screen_vertex[4] = 0;
3583 screen_vertex[5] = GBA_SCREEN_WIDTH - 0.5;
3584 screen_vertex[6] = GBA_SCREEN_HEIGHT - 0.5;
3585 screen_vertex[7] = PSP_SCREEN_WIDTH - 0.5;
3586 screen_vertex[8] = PSP_SCREEN_HEIGHT - 0.5;
3587 screen_vertex[9] = 0;
3589 // Set framebuffer to PSP VRAM
3590 GE_CMD(FBP, ((u32)psp_gu_vram_base & 0x00FFFFFF));
3591 GE_CMD(FBW, (((u32)psp_gu_vram_base & 0xFF000000) >> 8) | PSP_LINE_SIZE);
3592 // Set texture 0 to the screen texture
3593 GE_CMD(TBP0, ((u32)screen_texture & 0x00FFFFFF));
3594 GE_CMD(TBW0, (((u32)screen_texture & 0xFF000000) >> 8) | GBA_SCREEN_WIDTH);
3595 // Set the texture size to 256 by 256 (2^8 by 2^8)
3596 GE_CMD(TSIZE0, (8 << 8) | 8);
3597 // Flush the texture cache
3599 // Use 2D coordinates, no indeces, no weights, 32bit float positions,
3600 // 32bit float texture coordinates
3601 GE_CMD(VTYPE, (1 << 23) | (0 << 11) | (0 << 9) |
3602 (3 << 7) | (0 << 5) | (0 << 2) | 3);
3603 // Set the base of the index list pointer to 0
3605 // Set the rest of index list pointer to 0 (not being used)
3607 // Set the base of the screen vertex list pointer
3608 GE_CMD(BASE, ((u32)screen_vertex & 0xFF000000) >> 8);
3609 // Set the rest of the screen vertex list pointer
3610 GE_CMD(VADDR, ((u32)screen_vertex & 0x00FFFFFF));
3611 // Primitive kick: render sprite (primitive 6), 2 vertices
3612 GE_CMD(PRIM, (6 << 16) | 2);
3613 // Done with commands
3615 // Raise signal interrupt
3621 #elif defined(WIZ_BUILD) || defined(PND_BUILD)
3631 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE);
3634 SDL_GP2X_AllowGfxMemory(NULL, 0);
3636 hw_screen = SDL_SetVideoMode(320 * video_scale, 240 * video_scale,
3639 screen = SDL_CreateRGBSurface(SDL_HWSURFACE, 240 * video_scale,
3640 160 * video_scale, 16, 0xFFFF, 0xFFFF, 0xFFFF, 0);
3642 warm_change_cb_upper(WCB_C_BIT|WCB_B_BIT, 1);
3644 screen = SDL_SetVideoMode(240 * video_scale, 160 * video_scale, 16, 0);
3651 video_scale_type screen_scale = scaled_aspect;
3652 video_scale_type current_scale = scaled_aspect;
3653 video_filter_type screen_filter = filter_bilinear;
3658 void video_resolution_large()
3660 if(video_direct != 1)
3663 screen_pixels = psp_gu_vram_base;
3665 sceGuStart(GU_DIRECT, display_list);
3666 sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
3667 (void*)0, PSP_LINE_SIZE);
3672 void set_gba_resolution(video_scale_type scale)
3674 u32 filter_linear = 0;
3675 screen_scale = scale;
3679 screen_vertex[2] = 120 + 0.5;
3680 screen_vertex[3] = 56 + 0.5;
3681 screen_vertex[7] = GBA_SCREEN_WIDTH + 120 - 0.5;
3682 screen_vertex[8] = GBA_SCREEN_HEIGHT + 56 - 0.5;
3686 screen_vertex[2] = 36 + 0.5;
3687 screen_vertex[3] = 0 + 0.5;
3688 screen_vertex[7] = 408 + 36 - 0.5;
3689 screen_vertex[8] = PSP_SCREEN_HEIGHT - 0.5;
3693 screen_vertex[2] = 0;
3694 screen_vertex[3] = 0;
3695 screen_vertex[7] = PSP_SCREEN_WIDTH;
3696 screen_vertex[8] = PSP_SCREEN_HEIGHT;
3700 sceGuStart(GU_DIRECT, display_list);
3701 if(screen_filter == filter_bilinear)
3702 sceGuTexFilter(GU_LINEAR, GU_LINEAR);
3704 sceGuTexFilter(GU_NEAREST, GU_NEAREST);
3709 clear_screen(0x0000);
3712 void video_resolution_small()
3714 if(video_direct != 0)
3716 set_gba_resolution(screen_scale);
3718 screen_pixels = screen_texture;
3721 sceGuStart(GU_DIRECT, display_list);
3722 sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
3723 (void*)0, PSP_LINE_SIZE);
3728 void clear_screen(u16 color)
3731 u16 *src_ptr = get_screen_pixels();
3735 for(i = 0; i < (512 * 272); i++, src_ptr++)
3740 // I don't know why this doesn't work.
3741 /* color = (((color & 0x1F) * 255 / 31) << 0) |
3742 ((((color >> 5) & 0x3F) * 255 / 63) << 8) |
3743 ((((color >> 11) & 0x1F) * 255 / 31) << 16) | (0xFF << 24);
3745 sceGuStart(GU_DIRECT, display_list);
3746 sceGuDrawBuffer(GU_PSM_5650, (void*)0, PSP_LINE_SIZE);
3747 //sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
3748 // (void*)0, PSP_LINE_SIZE);
3749 sceGuClearColor(color);
3750 sceGuClear(GU_COLOR_BUFFER_BIT);
3755 #elif defined(WIZ_BUILD)
3757 void video_resolution_large()
3760 resolution_width = 320;
3761 resolution_height = 240;
3766 wiz_lcd_set_portrait(0);
3769 void video_resolution_small()
3773 switch (screen_scale)
3776 screen_offset = 320*40 + 40;
3777 wiz_lcd_set_portrait(0);
3780 screen_offset = 320*(80 - 14) + 80;
3781 wiz_lcd_set_portrait(0);
3784 wiz_lcd_set_portrait(1);
3785 rot_lines_total = 4;
3788 case scaled_aspect_rot:
3789 wiz_lcd_set_portrait(1);
3790 rot_lines_total = 3;
3798 resolution_width = 240;
3799 resolution_height = 160;
3802 void set_gba_resolution(video_scale_type scale)
3804 screen_scale = scale;
3807 void clear_screen(u16 color)
3809 u32 col = ((u32)color << 16) | color;
3810 u32 *p = gpsp_gp2x_screen;
3816 #elif defined(PND_BUILD)
3818 void video_resolution_large()
3820 resolution_width = 400;
3821 resolution_height = 272;
3823 fb_set_mode(400, 272, 1, 15, screen_filter);
3828 void video_resolution_small()
3830 resolution_width = 240;
3831 resolution_height = 160;
3833 fb_set_mode(240, 160, 4, screen_scale, screen_filter);
3838 void set_gba_resolution(video_scale_type scale)
3840 screen_scale = scale;
3843 void clear_screen(u16 color)
3845 u32 col = ((u32)color << 16) | color;
3846 u32 *p = (u32 *)get_screen_pixels();
3847 int c = resolution_width * resolution_height / 2;
3854 void video_resolution_large()
3856 current_scale = unscaled;
3859 SDL_FreeSurface(screen);
3860 SDL_GP2X_AllowGfxMemory(NULL, 0);
3861 hw_screen = SDL_SetVideoMode(320, 240, 16, SDL_HWSURFACE);
3862 screen = SDL_CreateRGBSurface(SDL_HWSURFACE, 320, 240, 16, 0xFFFF,
3864 resolution_width = 320;
3865 resolution_height = 240;
3868 warm_change_cb_upper(WCB_C_BIT|WCB_B_BIT, 1);
3870 screen = SDL_SetVideoMode(480, 272, 16, 0);
3871 resolution_width = 480;
3872 resolution_height = 272;
3876 void video_resolution_small()
3878 current_scale = screen_scale;
3882 SDL_FreeSurface(screen);
3883 SDL_GP2X_AllowGfxMemory(NULL, 0);
3886 if (screen_scale == scaled_aspect || screen_scale == fullscreen)
3888 w = small_resolution_width * video_scale;
3889 h = small_resolution_height * video_scale;
3891 if (screen_scale == scaled_aspect) h += 20;
3892 hw_screen = SDL_SetVideoMode(w, h, 16, SDL_HWSURFACE);
3894 w = small_resolution_width * video_scale;
3895 if (screen_scale == scaled_aspect_sw)
3897 screen = SDL_CreateRGBSurface(SDL_HWSURFACE,
3898 w, small_resolution_height * video_scale,
3899 16, 0xFFFF, 0xFFFF, 0xFFFF, 0);
3903 warm_change_cb_upper(WCB_C_BIT|WCB_B_BIT, 1);
3905 screen = SDL_SetVideoMode(small_resolution_width * video_scale,
3906 small_resolution_height * video_scale, 16, 0);
3908 resolution_width = small_resolution_width;
3909 resolution_height = small_resolution_height;
3912 void set_gba_resolution(video_scale_type scale)
3914 if(screen_scale != scale)
3916 screen_scale = scale;
3922 small_resolution_width = 240 * video_scale;
3923 small_resolution_height = 160 * video_scale;
3929 void clear_screen(u16 color)
3931 u16 *dest_ptr = get_screen_pixels();
3932 u32 line_skip = get_screen_pitch() - screen->w;
3935 for(y = 0; y < screen->h; y++)
3937 for(x = 0; x < screen->w; x++, dest_ptr++)
3941 dest_ptr += line_skip;
3949 u16 *copy = malloc(240 * 160 * 2);
3950 memcpy(copy, get_screen_pixels(), 240 * 160 * 2);
3954 void blit_to_screen(u16 *src, u32 w, u32 h, u32 dest_x, u32 dest_y)
3956 u32 pitch = get_screen_pitch();
3957 u16 *dest_ptr = get_screen_pixels() + dest_x + (dest_y * pitch);
3959 s32 w1 = dest_x + w > pitch ? pitch - dest_x : w;
3963 for(y = 0; y < h; y++)
3965 for(x = 0; x < w1; x++)
3967 dest_ptr[x] = src_ptr[x];
3974 void print_string_ext(const char *str, u16 fg_color, u16 bg_color,
3975 u32 x, u32 y, void *_dest_ptr, u32 pitch, u32 pad, u32 h_offset, u32 height)
3977 u16 *dest_ptr = (u16 *)_dest_ptr + (y * pitch) + x;
3978 u8 current_char = str[0];
3981 u32 i = 0, i2, i3, h;
3985 if(y + height > resolution_height)
3990 if(current_char == '\n')
3994 dest_ptr = get_screen_pixels() + (y * pitch) + x;
3998 glyph_offset = _font_offset[current_char];
3999 current_x += FONT_WIDTH;
4000 glyph_offset += h_offset;
4001 for(i2 = h_offset, h = 0; i2 < FONT_HEIGHT && h < height; i2++, h++, glyph_offset++)
4003 current_row = _font_bits[glyph_offset];
4004 for(i3 = 0; i3 < FONT_WIDTH; i3++)
4006 if((current_row >> (15 - i3)) & 0x01)
4007 *dest_ptr = fg_color;
4009 *dest_ptr = bg_color;
4012 dest_ptr += (pitch - FONT_WIDTH);
4014 dest_ptr = dest_ptr - (pitch * h) + FONT_WIDTH;
4019 current_char = str[str_index];
4021 if((i < pad) && (current_char == 0))
4030 if(current_x + FONT_WIDTH > resolution_width /* EDIT */)
4032 while (current_char && current_char != '\n')
4034 current_char = str[str_index++];
4040 void print_string(const char *str, u16 fg_color, u16 bg_color,
4044 if ((screen_scale == unscaled_rot || screen_scale == scaled_aspect_rot) &&
4045 (resolution_width == small_resolution_width) &&
4046 (resolution_height == small_resolution_height))
4048 snprintf(rot_msg_buff, sizeof(rot_msg_buff), "%s", str);
4052 print_string_ext(str, fg_color, bg_color, x, y, get_screen_pixels(),
4053 get_screen_pitch(), 0, 0, FONT_HEIGHT);
4056 void print_string_pad(const char *str, u16 fg_color, u16 bg_color,
4057 u32 x, u32 y, u32 pad)
4059 print_string_ext(str, fg_color, bg_color, x, y, get_screen_pixels(),
4060 get_screen_pitch(), pad, 0, FONT_HEIGHT);
4063 u32 debug_cursor_x = 0;
4064 u32 debug_cursor_y = 0;
4068 void debug_screen_clear()
4072 void debug_screen_start()
4076 void debug_screen_end()
4080 void debug_screen_update()
4084 void debug_screen_printf(const char *format, ...)
4088 va_start(ap, format);
4089 vprintf(format, ap);
4093 void debug_screen_newline(u32 count)
4101 void debug_screen_clear()
4105 clear_screen(0x0000);
4108 void debug_screen_start()
4110 video_resolution_large();
4111 debug_screen_clear();
4114 void debug_screen_end()
4116 video_resolution_small();
4119 void debug_screen_update()
4124 void debug_screen_printf(const char *format, ...)
4126 char str_buffer[512];
4127 u32 str_buffer_length;
4130 va_start(ap, format);
4131 str_buffer_length = vsnprintf(str_buffer, 512, format, ap);
4134 printf("printing debug string %s at %d %d\n", str_buffer,
4135 debug_cursor_x, debug_cursor_y);
4137 print_string(str_buffer, 0xFFFF, 0x0000, debug_cursor_x, debug_cursor_y);
4138 debug_cursor_x += FONT_WIDTH * str_buffer_length;
4141 void debug_screen_newline(u32 count)
4144 debug_cursor_y += FONT_HEIGHT * count;
4149 void debug_screen_printl(const char *format, ...)
4153 va_start(ap, format);
4154 debug_screen_printf(format, ap);
4155 debug_screen_newline(1);
4156 // debug_screen_printf("\n");
4161 #define video_savestate_builder(type) \
4162 void video_##type##_savestate(file_tag_type savestate_file) \
4164 file_##type##_array(savestate_file, affine_reference_x); \
4165 file_##type##_array(savestate_file, affine_reference_y); \
4168 video_savestate_builder(read);
4169 video_savestate_builder(write_mem);