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
21 #define WANT_FONT_BITS
28 #include <pspkernel.h>
30 #include <pspdisplay.h>
36 static float *screen_vertex = (float *)0x441FC100;
37 static u32 *ge_cmd = (u32 *)0x441FC000;
38 static u16 *psp_gu_vram_base = (u16 *)(0x44000000);
39 static u32 *ge_cmd_ptr = (u32 *)0x441FC000;
41 static u32 video_direct = 0;
43 static u32 __attribute__((aligned(16))) display_list[32];
45 #define GBA_SCREEN_WIDTH 240
46 #define GBA_SCREEN_HEIGHT 160
48 #define PSP_SCREEN_WIDTH 480
49 #define PSP_SCREEN_HEIGHT 272
50 #define PSP_LINE_SIZE 512
52 #define PSP_ALL_BUTTON_MASK 0xFFFF
54 #define GE_CMD_FBP 0x9C
55 #define GE_CMD_FBW 0x9D
56 #define GE_CMD_TBP0 0xA0
57 #define GE_CMD_TBW0 0xA8
58 #define GE_CMD_TSIZE0 0xB8
59 #define GE_CMD_TFLUSH 0xCB
60 #define GE_CMD_CLEAR 0xD3
61 #define GE_CMD_VTYPE 0x12
62 #define GE_CMD_BASE 0x10
63 #define GE_CMD_VADDR 0x01
64 #define GE_CMD_IADDR 0x02
65 #define GE_CMD_PRIM 0x04
66 #define GE_CMD_FINISH 0x0F
67 #define GE_CMD_SIGNAL 0x0C
68 #define GE_CMD_NOP 0x00
70 #define GE_CMD(cmd, operand) \
71 *ge_cmd_ptr = (((GE_CMD_##cmd) << 24) | (operand)); \
74 static u16 *screen_texture = (u16 *)(0x4000000 + (512 * 272 * 2));
75 static u16 *current_screen_texture = (u16 *)(0x4000000 + (512 * 272 * 2));
76 static u16 *screen_pixels = (u16 *)(0x4000000 + (512 * 272 * 2));
77 static u32 screen_pitch = 240;
79 static void Ge_Finish_Callback(int id, void *arg)
83 #define get_screen_pixels() \
86 #define get_screen_pitch() \
89 #elif defined(POLLUX_BUILD)
91 static u16 rot_buffer[240*4];
92 static u32 rot_lines_total = 4;
93 static u32 rot_line_count = 0;
95 static char rot_msg_buff[64];
98 static u32 screen_offset = 0;
99 static u16 *screen_pixels = NULL;
100 const u32 screen_pitch = 320;
102 #define get_screen_pixels() \
105 #define get_screen_pitch() \
108 #elif defined(PND_BUILD) || defined(RPI_BUILD)
110 static u16 *screen_pixels = NULL;
112 #define get_screen_pixels() \
115 #define get_screen_pitch() \
121 #include "SDL_gp2x.h"
122 SDL_Surface *hw_screen;
125 const u32 video_scale = 1;
127 #define get_screen_pixels() \
128 ((u16 *)screen->pixels) \
130 #define get_screen_pitch() \
131 (screen->pitch / 2) \
135 static void render_scanline_conditional_tile(u32 start, u32 end, u16 *scanline,
136 u32 enable_flags, u32 dispcnt, u32 bldcnt, const tile_layer_render_struct
138 static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline,
139 u32 enable_flags, u32 dispcnt, u32 bldcnt, const bitmap_layer_render_struct
144 // This old version is not necessary if the palette is either being converted
145 // transparently or the ABGR 1555 format is being used natively. The direct
146 // version (without conversion) is much faster.
148 #define tile_lookup_palette_full(palette, source) \
149 current_pixel = palette[source]; \
150 convert_palette(current_pixel) \
152 #define tile_lookup_palette(palette, source) \
153 current_pixel = palette[source]; \
156 #ifdef RENDER_COLOR16_NORMAL
158 #define tile_expand_base_normal(index) \
159 tile_expand_base_color16(index) \
163 #define tile_expand_base_normal(index) \
164 tile_lookup_palette(palette, current_pixel); \
165 dest_ptr[index] = current_pixel \
169 #define tile_expand_transparent_normal(index) \
170 tile_expand_base_normal(index) \
172 #define tile_expand_copy(index) \
173 dest_ptr[index] = copy_ptr[index] \
176 #define advance_dest_ptr_base(delta) \
179 #define advance_dest_ptr_transparent(delta) \
180 advance_dest_ptr_base(delta) \
182 #define advance_dest_ptr_copy(delta) \
183 advance_dest_ptr_base(delta); \
187 #define color_combine_mask_a(layer) \
188 ((io_registers[REG_BLDCNT] >> layer) & 0x01) \
190 // For color blending operations, will create a mask that has in bit
191 // 10 if the layer is target B, and bit 9 if the layer is target A.
193 #define color_combine_mask(layer) \
194 (color_combine_mask_a(layer) | \
195 ((io_registers[REG_BLDCNT] >> (layer + 7)) & 0x02)) << 9 \
197 // For alpha blending renderers, draw the palette index (9bpp) and
198 // layer bits rather than the raw RGB. For the base this should write to
199 // the 32bit location directly.
201 #define tile_expand_base_alpha(index) \
202 dest_ptr[index] = current_pixel | pixel_combine \
204 #define tile_expand_base_bg(index) \
205 dest_ptr[index] = bg_combine \
208 // For layered (transparent) writes this should shift the "stack" and write
209 // to the bottom. This will preserve the topmost pixel and the most recent
212 #define tile_expand_transparent_alpha(index) \
213 dest_ptr[index] = (dest_ptr[index] << 16) | current_pixel | pixel_combine \
216 // OBJ should only shift if the top isn't already OBJ
217 #define tile_expand_transparent_alpha_obj(index) \
218 dest = dest_ptr[index]; \
219 if(dest & 0x00000100) \
221 dest_ptr[index] = (dest & 0xFFFF0000) | current_pixel | pixel_combine; \
225 dest_ptr[index] = (dest << 16) | current_pixel | pixel_combine; \
229 // For color effects that don't need to preserve the previous layer.
230 // The color32 version should be used with 32bit wide dest_ptr so as to be
231 // compatible with alpha combine on top of it.
233 #define tile_expand_base_color16(index) \
234 dest_ptr[index] = current_pixel | pixel_combine \
236 #define tile_expand_transparent_color16(index) \
237 tile_expand_base_color16(index) \
239 #define tile_expand_base_color32(index) \
240 tile_expand_base_color16(index) \
242 #define tile_expand_transparent_color32(index) \
243 tile_expand_base_color16(index) \
246 // Operations for isolation 8bpp pixels within 32bpp pixel blocks.
248 #define tile_8bpp_pixel_op_mask(op_param) \
249 current_pixel = current_pixels & 0xFF \
251 #define tile_8bpp_pixel_op_shift_mask(shift) \
252 current_pixel = (current_pixels >> shift) & 0xFF \
254 #define tile_8bpp_pixel_op_shift(shift) \
255 current_pixel = current_pixels >> shift \
257 #define tile_8bpp_pixel_op_none(shift) \
259 // Base should always draw raw in 8bpp mode; color 0 will be drawn where
262 #define tile_8bpp_draw_base_normal(index) \
263 tile_expand_base_normal(index) \
265 #define tile_8bpp_draw_base_alpha(index) \
268 tile_expand_base_alpha(index); \
272 tile_expand_base_bg(index); \
276 #define tile_8bpp_draw_base_color16(index) \
277 tile_8bpp_draw_base_alpha(index) \
279 #define tile_8bpp_draw_base_color32(index) \
280 tile_8bpp_draw_base_alpha(index) \
283 #define tile_8bpp_draw_base(index, op, op_param, alpha_op) \
284 tile_8bpp_pixel_op_##op(op_param); \
285 tile_8bpp_draw_base_##alpha_op(index) \
287 // Transparent (layered) writes should only replace what is there if the
288 // pixel is not transparent (zero)
290 #define tile_8bpp_draw_transparent(index, op, op_param, alpha_op) \
291 tile_8bpp_pixel_op_##op(op_param); \
294 tile_expand_transparent_##alpha_op(index); \
297 #define tile_8bpp_draw_copy(index, op, op_param, alpha_op) \
298 tile_8bpp_pixel_op_##op(op_param); \
301 tile_expand_copy(index); \
304 // Get the current tile from the map in 8bpp mode
306 #define get_tile_8bpp() \
307 current_tile = *map_ptr; \
308 tile_ptr = tile_base + ((current_tile & 0x3FF) * 64) \
311 // Draw half of a tile in 8bpp mode, for base renderer
313 #define tile_8bpp_draw_four_noflip(index, combine_op, alpha_op) \
314 tile_8bpp_draw_##combine_op(index + 0, mask, 0, alpha_op); \
315 tile_8bpp_draw_##combine_op(index + 1, shift_mask, 8, alpha_op); \
316 tile_8bpp_draw_##combine_op(index + 2, shift_mask, 16, alpha_op); \
317 tile_8bpp_draw_##combine_op(index + 3, shift, 24, alpha_op) \
320 // Like the above, but draws the half-tile horizontally flipped
322 #define tile_8bpp_draw_four_flip(index, combine_op, alpha_op) \
323 tile_8bpp_draw_##combine_op(index + 3, mask, 0, alpha_op); \
324 tile_8bpp_draw_##combine_op(index + 2, shift_mask, 8, alpha_op); \
325 tile_8bpp_draw_##combine_op(index + 1, shift_mask, 16, alpha_op); \
326 tile_8bpp_draw_##combine_op(index + 0, shift, 24, alpha_op) \
328 #define tile_8bpp_draw_four_base(index, alpha_op, flip_op) \
329 tile_8bpp_draw_four_##flip_op(index, base, alpha_op) \
332 // Draw half of a tile in 8bpp mode, for transparent renderer; as an
333 // optimization the entire thing is checked against zero (in transparent
334 // capable renders it is more likely for the pixels to be transparent than
337 #define tile_8bpp_draw_four_transparent(index, alpha_op, flip_op) \
338 if(current_pixels != 0) \
340 tile_8bpp_draw_four_##flip_op(index, transparent, alpha_op); \
343 #define tile_8bpp_draw_four_copy(index, alpha_op, flip_op) \
344 if(current_pixels != 0) \
346 tile_8bpp_draw_four_##flip_op(index, copy, alpha_op); \
349 // Helper macro for drawing 8bpp tiles clipped against the edge of the screen
351 #define partial_tile_8bpp(combine_op, alpha_op) \
352 for(i = 0; i < partial_tile_run; i++) \
354 tile_8bpp_draw_##combine_op(0, mask, 0, alpha_op); \
355 current_pixels >>= 8; \
356 advance_dest_ptr_##combine_op(1); \
360 // Draws 8bpp tiles clipped against the left side of the screen,
361 // partial_tile_offset indicates how much clipped in it is, partial_tile_run
362 // indicates how much it should draw.
364 #define partial_tile_right_noflip_8bpp(combine_op, alpha_op) \
365 if(partial_tile_offset >= 4) \
367 current_pixels = *((u32 *)(tile_ptr + 4)) >> \
368 ((partial_tile_offset - 4) * 8); \
369 partial_tile_8bpp(combine_op, alpha_op); \
373 partial_tile_run -= 4; \
374 current_pixels = *((u32 *)tile_ptr) >> (partial_tile_offset * 8); \
375 partial_tile_8bpp(combine_op, alpha_op); \
376 current_pixels = *((u32 *)(tile_ptr + 4)); \
377 tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \
378 advance_dest_ptr_##combine_op(4); \
382 // Draws 8bpp tiles clipped against both the left and right side of the
383 // screen, IE, runs of less than 8 - partial_tile_offset.
385 #define partial_tile_mid_noflip_8bpp(combine_op, alpha_op) \
386 if(partial_tile_offset >= 4) \
388 current_pixels = *((u32 *)(tile_ptr + 4)) >> \
389 ((partial_tile_offset - 4) * 8); \
390 partial_tile_8bpp(combine_op, alpha_op); \
394 current_pixels = *((u32 *)tile_ptr) >> (partial_tile_offset * 8); \
395 if((partial_tile_offset + partial_tile_run) > 4) \
397 u32 old_run = partial_tile_run; \
398 partial_tile_run = 4 - partial_tile_offset; \
399 partial_tile_8bpp(combine_op, alpha_op); \
400 partial_tile_run = old_run - partial_tile_run; \
401 current_pixels = *((u32 *)(tile_ptr + 4)); \
402 partial_tile_8bpp(combine_op, alpha_op); \
406 partial_tile_8bpp(combine_op, alpha_op); \
411 // Draws 8bpp tiles clipped against the right side of the screen,
412 // partial_tile_run indicates how much there is to draw.
414 #define partial_tile_left_noflip_8bpp(combine_op, alpha_op) \
415 if(partial_tile_run >= 4) \
417 current_pixels = *((u32 *)tile_ptr); \
418 tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \
419 advance_dest_ptr_##combine_op(4); \
421 partial_tile_run -= 4; \
424 current_pixels = *((u32 *)(tile_ptr)); \
425 partial_tile_8bpp(combine_op, alpha_op) \
428 // Draws a non-clipped (complete) 8bpp tile.
430 #define tile_noflip_8bpp(combine_op, alpha_op) \
431 current_pixels = *((u32 *)tile_ptr); \
432 tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \
433 current_pixels = *((u32 *)(tile_ptr + 4)); \
434 tile_8bpp_draw_four_##combine_op(4, alpha_op, noflip) \
437 // Like the above versions but draws flipped tiles.
439 #define partial_tile_flip_8bpp(combine_op, alpha_op) \
440 for(i = 0; i < partial_tile_run; i++) \
442 tile_8bpp_draw_##combine_op(0, shift, 24, alpha_op); \
443 current_pixels <<= 8; \
444 advance_dest_ptr_##combine_op(1); \
447 #define partial_tile_right_flip_8bpp(combine_op, alpha_op) \
448 if(partial_tile_offset >= 4) \
450 current_pixels = *((u32 *)tile_ptr) << ((partial_tile_offset - 4) * 8); \
451 partial_tile_flip_8bpp(combine_op, alpha_op); \
455 partial_tile_run -= 4; \
456 current_pixels = *((u32 *)(tile_ptr + 4)) << \
457 ((partial_tile_offset - 4) * 8); \
458 partial_tile_flip_8bpp(combine_op, alpha_op); \
459 current_pixels = *((u32 *)tile_ptr); \
460 tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \
461 advance_dest_ptr_##combine_op(4); \
464 #define partial_tile_mid_flip_8bpp(combine_op, alpha_op) \
465 if(partial_tile_offset >= 4) \
467 current_pixels = *((u32 *)tile_ptr) << ((partial_tile_offset - 4) * 8); \
468 partial_tile_flip_8bpp(combine_op, alpha_op); \
472 current_pixels = *((u32 *)(tile_ptr + 4)) << \
473 ((partial_tile_offset - 4) * 8); \
475 if((partial_tile_offset + partial_tile_run) > 4) \
477 u32 old_run = partial_tile_run; \
478 partial_tile_run = 4 - partial_tile_offset; \
479 partial_tile_flip_8bpp(combine_op, alpha_op); \
480 partial_tile_run = old_run - partial_tile_run; \
481 current_pixels = *((u32 *)(tile_ptr)); \
482 partial_tile_flip_8bpp(combine_op, alpha_op); \
486 partial_tile_flip_8bpp(combine_op, alpha_op); \
490 #define partial_tile_left_flip_8bpp(combine_op, alpha_op) \
491 if(partial_tile_run >= 4) \
493 current_pixels = *((u32 *)(tile_ptr + 4)); \
494 tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \
495 advance_dest_ptr_##combine_op(4); \
497 partial_tile_run -= 4; \
500 current_pixels = *((u32 *)(tile_ptr + 4)); \
501 partial_tile_flip_8bpp(combine_op, alpha_op) \
503 #define tile_flip_8bpp(combine_op, alpha_op) \
504 current_pixels = *((u32 *)(tile_ptr + 4)); \
505 tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \
506 current_pixels = *((u32 *)tile_ptr); \
507 tile_8bpp_draw_four_##combine_op(4, alpha_op, flip) \
510 // Operations for isolating 4bpp tiles in a 32bit block
512 #define tile_4bpp_pixel_op_mask(op_param) \
513 current_pixel = current_pixels & 0x0F \
515 #define tile_4bpp_pixel_op_shift_mask(shift) \
516 current_pixel = (current_pixels >> shift) & 0x0F \
518 #define tile_4bpp_pixel_op_shift(shift) \
519 current_pixel = current_pixels >> shift \
521 #define tile_4bpp_pixel_op_none(op_param) \
523 // Draws a single 4bpp pixel as base, normal renderer; checks to see if the
524 // pixel is zero because if so the current palette should not be applied.
525 // These ifs can be replaced with a lookup table, may or may not be superior
526 // this way, should be benchmarked. The lookup table would be from 0-255
527 // identity map except for multiples of 16, which would map to 0.
529 #define tile_4bpp_draw_base_normal(index) \
532 current_pixel |= current_palette; \
533 tile_expand_base_normal(index); \
537 tile_expand_base_normal(index); \
541 #define tile_4bpp_draw_base_alpha(index) \
544 current_pixel |= current_palette; \
545 tile_expand_base_alpha(index); \
549 tile_expand_base_bg(index); \
552 #define tile_4bpp_draw_base_color16(index) \
553 tile_4bpp_draw_base_alpha(index) \
555 #define tile_4bpp_draw_base_color32(index) \
556 tile_4bpp_draw_base_alpha(index) \
559 #define tile_4bpp_draw_base(index, op, op_param, alpha_op) \
560 tile_4bpp_pixel_op_##op(op_param); \
561 tile_4bpp_draw_base_##alpha_op(index) \
564 // Draws a single 4bpp pixel as layered, if not transparent.
566 #define tile_4bpp_draw_transparent(index, op, op_param, alpha_op) \
567 tile_4bpp_pixel_op_##op(op_param); \
570 current_pixel |= current_palette; \
571 tile_expand_transparent_##alpha_op(index); \
574 #define tile_4bpp_draw_copy(index, op, op_param, alpha_op) \
575 tile_4bpp_pixel_op_##op(op_param); \
578 current_pixel |= current_palette; \
579 tile_expand_copy(index); \
583 // Draws eight background pixels in transparent mode, for alpha or normal
586 #define tile_4bpp_draw_eight_base_zero(value) \
587 dest_ptr[0] = value; \
588 dest_ptr[1] = value; \
589 dest_ptr[2] = value; \
590 dest_ptr[3] = value; \
591 dest_ptr[4] = value; \
592 dest_ptr[5] = value; \
593 dest_ptr[6] = value; \
594 dest_ptr[7] = value \
597 // Draws eight background pixels for the alpha renderer, basically color zero
598 // with the background flag high.
600 #define tile_4bpp_draw_eight_base_zero_alpha() \
601 tile_4bpp_draw_eight_base_zero(bg_combine) \
603 #define tile_4bpp_draw_eight_base_zero_color16() \
604 tile_4bpp_draw_eight_base_zero_alpha() \
606 #define tile_4bpp_draw_eight_base_zero_color32() \
607 tile_4bpp_draw_eight_base_zero_alpha() \
610 // Draws eight background pixels for the normal renderer, just a bunch of
613 #ifdef RENDER_COLOR16_NORMAL
615 #define tile_4bpp_draw_eight_base_zero_normal() \
617 tile_4bpp_draw_eight_base_zero(current_pixel) \
621 #define tile_4bpp_draw_eight_base_zero_normal() \
622 current_pixel = palette[0]; \
623 tile_4bpp_draw_eight_base_zero(current_pixel) \
628 // Draws eight 4bpp pixels.
630 #define tile_4bpp_draw_eight_noflip(combine_op, alpha_op) \
631 tile_4bpp_draw_##combine_op(0, mask, 0, alpha_op); \
632 tile_4bpp_draw_##combine_op(1, shift_mask, 4, alpha_op); \
633 tile_4bpp_draw_##combine_op(2, shift_mask, 8, alpha_op); \
634 tile_4bpp_draw_##combine_op(3, shift_mask, 12, alpha_op); \
635 tile_4bpp_draw_##combine_op(4, shift_mask, 16, alpha_op); \
636 tile_4bpp_draw_##combine_op(5, shift_mask, 20, alpha_op); \
637 tile_4bpp_draw_##combine_op(6, shift_mask, 24, alpha_op); \
638 tile_4bpp_draw_##combine_op(7, shift, 28, alpha_op) \
641 // Draws eight 4bpp pixels in reverse order (for hflip).
643 #define tile_4bpp_draw_eight_flip(combine_op, alpha_op) \
644 tile_4bpp_draw_##combine_op(7, mask, 0, alpha_op); \
645 tile_4bpp_draw_##combine_op(6, shift_mask, 4, alpha_op); \
646 tile_4bpp_draw_##combine_op(5, shift_mask, 8, alpha_op); \
647 tile_4bpp_draw_##combine_op(4, shift_mask, 12, alpha_op); \
648 tile_4bpp_draw_##combine_op(3, shift_mask, 16, alpha_op); \
649 tile_4bpp_draw_##combine_op(2, shift_mask, 20, alpha_op); \
650 tile_4bpp_draw_##combine_op(1, shift_mask, 24, alpha_op); \
651 tile_4bpp_draw_##combine_op(0, shift, 28, alpha_op) \
654 // Draws eight 4bpp pixels in base mode, checks if all are zero, if so draws
655 // the appropriate background pixels.
657 #define tile_4bpp_draw_eight_base(alpha_op, flip_op) \
658 if(current_pixels != 0) \
660 tile_4bpp_draw_eight_##flip_op(base, alpha_op); \
664 tile_4bpp_draw_eight_base_zero_##alpha_op(); \
668 // Draws eight 4bpp pixels in transparent (layered) mode, checks if all are
669 // zero and if so draws nothing.
671 #define tile_4bpp_draw_eight_transparent(alpha_op, flip_op) \
672 if(current_pixels != 0) \
674 tile_4bpp_draw_eight_##flip_op(transparent, alpha_op); \
678 #define tile_4bpp_draw_eight_copy(alpha_op, flip_op) \
679 if(current_pixels != 0) \
681 tile_4bpp_draw_eight_##flip_op(copy, alpha_op); \
684 // Gets the current tile in 4bpp mode, also getting the current palette and
687 #define get_tile_4bpp() \
688 current_tile = *map_ptr; \
689 current_palette = (current_tile >> 12) << 4; \
690 tile_ptr = tile_base + ((current_tile & 0x3FF) * 32); \
693 // Helper macro for drawing clipped 4bpp tiles.
695 #define partial_tile_4bpp(combine_op, alpha_op) \
696 for(i = 0; i < partial_tile_run; i++) \
698 tile_4bpp_draw_##combine_op(0, mask, 0, alpha_op); \
699 current_pixels >>= 4; \
700 advance_dest_ptr_##combine_op(1); \
704 // Draws a 4bpp tile clipped against the left edge of the screen.
705 // partial_tile_offset is how far in it's clipped, partial_tile_run is
708 #define partial_tile_right_noflip_4bpp(combine_op, alpha_op) \
709 current_pixels = *((u32 *)tile_ptr) >> (partial_tile_offset * 4); \
710 partial_tile_4bpp(combine_op, alpha_op) \
713 // Draws a 4bpp tile clipped against both edges of the screen, same as right.
715 #define partial_tile_mid_noflip_4bpp(combine_op, alpha_op) \
716 partial_tile_right_noflip_4bpp(combine_op, alpha_op) \
719 // Draws a 4bpp tile clipped against the right edge of the screen.
720 // partial_tile_offset is how many to draw.
722 #define partial_tile_left_noflip_4bpp(combine_op, alpha_op) \
723 current_pixels = *((u32 *)tile_ptr); \
724 partial_tile_4bpp(combine_op, alpha_op) \
727 // Draws a complete 4bpp tile row (not clipped)
728 #define tile_noflip_4bpp(combine_op, alpha_op) \
729 current_pixels = *((u32 *)tile_ptr); \
730 tile_4bpp_draw_eight_##combine_op(alpha_op, noflip) \
733 // Like the above, but draws flipped tiles.
735 #define partial_tile_flip_4bpp(combine_op, alpha_op) \
736 for(i = 0; i < partial_tile_run; i++) \
738 tile_4bpp_draw_##combine_op(0, shift, 28, alpha_op); \
739 current_pixels <<= 4; \
740 advance_dest_ptr_##combine_op(1); \
743 #define partial_tile_right_flip_4bpp(combine_op, alpha_op) \
744 current_pixels = *((u32 *)tile_ptr) << (partial_tile_offset * 4); \
745 partial_tile_flip_4bpp(combine_op, alpha_op) \
747 #define partial_tile_mid_flip_4bpp(combine_op, alpha_op) \
748 partial_tile_right_flip_4bpp(combine_op, alpha_op) \
750 #define partial_tile_left_flip_4bpp(combine_op, alpha_op) \
751 current_pixels = *((u32 *)tile_ptr); \
752 partial_tile_flip_4bpp(combine_op, alpha_op) \
754 #define tile_flip_4bpp(combine_op, alpha_op) \
755 current_pixels = *((u32 *)tile_ptr); \
756 tile_4bpp_draw_eight_##combine_op(alpha_op, flip) \
759 // Draws a single (partial or complete) tile from the tilemap, flipping
762 #define single_tile_map(tile_type, combine_op, color_depth, alpha_op) \
763 get_tile_##color_depth(); \
764 if(current_tile & 0x800) \
765 tile_ptr += vertical_pixel_flip; \
767 if(current_tile & 0x400) \
769 tile_type##_flip_##color_depth(combine_op, alpha_op); \
773 tile_type##_noflip_##color_depth(combine_op, alpha_op); \
777 // Draws multiple sequential tiles from the tilemap, hflips and vflips as
780 #define multiple_tile_map(combine_op, color_depth, alpha_op) \
781 for(i = 0; i < tile_run; i++) \
783 single_tile_map(tile, combine_op, color_depth, alpha_op); \
784 advance_dest_ptr_##combine_op(8); \
788 // Draws a partial tile from a tilemap clipped against the left edge of the
791 #define partial_tile_right_map(combine_op, color_depth, alpha_op) \
792 single_tile_map(partial_tile_right, combine_op, color_depth, alpha_op); \
795 // Draws a partial tile from a tilemap clipped against both edges of the
798 #define partial_tile_mid_map(combine_op, color_depth, alpha_op) \
799 single_tile_map(partial_tile_mid, combine_op, color_depth, alpha_op) \
801 // Draws a partial tile from a tilemap clipped against the right edge of the
804 #define partial_tile_left_map(combine_op, color_depth, alpha_op) \
805 single_tile_map(partial_tile_left, combine_op, color_depth, alpha_op) \
808 // Advances a non-flipped 4bpp obj to the next tile.
810 #define obj_advance_noflip_4bpp() \
814 // Advances a non-flipped 8bpp obj to the next tile.
816 #define obj_advance_noflip_8bpp() \
820 // Advances a flipped 4bpp obj to the next tile.
822 #define obj_advance_flip_4bpp() \
826 // Advances a flipped 8bpp obj to the next tile.
828 #define obj_advance_flip_8bpp() \
833 // Draws multiple sequential tiles from an obj, flip_op determines if it should
834 // be flipped or not (set to flip or noflip)
836 #define multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op) \
837 for(i = 0; i < tile_run; i++) \
839 tile_##flip_op##_##color_depth(combine_op, alpha_op); \
840 obj_advance_##flip_op##_##color_depth(); \
841 advance_dest_ptr_##combine_op(8); \
845 // Draws an obj's tile clipped against the left side of the screen
847 #define partial_tile_right_obj(combine_op, color_depth, alpha_op, flip_op) \
848 partial_tile_right_##flip_op##_##color_depth(combine_op, alpha_op); \
849 obj_advance_##flip_op##_##color_depth() \
851 // Draws an obj's tile clipped against both sides of the screen
853 #define partial_tile_mid_obj(combine_op, color_depth, alpha_op, flip_op) \
854 partial_tile_mid_##flip_op##_##color_depth(combine_op, alpha_op) \
856 // Draws an obj's tile clipped against the right side of the screen
858 #define partial_tile_left_obj(combine_op, color_depth, alpha_op, flip_op) \
859 partial_tile_left_##flip_op##_##color_depth(combine_op, alpha_op) \
862 // Extra variables specific for 8bpp/4bpp tile renderers.
864 #define tile_extra_variables_8bpp() \
866 #define tile_extra_variables_4bpp() \
867 u32 current_palette \
870 // Byte lengths of complete tiles and tile rows in 4bpp and 8bpp.
872 #define tile_width_4bpp 4
873 #define tile_size_4bpp 32
874 #define tile_width_8bpp 8
875 #define tile_size_8bpp 64
878 // Render a single scanline of text tiles
880 #define tile_render(color_depth, combine_op, alpha_op) \
882 u32 vertical_pixel_offset = (vertical_offset % 8) * \
883 tile_width_##color_depth; \
884 u32 vertical_pixel_flip = \
885 ((tile_size_##color_depth - tile_width_##color_depth) - \
886 vertical_pixel_offset) - vertical_pixel_offset; \
887 tile_extra_variables_##color_depth(); \
888 u8 *tile_base = vram + (((bg_control >> 2) & 0x03) * (1024 * 16)) + \
889 vertical_pixel_offset; \
890 u32 pixel_run = 256 - (horizontal_offset % 256); \
893 map_base += ((vertical_offset % 256) / 8) * 32; \
894 partial_tile_offset = (horizontal_offset % 8); \
896 if(pixel_run >= end) \
898 if(partial_tile_offset) \
900 partial_tile_run = 8 - partial_tile_offset; \
901 if(end < partial_tile_run) \
903 partial_tile_run = end; \
904 partial_tile_mid_map(combine_op, color_depth, alpha_op); \
909 end -= partial_tile_run; \
910 partial_tile_right_map(combine_op, color_depth, alpha_op); \
914 tile_run = end / 8; \
915 multiple_tile_map(combine_op, color_depth, alpha_op); \
917 partial_tile_run = end % 8; \
919 if(partial_tile_run) \
921 partial_tile_left_map(combine_op, color_depth, alpha_op); \
926 if(partial_tile_offset) \
928 partial_tile_run = 8 - partial_tile_offset; \
929 partial_tile_right_map(combine_op, color_depth, alpha_op); \
932 tile_run = (pixel_run - partial_tile_run) / 8; \
933 multiple_tile_map(combine_op, color_depth, alpha_op); \
934 map_ptr = second_ptr; \
936 tile_run = end / 8; \
937 multiple_tile_map(combine_op, color_depth, alpha_op); \
939 partial_tile_run = end % 8; \
940 if(partial_tile_run) \
942 partial_tile_left_map(combine_op, color_depth, alpha_op); \
947 #define render_scanline_dest_normal u16
948 #define render_scanline_dest_alpha u32
949 #define render_scanline_dest_alpha_obj u32
950 #define render_scanline_dest_color16 u16
951 #define render_scanline_dest_color32 u32
952 #define render_scanline_dest_partial_alpha u32
953 #define render_scanline_dest_copy_tile u16
954 #define render_scanline_dest_copy_bitmap u16
957 // If rendering a scanline that is not a target A then there's no point in
958 // keeping what's underneath it because it can't blend with it.
960 #define render_scanline_skip_alpha(bg_type, combine_op) \
961 if((pixel_combine & 0x00000200) == 0) \
963 render_scanline_##bg_type##_##combine_op##_color32(layer, \
964 start, end, scanline); \
969 #ifdef RENDER_COLOR16_NORMAL
971 #define render_scanline_extra_variables_base_normal(bg_type) \
972 const u32 pixel_combine = 0 \
976 #define render_scanline_extra_variables_base_normal(bg_type) \
977 u16 *palette = palette_ram_converted \
982 #define render_scanline_extra_variables_base_alpha(bg_type) \
983 u32 bg_combine = color_combine_mask(5); \
984 u32 pixel_combine = color_combine_mask(layer) | (bg_combine << 16); \
985 render_scanline_skip_alpha(bg_type, base) \
987 #define render_scanline_extra_variables_base_color() \
988 u32 bg_combine = color_combine_mask(5); \
989 u32 pixel_combine = color_combine_mask(layer) \
991 #define render_scanline_extra_variables_base_color16(bg_type) \
992 render_scanline_extra_variables_base_color() \
994 #define render_scanline_extra_variables_base_color32(bg_type) \
995 render_scanline_extra_variables_base_color() \
998 #define render_scanline_extra_variables_transparent_normal(bg_type) \
999 render_scanline_extra_variables_base_normal(bg_type) \
1001 #define render_scanline_extra_variables_transparent_alpha(bg_type) \
1002 u32 pixel_combine = color_combine_mask(layer); \
1003 render_scanline_skip_alpha(bg_type, transparent) \
1005 #define render_scanline_extra_variables_transparent_color() \
1006 u32 pixel_combine = color_combine_mask(layer) \
1008 #define render_scanline_extra_variables_transparent_color16(bg_type) \
1009 render_scanline_extra_variables_transparent_color() \
1011 #define render_scanline_extra_variables_transparent_color32(bg_type) \
1012 render_scanline_extra_variables_transparent_color() \
1017 static const u32 map_widths[] = { 256, 512, 256, 512 };
1019 // Build text scanline rendering functions.
1021 #define render_scanline_text_builder(combine_op, alpha_op) \
1022 static void render_scanline_text_##combine_op##_##alpha_op(u32 layer, \
1023 u32 start, u32 end, void *scanline) \
1025 render_scanline_extra_variables_##combine_op##_##alpha_op(text); \
1026 u32 bg_control = io_registers[REG_BG0CNT + layer]; \
1027 u32 map_size = (bg_control >> 14) & 0x03; \
1028 u32 map_width = map_widths[map_size]; \
1029 u32 horizontal_offset = \
1030 (io_registers[REG_BG0HOFS + (layer * 2)] + start) % 512; \
1031 u32 vertical_offset = (io_registers[REG_VCOUNT] + \
1032 io_registers[REG_BG0VOFS + (layer * 2)]) % 512; \
1033 u32 current_pixel; \
1034 u32 current_pixels; \
1035 u32 partial_tile_run = 0; \
1036 u32 partial_tile_offset; \
1039 render_scanline_dest_##alpha_op *dest_ptr = \
1040 ((render_scanline_dest_##alpha_op *)scanline) + start; \
1042 u16 *map_base = (u16 *)(vram + ((bg_control >> 8) & 0x1F) * (1024 * 2)); \
1043 u16 *map_ptr, *second_ptr; \
1048 if((map_size & 0x02) && (vertical_offset >= 256)) \
1050 map_base += ((map_width / 8) * 32) + \
1051 (((vertical_offset - 256) / 8) * 32); \
1055 map_base += (((vertical_offset % 256) / 8) * 32); \
1058 if(map_size & 0x01) \
1060 if(horizontal_offset >= 256) \
1062 horizontal_offset -= 256; \
1063 map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); \
1064 second_ptr = map_base; \
1068 map_ptr = map_base + (horizontal_offset / 8); \
1069 second_ptr = map_base + (32 * 32); \
1074 horizontal_offset %= 256; \
1075 map_ptr = map_base + (horizontal_offset / 8); \
1076 second_ptr = map_base; \
1079 if(bg_control & 0x80) \
1081 tile_render(8bpp, combine_op, alpha_op); \
1085 tile_render(4bpp, combine_op, alpha_op); \
1089 render_scanline_text_builder(base, normal);
1090 render_scanline_text_builder(transparent, normal);
1091 render_scanline_text_builder(base, color16);
1092 render_scanline_text_builder(transparent, color16);
1093 render_scanline_text_builder(base, color32);
1094 render_scanline_text_builder(transparent, color32);
1095 render_scanline_text_builder(base, alpha);
1096 render_scanline_text_builder(transparent, alpha);
1099 s32 affine_reference_x[2];
1100 s32 affine_reference_y[2];
1102 #define affine_render_bg_pixel_normal() \
1103 current_pixel = palette_ram_converted[0] \
1105 #define affine_render_bg_pixel_alpha() \
1106 current_pixel = bg_combine \
1108 #define affine_render_bg_pixel_color16() \
1109 affine_render_bg_pixel_alpha() \
1111 #define affine_render_bg_pixel_color32() \
1112 affine_render_bg_pixel_alpha() \
1114 #define affine_render_bg_pixel_base(alpha_op) \
1115 affine_render_bg_pixel_##alpha_op() \
1117 #define affine_render_bg_pixel_transparent(alpha_op) \
1119 #define affine_render_bg_pixel_copy(alpha_op) \
1121 #define affine_render_bg_base(alpha_op) \
1122 dest_ptr[0] = current_pixel
1124 #define affine_render_bg_transparent(alpha_op) \
1126 #define affine_render_bg_copy(alpha_op) \
1128 #define affine_render_bg_remainder_base(alpha_op) \
1129 affine_render_bg_pixel_##alpha_op(); \
1130 for(; i < end; i++) \
1132 affine_render_bg_base(alpha_op); \
1133 advance_dest_ptr_base(1); \
1136 #define affine_render_bg_remainder_transparent(alpha_op) \
1138 #define affine_render_bg_remainder_copy(alpha_op) \
1140 #define affine_render_next(combine_op) \
1143 advance_dest_ptr_##combine_op(1) \
1145 #define affine_render_scale_offset() \
1146 tile_base += ((pixel_y % 8) * 8); \
1147 map_base += (pixel_y / 8) << map_pitch \
1149 #define affine_render_scale_pixel(combine_op, alpha_op) \
1150 map_offset = (pixel_x / 8); \
1151 if(map_offset != last_map_offset) \
1153 tile_ptr = tile_base + (map_base[map_offset] * 64); \
1154 last_map_offset = map_offset; \
1156 tile_ptr = tile_base + (map_base[(pixel_x / 8)] * 64); \
1157 current_pixel = tile_ptr[(pixel_x % 8)]; \
1158 tile_8bpp_draw_##combine_op(0, none, 0, alpha_op); \
1159 affine_render_next(combine_op) \
1161 #define affine_render_scale(combine_op, alpha_op) \
1163 pixel_y = source_y >> 8; \
1165 affine_render_bg_pixel_##combine_op(alpha_op); \
1166 if((u32)pixel_y < (u32)width_height) \
1168 affine_render_scale_offset(); \
1169 for(; i < end; i++) \
1171 pixel_x = source_x >> 8; \
1173 if((u32)pixel_x < (u32)width_height) \
1178 affine_render_bg_##combine_op(alpha_op); \
1179 affine_render_next(combine_op); \
1182 for(; i < end; i++) \
1184 pixel_x = source_x >> 8; \
1186 if((u32)pixel_x >= (u32)width_height) \
1189 affine_render_scale_pixel(combine_op, alpha_op); \
1192 affine_render_bg_remainder_##combine_op(alpha_op); \
1195 #define affine_render_scale_wrap(combine_op, alpha_op) \
1197 u32 wrap_mask = width_height - 1; \
1198 pixel_y = (source_y >> 8) & wrap_mask; \
1199 if((u32)pixel_y < (u32)width_height) \
1201 affine_render_scale_offset(); \
1202 for(i = 0; i < end; i++) \
1204 pixel_x = (source_x >> 8) & wrap_mask; \
1205 affine_render_scale_pixel(combine_op, alpha_op); \
1211 #define affine_render_rotate_pixel(combine_op, alpha_op) \
1212 map_offset = (pixel_x / 8) + ((pixel_y / 8) << map_pitch); \
1213 if(map_offset != last_map_offset) \
1215 tile_ptr = tile_base + (map_base[map_offset] * 64); \
1216 last_map_offset = map_offset; \
1219 current_pixel = tile_ptr[(pixel_x % 8) + ((pixel_y % 8) * 8)]; \
1220 tile_8bpp_draw_##combine_op(0, none, 0, alpha_op); \
1221 affine_render_next(combine_op) \
1223 #define affine_render_rotate(combine_op, alpha_op) \
1225 affine_render_bg_pixel_##combine_op(alpha_op); \
1226 for(i = 0; i < end; i++) \
1228 pixel_x = source_x >> 8; \
1229 pixel_y = source_y >> 8; \
1231 if(((u32)pixel_x < (u32)width_height) && \
1232 ((u32)pixel_y < (u32)width_height)) \
1236 affine_render_bg_##combine_op(alpha_op); \
1237 affine_render_next(combine_op); \
1240 for(; i < end; i++) \
1242 pixel_x = source_x >> 8; \
1243 pixel_y = source_y >> 8; \
1245 if(((u32)pixel_x >= (u32)width_height) || \
1246 ((u32)pixel_y >= (u32)width_height)) \
1248 affine_render_bg_remainder_##combine_op(alpha_op); \
1252 affine_render_rotate_pixel(combine_op, alpha_op); \
1256 #define affine_render_rotate_wrap(combine_op, alpha_op) \
1258 u32 wrap_mask = width_height - 1; \
1259 for(i = 0; i < end; i++) \
1261 pixel_x = (source_x >> 8) & wrap_mask; \
1262 pixel_y = (source_y >> 8) & wrap_mask; \
1264 affine_render_rotate_pixel(combine_op, alpha_op); \
1269 // Build affine background renderers.
1271 #define render_scanline_affine_builder(combine_op, alpha_op) \
1272 void render_scanline_affine_##combine_op##_##alpha_op(u32 layer, \
1273 u32 start, u32 end, void *scanline) \
1275 render_scanline_extra_variables_##combine_op##_##alpha_op(affine); \
1276 u32 bg_control = io_registers[REG_BG0CNT + layer]; \
1277 u32 current_pixel; \
1278 s32 source_x, source_y; \
1279 u32 pixel_x, pixel_y; \
1280 u32 layer_offset = (layer - 2) * 8; \
1282 u32 map_size = (bg_control >> 14) & 0x03; \
1283 u32 width_height = 1 << (7 + map_size); \
1284 u32 map_pitch = map_size + 4; \
1285 u8 *map_base = vram + (((bg_control >> 8) & 0x1F) * (1024 * 2)); \
1286 u8 *tile_base = vram + (((bg_control >> 2) & 0x03) * (1024 * 16)); \
1287 u8 *tile_ptr = NULL; \
1288 u32 map_offset, last_map_offset = (u32)-1; \
1290 render_scanline_dest_##alpha_op *dest_ptr = \
1291 ((render_scanline_dest_##alpha_op *)scanline) + start; \
1293 dx = (s16)io_registers[REG_BG2PA + layer_offset]; \
1294 dy = (s16)io_registers[REG_BG2PC + layer_offset]; \
1295 source_x = affine_reference_x[layer - 2] + (start * dx); \
1296 source_y = affine_reference_y[layer - 2] + (start * dy); \
1300 switch(((bg_control >> 12) & 0x02) | (dy != 0)) \
1303 affine_render_scale(combine_op, alpha_op); \
1307 affine_render_rotate(combine_op, alpha_op); \
1311 affine_render_scale_wrap(combine_op, alpha_op); \
1315 affine_render_rotate_wrap(combine_op, alpha_op); \
1320 render_scanline_affine_builder(base, normal);
1321 render_scanline_affine_builder(transparent, normal);
1322 render_scanline_affine_builder(base, color16);
1323 render_scanline_affine_builder(transparent, color16);
1324 render_scanline_affine_builder(base, color32);
1325 render_scanline_affine_builder(transparent, color32);
1326 render_scanline_affine_builder(base, alpha);
1327 render_scanline_affine_builder(transparent, alpha);
1330 #define bitmap_render_pixel_mode3(alpha_op) \
1331 convert_palette(current_pixel); \
1332 *dest_ptr = current_pixel \
1334 #define bitmap_render_pixel_mode4(alpha_op) \
1335 tile_expand_base_##alpha_op(0) \
1337 #define bitmap_render_pixel_mode5(alpha_op) \
1338 bitmap_render_pixel_mode3(alpha_op) \
1341 #define bitmap_render_scale(type, alpha_op, width, height) \
1342 pixel_y = (source_y >> 8); \
1343 if((u32)pixel_y < (u32)height) \
1345 pixel_x = (source_x >> 8); \
1346 src_ptr += (pixel_y * width); \
1352 dest_ptr -= pixel_x; \
1359 src_ptr += pixel_x; \
1362 if((pixel_x + end) >= width) \
1363 end = (width - pixel_x); \
1365 for(i = 0; (s32)i < (s32)end; i++) \
1367 current_pixel = *src_ptr; \
1368 bitmap_render_pixel_##type(alpha_op); \
1375 if((u32)(source_y >> 8) < (u32)height) \
1377 for(i = 0; i < end; i++) \
1379 pixel_x = (source_x >> 8); \
1381 if((u32)pixel_x < (u32)width) \
1388 for(; i < end; i++) \
1390 pixel_x = (source_x >> 8); \
1392 if((u32)pixel_x >= (u32)width) \
1395 current_pixel = src_ptr[pixel_x]; \
1396 bitmap_render_pixel_##type(alpha_op); \
1405 #define bitmap_render_rotate(type, alpha_op, width, height) \
1406 for(i = 0; i < end; i++) \
1408 pixel_x = source_x >> 8; \
1409 pixel_y = source_y >> 8; \
1411 if(((u32)pixel_x < (u32)width) && ((u32)pixel_y < (u32)height)) \
1419 for(; i < end; i++) \
1421 pixel_x = (source_x >> 8); \
1422 pixel_y = (source_y >> 8); \
1424 if(((u32)pixel_x >= (u32)width) || ((u32)pixel_y >= (u32)height)) \
1427 current_pixel = src_ptr[pixel_x + (pixel_y * width)]; \
1428 bitmap_render_pixel_##type(alpha_op); \
1436 #define render_scanline_vram_setup_mode3() \
1437 u16 *src_ptr = (u16 *)vram \
1439 #define render_scanline_vram_setup_mode5() \
1441 if(io_registers[REG_DISPCNT] & 0x10) \
1442 src_ptr = (u16 *)(vram + 0xA000); \
1444 src_ptr = (u16 *)vram \
1447 #ifdef RENDER_COLOR16_NORMAL
1449 #define render_scanline_vram_setup_mode4() \
1450 const u32 pixel_combine = 0; \
1452 if(io_registers[REG_DISPCNT] & 0x10) \
1453 src_ptr = vram + 0xA000; \
1460 #define render_scanline_vram_setup_mode4() \
1461 u16 *palette = palette_ram_converted; \
1463 if(io_registers[REG_DISPCNT] & 0x10) \
1464 src_ptr = vram + 0xA000; \
1472 // Build bitmap scanline rendering functions.
1474 #define render_scanline_bitmap_builder(type, alpha_op, width, height) \
1475 static void render_scanline_bitmap_##type##_##alpha_op(u32 start, u32 end, \
1478 u32 current_pixel; \
1479 s32 source_x, source_y; \
1480 s32 pixel_x, pixel_y; \
1482 s32 dx = (s16)io_registers[REG_BG2PA]; \
1483 s32 dy = (s16)io_registers[REG_BG2PC]; \
1487 render_scanline_dest_##alpha_op *dest_ptr = \
1488 ((render_scanline_dest_##alpha_op *)scanline) + start; \
1489 render_scanline_vram_setup_##type(); \
1493 source_x = affine_reference_x[0] + (start * dx); \
1494 source_y = affine_reference_y[0] + (start * dy); \
1498 bitmap_render_scale(type, alpha_op, width, height); \
1502 bitmap_render_rotate(type, alpha_op, width, height); \
1506 render_scanline_bitmap_builder(mode3, normal, 240, 160);
1507 render_scanline_bitmap_builder(mode4, normal, 240, 160);
1508 render_scanline_bitmap_builder(mode5, normal, 160, 128);
1511 // Fill in the renderers for a layer based on the mode type,
1513 #define tile_layer_render_functions(type) \
1515 render_scanline_##type##_base_normal, \
1516 render_scanline_##type##_transparent_normal, \
1517 render_scanline_##type##_base_alpha, \
1518 render_scanline_##type##_transparent_alpha, \
1519 render_scanline_##type##_base_color16, \
1520 render_scanline_##type##_transparent_color16, \
1521 render_scanline_##type##_base_color32, \
1522 render_scanline_##type##_transparent_color32 \
1526 // Use if a layer is unsupported for that mode.
1528 #define tile_layer_render_null() \
1530 NULL, NULL, NULL, NULL \
1533 #define bitmap_layer_render_functions(type) \
1535 render_scanline_bitmap_##type##_normal \
1538 // Structs containing functions to render the layers for each mode, for
1539 // each render type.
1540 static const tile_layer_render_struct tile_mode_renderers[3][4] =
1543 tile_layer_render_functions(text), tile_layer_render_functions(text),
1544 tile_layer_render_functions(text), tile_layer_render_functions(text)
1547 tile_layer_render_functions(text), tile_layer_render_functions(text),
1548 tile_layer_render_functions(affine), tile_layer_render_functions(text)
1551 tile_layer_render_functions(text), tile_layer_render_functions(text),
1552 tile_layer_render_functions(affine), tile_layer_render_functions(affine)
1556 static const bitmap_layer_render_struct bitmap_mode_renderers[3] =
1558 bitmap_layer_render_functions(mode3),
1559 bitmap_layer_render_functions(mode4),
1560 bitmap_layer_render_functions(mode5)
1564 #define render_scanline_layer_functions_tile() \
1565 const tile_layer_render_struct *layer_renderers = \
1566 tile_mode_renderers[dispcnt & 0x07] \
1568 #define render_scanline_layer_functions_bitmap() \
1569 const bitmap_layer_render_struct *layer_renderers = \
1570 bitmap_mode_renderers + ((dispcnt & 0x07) - 3) \
1573 // Adjust a flipped obj's starting position
1575 #define obj_tile_offset_noflip(color_depth) \
1577 #define obj_tile_offset_flip(color_depth) \
1578 + (tile_size_##color_depth * ((obj_width - 8) / 8)) \
1581 // Adjust the obj's starting point if it goes too far off the left edge of
1584 #define obj_tile_right_offset_noflip(color_depth) \
1585 tile_ptr += (partial_tile_offset / 8) * tile_size_##color_depth \
1587 #define obj_tile_right_offset_flip(color_depth) \
1588 tile_ptr -= (partial_tile_offset / 8) * tile_size_##color_depth \
1590 // Get the current row offset into an obj in 1D map space
1592 #define obj_tile_offset_1D(color_depth, flip_op) \
1593 tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) \
1594 + ((vertical_offset / 8) * (obj_width / 8) * tile_size_##color_depth) \
1595 + ((vertical_offset % 8) * tile_width_##color_depth) \
1596 obj_tile_offset_##flip_op(color_depth) \
1598 // Get the current row offset into an obj in 2D map space
1600 #define obj_tile_offset_2D(color_depth, flip_op) \
1601 tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) \
1602 + ((vertical_offset / 8) * 1024) \
1603 + ((vertical_offset % 8) * tile_width_##color_depth) \
1604 obj_tile_offset_##flip_op(color_depth) \
1607 // Get the palette for 4bpp obj.
1609 #define obj_get_palette_4bpp() \
1610 current_palette = (obj_attribute_2 >> 8) & 0xF0 \
1612 #define obj_get_palette_8bpp() \
1615 // Render the current row of an obj.
1617 #define obj_render(combine_op, color_depth, alpha_op, map_space, flip_op) \
1619 obj_get_palette_##color_depth(); \
1620 obj_tile_offset_##map_space(color_depth, flip_op); \
1622 if(obj_x < (s32)start) \
1624 dest_ptr = scanline + start; \
1625 pixel_run = obj_width - (start - obj_x); \
1626 if((s32)pixel_run > 0) \
1628 if((obj_x + obj_width) >= end) \
1630 pixel_run = end - start; \
1631 partial_tile_offset = start - obj_x; \
1632 obj_tile_right_offset_##flip_op(color_depth); \
1633 partial_tile_offset %= 8; \
1635 if(partial_tile_offset) \
1637 partial_tile_run = 8 - partial_tile_offset; \
1638 if((s32)pixel_run < (s32)partial_tile_run) \
1640 if((s32)pixel_run > 0) \
1642 partial_tile_run = pixel_run; \
1643 partial_tile_mid_obj(combine_op, color_depth, alpha_op, \
1650 pixel_run -= partial_tile_run; \
1651 partial_tile_right_obj(combine_op, color_depth, alpha_op, \
1655 tile_run = pixel_run / 8; \
1656 multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \
1657 partial_tile_run = pixel_run % 8; \
1658 if(partial_tile_run) \
1660 partial_tile_left_obj(combine_op, color_depth, alpha_op, \
1666 partial_tile_offset = start - obj_x; \
1667 obj_tile_right_offset_##flip_op(color_depth); \
1668 partial_tile_offset %= 8; \
1669 if(partial_tile_offset) \
1671 partial_tile_run = 8 - partial_tile_offset; \
1672 partial_tile_right_obj(combine_op, color_depth, alpha_op, \
1675 tile_run = pixel_run / 8; \
1676 multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \
1682 if((obj_x + obj_width) >= end) \
1684 pixel_run = end - obj_x; \
1685 if((s32)pixel_run > 0) \
1687 dest_ptr = scanline + obj_x; \
1688 tile_run = pixel_run / 8; \
1689 multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \
1690 partial_tile_run = pixel_run % 8; \
1691 if(partial_tile_run) \
1693 partial_tile_left_obj(combine_op, color_depth, alpha_op, flip_op); \
1699 dest_ptr = scanline + obj_x; \
1700 tile_run = obj_width / 8; \
1701 multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \
1705 #define obj_scale_offset_1D(color_depth) \
1706 tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) \
1707 + ((vertical_offset / 8) * (max_x / 8) * tile_size_##color_depth) \
1708 + ((vertical_offset % 8) * tile_width_##color_depth) \
1710 // Get the current row offset into an obj in 2D map space
1712 #define obj_scale_offset_2D(color_depth) \
1713 tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) \
1714 + ((vertical_offset / 8) * 1024) \
1715 + ((vertical_offset % 8) * tile_width_##color_depth) \
1717 #define obj_render_scale_pixel_4bpp(combine_op, alpha_op) \
1720 current_pixel = tile_ptr[tile_map_offset + ((tile_x >> 1) & 0x03)] >> 4; \
1725 tile_ptr[tile_map_offset + ((tile_x >> 1) & 0x03)] & 0x0F; \
1728 tile_4bpp_draw_##combine_op(0, none, 0, alpha_op) \
1731 #define obj_render_scale_pixel_8bpp(combine_op, alpha_op) \
1732 current_pixel = tile_ptr[tile_map_offset + (tile_x & 0x07)]; \
1733 tile_8bpp_draw_##combine_op(0, none, 0, alpha_op); \
1735 #define obj_render_scale(combine_op, color_depth, alpha_op, map_space) \
1737 u32 vertical_offset; \
1738 source_y += (y_delta * dmy); \
1739 vertical_offset = (source_y >> 8); \
1740 if((u32)vertical_offset < (u32)max_y) \
1742 obj_scale_offset_##map_space(color_depth); \
1743 source_x += (y_delta * dmx) - (middle_x * dx); \
1745 for(i = 0; i < obj_width; i++) \
1747 tile_x = (source_x >> 8); \
1749 if((u32)tile_x < (u32)max_x) \
1753 advance_dest_ptr_##combine_op(1); \
1756 for(; i < obj_width; i++) \
1758 tile_x = (source_x >> 8); \
1760 if((u32)tile_x >= (u32)max_x) \
1763 tile_map_offset = (tile_x >> 3) * tile_size_##color_depth; \
1764 obj_render_scale_pixel_##color_depth(combine_op, alpha_op); \
1767 advance_dest_ptr_##combine_op(1); \
1773 #define obj_rotate_offset_1D(color_depth) \
1774 obj_tile_pitch = (max_x / 8) * tile_size_##color_depth \
1776 #define obj_rotate_offset_2D(color_depth) \
1777 obj_tile_pitch = 1024 \
1779 #define obj_render_rotate_pixel_4bpp(combine_op, alpha_op) \
1782 current_pixel = tile_ptr[tile_map_offset + \
1783 ((tile_x >> 1) & 0x03) + ((tile_y & 0x07) * obj_pitch)] >> 4; \
1787 current_pixel = tile_ptr[tile_map_offset + \
1788 ((tile_x >> 1) & 0x03) + ((tile_y & 0x07) * obj_pitch)] & 0x0F; \
1791 tile_4bpp_draw_##combine_op(0, none, 0, alpha_op) \
1793 #define obj_render_rotate_pixel_8bpp(combine_op, alpha_op) \
1794 current_pixel = tile_ptr[tile_map_offset + \
1795 (tile_x & 0x07) + ((tile_y & 0x07) * obj_pitch)]; \
1797 tile_8bpp_draw_##combine_op(0, none, 0, alpha_op) \
1799 #define obj_render_rotate(combine_op, color_depth, alpha_op, map_space) \
1801 tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32); \
1802 obj_rotate_offset_##map_space(color_depth); \
1804 source_x += (y_delta * dmx) - (middle_x * dx); \
1805 source_y += (y_delta * dmy) - (middle_x * dy); \
1807 for(i = 0; i < obj_width; i++) \
1809 tile_x = (source_x >> 8); \
1810 tile_y = (source_y >> 8); \
1812 if(((u32)tile_x < (u32)max_x) && ((u32)tile_y < (u32)max_y)) \
1817 advance_dest_ptr_##combine_op(1); \
1820 for(; i < obj_width; i++) \
1822 tile_x = (source_x >> 8); \
1823 tile_y = (source_y >> 8); \
1825 if(((u32)tile_x >= (u32)max_x) || ((u32)tile_y >= (u32)max_y)) \
1828 tile_map_offset = ((tile_x >> 3) * tile_size_##color_depth) + \
1829 ((tile_y >> 3) * obj_tile_pitch); \
1830 obj_render_rotate_pixel_##color_depth(combine_op, alpha_op); \
1834 advance_dest_ptr_##combine_op(1); \
1838 // Render the current row of an affine transformed OBJ.
1840 #define obj_render_affine(combine_op, color_depth, alpha_op, map_space) \
1842 s16 *params = (s16 *)oam_ram + (((obj_attribute_1 >> 9) & 0x1F) * 16); \
1843 s32 dx = params[3]; \
1844 s32 dmx = params[7]; \
1845 s32 dy = params[11]; \
1846 s32 dmy = params[15]; \
1847 s32 source_x, source_y; \
1848 s32 tile_x, tile_y; \
1849 u32 tile_map_offset; \
1852 s32 max_x = obj_width; \
1853 s32 max_y = obj_height; \
1855 u32 obj_pitch = tile_width_##color_depth; \
1856 u32 obj_tile_pitch; \
1858 middle_x = (obj_width / 2); \
1859 middle_y = (obj_height / 2); \
1861 source_x = (middle_x << 8); \
1862 source_y = (middle_y << 8); \
1865 if(obj_attribute_0 & 0x200) \
1873 if((s32)obj_x < (s32)start) \
1875 u32 x_delta = start - obj_x; \
1876 middle_x -= x_delta; \
1877 obj_width -= x_delta; \
1880 if((s32)obj_width <= 0) \
1884 if((s32)(obj_x + obj_width) >= (s32)end) \
1886 obj_width = end - obj_x; \
1888 if((s32)obj_width <= 0) \
1891 dest_ptr = scanline + obj_x; \
1893 y_delta = vcount - (obj_y + middle_y); \
1895 obj_get_palette_##color_depth(); \
1899 obj_render_scale(combine_op, color_depth, alpha_op, map_space); \
1903 obj_render_rotate(combine_op, color_depth, alpha_op, map_space); \
1907 static const u32 obj_width_table[] =
1908 { 8, 16, 32, 64, 16, 32, 32, 64, 8, 8, 16, 32 };
1909 static const u32 obj_height_table[] =
1910 { 8, 16, 32, 64, 8, 8, 16, 32, 16, 32, 32, 64 };
1912 static u8 obj_priority_list[5][160][128];
1913 static u32 obj_priority_count[5][160];
1914 static u32 obj_alpha_count[160];
1917 // Build obj rendering functions
1919 #ifdef RENDER_COLOR16_NORMAL
1921 #define render_scanline_obj_extra_variables_normal(bg_type) \
1922 const u32 pixel_combine = (1 << 8) \
1926 #define render_scanline_obj_extra_variables_normal(bg_type) \
1927 u16 *palette = palette_ram_converted + 256 \
1932 #define render_scanline_obj_extra_variables_color() \
1933 u32 pixel_combine = color_combine_mask(4) | (1 << 8) \
1935 #define render_scanline_obj_extra_variables_alpha_obj(map_space) \
1936 render_scanline_obj_extra_variables_color(); \
1938 if((pixel_combine & 0x00000200) == 0) \
1940 render_scanline_obj_color32_##map_space(priority, start, end, scanline); \
1944 #define render_scanline_obj_extra_variables_color16(map_space) \
1945 render_scanline_obj_extra_variables_color() \
1947 #define render_scanline_obj_extra_variables_color32(map_space) \
1948 render_scanline_obj_extra_variables_color() \
1950 #define render_scanline_obj_extra_variables_partial_alpha(map_space) \
1951 render_scanline_obj_extra_variables_color(); \
1952 u32 base_pixel_combine = pixel_combine; \
1955 #define render_scanline_obj_extra_variables_copy(type) \
1956 u32 bldcnt = io_registers[REG_BLDCNT]; \
1957 u32 dispcnt = io_registers[REG_DISPCNT]; \
1958 u32 obj_enable = io_registers[REG_WINOUT] >> 8; \
1959 render_scanline_layer_functions_##type(); \
1960 u32 copy_start, copy_end; \
1961 u16 copy_buffer[240]; \
1964 #define render_scanline_obj_extra_variables_copy_tile(map_space) \
1965 render_scanline_obj_extra_variables_copy(tile) \
1967 #define render_scanline_obj_extra_variables_copy_bitmap(map_space) \
1968 render_scanline_obj_extra_variables_copy(bitmap) \
1971 #define render_scanline_obj_main(combine_op, alpha_op, map_space) \
1972 if(obj_attribute_0 & 0x100) \
1974 if((obj_attribute_0 >> 13) & 0x01) \
1976 obj_render_affine(combine_op, 8bpp, alpha_op, map_space); \
1980 obj_render_affine(combine_op, 4bpp, alpha_op, map_space); \
1985 vertical_offset = vcount - obj_y; \
1987 if((obj_attribute_1 >> 13) & 0x01) \
1988 vertical_offset = obj_height - vertical_offset - 1; \
1990 switch(((obj_attribute_0 >> 12) & 0x02) | \
1991 ((obj_attribute_1 >> 12) & 0x01)) \
1994 obj_render(combine_op, 4bpp, alpha_op, map_space, noflip); \
1998 obj_render(combine_op, 4bpp, alpha_op, map_space, flip); \
2002 obj_render(combine_op, 8bpp, alpha_op, map_space, noflip); \
2006 obj_render(combine_op, 8bpp, alpha_op, map_space, flip); \
2011 #define render_scanline_obj_no_partial_alpha(combine_op, alpha_op, map_space) \
2012 render_scanline_obj_main(combine_op, alpha_op, map_space) \
2014 #define render_scanline_obj_partial_alpha(combine_op, alpha_op, map_space) \
2015 if((obj_attribute_0 >> 10) & 0x03) \
2017 pixel_combine = 0x00000300; \
2018 render_scanline_obj_main(combine_op, alpha_obj, map_space); \
2022 pixel_combine = base_pixel_combine; \
2023 render_scanline_obj_main(combine_op, color32, map_space); \
2026 #define render_scanline_obj_prologue_transparent(alpha_op) \
2028 #define render_scanline_obj_prologue_copy_body(type) \
2029 copy_start = obj_x; \
2030 if(obj_attribute_0 & 0x200) \
2031 copy_end = obj_x + (obj_width * 2); \
2033 copy_end = obj_x + obj_width; \
2035 if(copy_start < start) \
2036 copy_start = start; \
2037 if(copy_end > end) \
2040 if((copy_start < end) && (copy_end > start)) \
2042 render_scanline_conditional_##type(copy_start, copy_end, copy_buffer, \
2043 obj_enable, dispcnt, bldcnt, layer_renderers); \
2044 copy_ptr = copy_buffer + copy_start; \
2051 #define render_scanline_obj_prologue_copy_tile() \
2052 render_scanline_obj_prologue_copy_body(tile) \
2054 #define render_scanline_obj_prologue_copy_bitmap() \
2055 render_scanline_obj_prologue_copy_body(bitmap) \
2057 #define render_scanline_obj_prologue_copy(alpha_op) \
2058 render_scanline_obj_prologue_##alpha_op() \
2061 #define render_scanline_obj_builder(combine_op, alpha_op, map_space, \
2063 static void render_scanline_obj_##alpha_op##_##map_space(u32 priority, \
2064 u32 start, u32 end, render_scanline_dest_##alpha_op *scanline) \
2066 render_scanline_obj_extra_variables_##alpha_op(map_space); \
2070 s32 obj_width, obj_height; \
2071 u32 obj_attribute_0, obj_attribute_1, obj_attribute_2; \
2072 s32 vcount = io_registers[REG_VCOUNT]; \
2074 u32 current_pixels; \
2075 u32 current_pixel; \
2076 u32 current_palette; \
2077 u32 vertical_offset; \
2078 u32 partial_tile_run, partial_tile_offset; \
2081 render_scanline_dest_##alpha_op *dest_ptr; \
2082 u8 *tile_base = vram + 0x10000; \
2084 u32 obj_count = obj_priority_count[priority][vcount]; \
2085 u8 *obj_list = obj_priority_list[priority][vcount]; \
2087 for(obj_num = 0; obj_num < obj_count; obj_num++) \
2089 oam_ptr = oam_ram + (obj_list[obj_num] * 4); \
2090 obj_attribute_0 = oam_ptr[0]; \
2091 obj_attribute_1 = oam_ptr[1]; \
2092 obj_attribute_2 = oam_ptr[2]; \
2093 obj_size = ((obj_attribute_0 >> 12) & 0x0C) | (obj_attribute_1 >> 14); \
2095 obj_x = (s32)(obj_attribute_1 << 23) >> 23; \
2096 obj_width = obj_width_table[obj_size]; \
2098 render_scanline_obj_prologue_##combine_op(alpha_op); \
2100 obj_y = obj_attribute_0 & 0xFF; \
2105 obj_height = obj_height_table[obj_size]; \
2106 render_scanline_obj_##partial_alpha_op(combine_op, alpha_op, map_space); \
2110 render_scanline_obj_builder(transparent, normal, 1D, no_partial_alpha);
2111 render_scanline_obj_builder(transparent, normal, 2D, no_partial_alpha);
2112 render_scanline_obj_builder(transparent, color16, 1D, no_partial_alpha);
2113 render_scanline_obj_builder(transparent, color16, 2D, no_partial_alpha);
2114 render_scanline_obj_builder(transparent, color32, 1D, no_partial_alpha);
2115 render_scanline_obj_builder(transparent, color32, 2D, no_partial_alpha);
2116 render_scanline_obj_builder(transparent, alpha_obj, 1D, no_partial_alpha);
2117 render_scanline_obj_builder(transparent, alpha_obj, 2D, no_partial_alpha);
2118 render_scanline_obj_builder(transparent, partial_alpha, 1D, partial_alpha);
2119 render_scanline_obj_builder(transparent, partial_alpha, 2D, partial_alpha);
2120 render_scanline_obj_builder(copy, copy_tile, 1D, no_partial_alpha);
2121 render_scanline_obj_builder(copy, copy_tile, 2D, no_partial_alpha);
2122 render_scanline_obj_builder(copy, copy_bitmap, 1D, no_partial_alpha);
2123 render_scanline_obj_builder(copy, copy_bitmap, 2D, no_partial_alpha);
2127 static void order_obj(u32 video_mode)
2129 s32 obj_num, priority, row;
2131 s32 obj_size, obj_mode;
2132 s32 obj_width, obj_height;
2134 u32 obj_attribute_0, obj_attribute_1, obj_attribute_2;
2136 u16 *oam_ptr = oam_ram + 508;
2138 for(priority = 0; priority < 5; priority++)
2140 for(row = 0; row < 160; row++)
2142 obj_priority_count[priority][row] = 0;
2146 for(row = 0; row < 160; row++)
2148 obj_alpha_count[row] = 0;
2151 for(obj_num = 127; obj_num >= 0; obj_num--, oam_ptr -= 4)
2153 obj_attribute_0 = oam_ptr[0];
2154 obj_attribute_2 = oam_ptr[2];
2155 obj_size = obj_attribute_0 & 0xC000;
2156 obj_priority = (obj_attribute_2 >> 10) & 0x03;
2157 obj_mode = (obj_attribute_0 >> 10) & 0x03;
2159 if(((obj_attribute_0 & 0x0300) != 0x0200) && (obj_size != 0xC000) &&
2160 (obj_mode != 3) && ((video_mode < 3) ||
2161 ((obj_attribute_2 & 0x3FF) >= 512)))
2163 obj_y = obj_attribute_0 & 0xFF;
2167 obj_attribute_1 = oam_ptr[1];
2168 obj_size = ((obj_size >> 12) & 0x0C) | (obj_attribute_1 >> 14);
2169 obj_height = obj_height_table[obj_size];
2170 obj_width = obj_width_table[obj_size];
2172 if(obj_attribute_0 & 0x200)
2178 if(((obj_y + obj_height) > 0) && (obj_y < 160))
2180 obj_x = (s32)(obj_attribute_1 << 23) >> 23;
2182 if(((obj_x + obj_width) > 0) && (obj_x < 240))
2186 obj_height += obj_y;
2190 if((obj_y + obj_height) >= 160)
2192 obj_height = 160 - obj_y;
2197 for(row = obj_y; row < obj_y + obj_height; row++)
2199 current_count = obj_priority_count[obj_priority][row];
2200 obj_priority_list[obj_priority][row][current_count] = obj_num;
2201 obj_priority_count[obj_priority][row] = current_count + 1;
2202 obj_alpha_count[row]++;
2212 for(row = obj_y; row < obj_y + obj_height; row++)
2214 current_count = obj_priority_count[obj_priority][row];
2215 obj_priority_list[obj_priority][row][current_count] = obj_num;
2216 obj_priority_count[obj_priority][row] = current_count + 1;
2225 u32 layer_order[16];
2228 static void order_layers(u32 layer_flags)
2230 s32 priority, layer_number;
2233 for(priority = 3; priority >= 0; priority--)
2235 for(layer_number = 3; layer_number >= 0; layer_number--)
2237 if(((layer_flags >> layer_number) & 1) &&
2238 ((io_registers[REG_BG0CNT + layer_number] & 0x03) == priority))
2240 layer_order[layer_count] = layer_number;
2245 if((obj_priority_count[priority][io_registers[REG_VCOUNT]] > 0)
2246 && (layer_flags & 0x10))
2248 layer_order[layer_count] = priority | 0x04;
2254 #define fill_line(_start, _end) \
2257 for(i = _start; i < _end; i++) \
2259 dest_ptr[i] = color; \
2263 #define fill_line_color_normal() \
2264 color = palette_ram_converted[color] \
2266 #define fill_line_color_alpha() \
2268 #define fill_line_color_color16() \
2270 #define fill_line_color_color32() \
2272 #define fill_line_builder(type) \
2273 static void fill_line_##type(u16 color, render_scanline_dest_##type *dest_ptr,\
2274 u32 start, u32 end) \
2276 fill_line_color_##type(); \
2277 fill_line(start, end); \
2280 fill_line_builder(normal);
2281 fill_line_builder(alpha);
2282 fill_line_builder(color16);
2283 fill_line_builder(color32);
2286 // Alpha blend two pixels (pixel_top and pixel_bottom).
2288 #define blend_pixel() \
2289 pixel_bottom = palette_ram_converted[(pixel_pair >> 16) & 0x1FF]; \
2290 pixel_bottom = (pixel_bottom | (pixel_bottom << 16)) & 0x07E0F81F; \
2291 pixel_top = ((pixel_top * blend_a) + (pixel_bottom * blend_b)) >> 4 \
2294 // Alpha blend two pixels, allowing for saturation (individual channels > 31).
2295 // The operation is optimized towards saturation not occuring.
2297 #define blend_saturate_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; \
2301 if(pixel_top & 0x08010020) \
2303 if(pixel_top & 0x08000000) \
2304 pixel_top |= 0x07E00000; \
2306 if(pixel_top & 0x00010000) \
2307 pixel_top |= 0x0000F800; \
2309 if(pixel_top & 0x00000020) \
2310 pixel_top |= 0x0000001F; \
2313 #define brighten_pixel() \
2314 pixel_top = upper + ((pixel_top * blend) >> 4); \
2316 #define darken_pixel() \
2317 pixel_top = (pixel_top * blend) >> 4; \
2319 #define effect_condition_alpha \
2320 ((pixel_pair & 0x04000200) == 0x04000200) \
2322 #define effect_condition_fade(pixel_source) \
2323 ((pixel_source & 0x00000200) == 0x00000200) \
2325 #define expand_pixel_no_dest(expand_type, pixel_source) \
2326 pixel_top = (pixel_top | (pixel_top << 16)) & 0x07E0F81F; \
2327 expand_type##_pixel(); \
2328 pixel_top &= 0x07E0F81F; \
2329 pixel_top = (pixel_top >> 16) | pixel_top \
2331 #define expand_pixel(expand_type, pixel_source) \
2332 pixel_top = palette_ram_converted[pixel_source & 0x1FF]; \
2333 expand_pixel_no_dest(expand_type, pixel_source); \
2334 *screen_dest_ptr = pixel_top \
2336 #define expand_loop(expand_type, effect_condition, pixel_source) \
2337 screen_src_ptr += start; \
2338 screen_dest_ptr += start; \
2342 for(i = 0; i < end; i++) \
2344 pixel_source = *screen_src_ptr; \
2345 if(effect_condition) \
2347 expand_pixel(expand_type, pixel_source); \
2351 *screen_dest_ptr = \
2352 palette_ram_converted[pixel_source & 0x1FF]; \
2356 screen_dest_ptr++; \
2360 #define expand_loop_partial_alpha(alpha_expand, expand_type) \
2361 screen_src_ptr += start; \
2362 screen_dest_ptr += start; \
2366 for(i = 0; i < end; i++) \
2368 pixel_pair = *screen_src_ptr; \
2369 if(effect_condition_fade(pixel_pair)) \
2371 if(effect_condition_alpha) \
2373 expand_pixel(alpha_expand, pixel_pair); \
2377 expand_pixel(expand_type, pixel_pair); \
2382 *screen_dest_ptr = \
2383 palette_ram_converted[pixel_pair & 0x1FF]; \
2387 screen_dest_ptr++; \
2391 #define expand_partial_alpha(expand_type) \
2392 if((blend_a + blend_b) > 16) \
2394 expand_loop_partial_alpha(blend_saturate, expand_type); \
2398 expand_loop_partial_alpha(blend, expand_type); \
2403 // Blend top two pixels of scanline with each other.
2405 #ifdef RENDER_COLOR16_NORMAL
2409 void expand_normal(u16 *screen_ptr, u32 start, u32 end)
2411 u32 i, pixel_source;
2412 screen_ptr += start;
2418 for(i = 0; i < end; i++)
2420 pixel_source = *screen_ptr;
2421 *screen_ptr = palette_ram_converted[pixel_source];
2431 #define expand_normal(screen_ptr, start, end)
2436 void expand_blend(u32 *screen_src_ptr, u16 *screen_dest_ptr,
2437 u32 start, u32 end);
2441 void expand_blend(u32 *screen_src_ptr, u16 *screen_dest_ptr,
2445 u32 pixel_top, pixel_bottom;
2446 u32 bldalpha = io_registers[REG_BLDALPHA];
2447 u32 blend_a = bldalpha & 0x1F;
2448 u32 blend_b = (bldalpha >> 8) & 0x1F;
2457 // The individual colors can saturate over 31, this should be taken
2458 // care of in an alternate pass as it incurs a huge additional speedhit.
2459 if((blend_a + blend_b) > 16)
2461 expand_loop(blend_saturate, effect_condition_alpha, pixel_pair);
2465 expand_loop(blend, effect_condition_alpha, pixel_pair);
2471 // Blend scanline with white.
2473 static void expand_darken(u16 *screen_src_ptr, u16 *screen_dest_ptr,
2477 s32 blend = 16 - (io_registers[REG_BLDY] & 0x1F);
2483 expand_loop(darken, effect_condition_fade(pixel_top), pixel_top);
2487 // Blend scanline with black.
2489 static void expand_brighten(u16 *screen_src_ptr, u16 *screen_dest_ptr,
2493 u32 blend = io_registers[REG_BLDY] & 0x1F;
2500 upper = ((0x07E0F81F * blend) >> 4) & 0x07E0F81F;
2503 expand_loop(brighten, effect_condition_fade(pixel_top), pixel_top);
2508 // Expand scanline such that if both top and bottom pass it's alpha,
2509 // if only top passes it's as specified, and if neither pass it's normal.
2511 static void expand_darken_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ptr,
2514 s32 blend = 16 - (io_registers[REG_BLDY] & 0x1F);
2516 u32 pixel_top, pixel_bottom;
2517 u32 bldalpha = io_registers[REG_BLDALPHA];
2518 u32 blend_a = bldalpha & 0x1F;
2519 u32 blend_b = (bldalpha >> 8) & 0x1F;
2531 expand_partial_alpha(darken);
2535 static void expand_brighten_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ptr,
2538 s32 blend = io_registers[REG_BLDY] & 0x1F;
2540 u32 pixel_top, pixel_bottom;
2541 u32 bldalpha = io_registers[REG_BLDALPHA];
2542 u32 blend_a = bldalpha & 0x1F;
2543 u32 blend_b = (bldalpha >> 8) & 0x1F;
2550 upper = ((0x07E0F81F * blend) >> 4) & 0x07E0F81F;
2559 expand_partial_alpha(brighten);
2563 // Render an OBJ layer from start to end, depending on the type (1D or 2D)
2564 // stored in dispcnt.
2566 #define render_obj_layer(type, dest, _start, _end) \
2567 current_layer &= ~0x04; \
2568 if(dispcnt & 0x40) \
2569 render_scanline_obj_##type##_1D(current_layer, _start, _end, dest); \
2571 render_scanline_obj_##type##_2D(current_layer, _start, _end, dest) \
2574 // Render a target all the way with the background color as taken from the
2577 #define fill_line_bg(type, dest, _start, _end) \
2578 fill_line_##type(0, dest, _start, _end) \
2581 // Render all layers as they appear in the layer order.
2583 #define render_layers(tile_alpha, obj_alpha, dest) \
2585 current_layer = layer_order[0]; \
2586 if(current_layer & 0x04) \
2588 /* If the first one is OBJ render the background then render it. */ \
2589 fill_line_bg(tile_alpha, dest, 0, 240); \
2590 render_obj_layer(obj_alpha, dest, 0, 240); \
2594 /* Otherwise render a base layer. */ \
2595 layer_renderers[current_layer].tile_alpha##_render_base(current_layer, \
2599 /* Render the rest of the layers. */ \
2600 for(layer_order_pos = 1; layer_order_pos < layer_count; layer_order_pos++) \
2602 current_layer = layer_order[layer_order_pos]; \
2603 if(current_layer & 0x04) \
2605 render_obj_layer(obj_alpha, dest, 0, 240); \
2609 layer_renderers[current_layer]. \
2610 tile_alpha##_render_transparent(current_layer, 0, 240, dest); \
2615 #define render_condition_alpha \
2616 (((io_registers[REG_BLDALPHA] & 0x1F1F) != 0x001F) && \
2617 ((io_registers[REG_BLDCNT] & 0x3F) != 0) && \
2618 ((io_registers[REG_BLDCNT] & 0x3F00) != 0)) \
2620 #define render_condition_fade \
2621 (((io_registers[REG_BLDY] & 0x1F) != 0) && \
2622 ((io_registers[REG_BLDCNT] & 0x3F) != 0)) \
2624 #define render_layers_color_effect(renderer, layer_condition, \
2625 alpha_condition, fade_condition, _start, _end) \
2627 if(layer_condition) \
2629 if(obj_alpha_count[io_registers[REG_VCOUNT]] > 0) \
2631 /* Render based on special effects mode. */ \
2632 u32 screen_buffer[240]; \
2633 switch((bldcnt >> 6) & 0x03) \
2638 if(alpha_condition) \
2640 renderer(alpha, alpha_obj, screen_buffer); \
2641 expand_blend(screen_buffer, scanline, _start, _end); \
2647 /* Fade to white */ \
2650 if(fade_condition) \
2652 renderer(color32, partial_alpha, screen_buffer); \
2653 expand_brighten_partial_alpha(screen_buffer, scanline, \
2660 /* Fade to black */ \
2663 if(fade_condition) \
2665 renderer(color32, partial_alpha, screen_buffer); \
2666 expand_darken_partial_alpha(screen_buffer, scanline, \
2674 renderer(color32, partial_alpha, screen_buffer); \
2675 expand_blend(screen_buffer, scanline, _start, _end); \
2679 /* Render based on special effects mode. */ \
2680 switch((bldcnt >> 6) & 0x03) \
2685 if(alpha_condition) \
2687 u32 screen_buffer[240]; \
2688 renderer(alpha, alpha_obj, screen_buffer); \
2689 expand_blend(screen_buffer, scanline, _start, _end); \
2695 /* Fade to white */ \
2698 if(fade_condition) \
2700 renderer(color16, color16, scanline); \
2701 expand_brighten(scanline, scanline, _start, _end); \
2707 /* Fade to black */ \
2710 if(fade_condition) \
2712 renderer(color16, color16, scanline); \
2713 expand_darken(scanline, scanline, _start, _end); \
2720 renderer(normal, normal, scanline); \
2721 expand_normal(scanline, _start, _end); \
2726 u32 pixel_top = palette_ram_converted[0]; \
2727 switch((bldcnt >> 6) & 0x03) \
2729 /* Fade to white */ \
2732 if(color_combine_mask_a(5)) \
2734 u32 blend = io_registers[REG_BLDY] & 0x1F; \
2740 upper = ((0x07E0F81F * blend) >> 4) & 0x07E0F81F; \
2741 blend = 16 - blend; \
2743 expand_pixel_no_dest(brighten, pixel_top); \
2748 /* Fade to black */ \
2751 if(color_combine_mask_a(5)) \
2753 s32 blend = 16 - (io_registers[REG_BLDY] & 0x1F); \
2758 expand_pixel_no_dest(darken, pixel_top); \
2763 fill_line_color16(pixel_top, scanline, _start, _end); \
2768 // Renders an entire scanline from 0 to 240, based on current color mode.
2770 static void render_scanline_tile(u16 *scanline, u32 dispcnt)
2773 u32 layer_order_pos;
2774 u32 bldcnt = io_registers[REG_BLDCNT];
2775 render_scanline_layer_functions_tile();
2777 render_layers_color_effect(render_layers, layer_count,
2778 render_condition_alpha, render_condition_fade, 0, 240);
2781 static void render_scanline_bitmap(u16 *scanline, u32 dispcnt)
2783 render_scanline_layer_functions_bitmap();
2785 u32 layer_order_pos;
2787 fill_line_bg(normal, scanline, 0, 240);
2789 for(layer_order_pos = 0; layer_order_pos < layer_count; layer_order_pos++)
2791 current_layer = layer_order[layer_order_pos];
2792 if(current_layer & 0x04)
2794 render_obj_layer(normal, scanline, 0, 240);
2798 layer_renderers->normal_render(0, 240, scanline);
2803 // Render layers from start to end based on if they're allowed in the
2806 #define render_layers_conditional(tile_alpha, obj_alpha, dest) \
2809 current_layer = layer_order[layer_order_pos]; \
2810 /* If OBJ aren't enabled skip to the first non-OBJ layer */ \
2811 if(!(enable_flags & 0x10)) \
2813 while((current_layer & 0x04) || !((1 << current_layer) & enable_flags)) \
2815 layer_order_pos++; \
2816 current_layer = layer_order[layer_order_pos]; \
2818 /* Oops, ran out of layers, render the background. */ \
2819 if(layer_order_pos == layer_count) \
2821 fill_line_bg(tile_alpha, dest, start, end); \
2826 /* Render the first valid layer */ \
2827 layer_renderers[current_layer].tile_alpha##_render_base(current_layer, \
2828 start, end, dest); \
2830 layer_order_pos++; \
2832 /* Render the rest of the layers if active, skipping OBJ ones. */ \
2833 for(; layer_order_pos < layer_count; layer_order_pos++) \
2835 current_layer = layer_order[layer_order_pos]; \
2836 if(!(current_layer & 0x04) && ((1 << current_layer) & enable_flags)) \
2838 layer_renderers[current_layer]. \
2839 tile_alpha##_render_transparent(current_layer, start, end, dest); \
2845 /* Find the first active layer, skip all of the inactive ones */ \
2846 while(!((current_layer & 0x04) || ((1 << current_layer) & enable_flags))) \
2848 layer_order_pos++; \
2849 current_layer = layer_order[layer_order_pos]; \
2851 /* Oops, ran out of layers, render the background. */ \
2852 if(layer_order_pos == layer_count) \
2854 fill_line_bg(tile_alpha, dest, start, end); \
2859 if(current_layer & 0x04) \
2861 /* If the first one is OBJ render the background then render it. */ \
2862 fill_line_bg(tile_alpha, dest, start, end); \
2863 render_obj_layer(obj_alpha, dest, start, end); \
2867 /* Otherwise render a base layer. */ \
2868 layer_renderers[current_layer]. \
2869 tile_alpha##_render_base(current_layer, start, end, dest); \
2872 layer_order_pos++; \
2874 /* Render the rest of the layers. */ \
2875 for(; layer_order_pos < layer_count; layer_order_pos++) \
2877 current_layer = layer_order[layer_order_pos]; \
2878 if(current_layer & 0x04) \
2880 render_obj_layer(obj_alpha, dest, start, end); \
2884 if(enable_flags & (1 << current_layer)) \
2886 layer_renderers[current_layer]. \
2887 tile_alpha##_render_transparent(current_layer, start, end, dest); \
2898 // Render all of the BG and OBJ in a tiled scanline from start to end ONLY if
2899 // enable_flag allows that layer/OBJ. Also conditionally render color effects.
2901 static void render_scanline_conditional_tile(u32 start, u32 end, u16 *scanline,
2902 u32 enable_flags, u32 dispcnt, u32 bldcnt, const tile_layer_render_struct
2906 u32 layer_order_pos = 0;
2908 render_layers_color_effect(render_layers_conditional,
2909 (layer_count && (enable_flags & 0x1F)),
2910 ((enable_flags & 0x20) && render_condition_alpha),
2911 ((enable_flags & 0x20) && render_condition_fade), start, end);
2915 // Render the BG and OBJ in a bitmap scanline from start to end ONLY if
2916 // enable_flag allows that layer/OBJ. Also conditionally render color effects.
2918 static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline,
2919 u32 enable_flags, u32 dispcnt, u32 bldcnt, const bitmap_layer_render_struct
2923 u32 layer_order_pos;
2925 fill_line_bg(normal, scanline, start, end);
2927 for(layer_order_pos = 0; layer_order_pos < layer_count; layer_order_pos++)
2929 current_layer = layer_order[layer_order_pos];
2930 if(current_layer & 0x04)
2932 if(enable_flags & 0x10)
2934 render_obj_layer(normal, scanline, start, end);
2939 if(enable_flags & 0x04)
2940 layer_renderers->normal_render(start, end, scanline);
2946 #define window_x_coords(window_number) \
2947 window_##window_number##_x1 = \
2948 io_registers[REG_WIN##window_number##H] >> 8; \
2949 window_##window_number##_x2 = \
2950 io_registers[REG_WIN##window_number##H] & 0xFF; \
2951 window_##window_number##_enable = \
2952 (winin >> (window_number * 8)) & 0x3F; \
2954 if(window_##window_number##_x1 > 240) \
2955 window_##window_number##_x1 = 240; \
2957 if(window_##window_number##_x2 > 240) \
2958 window_##window_number##_x2 = 240 \
2960 #define window_coords(window_number) \
2961 u32 window_##window_number##_x1, window_##window_number##_x2; \
2962 u32 window_##window_number##_y1, window_##window_number##_y2; \
2963 u32 window_##window_number##_enable = 0; \
2964 window_##window_number##_y1 = \
2965 io_registers[REG_WIN##window_number##V] >> 8; \
2966 window_##window_number##_y2 = \
2967 io_registers[REG_WIN##window_number##V] & 0xFF; \
2969 if(window_##window_number##_y1 > window_##window_number##_y2) \
2971 if((((vcount <= window_##window_number##_y2) || \
2972 (vcount > window_##window_number##_y1)) || \
2973 (window_##window_number##_y2 > 227)) && \
2974 (window_##window_number##_y1 <= 227)) \
2976 window_x_coords(window_number); \
2980 window_##window_number##_x1 = 240; \
2981 window_##window_number##_x2 = 240; \
2986 if((((vcount >= window_##window_number##_y1) && \
2987 (vcount < window_##window_number##_y2)) || \
2988 (window_##window_number##_y2 > 227)) && \
2989 (window_##window_number##_y1 <= 227)) \
2991 window_x_coords(window_number); \
2995 window_##window_number##_x1 = 240; \
2996 window_##window_number##_x2 = 240; \
3000 #define render_window_segment(type, start, end, window_type) \
3003 render_scanline_conditional_##type(start, end, scanline, \
3004 window_##window_type##_enable, dispcnt, bldcnt, layer_renderers); \
3007 #define render_window_segment_unequal(type, start, end, window_type) \
3008 render_scanline_conditional_##type(start, end, scanline, \
3009 window_##window_type##_enable, dispcnt, bldcnt, layer_renderers) \
3011 #define render_window_segment_clip(type, clip_start, clip_end, start, end, \
3016 if(start < clip_start) \
3018 if(end > clip_start) \
3020 if(end > clip_end) \
3022 render_window_segment_unequal(type, clip_start, clip_end, \
3027 render_window_segment_unequal(type, clip_start, end, window_type); \
3033 if(end > clip_end) \
3035 if(start < clip_end) \
3036 render_window_segment_unequal(type, start, clip_end, window_type); \
3040 render_window_segment_unequal(type, start, end, window_type); \
3045 #define render_window_clip_1(type, start, end) \
3046 if(window_1_x1 != 240) \
3048 if(window_1_x1 > window_1_x2) \
3050 render_window_segment_clip(type, start, end, 0, window_1_x2, 1); \
3051 render_window_segment_clip(type, start, end, window_1_x2, window_1_x1, \
3053 render_window_segment_clip(type, start, end, window_1_x1, 240, 1); \
3057 render_window_segment_clip(type, start, end, 0, window_1_x1, out); \
3058 render_window_segment_clip(type, start, end, window_1_x1, window_1_x2, \
3060 render_window_segment_clip(type, start, end, window_1_x2, 240, out); \
3065 render_window_segment(type, start, end, out); \
3068 #define render_window_clip_obj(type, start, end); \
3069 render_window_segment(type, start, end, out); \
3070 if(dispcnt & 0x40) \
3071 render_scanline_obj_copy_##type##_1D(4, start, end, scanline); \
3073 render_scanline_obj_copy_##type##_2D(4, start, end, scanline) \
3076 #define render_window_segment_clip_obj(type, clip_start, clip_end, start, \
3081 if(start < clip_start) \
3083 if(end > clip_start) \
3085 if(end > clip_end) \
3087 render_window_clip_obj(type, clip_start, clip_end); \
3091 render_window_clip_obj(type, clip_start, end); \
3097 if(end > clip_end) \
3099 if(start < clip_end) \
3101 render_window_clip_obj(type, start, clip_end); \
3106 render_window_clip_obj(type, start, end); \
3112 #define render_window_clip_1_obj(type, start, end) \
3113 if(window_1_x1 != 240) \
3115 if(window_1_x1 > window_1_x2) \
3117 render_window_segment_clip(type, start, end, 0, window_1_x2, 1); \
3118 render_window_segment_clip_obj(type, start, end, window_1_x2, \
3120 render_window_segment_clip(type, start, end, window_1_x1, 240, 1); \
3124 render_window_segment_clip_obj(type, start, end, 0, window_1_x1); \
3125 render_window_segment_clip(type, start, end, window_1_x1, window_1_x2, \
3127 render_window_segment_clip_obj(type, start, end, window_1_x2, 240); \
3132 render_window_clip_obj(type, start, end); \
3137 #define render_window_single(type, window_number) \
3138 u32 winin = io_registers[REG_WININ]; \
3139 window_coords(window_number); \
3140 if(window_##window_number##_x1 > window_##window_number##_x2) \
3142 render_window_segment(type, 0, window_##window_number##_x2, \
3144 render_window_segment(type, window_##window_number##_x2, \
3145 window_##window_number##_x1, out); \
3146 render_window_segment(type, window_##window_number##_x1, 240, \
3151 render_window_segment(type, 0, window_##window_number##_x1, out); \
3152 render_window_segment(type, window_##window_number##_x1, \
3153 window_##window_number##_x2, window_number); \
3154 render_window_segment(type, window_##window_number##_x2, 240, out); \
3157 #define render_window_multi(type, front, back) \
3158 if(window_##front##_x1 > window_##front##_x2) \
3160 render_window_segment(type, 0, window_##front##_x2, front); \
3161 render_window_clip_##back(type, window_##front##_x2, \
3162 window_##front##_x1); \
3163 render_window_segment(type, window_##front##_x1, 240, front); \
3167 render_window_clip_##back(type, 0, window_##front##_x1); \
3168 render_window_segment(type, window_##front##_x1, window_##front##_x2, \
3170 render_window_clip_##back(type, window_##front##_x2, 240); \
3173 #define render_scanline_window_builder(type) \
3174 static void render_scanline_window_##type(u16 *scanline, u32 dispcnt) \
3176 u32 vcount = io_registers[REG_VCOUNT]; \
3177 u32 winout = io_registers[REG_WINOUT]; \
3178 u32 bldcnt = io_registers[REG_BLDCNT]; \
3179 u32 window_out_enable = winout & 0x3F; \
3181 render_scanline_layer_functions_##type(); \
3183 switch(dispcnt >> 13) \
3185 /* Just window 0 */ \
3188 render_window_single(type, 0); \
3192 /* Just window 1 */ \
3195 render_window_single(type, 1); \
3199 /* Windows 1 and 2 */ \
3202 u32 winin = io_registers[REG_WININ]; \
3205 render_window_multi(type, 0, 1); \
3209 /* Just OBJ windows */ \
3212 render_window_clip_obj(type, 0, 240); \
3216 /* Window 0 and OBJ window */ \
3219 u32 winin = io_registers[REG_WININ]; \
3221 render_window_multi(type, 0, obj); \
3225 /* Window 1 and OBJ window */ \
3228 u32 winin = io_registers[REG_WININ]; \
3230 render_window_multi(type, 1, obj); \
3234 /* Window 0, 1, and OBJ window */ \
3237 u32 winin = io_registers[REG_WININ]; \
3240 render_window_multi(type, 0, 1_obj); \
3246 render_scanline_window_builder(tile);
3247 render_scanline_window_builder(bitmap);
3249 static const u32 active_layers[6] = { 0x1F, 0x17, 0x1C, 0x14, 0x14, 0x14 };
3251 u32 small_resolution_width = 240;
3252 u32 small_resolution_height = 160;
3253 u32 resolution_width, resolution_height;
3255 void update_scanline()
3257 u32 pitch = get_screen_pitch();
3258 u32 dispcnt = io_registers[REG_DISPCNT];
3259 u32 vcount = io_registers[REG_VCOUNT];
3260 u16 *screen_offset = get_screen_pixels() + (vcount * pitch);
3261 u32 video_mode = dispcnt & 0x07;
3263 // If OAM has been modified since the last scanline has been updated then
3264 // reorder and reprofile the OBJ lists.
3267 order_obj(video_mode);
3271 order_layers((dispcnt >> 8) & active_layers[video_mode]);
3277 if (screen_scale == unscaled_rot || screen_scale == scaled_aspect_rot)
3279 if (rot_line_count == rot_lines_total)
3282 if (vcount - rot_lines_total < FONT_HEIGHT && rot_msg_buff[0])
3284 print_string_ext(rot_msg_buff, 0xFFFF, 0x0000, 0, 0,
3285 rot_buffer, 240, 0, vcount - rot_lines_total, rot_lines_total);
3286 if (vcount >= FONT_HEIGHT)
3287 rot_msg_buff[0] = 0;
3289 if (screen_scale == unscaled_rot)
3290 do_rotated_blit(gpsp_gp2x_screen, rot_buffer, vcount);
3292 upscale_aspect_row(gpsp_gp2x_screen, rot_buffer, vcount/3);
3294 screen_offset = &rot_buffer[rot_line_count++ * 240];
3298 // If the screen is in in forced blank draw pure white.
3301 fill_line_color16(0xFFFF, screen_offset, 0, 240);
3309 render_scanline_window_tile(screen_offset, dispcnt);
3313 render_scanline_tile(screen_offset, dispcnt);
3319 render_scanline_window_bitmap(screen_offset, dispcnt);
3321 render_scanline_bitmap(screen_offset, dispcnt);
3325 affine_reference_x[0] += (s16)io_registers[REG_BG2PB];
3326 affine_reference_y[0] += (s16)io_registers[REG_BG2PD];
3327 affine_reference_x[1] += (s16)io_registers[REG_BG3PB];
3328 affine_reference_y[1] += (s16)io_registers[REG_BG3PD];
3333 u32 screen_flip = 0;
3337 if(video_direct == 0)
3339 u32 *old_ge_cmd_ptr = ge_cmd_ptr;
3340 sceKernelDcacheWritebackAll();
3342 // Render the current screen
3343 ge_cmd_ptr = ge_cmd + 2;
3344 GE_CMD(TBP0, ((u32)screen_pixels & 0x00FFFFFF));
3345 GE_CMD(TBW0, (((u32)screen_pixels & 0xFF000000) >> 8) |
3347 ge_cmd_ptr = old_ge_cmd_ptr;
3349 sceGeListEnQueue(ge_cmd, ge_cmd_ptr, gecbid, NULL);
3351 // Flip to the next screen
3355 screen_pixels = screen_texture + (240 * 160 * 2);
3357 screen_pixels = screen_texture;
3361 #elif defined(POLLUX_BUILD)
3365 if((resolution_width == small_resolution_width) &&
3366 (resolution_height == small_resolution_height))
3368 switch(screen_scale)
3373 upscale_aspect(gpsp_gp2x_screen, screen_pixels);
3376 do_rotated_blit(gpsp_gp2x_screen, rot_buffer, 160);
3379 case scaled_aspect_rot:
3384 warm_cache_op_all(WOP_D_CLEAN);
3387 pollux_video_flip();
3388 screen_pixels = (u16 *)gpsp_gp2x_screen + screen_offset;
3391 #elif defined(PND_BUILD) || defined(RPI_BUILD)
3395 screen_pixels = fb_flip_screen();
3400 #define integer_scale_copy_2() \
3401 current_scanline_ptr[x2] = current_pixel; \
3402 current_scanline_ptr[x2 - 1] = current_pixel; \
3405 #define integer_scale_copy_3() \
3406 current_scanline_ptr[x2] = current_pixel; \
3407 current_scanline_ptr[x2 - 1] = current_pixel; \
3408 current_scanline_ptr[x2 - 2] = current_pixel; \
3411 #define integer_scale_copy_4() \
3412 current_scanline_ptr[x2] = current_pixel; \
3413 current_scanline_ptr[x2 - 1] = current_pixel; \
3414 current_scanline_ptr[x2 - 2] = current_pixel; \
3415 current_scanline_ptr[x2 - 3] = current_pixel; \
3418 #define integer_scale_horizontal(scale_factor) \
3419 for(y = 0; y < 160; y++) \
3421 for(x = 239, x2 = (240 * video_scale) - 1; x >= 0; x--) \
3423 current_pixel = current_scanline_ptr[x]; \
3424 integer_scale_copy_##scale_factor(); \
3425 current_scanline_ptr[x2] = current_scanline_ptr[x]; \
3426 current_scanline_ptr[x2 - 1] = current_scanline_ptr[x]; \
3427 current_scanline_ptr[x2 - 2] = current_scanline_ptr[x]; \
3429 current_scanline_ptr += pitch; \
3434 if((video_scale != 1) && (current_scale != unscaled))
3438 u16 *screen_ptr = get_screen_pixels();
3439 u16 *current_scanline_ptr = screen_ptr;
3440 u32 pitch = get_screen_pitch();
3447 integer_scale_horizontal(2);
3451 integer_scale_horizontal(3);
3456 integer_scale_horizontal(4);
3461 for(y = 159, y2 = (160 * video_scale) - 1; y >= 0; y--)
3463 for(i = 0; i < video_scale; i++)
3465 memcpy(screen_ptr + (y2 * pitch),
3466 screen_ptr + (y * pitch), 480 * video_scale);
3473 if((resolution_width == small_resolution_width) &&
3474 (resolution_height == small_resolution_height))
3476 switch (screen_scale)
3480 SDL_Rect srect = {0, 0, 240, 160};
3481 SDL_Rect drect = {40, 40, 240, 160};
3482 warm_cache_op_all(WOP_D_CLEAN);
3483 SDL_BlitSurface(screen, &srect, hw_screen, &drect);
3488 SDL_Rect drect = {0, 10, 0, 0};
3489 warm_cache_op_all(WOP_D_CLEAN);
3490 SDL_BlitSurface(screen, NULL, hw_screen, &drect);
3493 case scaled_aspect_sw:
3495 upscale_aspect(hw_screen->pixels, get_screen_pixels());
3502 warm_cache_op_all(WOP_D_CLEAN);
3503 SDL_BlitSurface(screen, NULL, hw_screen, NULL);
3512 u32 frame_to_render;
3514 void update_screen()
3516 if(!skip_next_frame)
3524 sceDisplaySetMode(0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
3526 sceDisplayWaitVblankStart();
3527 sceDisplaySetFrameBuf((void*)psp_gu_vram_base, PSP_LINE_SIZE,
3528 PSP_DISPLAY_PIXEL_FORMAT_565, PSP_DISPLAY_SETBUF_NEXTFRAME);
3532 sceGuStart(GU_DIRECT, display_list);
3533 sceGuDrawBuffer(GU_PSM_5650, (void*)0, PSP_LINE_SIZE);
3534 sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
3535 (void*)0, PSP_LINE_SIZE);
3536 sceGuClear(GU_COLOR_BUFFER_BIT);
3538 sceGuOffset(2048 - (PSP_SCREEN_WIDTH / 2), 2048 - (PSP_SCREEN_HEIGHT / 2));
3539 sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
3541 sceGuScissor(0, 0, PSP_SCREEN_WIDTH + 1, PSP_SCREEN_HEIGHT + 1);
3542 sceGuEnable(GU_SCISSOR_TEST);
3543 sceGuTexMode(GU_PSM_5650, 0, 0, GU_FALSE);
3544 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
3545 sceGuTexFilter(GU_LINEAR, GU_LINEAR);
3546 sceGuEnable(GU_TEXTURE_2D);
3548 sceGuFrontFace(GU_CW);
3549 sceGuDisable(GU_BLEND);
3554 sceDisplayWaitVblankStart();
3555 sceGuDisplay(GU_TRUE);
3557 PspGeCallbackData gecb;
3558 gecb.signal_func = NULL;
3559 gecb.signal_arg = NULL;
3560 gecb.finish_func = Ge_Finish_Callback;
3561 gecb.finish_arg = NULL;
3562 gecbid = sceGeSetCallback(&gecb);
3564 screen_vertex[0] = 0 + 0.5;
3565 screen_vertex[1] = 0 + 0.5;
3566 screen_vertex[2] = 0 + 0.5;
3567 screen_vertex[3] = 0 + 0.5;
3568 screen_vertex[4] = 0;
3569 screen_vertex[5] = GBA_SCREEN_WIDTH - 0.5;
3570 screen_vertex[6] = GBA_SCREEN_HEIGHT - 0.5;
3571 screen_vertex[7] = PSP_SCREEN_WIDTH - 0.5;
3572 screen_vertex[8] = PSP_SCREEN_HEIGHT - 0.5;
3573 screen_vertex[9] = 0;
3575 // Set framebuffer to PSP VRAM
3576 GE_CMD(FBP, ((u32)psp_gu_vram_base & 0x00FFFFFF));
3577 GE_CMD(FBW, (((u32)psp_gu_vram_base & 0xFF000000) >> 8) | PSP_LINE_SIZE);
3578 // Set texture 0 to the screen texture
3579 GE_CMD(TBP0, ((u32)screen_texture & 0x00FFFFFF));
3580 GE_CMD(TBW0, (((u32)screen_texture & 0xFF000000) >> 8) | GBA_SCREEN_WIDTH);
3581 // Set the texture size to 256 by 256 (2^8 by 2^8)
3582 GE_CMD(TSIZE0, (8 << 8) | 8);
3583 // Flush the texture cache
3585 // Use 2D coordinates, no indeces, no weights, 32bit float positions,
3586 // 32bit float texture coordinates
3587 GE_CMD(VTYPE, (1 << 23) | (0 << 11) | (0 << 9) |
3588 (3 << 7) | (0 << 5) | (0 << 2) | 3);
3589 // Set the base of the index list pointer to 0
3591 // Set the rest of index list pointer to 0 (not being used)
3593 // Set the base of the screen vertex list pointer
3594 GE_CMD(BASE, ((u32)screen_vertex & 0xFF000000) >> 8);
3595 // Set the rest of the screen vertex list pointer
3596 GE_CMD(VADDR, ((u32)screen_vertex & 0x00FFFFFF));
3597 // Primitive kick: render sprite (primitive 6), 2 vertices
3598 GE_CMD(PRIM, (6 << 16) | 2);
3599 // Done with commands
3601 // Raise signal interrupt
3607 #elif defined(WIZ_BUILD) || defined(PND_BUILD) || defined (RPI_BUILD)
3617 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE);
3620 SDL_GP2X_AllowGfxMemory(NULL, 0);
3622 hw_screen = SDL_SetVideoMode(320 * video_scale, 240 * video_scale,
3625 screen = SDL_CreateRGBSurface(SDL_HWSURFACE, 240 * video_scale,
3626 160 * video_scale, 16, 0xFFFF, 0xFFFF, 0xFFFF, 0);
3628 warm_change_cb_upper(WCB_C_BIT|WCB_B_BIT, 1);
3630 screen = SDL_SetVideoMode(240 * video_scale, 160 * video_scale, 16, 0);
3637 video_scale_type screen_scale = scaled_aspect;
3638 video_scale_type current_scale = scaled_aspect;
3639 video_filter_type screen_filter = filter_bilinear;
3640 video_filter_type2 screen_filter2 = filter2_none;
3645 void video_resolution_large()
3647 if(video_direct != 1)
3650 screen_pixels = psp_gu_vram_base;
3652 sceGuStart(GU_DIRECT, display_list);
3653 sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
3654 (void*)0, PSP_LINE_SIZE);
3659 void set_gba_resolution(video_scale_type scale)
3661 u32 filter_linear = 0;
3662 screen_scale = scale;
3666 screen_vertex[2] = 120 + 0.5;
3667 screen_vertex[3] = 56 + 0.5;
3668 screen_vertex[7] = GBA_SCREEN_WIDTH + 120 - 0.5;
3669 screen_vertex[8] = GBA_SCREEN_HEIGHT + 56 - 0.5;
3673 screen_vertex[2] = 36 + 0.5;
3674 screen_vertex[3] = 0 + 0.5;
3675 screen_vertex[7] = 408 + 36 - 0.5;
3676 screen_vertex[8] = PSP_SCREEN_HEIGHT - 0.5;
3680 screen_vertex[2] = 0;
3681 screen_vertex[3] = 0;
3682 screen_vertex[7] = PSP_SCREEN_WIDTH;
3683 screen_vertex[8] = PSP_SCREEN_HEIGHT;
3687 sceGuStart(GU_DIRECT, display_list);
3688 if(screen_filter == filter_bilinear)
3689 sceGuTexFilter(GU_LINEAR, GU_LINEAR);
3691 sceGuTexFilter(GU_NEAREST, GU_NEAREST);
3696 clear_screen(0x0000);
3699 void video_resolution_small()
3701 if(video_direct != 0)
3703 set_gba_resolution(screen_scale);
3705 screen_pixels = screen_texture;
3708 sceGuStart(GU_DIRECT, display_list);
3709 sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
3710 (void*)0, PSP_LINE_SIZE);
3715 void clear_screen(u16 color)
3718 u16 *src_ptr = get_screen_pixels();
3722 for(i = 0; i < (512 * 272); i++, src_ptr++)
3727 // I don't know why this doesn't work.
3728 /* color = (((color & 0x1F) * 255 / 31) << 0) |
3729 ((((color >> 5) & 0x3F) * 255 / 63) << 8) |
3730 ((((color >> 11) & 0x1F) * 255 / 31) << 16) | (0xFF << 24);
3732 sceGuStart(GU_DIRECT, display_list);
3733 sceGuDrawBuffer(GU_PSM_5650, (void*)0, PSP_LINE_SIZE);
3734 //sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT,
3735 // (void*)0, PSP_LINE_SIZE);
3736 sceGuClearColor(color);
3737 sceGuClear(GU_COLOR_BUFFER_BIT);
3742 #elif defined(POLLUX_BUILD)
3744 void video_resolution_large()
3747 resolution_width = 320;
3748 resolution_height = 240;
3753 wiz_lcd_set_portrait(0);
3756 void video_resolution_small()
3760 switch (screen_scale)
3763 screen_offset = 320*40 + 40;
3764 wiz_lcd_set_portrait(0);
3767 screen_offset = 320*(80 - 14) + 80;
3768 wiz_lcd_set_portrait(0);
3771 wiz_lcd_set_portrait(1);
3772 rot_lines_total = 4;
3775 case scaled_aspect_rot:
3776 wiz_lcd_set_portrait(1);
3777 rot_lines_total = 3;
3785 resolution_width = 240;
3786 resolution_height = 160;
3789 void set_gba_resolution(video_scale_type scale)
3791 screen_scale = scale;
3794 void clear_screen(u16 color)
3796 u32 col = ((u32)color << 16) | color;
3797 u32 *p = gpsp_gp2x_screen;
3803 #elif defined(PND_BUILD) || defined(RPI_BUILD)
3805 void video_resolution_large()
3807 #if defined (RPI_BUILD)
3808 resolution_width = 480;
3810 resolution_width = 400;
3812 resolution_height = 272;
3814 fb_set_mode(resolution_width, resolution_height, 1, 15, screen_filter, screen_filter2);
3819 void video_resolution_small()
3821 resolution_width = 240;
3822 resolution_height = 160;
3824 fb_set_mode(resolution_width, resolution_height, 3, screen_scale, screen_filter, screen_filter2);
3829 void set_gba_resolution(video_scale_type scale)
3831 screen_scale = scale;
3834 void clear_screen(u16 color)
3836 u32 col = ((u32)color << 16) | color;
3837 u32 *p = (u32 *)get_screen_pixels();
3838 int c = resolution_width * resolution_height / 2;
3845 void video_resolution_large()
3847 current_scale = unscaled;
3850 SDL_FreeSurface(screen);
3851 SDL_GP2X_AllowGfxMemory(NULL, 0);
3852 hw_screen = SDL_SetVideoMode(320, 240, 16, SDL_HWSURFACE);
3853 screen = SDL_CreateRGBSurface(SDL_HWSURFACE, 320, 240, 16, 0xFFFF,
3855 resolution_width = 320;
3856 resolution_height = 240;
3859 warm_change_cb_upper(WCB_C_BIT|WCB_B_BIT, 1);
3861 screen = SDL_SetVideoMode(480, 272, 16, 0);
3862 resolution_width = 480;
3863 resolution_height = 272;
3867 void video_resolution_small()
3869 current_scale = screen_scale;
3873 SDL_FreeSurface(screen);
3874 SDL_GP2X_AllowGfxMemory(NULL, 0);
3877 if (screen_scale == scaled_aspect || screen_scale == fullscreen)
3879 w = small_resolution_width * video_scale;
3880 h = small_resolution_height * video_scale;
3882 if (screen_scale == scaled_aspect) h += 20;
3883 hw_screen = SDL_SetVideoMode(w, h, 16, SDL_HWSURFACE);
3885 w = small_resolution_width * video_scale;
3886 if (screen_scale == scaled_aspect_sw)
3888 screen = SDL_CreateRGBSurface(SDL_HWSURFACE,
3889 w, small_resolution_height * video_scale,
3890 16, 0xFFFF, 0xFFFF, 0xFFFF, 0);
3894 warm_change_cb_upper(WCB_C_BIT|WCB_B_BIT, 1);
3896 screen = SDL_SetVideoMode(small_resolution_width * video_scale,
3897 small_resolution_height * video_scale, 16, 0);
3899 resolution_width = small_resolution_width;
3900 resolution_height = small_resolution_height;
3903 void set_gba_resolution(video_scale_type scale)
3905 if(screen_scale != scale)
3907 screen_scale = scale;
3908 small_resolution_width = 240 * video_scale;
3909 small_resolution_height = 160 * video_scale;
3913 void clear_screen(u16 color)
3915 u16 *dest_ptr = get_screen_pixels();
3916 u32 line_skip = get_screen_pitch() - screen->w;
3919 for(y = 0; y < screen->h; y++)
3921 for(x = 0; x < screen->w; x++, dest_ptr++)
3925 dest_ptr += line_skip;
3933 u16 *copy = malloc(240 * 160 * 2);
3934 memcpy(copy, get_screen_pixels(), 240 * 160 * 2);
3938 void blit_to_screen(u16 *src, u32 w, u32 h, u32 dest_x, u32 dest_y)
3940 u32 pitch = get_screen_pitch();
3941 u16 *dest_ptr = get_screen_pixels() + dest_x + (dest_y * pitch);
3943 s32 w1 = dest_x + w > pitch ? pitch - dest_x : w;
3947 for(y = 0; y < h; y++)
3949 for(x = 0; x < w1; x++)
3951 dest_ptr[x] = src_ptr[x];
3958 void print_string_ext(const char *str, u16 fg_color, u16 bg_color,
3959 u32 x, u32 y, void *_dest_ptr, u32 pitch, u32 pad, u32 h_offset, u32 height)
3961 u16 *dest_ptr = (u16 *)_dest_ptr + (y * pitch) + x;
3962 u8 current_char = str[0];
3965 u32 i = 0, i2, i3, h;
3969 if(y + height > resolution_height)
3974 if(current_char == '\n')
3978 dest_ptr = get_screen_pixels() + (y * pitch) + x;
3982 glyph_offset = _font_offset[current_char];
3983 current_x += FONT_WIDTH;
3984 glyph_offset += h_offset;
3985 for(i2 = h_offset, h = 0; i2 < FONT_HEIGHT && h < height; i2++, h++, glyph_offset++)
3987 current_row = _font_bits[glyph_offset];
3988 for(i3 = 0; i3 < FONT_WIDTH; i3++)
3990 if((current_row >> (15 - i3)) & 0x01)
3991 *dest_ptr = fg_color;
3993 *dest_ptr = bg_color;
3996 dest_ptr += (pitch - FONT_WIDTH);
3998 dest_ptr = dest_ptr - (pitch * h) + FONT_WIDTH;
4003 current_char = str[str_index];
4005 if((i < pad) && (current_char == 0))
4014 if(current_x + FONT_WIDTH > resolution_width /* EDIT */)
4016 while (current_char && current_char != '\n')
4018 current_char = str[str_index++];
4024 void print_string(const char *str, u16 fg_color, u16 bg_color,
4028 if ((screen_scale == unscaled_rot || screen_scale == scaled_aspect_rot) &&
4029 (resolution_width == small_resolution_width) &&
4030 (resolution_height == small_resolution_height))
4032 snprintf(rot_msg_buff, sizeof(rot_msg_buff), "%s", str);
4036 print_string_ext(str, fg_color, bg_color, x, y, get_screen_pixels(),
4037 get_screen_pitch(), 0, 0, FONT_HEIGHT);
4040 void print_string_pad(const char *str, u16 fg_color, u16 bg_color,
4041 u32 x, u32 y, u32 pad)
4043 print_string_ext(str, fg_color, bg_color, x, y, get_screen_pixels(),
4044 get_screen_pitch(), pad, 0, FONT_HEIGHT);
4047 u32 debug_cursor_x = 0;
4048 u32 debug_cursor_y = 0;
4052 void debug_screen_clear()
4056 void debug_screen_start()
4060 void debug_screen_end()
4064 void debug_screen_update()
4068 void debug_screen_printf(const char *format, ...)
4072 va_start(ap, format);
4073 vprintf(format, ap);
4077 void debug_screen_newline(u32 count)
4085 void debug_screen_clear()
4089 clear_screen(0x0000);
4092 void debug_screen_start()
4094 video_resolution_large();
4095 debug_screen_clear();
4098 void debug_screen_end()
4100 video_resolution_small();
4103 void debug_screen_update()
4108 void debug_screen_printf(const char *format, ...)
4110 char str_buffer[512];
4111 u32 str_buffer_length;
4114 va_start(ap, format);
4115 str_buffer_length = vsnprintf(str_buffer, 512, format, ap);
4118 printf("printing debug string %s at %d %d\n", str_buffer,
4119 debug_cursor_x, debug_cursor_y);
4121 print_string(str_buffer, 0xFFFF, 0x0000, debug_cursor_x, debug_cursor_y);
4122 debug_cursor_x += FONT_WIDTH * str_buffer_length;
4125 void debug_screen_newline(u32 count)
4128 debug_cursor_y += FONT_HEIGHT * count;
4133 void debug_screen_printl(const char *format, ...)
4137 va_start(ap, format);
4138 debug_screen_printf(format, ap);
4139 debug_screen_newline(1);
4140 // debug_screen_printf("\n");
4145 #define video_savestate_builder(type) \
4146 void video_##type##_savestate(file_tag_type savestate_file) \
4148 file_##type##_array(savestate_file, affine_reference_x); \
4149 file_##type##_array(savestate_file, affine_reference_y); \
4152 video_savestate_builder(read);
4153 video_savestate_builder(write_mem);