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: