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];
49 static int density
= 0;
53 static int sprsort
= 1;
56 #define DEF_PAL { 0x98d0e0, 0x68a0b0, 0x60707C, 0x2C3C3C }
58 static int dmg_pal
[4][4] = { DEF_PAL
, DEF_PAL
, DEF_PAL
, DEF_PAL
};
60 static int usefilter
, filterdmg
;
61 static int filter
[3][4] = {
67 rcvar_t lcd_exports
[] =
69 RCV_INT("scale", &scale
),
70 RCV_INT("density", &density
),
71 RCV_BOOL("rgb332", &rgb332
),
72 RCV_VECTOR("dmg_bgp", dmg_pal
[0], 4),
73 RCV_VECTOR("dmg_wndp", dmg_pal
[1], 4),
74 RCV_VECTOR("dmg_obp0", dmg_pal
[2], 4),
75 RCV_VECTOR("dmg_obp1", dmg_pal
[3], 4),
76 RCV_BOOL("sprsort", &sprsort
),
77 RCV_BOOL("sprdebug", &sprdebug
),
78 RCV_BOOL("colorfilter", &usefilter
),
79 RCV_BOOL("filterdmg", &filterdmg
),
80 RCV_VECTOR("red", filter
[0], 4),
81 RCV_VECTOR("green", filter
[1], 4),
82 RCV_VECTOR("blue", filter
[2], 4),
88 #ifdef ALLOW_UNALIGNED_IO /* long long is ok since this is i386-only anyway? */
89 #define MEMCPY8(d, s) ((*(long long *)(d)) = (*(long long *)(s)))
91 #define MEMCPY8(d, s) memcpy((d), (s), 8)
97 #ifndef ASM_UPDATEPATPIX
102 byte
*vram
= lcd
.vbank
[0];
104 if (!anydirty
) return;
105 for (i
= 0; i
< 1024; i
++)
107 if (i
== 384) i
= 512;
109 if (!patdirty
[i
]) continue;
111 for (j
= 0; j
< 8; j
++)
113 a
= ((i
<<4) | (j
<<1));
114 for (k
= 0; k
< 8; k
++)
116 c
= vram
[a
] & (1<<k
) ? 1 : 0;
117 c
|= vram
[a
+1] & (1<<k
) ? 2 : 0;
118 patpix
[i
+1024][j
][k
] = c
;
120 for (k
= 0; k
< 8; k
++)
122 patpix
[i
+1024][j
][7-k
];
124 for (j
= 0; j
< 8; j
++)
126 for (k
= 0; k
< 8; k
++)
128 patpix
[i
+2048][j
][k
] =
130 patpix
[i
+3072][j
][k
] =
131 patpix
[i
+1024][7-j
][k
];
137 #endif /* ASM_UPDATEPATPIX */
145 byte
*tilemap
, *attrmap
;
148 static int wraptable
[64] =
150 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
151 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,-32
154 base
= ((R_LCDC
&0x08)?0x1C00:0x1800) + (T
<<5) + S
;
155 tilemap
= lcd
.vbank
[0] + base
;
156 attrmap
= lcd
.vbank
[1] + base
;
158 wrap
= wraptable
+ S
;
159 cnt
= ((WX
+ 7) >> 3) + 1;
164 for (i
= cnt
; i
> 0; i
--)
166 *(tilebuf
++) = *tilemap
167 | (((int)*attrmap
& 0x08) << 6)
168 | (((int)*attrmap
& 0x60) << 5);
169 *(tilebuf
++) = (((int)*attrmap
& 0x07) << 2);
170 attrmap
+= *wrap
+ 1;
171 tilemap
+= *(wrap
++) + 1;
174 for (i
= cnt
; i
> 0; i
--)
176 *(tilebuf
++) = (256 + ((n8
)*tilemap
))
177 | (((int)*attrmap
& 0x08) << 6)
178 | (((int)*attrmap
& 0x60) << 5);
179 *(tilebuf
++) = (((int)*attrmap
& 0x07) << 2);
180 attrmap
+= *wrap
+ 1;
181 tilemap
+= *(wrap
++) + 1;
187 for (i
= cnt
; i
> 0; i
--)
189 *(tilebuf
++) = *(tilemap
++);
190 tilemap
+= *(wrap
++);
193 for (i
= cnt
; i
> 0; i
--)
195 *(tilebuf
++) = (256 + ((n8
)*(tilemap
++)));
196 tilemap
+= *(wrap
++);
200 if (WX
>= 160) return;
202 base
= ((R_LCDC
&0x40)?0x1C00:0x1800) + (WT
<<5);
203 tilemap
= lcd
.vbank
[0] + base
;
204 attrmap
= lcd
.vbank
[1] + base
;
206 cnt
= ((160 - WX
) >> 3) + 1;
211 for (i
= cnt
; i
> 0; i
--)
213 *(tilebuf
++) = *(tilemap
++)
214 | (((int)*attrmap
& 0x08) << 6)
215 | (((int)*attrmap
& 0x60) << 5);
216 *(tilebuf
++) = (((int)*(attrmap
++)&7) << 2);
219 for (i
= cnt
; i
> 0; i
--)
221 *(tilebuf
++) = (256 + ((n8
)*(tilemap
++)))
222 | (((int)*attrmap
& 0x08) << 6)
223 | (((int)*attrmap
& 0x60) << 5);
224 *(tilebuf
++) = (((int)*(attrmap
++)&7) << 2);
230 for (i
= cnt
; i
> 0; i
--)
231 *(tilebuf
++) = *(tilemap
++);
233 for (i
= cnt
; i
> 0; i
--)
234 *(tilebuf
++) = (256 + ((n8
)*(tilemap
++)));
250 src
= patpix
[*(tile
++)][V
] + U
;
251 memcpy(dest
, src
, 8-U
);
254 if (cnt
<= 0) return;
257 src
= patpix
[*(tile
++)][V
];
262 src
= patpix
[*tile
][V
];
264 *(dest
++) = *(src
++);
273 if (WX
>= 160) return;
280 src
= patpix
[*(tile
++)][WV
];
285 src
= patpix
[*tile
][WV
];
287 *(dest
++) = *(src
++);
290 static void blendcpy(byte
*dest
, byte
*src
, byte b
, int cnt
)
292 while (cnt
--) *(dest
++) = *(src
++) | b
;
295 static int priused(void *attr
)
298 return (int)((a
[0]|a
[1]|a
[2]|a
[3]|a
[4]|a
[5]|a
[6]|a
[7])&0x80808080);
310 src
= lcd
.vbank
[1] + ((R_LCDC
&0x08)?0x1C00:0x1800) + (T
<<5);
314 memset(dest
, 0, cnt
);
318 memset(dest
, src
[i
++&31]&128, 8-U
);
321 if (cnt
<= 0) return;
324 memset(dest
, src
[i
++&31]&128, 8);
328 memset(dest
, src
[i
&31]&128, cnt
);
336 if (WX
>= 160) return;
340 src
= lcd
.vbank
[1] + ((R_LCDC
&0x40)?0x1C00:0x1800) + (WT
<<5);
344 memset(dest
, 0, cnt
);
350 memset(dest
, src
[i
++]&128, 8);
354 memset(dest
, src
[i
]&128, cnt
);
357 #ifndef ASM_BG_SCAN_COLOR
369 src
= patpix
[*(tile
++)][V
] + U
;
370 blendcpy(dest
, src
, *(tile
++), 8-U
);
373 if (cnt
<= 0) return;
376 src
= patpix
[*(tile
++)][V
];
377 blendcpy(dest
, src
, *(tile
++), 8);
381 src
= patpix
[*(tile
++)][V
];
382 blendcpy(dest
, src
, *(tile
++), cnt
);
386 void wnd_scan_color()
392 if (WX
>= 160) return;
399 src
= patpix
[*(tile
++)][WV
];
400 blendcpy(dest
, src
, *(tile
++), 8);
404 src
= patpix
[*(tile
++)][WV
];
405 blendcpy(dest
, src
, *(tile
++), cnt
);
408 static void recolor(byte
*buf
, byte fill
, int cnt
)
410 while (cnt
--) *(buf
++) |= fill
;
419 if (!(R_LCDC
& 0x02)) return;
423 for (i
= 40; i
; i
--, o
++)
425 if (L
>= o
->y
|| L
+ 16 < o
->y
)
427 if (L
+ 8 >= o
->y
&& !(R_LCDC
& 0x04))
429 if (++NS
== 10) break;
437 struct vissprite ts
[10];
442 if (!(R_LCDC
& 0x02)) return;
446 for (i
= 40; i
; i
--, o
++)
448 if (L
>= o
->y
|| L
+ 16 < o
->y
)
450 if (L
+ 8 >= o
->y
&& !(R_LCDC
& 0x04))
452 VS
[NS
].x
= (int)o
->x
- 8;
453 v
= L
- (int)o
->y
+ 16;
456 pat
= o
->pat
| (((int)o
->flags
& 0x60) << 5)
457 | (((int)o
->flags
& 0x08) << 6);
458 VS
[NS
].pal
= 32 + ((o
->flags
& 0x07) << 2);
462 pat
= o
->pat
| (((int)o
->flags
& 0x60) << 5);
463 VS
[NS
].pal
= 32 + ((o
->flags
& 0x10) >> 2);
465 VS
[NS
].pri
= (o
->flags
& 0x80) >> 7;
474 if (o
->flags
& 0x40) pat
^= 1;
476 VS
[NS
].buf
= patpix
[pat
][v
];
477 if (++NS
== 10) break;
479 if (!sprsort
|| hw
.cgb
) return;
480 /* not quite optimal but it finally works! */
481 for (i
= 0; i
< NS
; i
++)
485 for (j
= 1; j
< NS
; j
++)
496 memcpy(VS
, ts
, sizeof VS
);
502 byte pal
, b
, ns
= NS
;
503 byte
*src
, *dest
, *bg
, *pri
;
504 struct vissprite
*vs
;
505 static byte bgdup
[256];
509 memcpy(bgdup
, BUF
, 256);
512 for (; ns
; ns
--, vs
--)
515 if (x
>= 160) continue;
516 if (x
<= -8) continue;
527 if (x
> 152) i
= 160 - x
;
533 bg
= bgdup
+ (dest
- BUF
);
537 if (b
&& !(bg
[i
]&3)) dest
[i
] = pal
|b
;
542 bg
= bgdup
+ (dest
- BUF
);
543 pri
= PRI
+ (dest
- BUF
);
547 if (b
&& (!pri
[i
] || !(bg
[i
]&3)))
551 else while (i
--) if (src
[i
]) dest
[i
] = pal
|src
[i
];
552 /* else while (i--) if (src[i]) dest[i] = 31 + ns; */
554 if (sprdebug
) for (i
= 0; i
< NS
; i
++) BUF
[i
<<1] = 36;
566 if (rgb332
) pal_set332();
569 while (scale
* 160 > fb
.w
|| scale
* 144 > fb
.h
) scale
--;
570 vdest
= fb
.ptr
+ ((fb
.w
*fb
.pelsize
)>>1)
571 - (80*fb
.pelsize
) * scale
572 + ((fb
.h
>>1) - 72*scale
) * fb
.pitch
;
576 void lcd_refreshline()
579 byte scalebuf
[160*4*4], *dest
;
581 if (!fb
.enabled
) return;
583 if (!(R_LCDC
& 0x80))
584 return; /* should not happen... */
590 Y
= (R_SCY
+ L
) & 0xff;
597 if (WY
>L
|| WY
<0 || WY
>143 || WX
<-7 || WX
>159 || !(R_LCDC
&0x20))
619 recolor(BUF
+WX
, 0x04, 160-WX
);
623 if (fb
.dirty
) memset(fb
.ptr
, 0, fb
.pitch
* fb
.h
);
625 if (density
> scale
) density
= scale
;
626 if (scale
== 1) density
= 1;
628 dest
= (density
!= 1) ? scalebuf
: vdest
;
637 refresh_1(dest
, BUF
, PAL1
, 160);
640 refresh_2(dest
, BUF
, PAL2
, 160);
643 refresh_3(dest
, BUF
, PAL4
, 160);
646 refresh_4(dest
, BUF
, PAL4
, 160);
654 refresh_2(dest
, BUF
, PAL2
, 160);
657 refresh_4(dest
, BUF
, PAL4
, 160);
660 refresh_3_2x(dest
, BUF
, PAL4
, 160);
663 refresh_4_2x(dest
, BUF
, PAL4
, 160);
671 refresh_3(dest
, BUF
, PAL4
, 160);
674 refresh_2_3x(dest
, BUF
, PAL2
, 160);
677 refresh_3_3x(dest
, BUF
, PAL4
, 160);
680 refresh_4_3x(dest
, BUF
, PAL4
, 160);
688 refresh_4(dest
, BUF
, PAL4
, 160);
691 refresh_4_2x(dest
, BUF
, PAL4
, 160);
694 refresh_3_4x(dest
, BUF
, PAL4
, 160);
697 refresh_4_4x(dest
, BUF
, PAL4
, 160);
707 for (i
= 0; i
< scale
; i
++)
709 if ((i
< density
) || ((density
<= 0) && !(i
&1)))
710 memcpy(vdest
, scalebuf
, 160 * fb
.pelsize
* scale
);
714 else vdest
+= fb
.pitch
* scale
;
723 static void updatepalette(int i
)
725 int c
, r
, g
, b
, y
, u
, v
, rr
, gg
;
727 c
= (lcd
.pal
[i
<<1] | ((int)lcd
.pal
[(i
<<1)|1] << 8)) & 0x7FFF;
728 r
= (c
& 0x001F) << 3;
729 g
= (c
& 0x03E0) >> 2;
730 b
= (c
& 0x7C00) >> 7;
735 if (usefilter
&& (filterdmg
|| hw
.cgb
))
737 rr
= ((r
* filter
[0][0] + g
* filter
[0][1] + b
* filter
[0][2]) >> 8) + filter
[0][3];
738 gg
= ((r
* filter
[1][0] + g
* filter
[1][1] + b
* filter
[1][2]) >> 8) + filter
[1][3];
739 b
= ((r
* filter
[2][0] + g
* filter
[2][1] + b
* filter
[2][2]) >> 8) + filter
[2][3];
746 y
= (((r
* 263) + (g
* 516) + (b
* 100)) >> 10) + 16;
747 u
= (((r
* 450) - (g
* 377) - (b
* 73)) >> 10) + 128;
748 v
= (((r
* -152) - (g
* 298) + (b
* 450)) >> 10) + 128;
750 if (y
> 255) y
= 255;
752 if (u
> 255) u
= 255;
754 if (v
> 255) v
= 255;
755 PAL4
[i
] = (y
<<fb
.cc
[0].l
) | (y
<<fb
.cc
[3].l
)
756 | (u
<<fb
.cc
[1].l
) | (v
<<fb
.cc
[2].l
);
762 pal_release(PAL1
[i
]);
763 c
= pal_getcolor(c
, r
, g
, b
);
765 PAL2
[i
] = (c
<<8) | c
;
766 PAL4
[i
] = (c
<<24) | (c
<<16) | (c
<<8) | c
;
770 r
= (r
>> fb
.cc
[0].r
) << fb
.cc
[0].l
;
771 g
= (g
>> fb
.cc
[1].r
) << fb
.cc
[1].l
;
772 b
= (b
>> fb
.cc
[2].r
) << fb
.cc
[2].l
;
779 PAL2
[i
] = (c
<<8) | c
;
780 PAL4
[i
] = (c
<<24) | (c
<<16) | (c
<<8) | c
;
784 PAL4
[i
] = (c
<<16) | c
;
793 void pal_write(int i
, byte b
)
795 if (lcd
.pal
[i
] == b
) return;
800 void pal_write_dmg(int i
, int mapnum
, byte d
)
803 int *cmap
= dmg_pal
[mapnum
];
808 /* if (mapnum >= 2) d = 0xe4; */
809 for (j
= 0; j
< 8; j
+= 2)
811 c
= cmap
[(d
>> j
) & 3];
813 g
= (c
& 0xf800) >> 6;
814 b
= (c
& 0xf80000) >> 9;
816 /* FIXME - handle directly without faking cgb */
817 pal_write(i
+j
, c
& 0xff);
818 pal_write(i
+j
+1, c
>> 8);
822 void vram_write(int a
, byte b
)
824 lcd
.vbank
[R_VBK
&1][a
] = b
;
825 if (a
>= 0x1800) return;
826 patdirty
[((R_VBK
&1)<<9)+(a
>>4)] = 1;
833 memset(patdirty
, 1, sizeof patdirty
);
841 pal_write_dmg(0, 0, R_BGP
);
842 pal_write_dmg(8, 1, R_BGP
);
843 pal_write_dmg(64, 2, R_OBP0
);
844 pal_write_dmg(72, 3, R_OBP1
);
846 for (i
= 0; i
< 64; i
++)
852 memset(&lcd
, 0, sizeof lcd
);