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 #ifdef ALLOW_UNALIGNED_IO /* long long is ok since this is i386-only anyway? */
90 #define MEMCPY8(d, s) ((*(long long *)(d)) = (*(long long *)(s)))
92 #define MEMCPY8(d, s) memcpy((d), (s), 8)
98 #ifndef ASM_UPDATEPATPIX
103 byte
*vram
= lcd
.vbank
[0];
105 if (!anydirty
) return;
106 for (i
= 0; i
< 1024; i
++)
108 if (i
== 384) i
= 512;
110 if (!patdirty
[i
]) continue;
112 for (j
= 0; j
< 8; j
++)
114 a
= ((i
<<4) | (j
<<1));
115 for (k
= 0; k
< 8; k
++)
117 c
= vram
[a
] & (1<<k
) ? 1 : 0;
118 c
|= vram
[a
+1] & (1<<k
) ? 2 : 0;
119 patpix
[i
+1024][j
][k
] = c
;
121 for (k
= 0; k
< 8; k
++)
123 patpix
[i
+1024][j
][7-k
];
125 for (j
= 0; j
< 8; j
++)
127 for (k
= 0; k
< 8; k
++)
129 patpix
[i
+2048][j
][k
] =
131 patpix
[i
+3072][j
][k
] =
132 patpix
[i
+1024][7-j
][k
];
138 #endif /* ASM_UPDATEPATPIX */
146 byte
*tilemap
, *attrmap
;
149 static int wraptable
[64] =
151 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
152 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,-32
155 base
= ((R_LCDC
&0x08)?0x1C00:0x1800) + (T
<<5) + S
;
156 tilemap
= lcd
.vbank
[0] + base
;
157 attrmap
= lcd
.vbank
[1] + base
;
159 wrap
= wraptable
+ S
;
160 cnt
= ((WX
+ 7) >> 3) + 1;
165 for (i
= cnt
; i
> 0; i
--)
167 *(tilebuf
++) = *tilemap
168 | (((int)*attrmap
& 0x08) << 6)
169 | (((int)*attrmap
& 0x60) << 5);
170 *(tilebuf
++) = (((int)*attrmap
& 0x07) << 2);
171 attrmap
+= *wrap
+ 1;
172 tilemap
+= *(wrap
++) + 1;
175 for (i
= cnt
; i
> 0; i
--)
177 *(tilebuf
++) = (256 + ((n8
)*tilemap
))
178 | (((int)*attrmap
& 0x08) << 6)
179 | (((int)*attrmap
& 0x60) << 5);
180 *(tilebuf
++) = (((int)*attrmap
& 0x07) << 2);
181 attrmap
+= *wrap
+ 1;
182 tilemap
+= *(wrap
++) + 1;
188 for (i
= cnt
; i
> 0; i
--)
190 *(tilebuf
++) = *(tilemap
++);
191 tilemap
+= *(wrap
++);
194 for (i
= cnt
; i
> 0; i
--)
196 *(tilebuf
++) = (256 + ((n8
)*(tilemap
++)));
197 tilemap
+= *(wrap
++);
201 if (WX
>= 160) return;
203 base
= ((R_LCDC
&0x40)?0x1C00:0x1800) + (WT
<<5);
204 tilemap
= lcd
.vbank
[0] + base
;
205 attrmap
= lcd
.vbank
[1] + base
;
207 cnt
= ((160 - WX
) >> 3) + 1;
212 for (i
= cnt
; i
> 0; i
--)
214 *(tilebuf
++) = *(tilemap
++)
215 | (((int)*attrmap
& 0x08) << 6)
216 | (((int)*attrmap
& 0x60) << 5);
217 *(tilebuf
++) = (((int)*(attrmap
++)&7) << 2);
220 for (i
= cnt
; i
> 0; i
--)
222 *(tilebuf
++) = (256 + ((n8
)*(tilemap
++)))
223 | (((int)*attrmap
& 0x08) << 6)
224 | (((int)*attrmap
& 0x60) << 5);
225 *(tilebuf
++) = (((int)*(attrmap
++)&7) << 2);
231 for (i
= cnt
; i
> 0; i
--)
232 *(tilebuf
++) = *(tilemap
++);
234 for (i
= cnt
; i
> 0; i
--)
235 *(tilebuf
++) = (256 + ((n8
)*(tilemap
++)));
251 src
= patpix
[*(tile
++)][V
] + U
;
252 memcpy(dest
, src
, 8-U
);
255 if (cnt
<= 0) return;
258 src
= patpix
[*(tile
++)][V
];
263 src
= patpix
[*tile
][V
];
265 *(dest
++) = *(src
++);
274 if (WX
>= 160) return;
281 src
= patpix
[*(tile
++)][WV
];
286 src
= patpix
[*tile
][WV
];
288 *(dest
++) = *(src
++);
291 static void blendcpy(byte
*dest
, byte
*src
, byte b
, int cnt
)
293 while (cnt
--) *(dest
++) = *(src
++) | b
;
296 static int priused(void *attr
)
299 return (int)((a
[0]|a
[1]|a
[2]|a
[3]|a
[4]|a
[5]|a
[6]|a
[7])&0x80808080);
311 src
= lcd
.vbank
[1] + ((R_LCDC
&0x08)?0x1C00:0x1800) + (T
<<5);
315 memset(dest
, 0, cnt
);
319 memset(dest
, src
[i
++&31]&128, 8-U
);
322 if (cnt
<= 0) return;
325 memset(dest
, src
[i
++&31]&128, 8);
329 memset(dest
, src
[i
&31]&128, cnt
);
337 if (WX
>= 160) return;
341 src
= lcd
.vbank
[1] + ((R_LCDC
&0x40)?0x1C00:0x1800) + (WT
<<5);
345 memset(dest
, 0, cnt
);
351 memset(dest
, src
[i
++]&128, 8);
355 memset(dest
, src
[i
]&128, cnt
);
358 #ifndef ASM_BG_SCAN_COLOR
370 src
= patpix
[*(tile
++)][V
] + U
;
371 blendcpy(dest
, src
, *(tile
++), 8-U
);
374 if (cnt
<= 0) return;
377 src
= patpix
[*(tile
++)][V
];
378 blendcpy(dest
, src
, *(tile
++), 8);
382 src
= patpix
[*(tile
++)][V
];
383 blendcpy(dest
, src
, *(tile
++), cnt
);
387 void wnd_scan_color()
393 if (WX
>= 160) return;
400 src
= patpix
[*(tile
++)][WV
];
401 blendcpy(dest
, src
, *(tile
++), 8);
405 src
= patpix
[*(tile
++)][WV
];
406 blendcpy(dest
, src
, *(tile
++), cnt
);
409 static void recolor(byte
*buf
, byte fill
, int cnt
)
411 while (cnt
--) *(buf
++) |= fill
;
420 if (!(R_LCDC
& 0x02)) return;
424 for (i
= 40; i
; i
--, o
++)
426 if (L
>= o
->y
|| L
+ 16 < o
->y
)
428 if (L
+ 8 >= o
->y
&& !(R_LCDC
& 0x04))
430 if (++NS
== 10) break;
438 struct vissprite ts
[10];
443 if (!(R_LCDC
& 0x02)) return;
447 for (i
= 40; i
; i
--, o
++)
449 if (L
>= o
->y
|| L
+ 16 < o
->y
)
451 if (L
+ 8 >= o
->y
&& !(R_LCDC
& 0x04))
453 VS
[NS
].x
= (int)o
->x
- 8;
454 v
= L
- (int)o
->y
+ 16;
457 pat
= o
->pat
| (((int)o
->flags
& 0x60) << 5)
458 | (((int)o
->flags
& 0x08) << 6);
459 VS
[NS
].pal
= 32 + ((o
->flags
& 0x07) << 2);
463 pat
= o
->pat
| (((int)o
->flags
& 0x60) << 5);
464 VS
[NS
].pal
= 32 + ((o
->flags
& 0x10) >> 2);
466 VS
[NS
].pri
= (o
->flags
& 0x80) >> 7;
475 if (o
->flags
& 0x40) pat
^= 1;
477 VS
[NS
].buf
= patpix
[pat
][v
];
478 if (++NS
== 10) break;
480 if (!sprsort
|| hw
.cgb
) return;
481 /* not quite optimal but it finally works! */
482 for (i
= 0; i
< NS
; i
++)
486 for (j
= 1; j
< NS
; j
++)
497 memcpy(VS
, ts
, sizeof VS
);
503 byte pal
, b
, ns
= NS
;
504 byte
*src
, *dest
, *bg
, *pri
;
505 struct vissprite
*vs
;
506 static byte bgdup
[256];
510 memcpy(bgdup
, BUF
, 256);
513 for (; ns
; ns
--, vs
--)
516 if (x
>= 160) continue;
517 if (x
<= -8) continue;
528 if (x
> 152) i
= 160 - x
;
534 bg
= bgdup
+ (dest
- BUF
);
538 if (b
&& !(bg
[i
]&3)) dest
[i
] = pal
|b
;
543 bg
= bgdup
+ (dest
- BUF
);
544 pri
= PRI
+ (dest
- BUF
);
548 if (b
&& (!pri
[i
] || !(bg
[i
]&3)))
552 else while (i
--) if (src
[i
]) dest
[i
] = pal
|src
[i
];
553 /* else while (i--) if (src[i]) dest[i] = 31 + ns; */
555 if (sprdebug
) for (i
= 0; i
< NS
; i
++) BUF
[i
<<1] = 36;
567 if (rgb332
) pal_set332();
570 while (scale
* 160 > fb
.w
|| scale
* 144 > fb
.h
) scale
--;
571 vdest
= fb
.ptr
+ ((fb
.w
*fb
.pelsize
)>>1)
572 - (80*fb
.pelsize
) * scale
573 + ((fb
.h
>>1) - 72*scale
) * fb
.pitch
;
577 void lcd_refreshline()
580 byte scalebuf
[160*4*MAX_SCALE
], *dest
;
582 if (!fb
.enabled
) return;
584 if (!(R_LCDC
& 0x80))
585 return; /* should not happen... */
591 Y
= (R_SCY
+ L
) & 0xff;
598 if (WY
>L
|| WY
<0 || WY
>143 || WX
<-7 || WX
>159 || !(R_LCDC
&0x20))
620 recolor(BUF
+WX
, 0x04, 160-WX
);
624 if (fb
.dirty
) memset(fb
.ptr
, 0, fb
.pitch
* fb
.h
);
626 if (density
> scale
) density
= scale
;
627 if (scale
== 1 || fb
.delegate_scaling
) density
= 1;
629 work_scale
= fb
.delegate_scaling
? 1: scale
;
631 dest
= (density
!= 1) ? scalebuf
: vdest
;
632 if(work_scale
> MAX_SCALE
) {
633 die("error: no code available to scale > %d!", MAX_SCALE
);
643 refresh_1(dest
, BUF
, PAL1
, 160);
646 refresh_2(dest
, BUF
, PAL2
, 160);
649 refresh_3(dest
, BUF
, PAL4
, 160);
652 refresh_4(dest
, BUF
, PAL4
, 160);
660 refresh_2(dest
, BUF
, PAL2
, 160);
663 refresh_4(dest
, BUF
, PAL4
, 160);
666 refresh_3_2x(dest
, BUF
, PAL4
, 160);
669 refresh_4_2x(dest
, BUF
, PAL4
, 160);
677 refresh_3(dest
, BUF
, PAL4
, 160);
680 refresh_2_3x(dest
, BUF
, PAL2
, 160);
683 refresh_3_3x(dest
, BUF
, PAL4
, 160);
686 refresh_4_3x(dest
, BUF
, PAL4
, 160);
694 refresh_4(dest
, BUF
, PAL4
, 160);
697 refresh_4_2x(dest
, BUF
, PAL4
, 160);
700 refresh_3_4x(dest
, BUF
, PAL4
, 160);
703 refresh_4_4x(dest
, BUF
, PAL4
, 160);
713 for (i
= 0; i
< scale
; i
++)
715 if ((i
< density
) || ((density
<= 0) && !(i
&1)))
716 memcpy(vdest
, scalebuf
, 160 * fb
.pelsize
* scale
);
720 else vdest
+= fb
.pitch
* work_scale
;
729 static void updatepalette(int i
)
731 int c
, r
, g
, b
, y
, u
, v
, rr
, gg
;
733 c
= (lcd
.pal
[i
<<1] | ((int)lcd
.pal
[(i
<<1)|1] << 8)) & 0x7FFF;
734 r
= (c
& 0x001F) << 3;
735 g
= (c
& 0x03E0) >> 2;
736 b
= (c
& 0x7C00) >> 7;
741 if (usefilter
&& (filterdmg
|| hw
.cgb
))
743 rr
= ((r
* filter
[0][0] + g
* filter
[0][1] + b
* filter
[0][2]) >> 8) + filter
[0][3];
744 gg
= ((r
* filter
[1][0] + g
* filter
[1][1] + b
* filter
[1][2]) >> 8) + filter
[1][3];
745 b
= ((r
* filter
[2][0] + g
* filter
[2][1] + b
* filter
[2][2]) >> 8) + filter
[2][3];
752 y
= (((r
* 263) + (g
* 516) + (b
* 100)) >> 10) + 16;
753 u
= (((r
* 450) - (g
* 377) - (b
* 73)) >> 10) + 128;
754 v
= (((r
* -152) - (g
* 298) + (b
* 450)) >> 10) + 128;
756 if (y
> 255) y
= 255;
758 if (u
> 255) u
= 255;
760 if (v
> 255) v
= 255;
761 PAL4
[i
] = (y
<<fb
.cc
[0].l
) | (y
<<fb
.cc
[3].l
)
762 | (u
<<fb
.cc
[1].l
) | (v
<<fb
.cc
[2].l
);
768 pal_release(PAL1
[i
]);
769 c
= pal_getcolor(c
, r
, g
, b
);
771 PAL2
[i
] = (c
<<8) | c
;
772 PAL4
[i
] = (c
<<24) | (c
<<16) | (c
<<8) | c
;
776 r
= (r
>> fb
.cc
[0].r
) << fb
.cc
[0].l
;
777 g
= (g
>> fb
.cc
[1].r
) << fb
.cc
[1].l
;
778 b
= (b
>> fb
.cc
[2].r
) << fb
.cc
[2].l
;
785 PAL2
[i
] = (c
<<8) | c
;
786 PAL4
[i
] = (c
<<24) | (c
<<16) | (c
<<8) | c
;
790 PAL4
[i
] = (c
<<16) | c
;
799 void pal_write(int i
, byte b
)
801 if (lcd
.pal
[i
] == b
) return;
806 void pal_write_dmg(int i
, int mapnum
, byte d
)
809 int *cmap
= dmg_pal
[mapnum
];
814 /* if (mapnum >= 2) d = 0xe4; */
815 for (j
= 0; j
< 8; j
+= 2)
817 c
= cmap
[(d
>> j
) & 3];
819 g
= (c
& 0xf800) >> 6;
820 b
= (c
& 0xf80000) >> 9;
822 /* FIXME - handle directly without faking cgb */
823 pal_write(i
+j
, c
& 0xff);
824 pal_write(i
+j
+1, c
>> 8);
828 void vram_write(int a
, byte b
)
830 lcd
.vbank
[R_VBK
&1][a
] = b
;
831 if (a
>= 0x1800) return;
832 patdirty
[((R_VBK
&1)<<9)+(a
>>4)] = 1;
839 memset(patdirty
, 1, sizeof patdirty
);
847 pal_write_dmg(0, 0, R_BGP
);
848 pal_write_dmg(8, 1, R_BGP
);
849 pal_write_dmg(64, 2, R_OBP0
);
850 pal_write_dmg(72, 3, R_OBP1
);
852 for (i
= 0; i
< 64; i
++)
858 memset(&lcd
, 0, sizeof lcd
);