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