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