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