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