1
0
Fork 0
forked from len0rd/rockbox
foxbox/apps/plugins/rockboy/lcd.c
Tom Ross 2882b26a99 Major Rockboy update.
1) Adapt Rockboy to smaller screens (H10, X5, and iPod Nano).
2) Add the ability to use a preset palette on color targets. Choose 'Set Palette' from the main menu.
3) Clean up the code to remove any unused code and variables.
4) Changed tabs to spaces.
5) Disable reading and writing sound when sound is disabled.
6) Disbable writing to the RTC since it is not implemented yet.
7) Minor optimizations from WAC gnuboy CE and iBoy.
8) Massive clean up of code to make it appear consistent.
9) Change all C++ style comments to C style.
10) Completely reorganize dynarec. Add fixmes to all unimplemented opcodes. Add debug writes for all opcodes. Attempt to implement a few opcodes myself.
11) Silence some warnings when built using dynarec.
12) Minor reshuffling of IRAM, may or not offer a speed increase.
13) Include fixes found in the short-lived gnuboy CVS.

All in all, there's about a 10% improvement on my test roms when sound is disabled and slight improvement with sound. Especially noticable when there are few sprites on screen and less action is occurring. See FS #6567.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12216 a1c6a512-1295-4272-9138-f99709370657
2007-02-06 21:41:08 +00:00

1176 lines
29 KiB
C

