gpsp-kai 

File Info

Rev. 316
Size 207,148 bytes
Time 2007-10-18 19:30:57
Author takka
Log Message

(empty log message)

Content

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