21 #define WND (scan.wnd)
22 #define BUF (scan.buf)
23 #define PRI (scan.pri)
25 #define PAL1 (scan.pal1)
26 #define PAL2 (scan.pal2)
27 #define PAL4 (scan.pal4)
29 #define VS (scan.vs) /* vissprites */
32 #define L (scan.l) /* line */
33 #define X (scan.x) /* screen position */
35 #define S (scan.s) /* tilemap position */
37 #define U (scan.u) /* position within tile */
44 byte patpix
[4096][8][8];
50 static int density
= 0;
54 static int sprsort
= 1;
57 #define DEF_PAL { 0x98d0e0, 0x68a0b0, 0x60707C, 0x2C3C3C }
59 static int dmg_pal
[4][4] = { DEF_PAL
, DEF_PAL
, DEF_PAL
, DEF_PAL
};
61 static int usefilter
, filterdmg
;
62 static int filter
[3][4] = {
68 rcvar_t lcd_exports
[] =
70 RCV_INT("scale", &scale
, "scaling factor"),
71 RCV_INT("density", &density
, "density!=scale: blank scanlines"),
72 RCV_BOOL("rgb332", &rgb332
, "hi-color game hack in 8bit mode"),
73 RCV_VECTOR("dmg_bgp", dmg_pal
[0], 4, "colors for bg palette"),
74 RCV_VECTOR("dmg_wndp", dmg_pal
[1], 4, "colors for window palette"),
75 RCV_VECTOR("dmg_obp0", dmg_pal
[2], 4, "colors for sprite pal 1"),
76 RCV_VECTOR("dmg_obp1", dmg_pal
[3], 4, "colors for sprite pal 2"),
77 RCV_BOOL("sprsort", &sprsort
, "speedhack: disable sprite sorting"),
78 RCV_BOOL("sprdebug", &sprdebug
, "debug sprite visibility"),
79 RCV_BOOL("colorfilter", &usefilter
, "washed out look like a real CGB"),
80 RCV_BOOL("filterdmg", &filterdmg
, "like colorfilter but for DMG"),
81 RCV_VECTOR("red", filter
[0], 4, "filter values for red"),
82 RCV_VECTOR("green", filter
[1], 4, "filter values for green"),
83 RCV_VECTOR("blue", filter
[2], 4, "filter values for blue"),
89 #if defined(ALLOW_UNALIGNED_IO) && defined(__GNUC__)
91 static __inline
void memcpy8(void *__restrict dest
, const void *__restrict src
)
93 typedef uint64_t u64a
__attribute__((__may_alias__
));
94 u64a
*d
= dest
; u64a
const* s
= src
;
97 #define MEMCPY8(d, s) memcpy8(d, s)
99 #define MEMCPY8(d, s) memcpy((d), (s), 8)
105 #ifndef ASM_UPDATEPATPIX
110 byte
*vram
= lcd
.vbank
[0];
112 if (!anydirty
) return;
113 for (i
= 0; i
< 1024; i
++)
115 if (i
== 384) i
= 512;
117 if (!patdirty
[i
]) continue;
119 for (j
= 0; j
< 8; j
++)
121 a
= ((i
<<4) | (j
<<1));
122 for (k
= 0; k
< 8; k
++)
124 c
= vram
[a
] & (1<<k
) ? 1 : 0;
125 c
|= vram
[a
+1] & (1<<k
) ? 2 : 0;
126 patpix
[i
+1024][j
][k
] = c
;
128 for (k
= 0; k
< 8; k
++)
130 patpix
[i
+1024][j
][7-k
];
132 for (j
= 0; j
< 8; j
++)
134 for (k
= 0; k
< 8; k
++)
136 patpix
[i
+2048][j
][k
] =
138 patpix
[i
+3072][j
][k
] =
139 patpix
[i
+1024][7-j
][k
];
145 #endif /* ASM_UPDATEPATPIX */
153 byte
*tilemap
, *attrmap
;
156 static int wraptable
[64] =
158 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
159 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,-32
162 base
= ((R_LCDC
& LCDC_BIT_BG_MAP
)?0x1C00:0x1800) + (T
<<5) + S
;
163 tilemap
= lcd
.vbank
[0] + base
;
164 attrmap
= lcd
.vbank
[1] + base
;
166 wrap
= wraptable
+ S
;
167 cnt
= ((WX
+ 7) >> 3) + 1;
171 if (R_LCDC
& LCDC_BIT_TILE_SEL
)
172 for (i
= cnt
; i
> 0; i
--)
174 *(tilebuf
++) = *tilemap
175 | (((int)*attrmap
& 0x08) << 6)
176 | (((int)*attrmap
& 0x60) << 5);
177 *(tilebuf
++) = (((int)*attrmap
& 0x07) << 2);
178 attrmap
+= *wrap
+ 1;
179 tilemap
+= *(wrap
++) + 1;
182 for (i
= cnt
; i
> 0; i
--)
184 *(tilebuf
++) = (256 + ((n8
)*tilemap
))
185 | (((int)*attrmap
& 0x08) << 6)
186 | (((int)*attrmap
& 0x60) << 5);
187 *(tilebuf
++) = (((int)*attrmap
& 0x07) << 2);
188 attrmap
+= *wrap
+ 1;
189 tilemap
+= *(wrap
++) + 1;
194 if (R_LCDC
& LCDC_BIT_TILE_SEL
)
195 for (i
= cnt
; i
> 0; i
--)
197 *(tilebuf
++) = *(tilemap
++);
198 tilemap
+= *(wrap
++);
201 for (i
= cnt
; i
> 0; i
--)
203 *(tilebuf
++) = (256 + ((n8
)*(tilemap
++)));
204 tilemap
+= *(wrap
++);
208 if (WX
>= 160) return;
210 base
= ((R_LCDC
& LCDC_BIT_WIN_MAP
)?0x1C00:0x1800) + (WT
<<5);
211 tilemap
= lcd
.vbank
[0] + base
;
212 attrmap
= lcd
.vbank
[1] + base
;
214 cnt
= ((160 - WX
) >> 3) + 1;
218 if (R_LCDC
& LCDC_BIT_TILE_SEL
)
219 for (i
= cnt
; i
> 0; i
--)
221 *(tilebuf
++) = *(tilemap
++)
222 | (((int)*attrmap
& 0x08) << 6)
223 | (((int)*attrmap
& 0x60) << 5);
224 *(tilebuf
++) = (((int)*(attrmap
++)&7) << 2);
227 for (i
= cnt
; i
> 0; i
--)
229 *(tilebuf
++) = (256 + ((n8
)*(tilemap
++)))
230 | (((int)*attrmap
& 0x08) << 6)
231 | (((int)*attrmap
& 0x60) << 5);
232 *(tilebuf
++) = (((int)*(attrmap
++)&7) << 2);
237 if (R_LCDC
& LCDC_BIT_TILE_SEL
)
238 for (i
= cnt
; i
> 0; i
--)
239 *(tilebuf
++) = *(tilemap
++);
241 for (i
= cnt
; i
> 0; i
--)
242 *(tilebuf
++) = (256 + ((n8
)*(tilemap
++)));
258 src
= patpix
[*(tile
++)][V
] + U
;
259 memcpy(dest
, src
, 8-U
);
262 if (cnt
<= 0) return;
265 src
= patpix
[*(tile
++)][V
];
270 src
= patpix
[*tile
][V
];
272 *(dest
++) = *(src
++);
281 if (WX
>= 160) return;
288 src
= patpix
[*(tile
++)][WV
];
293 src
= patpix
[*tile
][WV
];
295 *(dest
++) = *(src
++);
298 static void blendcpy(byte
*dest
, byte
*src
, byte b
, int cnt
)
300 while (cnt
--) *(dest
++) = *(src
++) | b
;
303 static int priused(void *attr
)
306 return (int)((a
[0]|a
[1]|a
[2]|a
[3]|a
[4]|a
[5]|a
[6]|a
[7])&0x80808080);
318 src
= lcd
.vbank
[1] + ((R_LCDC
& LCDC_BIT_BG_MAP
)?0x1C00:0x1800) + (T
<<5);
322 memset(dest
, 0, cnt
);
326 memset(dest
, src
[i
++&31]&128, 8-U
);
329 if (cnt
<= 0) return;
332 memset(dest
, src
[i
++&31]&128, 8);
336 memset(dest
, src
[i
&31]&128, cnt
);
344 if (WX
>= 160) return;
348 src
= lcd
.vbank
[1] + ((R_LCDC
& LCDC_BIT_WIN_MAP
)?0x1C00:0x1800) + (WT
<<5);
352 memset(dest
, 0, cnt
);
358 memset(dest
, src
[i
++]&128, 8);
362 memset(dest
, src
[i
]&128, cnt
);
365 #ifndef ASM_BG_SCAN_COLOR
377 src
= patpix
[*(tile
++)][V
] + U
;
378 blendcpy(dest
, src
, *(tile
++), 8-U
);
381 if (cnt
<= 0) return;
384 src
= patpix
[*(tile
++)][V
];
385 blendcpy(dest
, src
, *(tile
++), 8);
389 src
= patpix
[*(tile
++)][V
];
390 blendcpy(dest
, src
, *(tile
++), cnt
);
394 void wnd_scan_color()
400 if (WX
>= 160) return;
407 src
= patpix
[*(tile
++)][WV
];
408 blendcpy(dest
, src
, *(tile
++), 8);
412 src
= patpix
[*(tile
++)][WV
];
413 blendcpy(dest
, src
, *(tile
++), cnt
);
416 static void recolor(byte
*buf
, byte fill
, int cnt
)
418 while (cnt
--) *(buf
++) |= fill
;
427 if (!(R_LCDC
& LCDC_BIT_OBJ_EN
)) return;
431 for (i
= 40; i
; i
--, o
++)
433 if (L
>= o
->y
|| L
+ 16 < o
->y
)
435 if (L
+ 8 >= o
->y
&& !(R_LCDC
& LCDC_BIT_OBJ_SIZE
))
437 if (++NS
== 10) break;
445 struct vissprite ts
[10];
450 if (!(R_LCDC
& LCDC_BIT_OBJ_EN
)) return;
454 for (i
= 40; i
; i
--, o
++)
456 if (L
>= o
->y
|| L
+ 16 < o
->y
)
458 if (L
+ 8 >= o
->y
&& !(R_LCDC
& LCDC_BIT_OBJ_SIZE
))
460 VS
[NS
].x
= (int)o
->x
- 8;
461 v
= L
- (int)o
->y
+ 16;
464 pat
= o
->pat
| (((int)o
->flags
& 0x60) << 5)
465 | (((int)o
->flags
& 0x08) << 6);
466 VS
[NS
].pal
= 32 + ((o
->flags
& 0x07) << 2);
470 pat
= o
->pat
| (((int)o
->flags
& 0x60) << 5);
471 VS
[NS
].pal
= 32 + ((o
->flags
& 0x10) >> 2);
473 VS
[NS
].pri
= (o
->flags
& 0x80) >> 7;
474 if ((R_LCDC
& LCDC_BIT_OBJ_SIZE
))
482 if (o
->flags
& 0x40) pat
^= 1;
484 VS
[NS
].buf
= patpix
[pat
][v
];
485 if (++NS
== 10) break;
487 if (!sprsort
|| hw
.cgb
) return;
488 /* not quite optimal but it finally works! */
489 for (i
= 0; i
< NS
; i
++)
493 for (j
= 1; j
< NS
; j
++)
504 memcpy(VS
, ts
, sizeof ts
);
510 byte pal
, b
, ns
= NS
;
511 byte
*src
, *dest
, *bg
, *pri
;
512 struct vissprite
*vs
;
513 static byte bgdup
[256];
517 memcpy(bgdup
, BUF
, 256);
520 for (; ns
; ns
--, vs
--)
523 if (x
>= 160) continue;
524 if (x
<= -8) continue;
535 if (x
> 152) i
= 160 - x
;
541 bg
= bgdup
+ (dest
- BUF
);
545 if (b
&& !(bg
[i
]&3)) dest
[i
] = pal
|b
;
550 bg
= bgdup
+ (dest
- BUF
);
551 pri
= PRI
+ (dest
- BUF
);
555 if (b
&& (!pri
[i
] || !(bg
[i
]&3)))
559 else while (i
--) if (src
[i
]) dest
[i
] = pal
|src
[i
];
560 /* else while (i--) if (src[i]) dest[i] = 31 + ns; */
562 if (sprdebug
) for (i
= 0; i
< NS
; i
++) BUF
[i
<<1] = 36;
574 if (rgb332
) pal_set332();
577 while (scale
* 160 > fb
.w
|| scale
* 144 > fb
.h
) scale
--;
578 vdest
= fb
.ptr
+ ((fb
.w
*fb
.pelsize
)>>1)
579 - (80*fb
.pelsize
) * scale
580 + ((fb
.h
>>1) - 72*scale
) * fb
.pitch
;
584 void lcd_refreshline()
587 byte scalebuf
[160*4*MAX_SCALE
], *dest
;
590 if (!fb
.enabled
) return;
592 if (!(R_LCDC
& LCDC_BIT_LCD_EN
))
593 return; /* should not happen... */
599 Y
= (R_SCY
+ L
) & 0xff;
604 if (L
== 0) { WY
= R_WY
; WL
= 0; }
607 if (WY
>L
|| WY
<0 || WY
>143 || WX
<-7 || WX
>159 || !(R_LCDC
& LCDC_BIT_WIN_EN
))
610 /* in order to have these offsets correct we need to count
611 the number of lines that displayed a window */
634 recolor(BUF
+WX
, 0x04, 160-WX
);
638 if (fb
.dirty
) memset(fb
.ptr
, 0, fb
.pitch
* fb
.h
);
640 if (density
> scale
) density
= scale
;
641 if (scale
== 1 || fb
.delegate_scaling
) density
= 1;
643 work_scale
= fb
.delegate_scaling
? 1: scale
;
645 dest
= (density
!= 1) ? scalebuf
: vdest
;
646 if(work_scale
> MAX_SCALE
) {
647 die("error: no code available to scale > %d!", MAX_SCALE
);
657 refresh_1(dest
, BUF
, PAL1
, 160);
660 refresh_2(dest
, BUF
, PAL2
, 160);
663 refresh_3(dest
, BUF
, PAL4
, 160);
666 refresh_4(dest
, BUF
, PAL4
, 160);
674 refresh_2(dest
, BUF
, PAL2
, 160);
677 refresh_4(dest
, BUF
, PAL4
, 160);
680 refresh_3_2x(dest
, BUF
, PAL4
, 160);
683 refresh_4_2x(dest
, BUF
, PAL4
, 160);
691 refresh_3(dest
, BUF
, PAL4
, 160);
694 refresh_2_3x(dest
, BUF
, PAL2
, 160);
697 refresh_3_3x(dest
, BUF
, PAL4
, 160);
700 refresh_4_3x(dest
, BUF
, PAL4
, 160);
708 refresh_4(dest
, BUF
, PAL4
, 160);
711 refresh_4_2x(dest
, BUF
, PAL4
, 160);
714 refresh_3_4x(dest
, BUF
, PAL4
, 160);
717 refresh_4_4x(dest
, BUF
, PAL4
, 160);
727 for (i
= 0; i
< scale
; i
++)
729 if ((i
< density
) || ((density
<= 0) && !(i
&1)))
730 memcpy(vdest
, scalebuf
, 160 * fb
.pelsize
* scale
);
734 else vdest
+= fb
.pitch
* work_scale
;
743 static void updatepalette(int i
)
745 int c
, r
, g
, b
, y
, u
, v
, rr
, gg
;
747 c
= (lcd
.pal
[i
<<1] | ((int)lcd
.pal
[(i
<<1)|1] << 8)) & 0x7FFF;
748 r
= (c
& 0x001F) << 3;
749 g
= (c
& 0x03E0) >> 2;
750 b
= (c
& 0x7C00) >> 7;
755 if (usefilter
&& (filterdmg
|| hw
.cgb
))
757 rr
= ((r
* filter
[0][0] + g
* filter
[0][1] + b
* filter
[0][2]) >> 8) + filter
[0][3];
758 gg
= ((r
* filter
[1][0] + g
* filter
[1][1] + b
* filter
[1][2]) >> 8) + filter
[1][3];
759 b
= ((r
* filter
[2][0] + g
* filter
[2][1] + b
* filter
[2][2]) >> 8) + filter
[2][3];
766 y
= (((r
* 263) + (g
* 516) + (b
* 100)) >> 10) + 16;
767 u
= (((r
* 450) - (g
* 377) - (b
* 73)) >> 10) + 128;
768 v
= (((r
* -152) - (g
* 298) + (b
* 450)) >> 10) + 128;
770 if (y
> 255) y
= 255;
772 if (u
> 255) u
= 255;
774 if (v
> 255) v
= 255;
775 PAL4
[i
] = (y
<<fb
.cc
[0].l
) | (y
<<fb
.cc
[3].l
)
776 | (u
<<fb
.cc
[1].l
) | (v
<<fb
.cc
[2].l
);
782 pal_release(PAL1
[i
]);
783 c
= pal_getcolor(c
, r
, g
, b
);
785 PAL2
[i
] = (c
<<8) | c
;
786 PAL4
[i
] = (c
<<24) | (c
<<16) | (c
<<8) | c
;
790 r
= (r
>> fb
.cc
[0].r
) << fb
.cc
[0].l
;
791 g
= (g
>> fb
.cc
[1].r
) << fb
.cc
[1].l
;
792 b
= (b
>> fb
.cc
[2].r
) << fb
.cc
[2].l
;
799 PAL2
[i
] = (c
<<8) | c
;
800 PAL4
[i
] = (c
<<24) | (c
<<16) | (c
<<8) | c
;
804 PAL4
[i
] = (c
<<16) | c
;
813 void pal_write(int i
, byte b
)
815 if (lcd
.pal
[i
] == b
) return;
820 void pal_write_dmg(int i
, int mapnum
, byte d
)
823 int *cmap
= dmg_pal
[mapnum
];
828 /* if (mapnum >= 2) d = 0xe4; */
829 for (j
= 0; j
< 8; j
+= 2)
831 c
= cmap
[(d
>> j
) & 3];
833 g
= (c
& 0xf800) >> 6;
834 b
= (c
& 0xf80000) >> 9;
836 /* FIXME - handle directly without faking cgb */
837 pal_write(i
+j
, c
& 0xff);
838 pal_write(i
+j
+1, c
>> 8);
842 void vram_write(int a
, byte b
)
844 lcd
.vbank
[R_VBK
&1][a
] = b
;
845 if (a
>= 0x1800) return;
846 patdirty
[((R_VBK
&1)<<9)+(a
>>4)] = 1;
853 memset(patdirty
, 1, sizeof patdirty
);
861 pal_write_dmg(0, 0, R_BGP
);
862 pal_write_dmg(8, 1, R_BGP
);
863 pal_write_dmg(64, 2, R_OBP0
);
864 pal_write_dmg(72, 3, R_OBP1
);
866 for (i
= 0; i
< 64; i
++)
872 memset(&lcd
, 0, sizeof lcd
);