#include "rockmacros.h"
#include "defs.h"
#include "regs.h"
#include "hw.h"
#include "mem.h"
#include "lcd-gb.h"
#include "fb.h"
#include "palette-presets.h"
#ifdef USE_ASM
#include "asm.h"
#endif
struct lcd lcd;
struct scan scan IBSS_ATTR;
#define BG (scan.bg)
#define WND (scan.wnd)
#if LCD_DEPTH ==16
#define BUF (scan.buf)
#else
#define BUF (scan.buf[scanline_ind])
#endif
#define PRI (scan.pri)
#define PAL (scan.pal)
#define VS (scan.vs) /* vissprites */
#define NS (scan.ns)
#define L (scan.l) /* line */
#define X (scan.x) /* screen position */
#define Y (scan.y)
#define S (scan.s) /* tilemap position */
#define T (scan.t)
#define U (scan.u) /* position within tile */
#define V (scan.v)
#define WX (scan.wx)
#define WY (scan.wy)
#define WT (scan.wt)
#define WV (scan.wv)
byte patpix[4096][8][8]
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
__attribute__ ((aligned(16))) /* to profit from burst mode */
#endif
;
byte patdirty[1024];
byte anydirty;
#if LCD_DEPTH < 16
static int scanline_ind=0;
#endif
static int dmg_pal[4][4];
fb_data *vdest;
#ifndef ASM_UPDATEPATPIX
void updatepatpix(void)
{
int i, j;
#if ((CONFIG_CPU != SH7034) && !defined(CPU_COLDFIRE)) || defined(SIMULATOR)
int k, a, c;
#endif
byte *vram = lcd.vbank[0];
if (!anydirty) return;
for (i = 0; i < 1024; i++)
{
if (i == 384) i = 512;
if (i == 896) break;
if (!patdirty[i]) continue;
patdirty[i] = 0;
for (j = 0; j < 8; j++)
{
#if CONFIG_CPU == SH7034 && !defined(SIMULATOR)
asm volatile (
"mov.w @%2,r1 \n"
"swap.b r1,r2 \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@%0 \n"
"mov.b r0,@(7,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(1,%0) \n"
"mov.b r0,@(6,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(2,%0) \n"
"mov.b r0,@(5,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(3,%0) \n"
"mov.b r0,@(4,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(4,%0) \n"
"mov.b r0,@(3,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(5,%0) \n"
"mov.b r0,@(2,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(6,%0) \n"
"mov.b r0,@(1,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(7,%0) \n"
"mov.b r0,@%1 \n"
: /* outputs */
: /* inputs */
/* %0 */ "r"(patpix[i+1024][j]),
/* %1 */ "r"(patpix[i][j]),
/* %2 */ "r"(&vram[(i<<4)|(j<<1)])
: /* clobbers */
"r0", "r1", "r2"
);
#elif defined(CPU_COLDFIRE) && !defined(SIMULATOR)
asm volatile (
"move.b (%2),%%d2 \n"
"move.b (1,%2),%%d1 \n"
"addq.l #8,%1 \n"
"clr.l %%d0 \n"
"lsr.l #1,%%d1 \n"
"addx.l %%d0,%%d0 \n"
"lsr.l #1,%%d2 \n"
"addx.l %%d0,%%d0 \n"
"move.b %%d0,-(%1) \n"
"lsl.l #6,%%d0 \n"
"lsr.l #1,%%d1 \n"
"addx.l %%d0,%%d0 \n"
"lsr.l #1,%%d2 \n"
"addx.l %%d0,%%d0 \n"
"move.b %%d0,-(%1) \n"
"lsl.l #6,%%d0 \n"
"lsr.l #1,%%d1 \n"
"addx.l %%d0,%%d0 \n"
"lsr.l #1,%%d2 \n"
"addx.l %%d0,%%d0 \n"
"move.b %%d0,-(%1) \n"
"lsl.l #6,%%d0 \n"
"lsr.l #1,%%d1 \n"
"addx.l %%d0,%%d0 \n"
"lsr.l #1,%%d2 \n"
"addx.l %%d0,%%d0 \n"
"move.l %%d0,(%0) \n"
"move.b %%d0,-(%1) \n"
"clr.l %%d0 \n"
"lsr.l #1,%%d1 \n"
"addx.l %%d0,%%d0 \n"
"lsr.l #1,%%d2 \n"
"addx.l %%d0,%%d0 \n"
"move.b %%d0,-(%1) \n"
"lsl.l #6,%%d0 \n"
"lsr.l #1,%%d1 \n"
"addx.l %%d0,%%d0 \n"
"lsr.l #1,%%d2 \n"
"addx.l %%d0,%%d0 \n"
"move.b %%d0,-(%1) \n"
"lsl.l #6,%%d0 \n"
"lsr.l #1,%%d1 \n"
"addx.l %%d0,%%d0 \n"
"lsr.l #1,%%d2 \n"
"addx.l %%d0,%%d0 \n"
"move.b %%d0,-(%1) \n"
"lsl.l #6,%%d0 \n"
"lsr.l #1,%%d1 \n"
"addx.l %%d0,%%d0 \n"
"lsr.l #1,%%d2 \n"
"addx.l %%d0,%%d0 \n"
"move.l %%d0,(4,%0) \n"
"move.b %%d0,-(%1) \n"
: /* outputs */
: /* inputs */
/* %0 */ "a"(patpix[i+1024][j]),
/* %1 */ "a"(patpix[i][j]),
/* %2 */ "a"(&vram[(i<<4)|(j<<1)])
: /* clobbers */
"d0", "d1", "d2"
);
#else
a = ((i<<4) | (j<<1));
for (k = 0; k < 8; k++)
{
c = vram[a] & (1<<k) ? 1 : 0;
c |= vram[a+1] & (1<<k) ? 2 : 0;
patpix[i+1024][j][k] = c;
}
for (k = 0; k < 8; k++)
patpix[i][j][k] =
patpix[i+1024][j][7-k];
#endif
}
#if CONFIG_CPU == SH7034 && !defined(SIMULATOR)
asm volatile (
"mov.l @%0,r0 \n"
"mov.l @(4,%0),r1 \n"
"mov.l r0,@(56,%1) \n"
"mov.l r1,@(60,%1) \n"
"mov.l @(8,%0),r0 \n"
"mov.l @(12,%0),r1 \n"
"mov.l r0,@(48,%1) \n"
"mov.l r1,@(52,%1) \n"
"mov.l @(16,%0),r0 \n"
"mov.l @(20,%0),r1 \n"
"mov.l r0,@(40,%1) \n"
"mov.l r1,@(44,%1) \n"
"mov.l @(24,%0),r0 \n"
"mov.l @(28,%0),r1 \n"
"mov.l r0,@(32,%1) \n"
"mov.l r1,@(36,%1) \n"
"mov.l @(32,%0),r0 \n"
"mov.l @(36,%0),r1 \n"
"mov.l r0,@(24,%1) \n"
"mov.l r1,@(28,%1) \n"
"mov.l @(40,%0),r0 \n"
"mov.l @(44,%0),r1 \n"
"mov.l r0,@(16,%1) \n"
"mov.l r1,@(20,%1) \n"
"mov.l @(48,%0),r0 \n"
"mov.l @(52,%0),r1 \n"
"mov.l r0,@(8,%1) \n"
"mov.l r1,@(12,%1) \n"
"mov.l @(56,%0),r0 \n"
"mov.l @(60,%0),r1 \n"
"mov.l r0,@%1 \n"
"mov.l r1,@(4,%1) \n"
"add %2,%0 \n"
"add %2,%1 \n"
"mov.l @%0,r0 \n"
"mov.l @(4,%0),r1 \n"
"mov.l r0,@(56,%1) \n"
"mov.l r1,@(60,%1) \n"
"mov.l @(8,%0),r0 \n"
"mov.l @(12,%0),r1 \n"
"mov.l r0,@(48,%1) \n"
"mov.l r1,@(52,%1) \n"
"mov.l @(16,%0),r0 \n"
"mov.l @(20,%0),r1 \n"
"mov.l r0,@(40,%1) \n"
"mov.l r1,@(44,%1) \n"
"mov.l @(24,%0),r0 \n"
"mov.l @(28,%0),r1 \n"
"mov.l r0,@(32,%1) \n"
"mov.l r1,@(36,%1) \n"
"mov.l @(32,%0),r0 \n"
"mov.l @(36,%0),r1 \n"
"mov.l r0,@(24,%1) \n"
"mov.l r1,@(28,%1) \n"
"mov.l @(40,%0),r0 \n"
"mov.l @(44,%0),r1 \n"
"mov.l r0,@(16,%1) \n"
"mov.l r1,@(20,%1) \n"
"mov.l @(48,%0),r0 \n"
"mov.l @(52,%0),r1 \n"
"mov.l r0,@(8,%1) \n"
"mov.l r1,@(12,%1) \n"
"mov.l @(56,%0),r0 \n"
"mov.l @(60,%0),r1 \n"
"mov.l r0,@%1 \n"
"mov.l r1,@(4,%1) \n"
: /* outputs */
: /* inputs */
/* %0 */ "r"(patpix[i][0]),
/* %1 */ "r"(patpix[i+2048][0]),
/* %2 */ "r"(1024*64)
: /* clobbers */
"r0", "r1"
);
#elif defined(CPU_COLDFIRE) && !defined(SIMULATOR)
asm volatile (
"movem.l (%0),%%d0-%%d3 \n"
"move.l %%d0,%%d4 \n"
"move.l %%d1,%%d5 \n"
"movem.l %%d2-%%d5,(48,%1) \n"
"movem.l (16,%0),%%d0-%%d3 \n"
"move.l %%d0,%%d4 \n"
"move.l %%d1,%%d5 \n"
"movem.l %%d2-%%d5,(32,%1) \n"
"movem.l (32,%0),%%d0-%%d3 \n"
"move.l %%d0,%%d4 \n"
"move.l %%d1,%%d5 \n"
"movem.l %%d2-%%d5,(16,%1) \n"
"movem.l (48,%0),%%d0-%%d3 \n"
"move.l %%d0,%%d4 \n"
"move.l %%d1,%%d5 \n"
"movem.l %%d2-%%d5,(%1) \n"
"move.l %2,%%d0 \n"
"add.l %%d0,%0 \n"
"add.l %%d0,%1 \n"
"movem.l (%0),%%d0-%%d3 \n"
"move.l %%d0,%%d4 \n"
"move.l %%d1,%%d5 \n"
"movem.l %%d2-%%d5,(48,%1) \n"
"movem.l (16,%0),%%d0-%%d3 \n"
"move.l %%d0,%%d4 \n"
"move.l %%d1,%%d5 \n"
"movem.l %%d2-%%d5,(32,%1) \n"
"movem.l (32,%0),%%d0-%%d3 \n"
"move.l %%d0,%%d4 \n"
"move.l %%d1,%%d5 \n"
"movem.l %%d2-%%d5,(16,%1) \n"
"movem.l (48,%0),%%d0-%%d3 \n"
"move.l %%d0,%%d4 \n"
"move.l %%d1,%%d5 \n"
"movem.l %%d2-%%d5,(%1) \n"
: /* outputs */
: /* inputs */
/* %0 */ "a"(patpix[i][0]),
/* %1 */ "a"(patpix[i+2048][0]),
/* %2 */ "i"(1024*64)
: /* clobbers */
"d0", "d1", "d2", "d3", "d4", "d5"
);
#else
for (j = 0; j < 8; j++)
{
for (k = 0; k < 8; k++)
{
patpix[i+2048][j][k] =
patpix[i][7-j][k];
patpix[i+3072][j][k] =
patpix[i+1024][7-j][k];
}
}
#endif
}
anydirty = 0;
}
#endif /* ASM_UPDATEPATPIX */
void tilebuf(void)
{
int i, cnt;
int base;
byte *tilemap, *attrmap;
int *tilebuf;
int *wrap;
static int wraptable[64] =
{
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,-32
};
base = ((R_LCDC&0x08)?0x1C00:0x1800) + (T<<5) + S;
tilemap = lcd.vbank[0] + base;
attrmap = lcd.vbank[1] + base;
tilebuf = BG;
wrap = wraptable + S;
cnt = ((WX + 7) >> 3) + 1;
if (hw.cgb) {
if (R_LCDC & 0x10)
for (i = cnt; i > 0; i--)
{
*(tilebuf++) = *tilemap
| (((int)*attrmap & 0x08) << 6)
| (((int)*attrmap & 0x60) << 5);
*(tilebuf++) = (((int)*attrmap & 0x07) << 2);
attrmap += *wrap + 1;
tilemap += *(wrap++) + 1;
}
else
for (i = cnt; i > 0; i--)
{
*(tilebuf++) = (256 + ((n8)*tilemap))
| (((int)*attrmap & 0x08) << 6)
| (((int)*attrmap & 0x60) << 5);
*(tilebuf++) = (((int)*attrmap & 0x07) << 2);
attrmap += *wrap + 1;
tilemap += *(wrap++) + 1;
}
}
else
{
if (R_LCDC & 0x10)
for (i = cnt; i > 0; i--)
{
*(tilebuf++) = *(tilemap++);
tilemap += *(wrap++);
}
else
for (i = cnt; i > 0; i--)
{
*(tilebuf++) = (256 + ((n8)*(tilemap++)));
tilemap += *(wrap++);
}
}
if (WX >= 160) return;
base = ((R_LCDC&0x40)?0x1C00:0x1800) + (WT<<5);
tilemap = lcd.vbank[0] + base;
attrmap = lcd.vbank[1] + base;
tilebuf = WND;
cnt = ((160 - WX) >> 3) + 1;
if (hw.cgb)
{
if (R_LCDC & 0x10)
for (i = cnt; i > 0; i--)
{
*(tilebuf++) = *(tilemap++)
| (((int)*attrmap & 0x08) << 6)
| (((int)*attrmap & 0x60) << 5);
*(tilebuf++) = (((int)*(attrmap++)&7) << 2);
}
else
for (i = cnt; i > 0; i--)
{
*(tilebuf++) = (256 + ((n8)*(tilemap++)))
| (((int)*attrmap & 0x08) << 6)
| (((int)*attrmap & 0x60) << 5);
*(tilebuf++) = (((int)*(attrmap++)&7) << 2);
}
}
else
{
if (R_LCDC & 0x10)
for (i = cnt; i > 0; i--)
*(tilebuf++) = *(tilemap++);
else
for (i = cnt; i > 0; i--)
*(tilebuf++) = (256 + ((n8)*(tilemap++)));
}
}
/* V = vertical line
* WX = WND start (if 0, no need to do anything) -> WY
* U = start...something...thingy... 7 at most
*/
void bg_scan(void)
{
int cnt;
byte *src, *dest;
int *tile;
if (WX <= 0) return;
cnt = WX;
tile = BG;
dest = BUF;
src = patpix[*(tile++)][V] + U;
memcpy(dest, src, 8-U);
dest += 8-U;
cnt -= 8-U;
if (cnt <= 0) return;
while (cnt >= 8)
{
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
asm volatile (
"move.l (%1)+,(%0)+ \n"
"move.l (%1)+,(%0)+ \n"
: /*outputs*/
: /*inputs*/
/* %0 */ "a" (dest),
/* %1 */ "a" (patpix[*(tile++)][V])
//: /* clobbers */
);
#else
src = patpix[*(tile++)][V];
memcpy(dest,src,8);
dest += 8;
#endif
cnt -= 8;
}
src = patpix[*tile][V];
while (cnt--)
*(dest++) = *(src++);
}
void wnd_scan(void)
{
int cnt;
byte *src, *dest;
int *tile;
if (WX >= 160) return;
cnt = 160 - WX;
tile = WND;
dest = BUF + WX;
while (cnt >= 8)
{
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
asm volatile (
"move.l (%1)+,(%0)+ \n"
"move.l (%1)+,(%0)+ \n"
: /*outputs*/
: /*inputs*/
/* %0 */ "a" (dest),
/* %1 */ "a" (patpix[*(tile++)][WV])
//: /* clobbers */
);
#else
src = patpix[*(tile++)][WV];
memcpy(dest,src,8);
dest += 8;
#endif
cnt -= 8;
}
src = patpix[*tile][WV];
while (cnt--)
*(dest++) = *(src++);
}
static void blendcpy(byte *dest, byte *src, byte b, int cnt)
{
while (cnt--) *(dest++) = *(src++) | b;
}
static int priused(void *attr)
{
un32 *a = attr;
return (int)((a[0]|a[1]|a[2]|a[3]|a[4]|a[5]|a[6]|a[7])&0x80808080);
}
void bg_scan_pri(void)
{
int cnt, i;
byte *src, *dest;
if (WX <= 0) return;
i = S;
cnt = WX;
dest = PRI;
src = lcd.vbank[1] + ((R_LCDC&0x08)?0x1C00:0x1800) + (T<<5);
if (!priused(src))
{
memset(dest, 0, cnt);
return;
}
memset(dest, src[i++&31]&128, 8-U);
dest += 8-U;
cnt -= 8-U;
if (cnt <= 0) return;
while (cnt >= 8)
{
memset(dest, src[i++&31]&128, 8);
dest += 8;
cnt -= 8;
}
memset(dest, src[i&31]&128, cnt);
}
void wnd_scan_pri(void)
{
int cnt, i;
byte *src, *dest;
if (WX >= 160) return;
i = 0;
cnt = 160 - WX;
dest = PRI + WX;
src = lcd.vbank[1] + ((R_LCDC&0x40)?0x1C00:0x1800) + (WT<<5);
if (!priused(src))
{
memset(dest, 0, cnt);
return;
}
while (cnt >= 8)
{
memset(dest, src[i++]&128, 8);
dest += 8;
cnt -= 8;
}
memset(dest, src[i]&128, cnt);
}
void bg_scan_color(void)
{
int cnt;
byte *src, *dest;
int *tile;
if (WX <= 0) return;
cnt = WX;
tile = BG;
dest = BUF;
src = patpix[*(tile++)][V] + U;
blendcpy(dest, src, *(tile++), 8-U);
dest += 8-U;
cnt -= 8-U;
if (cnt <= 0) return;
while (cnt >= 8)
{
src = patpix[*(tile++)][V];
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
asm volatile (
"move.l (%2)+,%%d1 \n"
"move.b %%d1,%%d2 \n"
"move.b (%1)+,%%d0 \n"
"or.l %%d2,%%d0 \n"
"move.b %%d0,(%0)+ \n"
"move.b (%1)+,%%d0 \n"
"or.l %%d1,%%d0 \n"
"move.b %%d0,(%0)+ \n"
"move.b (%1)+,%%d0 \n"
"or.l %%d2,%%d0 \n"
"move.b %%d0,(%0)+ \n"
"move.b (%1)+,%%d0 \n"
"or.l %%d2,%%d0 \n"
"move.b %%d0,(%0)+ \n"
"move.b (%1)+,%%d0 \n"
"or.l %%d2,%%d0 \n"
"move.b %%d0,(%0)+ \n"
"move.b (%1)+,%%d0 \n"
"or.l %%d2,%%d0 \n"
"move.b %%d0,(%0)+ \n"
"move.b (%1)+,%%d0 \n"
"or.l %%d2,%%d0 \n"
"move.b %%d0,(%0)+ \n"
"move.b (%1)+,%%d0 \n"
"or.l %%d2,%%d0 \n"
"move.b %%d0,(%0)+ \n"
: /*outputs*/
: /*inputs*/
/* %0 */ "a" (dest),
/* %1 */ "a" (src),
/* %2 */ "a" (tile)
: /* clobbers */
"d0", "d1", "d2"
);
#else
blendcpy(dest, src, *(tile++), 8);
dest += 8;
#endif
cnt -= 8;
}
src = patpix[*(tile++)][V];
blendcpy(dest, src, *(tile++), cnt);
}
void wnd_scan_color(void)
{
int cnt;
byte *src, *dest;
int *tile;
if (WX >= 160) return;
cnt = 160 - WX;
tile = WND;
dest = BUF + WX;
while (cnt >= 8)
{
src = patpix[*(tile++)][WV];
blendcpy(dest, src, *(tile++), 8);
dest += 8;
cnt -= 8;
}
src = patpix[*(tile++)][WV];
blendcpy(dest, src, *(tile++), cnt);
}
static void recolor(byte *buf, byte fill, int cnt)
{
while (cnt--) *(buf++) |= fill;
}
void spr_enum(void)
{
int i, j;
struct obj *o;
struct vissprite ts;
int v, pat;
NS = 0;
if (!(R_LCDC & 0x02)) return;
o = lcd.oam.obj;
for (i = 40; i; i--, o++)
{
if (L >= o->y || L + 16 < o->y)
continue;
if (L + 8 >= o->y && !(R_LCDC & 0x04))
continue;
VS[NS].x = (int)o->x - 8;
v = L - (int)o->y + 16;
if (hw.cgb)
{
pat = o->pat | (((int)o->flags & 0x60) << 5)
| (((int)o->flags & 0x08) << 6);
VS[NS].pal = 32 + ((o->flags & 0x07) << 2);
}
else
{
pat = o->pat | (((int)o->flags & 0x60) << 5);
VS[NS].pal = 32 + ((o->flags & 0x10) >> 2);
}
VS[NS].pri = (o->flags & 0x80) >> 7;
if ((R_LCDC & 0x04))
{
pat &= ~1;
if (v >= 8)
{
v -= 8;
pat++;
}
if (o->flags & 0x40) pat ^= 1;
}
VS[NS].buf = patpix[pat][v];
if (++NS == 10) break;
}
if (hw.cgb) return;
for (i = 0; i < NS; i++)
{
for (j = i + 1; j < NS; j++)
{
if (VS[i].x > VS[j].x)
{
ts = VS[i];
VS[i] = VS[j];
VS[j] = ts;
}
}
}
}
void spr_scan(void)
{
int i, x;
byte pal, b, ns = NS;
byte *src, *dest, *bg, *pri;
struct vissprite *vs;
static byte bgdup[256];
if (!ns) return;
memcpy(bgdup, BUF, 256);
vs = &VS[ns-1];
for (; ns; ns--, vs--)
{
x = vs->x;
if (x > 159) continue;
if (x < -7) continue;
if (x < 0)
{
src = vs->buf - x;
dest = BUF;
i = 8 + x;
}
else
{
src = vs->buf;
dest = BUF + x;
if (x > 152) i = 160 - x;
else i = 8;
}
pal = vs->pal;
if (vs->pri)
{
bg = bgdup + (dest - BUF);
while (i--)
{
b = src[i];
if (b && !(bg[i]&3)) dest[i] = pal|b;
}
}
else if (hw.cgb)
{
bg = bgdup + (dest - BUF);
pri = PRI + (dest - BUF);
while (i--)
{
b = src[i];
if (b && (!pri[i] || !(bg[i]&3)))
dest[i] = pal|b;
}
}
else while (i--) if (src[i]) dest[i] = pal|src[i];
}
}
/* Scaling defines */
#define DX ((LCD_WIDTH<<16) / 160)
#define DXI ((160<<16) / LCD_WIDTH)
#define DY ((LCD_HEIGHT<<16) / 144)
#define DYI ((144<<16) / LCD_HEIGHT)
void lcd_begin(void)
{
#if (LCD_WIDTH>=160) && (LCD_HEIGHT>=144)
#define S1 ((LCD_HEIGHT-144)/2)*LCD_WIDTH + ((LCD_WIDTH-160)/2)
#define S2 0
#elif (LCD_WIDTH>=160) && (LCD_HEIGHT<=144)
#define S1 ((LCD_WIDTH-160)/2)
#define S2 ((LCD_WIDTH-160)/2)
#elif (LCD_WIDTH<=160) && (LCD_HEIGHT>=144)
#define S1 ((LCD_HEIGHT-144)/2)*LCD_WIDTH
#define S2 ((LCD_HEIGHT-144)/2)*LCD_WIDTH
#else
#define S1 0
#define S2 0
#endif
#if (LCD_WIDTH>LCD_HEIGHT)
#define S3 ((LCD_WIDTH-(160*LCD_HEIGHT/144))/2)
#else
#define S3 ((LCD_HEIGHT-(144*LCD_WIDTH/160))/2)*LCD_WIDTH
#endif
set_pal();
if(options.fullscreen == 0)
vdest=fb.ptr+S1;
else if (options.fullscreen == 1)
vdest=fb.ptr+S2;
else
vdest=fb.ptr+S3;
WY = R_WY;
}
int SCALEWL IDATA_ATTR=1<<16;
int SCALEWS IDATA_ATTR=1<<16;
int SCALEHL IDATA_ATTR=1<<16;
int SCALEHS IDATA_ATTR=1<<16;
int swidth IDATA_ATTR=160;
int sremain IDATA_ATTR=LCD_WIDTH-160;
void setvidmode(int mode)
{
switch(mode)
{
case 1:
#if (LCD_WIDTH>=160) && (LCD_HEIGHT>=144) /* Full screen scale */
SCALEWL=DX;
SCALEWS=DXI;
SCALEHL=DY;
SCALEHS=DYI;
#elif (LCD_WIDTH>=160) && (LCD_HEIGHT<144) /* scale the height */
SCALEWL=1<<16;
SCALEWS=1<<16;
SCALEHL=DY;
SCALEHS=DYI;
#elif (LCD_WIDTH<160) && (LCD_HEIGHT>=144) /* scale the width */
SCALEWL=DX;
SCALEWS=DXI;
SCALEHL=1<<16;
SCALEHS=1<<16;
#else
SCALEWL=DX;
SCALEWS=DXI;
SCALEHL=DY;
SCALEHS=DYI;
#endif
break;
case 2: /* Maintain Ratio */
if (DY<DX)
{
SCALEWL=DY;
SCALEWS=DYI;
SCALEHL=DY;
SCALEHS=DYI;
}
else
{
SCALEWL=DX;
SCALEWS=DXI;
SCALEHL=DX;
SCALEHS=DXI;
}
break;
default:
SCALEWL=1<<16;
SCALEWS=1<<16;
SCALEHL=1<<16;
SCALEHS=1<<16;
}
swidth=(160*SCALEWL)>>16;
sremain=LCD_WIDTH-swidth;
}
void lcd_refreshline(void)
{
#ifdef HAVE_LCD_COLOR
char frameout[30];
#endif
if (!(R_LCDC & 0x80))
return; /* should not happen... */
#if (LCD_HEIGHT <= 128) && !defined(HAVE_LCD_COLOR)
if ( (fb.mode==0&&(R_LY >= 128)) ||
(fb.mode==1&&(R_LY < 16)) ||
(fb.mode==2&&(R_LY<8||R_LY>=136)) ||
(fb.mode==3&&((R_LY%9)==8))
#if LCD_HEIGHT == 64
|| (R_LY & 1) /* calculate only even lines */
#endif
)
return;
#endif
updatepatpix();
L = R_LY;
X = R_SCX;
Y = (R_SCY + L) & 0xff;
S = X >> 3;
T = Y >> 3;
U = X & 7;
V = Y & 7;
WX = R_WX - 7;
if (WY>L || WY<0 || WY>143 || WX<-7 || WX>159 || !(R_LCDC&0x20))
WX = 160;
WT = (L - WY) >> 3;
WV = (L - WY) & 7;
spr_enum();
tilebuf();
if (hw.cgb)
{
bg_scan_color();
wnd_scan_color();
if (NS)
{
bg_scan_pri();
wnd_scan_pri();
}
}
else
{
bg_scan();
wnd_scan();
recolor(BUF+WX, 0x04, 160-WX);
}
spr_scan();
#if !defined(HAVE_LCD_COLOR)
#if LCD_DEPTH == 1
if (scanline_ind == 7)
#elif LCD_DEPTH == 2
if (scanline_ind == 3)
#endif
{
if(fb.mode!=3)
vid_update(L);
else
vid_update(L-((int)(L/9)));
#else
{
/* Universal Scaling pulled from PrBoom and modified for rockboy */
static int hpt IDATA_ATTR=0x8000;
while((hpt>>16)<L+1)
{
hpt+=SCALEHS;
register unsigned int srcpt=0x8000;
register unsigned int wcount=swidth;
register unsigned int remain=sremain;
while(wcount--)
{
#if LCD_HEIGHT<144 /* cut off the bottom part of the screen that won't fit */
if (options.fullscreen==0 && (hpt>>16)>LCD_HEIGHT)
break;
#endif
#if LCD_WIDTH<160 /* cut off the right part of the screen that won't fit */
if(options.fullscreen==0 && wcount<(160-LCD_WIDTH)) {
vdest+=wcount;
wcount = 0;
}
#endif
*vdest++ = PAL[BUF[srcpt>>16]];
srcpt+=SCALEWS;
}
#if LCD_HEIGHT<144
if (options.fullscreen!=0 || (hpt>>16)<(LCD_HEIGHT))
#endif
vdest+=remain;
}
if(L==143)
{
if(options.showstats)
{
snprintf(frameout,sizeof(frameout),"FPS: %d Frameskip: %d ",options.fps, options.frameskip);
rb->lcd_putsxy(0,LCD_HEIGHT-10,frameout);
}
hpt=0x8000;
rb->lcd_update();
}
#endif
}
#if LCD_DEPTH == 1
scanline_ind = (scanline_ind+1) % 8;
#elif LCD_DEPTH == 2
scanline_ind = (scanline_ind+1) % 4;
#endif
}
void set_pal(void)
{
memcpy(dmg_pal,palettes[options.pal], sizeof dmg_pal);
pal_dirty();
}
#if HAVE_LCD_COLOR
static void updatepalette(int i)
{
int c, r, g, b;
c = (lcd.pal[i<<1] | ((int)lcd.pal[(i<<1)|1] << 8)) & 0x7FFF;
r = (c & 0x001F) << 3;
g = (c & 0x03E0) >> 2;
b = (c & 0x7C00) >> 7;
r |= (r >> 5);
g |= (g >> 5);
b |= (b >> 5);
r = (r >> fb.cc[0].r) << fb.cc[0].l;
g = (g >> fb.cc[1].r) << fb.cc[1].l;
b = (b >> fb.cc[2].r) << fb.cc[2].l;
#if LCD_PIXELFORMAT == RGB565
c = r|g|b;
#elif LCD_PIXELFORMAT == RGB565SWAPPED
c = swap16(r|g|b);
#endif
PAL[i] = c;
}
#endif
void pal_write(int i, byte b)
{
if (lcd.pal[i] == b) return;
lcd.pal[i] = b;
#if LCD_DEPTH ==16
updatepalette(i>>1);
#endif
}
void pal_write_dmg(int i, int mapnum, byte d)
{
int j;
int *cmap = dmg_pal[mapnum];
int c, r, g, b;
if (hw.cgb) return;
for (j = 0; j < 8; j += 2)
{
c = cmap[(d >> j) & 3];
r = (c & 0xf8) >> 3;
g = (c & 0xf800) >> 6;
b = (c & 0xf80000) >> 9;
c = r|g|b;
/* FIXME - handle directly without faking cgb */
pal_write(i+j, c & 0xff);
pal_write(i+j+1, c >> 8);
}
}
void vram_write(addr a, byte b)
{
lcd.vbank[R_VBK&1][a] = b;
if (a >= 0x1800) return;
patdirty[((R_VBK&1)<<9)+(a>>4)] = 1;
anydirty = 1;
}
void vram_dirty(void)
{
anydirty = 1;
memset(patdirty, 1, sizeof patdirty);
}
void pal_dirty(void)
{
#if LCD_DEPTH ==16
int i;
#endif
if (!hw.cgb)
{
pal_write_dmg(0, 0, R_BGP);
pal_write_dmg(8, 1, R_BGP);
pal_write_dmg(64, 2, R_OBP0);
pal_write_dmg(72, 3, R_OBP1);
}
#if LCD_DEPTH ==16
for (i = 0; i < 64; i++)
updatepalette(i);
#endif
}
void lcd_reset(void)
{
memset(&lcd, 0, sizeof lcd);
lcd_begin();
vram_dirty();
}