mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 07:17:45 -04:00
sms vdp, separate SAT parsing
This commit is contained in:
parent
f55ce7bf47
commit
1ce2b0923c
3 changed files with 111 additions and 49 deletions
127
pico/mode4.c
127
pico/mode4.c
|
@ -20,6 +20,14 @@ static int skip_next_line;
|
|||
static int screen_offset, line_offset;
|
||||
static u8 mode;
|
||||
|
||||
static unsigned int sprites_addr[32]; // bitmap address
|
||||
static unsigned char sprites_c[32]; // TMS sprites color
|
||||
static int sprites_x[32]; // x position
|
||||
static int sprites; // count
|
||||
static unsigned char sprites_map[2+256/8+2]; // collision detection map
|
||||
|
||||
unsigned int sprites_status;
|
||||
|
||||
/* sprite collision detection */
|
||||
static int CollisionDetect(u8 *mb, u16 sx, unsigned int pack, int zoomed)
|
||||
{
|
||||
|
@ -139,17 +147,14 @@ static void TileDoubleSprM4(int sx, unsigned int pack, int pal)
|
|||
PLANAR_PIXELSP(15, 7)
|
||||
}
|
||||
|
||||
static void DrawSpritesM4(int scanline)
|
||||
static void ParseSpritesM4(int scanline)
|
||||
{
|
||||
struct PicoVideo *pv = &Pico.video;
|
||||
unsigned char mb[1+256/8+2] = {0}; // zoomed
|
||||
unsigned int sprites_addr[64];
|
||||
unsigned int sprites_x[64];
|
||||
unsigned int pack;
|
||||
u8 *sat;
|
||||
int xoff = 8; // relative to HighCol, which is (screen - 8)
|
||||
int sprite_base, addr_mask;
|
||||
int zoomed = pv->reg[1] & 0x1; // zoomed sprites, e.g. Earthworm Jim
|
||||
unsigned int pack;
|
||||
int i, s, h, m;
|
||||
|
||||
if (pv->reg[0] & 8)
|
||||
|
@ -157,7 +162,6 @@ static void DrawSpritesM4(int scanline)
|
|||
xoff += line_offset;
|
||||
if ((Pico.m.hardware & 0x3) == 0x3)
|
||||
xoff -= 48; // GG LCD, adjust to center 160 px
|
||||
scanline --;
|
||||
|
||||
sat = (u8 *)PicoMem.vram + ((pv->reg[5] & 0x7e) << 7);
|
||||
if (pv->reg[1] & 2) {
|
||||
|
@ -168,6 +172,8 @@ static void DrawSpritesM4(int scanline)
|
|||
if (zoomed) h *= 2;
|
||||
sprite_base = (pv->reg[6] & 4) << (13-2-1);
|
||||
|
||||
m = 0;
|
||||
memset(sprites_map, 0, sizeof(sprites_map));
|
||||
for (i = s = 0; i < 64; i++)
|
||||
{
|
||||
int y;
|
||||
|
@ -180,8 +186,8 @@ static void DrawSpritesM4(int scanline)
|
|||
if (y + h <= scanline || scanline < y)
|
||||
continue; // not on this line
|
||||
if (s >= 8) {
|
||||
pv->status |= SR_SOVR;
|
||||
if (!(PicoIn.opt & POPT_DIS_SPRITE_LIM) || s >= 64)
|
||||
if (scanline >= 0) sprites_status |= SR_SOVR;
|
||||
if (!(PicoIn.opt & POPT_DIS_SPRITE_LIM) || s >= 32)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -189,22 +195,34 @@ static void DrawSpritesM4(int scanline)
|
|||
sprites_x[s] = xoff + sat[MEM_LE2(0x80 + i*2)];
|
||||
sprites_addr[s] = sprite_base + ((sat[MEM_LE2(0x80 + i*2 + 1)] & addr_mask) << (5-1)) +
|
||||
((scanline - y) >> zoomed << (2-1));
|
||||
if (Pico.video.reg[1] & 0x40) {
|
||||
// collision detection. Do it here since off-screen lines aren't drawn
|
||||
pack = CPU_LE2(*(u32 *)(PicoMem.vram + sprites_addr[s]));
|
||||
// make sprite pixel map by merging the 4 bitplanes
|
||||
pack = ((pack | (pack>>16)) | ((pack | (pack>>16))>>8)) & 0xff;
|
||||
if (!m) m = CollisionDetect(sprites_map, sprites_x[s], pack, zoomed);
|
||||
}
|
||||
s++;
|
||||
}
|
||||
}
|
||||
if (m)
|
||||
sprites_status |= SR_C;
|
||||
sprites = s;
|
||||
}
|
||||
|
||||
static void DrawSpritesM4(void)
|
||||
{
|
||||
struct PicoVideo *pv = &Pico.video;
|
||||
unsigned int pack;
|
||||
int zoomed = pv->reg[1] & 0x1; // zoomed sprites, e.g. Earthworm Jim
|
||||
int s = sprites;
|
||||
|
||||
// now draw all sprites backwards
|
||||
m = 0;
|
||||
for (--s; s >= 0; s--) {
|
||||
pack = CPU_LE2(*(u32 *)(PicoMem.vram + sprites_addr[s]));
|
||||
if (zoomed) TileDoubleSprM4(sprites_x[s], pack, 0x10);
|
||||
else TileNormSprM4(sprites_x[s], pack, 0x10);
|
||||
// make sprite pixel map by merging the 4 bitplanes
|
||||
pack = ((pack | (pack>>16)) | ((pack | (pack>>16))>>8)) & 0xff;
|
||||
if (!m) m = CollisionDetect(mb, sprites_x[s], pack, zoomed);
|
||||
}
|
||||
if (m)
|
||||
pv->status |= SR_C;
|
||||
}
|
||||
|
||||
// cells_dx, tilex_ty merged to reduce register pressure
|
||||
|
@ -295,7 +313,7 @@ static void DrawDisplayM4(int scanline)
|
|||
|
||||
// sprites
|
||||
if (!(pv->debug_p & PVD_KILL_S_LO))
|
||||
DrawSpritesM4(scanline);
|
||||
DrawSpritesM4();
|
||||
|
||||
if ((pv->reg[0] & 0x20) && (Pico.m.hardware & 0x3) != 0x3) {
|
||||
// first column masked with background, caculate offset to start of line
|
||||
|
@ -376,13 +394,9 @@ static void TileDoubleSprTMS(u16 sx, unsigned int pack, int pal)
|
|||
TMS_PIXELSP(15, 7)
|
||||
}
|
||||
|
||||
/* Draw sprites into a scanline, max 4 */
|
||||
static void DrawSpritesTMS(int scanline)
|
||||
static void ParseSpritesTMS(int scanline)
|
||||
{
|
||||
struct PicoVideo *pv = &Pico.video;
|
||||
unsigned char mb[1+256/8+4] = {0}; // zoomed+doublesize
|
||||
unsigned int sprites_addr[32];
|
||||
unsigned int sprites_x[32];
|
||||
unsigned int pack;
|
||||
u8 *sat;
|
||||
int xoff = 8; // relative to HighCol, which is (screen - 8)
|
||||
|
@ -391,7 +405,6 @@ static void DrawSpritesTMS(int scanline)
|
|||
int i, s, h, m;
|
||||
|
||||
xoff += line_offset;
|
||||
scanline --;
|
||||
|
||||
sat = (u8 *)PicoMem.vramb + ((pv->reg[5] & 0x7e) << 7);
|
||||
if (pv->reg[1] & 2) {
|
||||
|
@ -400,13 +413,14 @@ static void DrawSpritesTMS(int scanline)
|
|||
addr_mask = 0xff; h = 8;
|
||||
}
|
||||
if (zoomed) h *= 2;
|
||||
|
||||
sprite_base = (pv->reg[6] & 0x7) << 11;
|
||||
|
||||
m = 0;
|
||||
memset(sprites_map, 0, sizeof(sprites_map));
|
||||
/* find sprites on this scanline */
|
||||
for (i = s = 0; i < 32; i++)
|
||||
{
|
||||
int y;
|
||||
int x, y;
|
||||
y = sat[MEM_LE2(4*i)];
|
||||
if (y == 0xd0)
|
||||
break;
|
||||
|
@ -416,42 +430,62 @@ static void DrawSpritesTMS(int scanline)
|
|||
if (y + h <= scanline || scanline < y)
|
||||
continue; // not on this line
|
||||
if (s >= 4) {
|
||||
pv->status |= SR_SOVR | i;
|
||||
if (scanline >= 0) sprites_status |= SR_SOVR | i;
|
||||
if (!(PicoIn.opt & POPT_DIS_SPRITE_LIM) || s >= 32)
|
||||
break;
|
||||
}
|
||||
x = sat[MEM_LE2(4*i+1)] + xoff;
|
||||
if (sat[MEM_LE2(4*i+3)] & 0x80)
|
||||
x -= 32;
|
||||
|
||||
sprites_x[s] = 4*i;
|
||||
sprites_c[s] = sat[MEM_LE2(4*i+3)] & 0x0f;
|
||||
sprites_x[s] = x;
|
||||
sprites_addr[s] = sprite_base + ((sat[MEM_LE2(4*i + 2)] & addr_mask) << 3) +
|
||||
((scanline - y) >> zoomed);
|
||||
if (Pico.video.reg[1] & 0x40) {
|
||||
// collision detection. Do it here since off-screen lines aren't drawn
|
||||
if (sprites_c[s] && x > 0) {
|
||||
pack = PicoMem.vramb[MEM_LE2(sprites_addr[s])];
|
||||
if (!m) m = CollisionDetect(sprites_map, x, pack, zoomed);
|
||||
}
|
||||
x += (zoomed ? 16:8);
|
||||
if (sprites_c[s] && (pv->reg[1] & 0x2) && x > 0 && x < 8+256) {
|
||||
pack = PicoMem.vramb[MEM_LE2(sprites_addr[s]+0x10)];
|
||||
if (!m) m = CollisionDetect(sprites_map, x, pack, zoomed);
|
||||
}
|
||||
}
|
||||
s++;
|
||||
}
|
||||
if (m)
|
||||
sprites_status |= SR_C;
|
||||
sprites = s;
|
||||
}
|
||||
|
||||
/* Draw sprites into a scanline, max 4 */
|
||||
static void DrawSpritesTMS(void)
|
||||
{
|
||||
struct PicoVideo *pv = &Pico.video;
|
||||
unsigned int pack;
|
||||
int zoomed = pv->reg[1] & 0x1; // zoomed sprites
|
||||
int s = sprites;
|
||||
|
||||
// now draw all sprites backwards
|
||||
m = 0;
|
||||
for (--s; s >= 0; s--) {
|
||||
int x, c, w = (zoomed ? 16: 8);
|
||||
i = sprites_x[s];
|
||||
x = sat[MEM_LE2(i+1)] + xoff;
|
||||
if (sat[MEM_LE2(i+3)] & 0x80)
|
||||
x -= 32;
|
||||
c = sat[MEM_LE2(i+3)] & 0x0f;
|
||||
x = sprites_x[s];
|
||||
c = sprites_c[s];
|
||||
// c may be 0 (transparent): sprite invisible
|
||||
if (x > 0) {
|
||||
if (c && x > 0) {
|
||||
pack = PicoMem.vramb[MEM_LE2(sprites_addr[s])];
|
||||
if (zoomed && c) TileDoubleSprTMS(x, pack, c);
|
||||
else if (c) TileNormSprTMS(x, pack, c);
|
||||
if (!m) m = CollisionDetect(mb, x, pack, zoomed);
|
||||
if (zoomed) TileDoubleSprTMS(x, pack, c);
|
||||
else TileNormSprTMS(x, pack, c);
|
||||
}
|
||||
if((pv->reg[1] & 0x2) && (x+=w) > 0 && x < 8+256) {
|
||||
if (c && (pv->reg[1] & 0x2) && (x+=w) > 0 && x < 8+256) {
|
||||
pack = PicoMem.vramb[MEM_LE2(sprites_addr[s]+0x10)];
|
||||
if (zoomed && c) TileDoubleSprTMS(x, pack, c);
|
||||
else if (c) TileNormSprTMS(x, pack, c);
|
||||
if (!m) m = CollisionDetect(mb, x, pack, zoomed);
|
||||
if (zoomed) TileDoubleSprTMS(x, pack, c);
|
||||
else TileNormSprTMS(x, pack, c);
|
||||
}
|
||||
}
|
||||
if (m)
|
||||
pv->status |= SR_C;
|
||||
}
|
||||
|
||||
/* Mode 2 */
|
||||
|
@ -501,7 +535,7 @@ static void DrawDisplayM2(int scanline)
|
|||
|
||||
// sprites
|
||||
if (!(pv->debug_p & PVD_KILL_S_LO))
|
||||
DrawSpritesTMS(scanline);
|
||||
DrawSpritesTMS();
|
||||
}
|
||||
|
||||
/* Mode 0 */
|
||||
|
@ -550,7 +584,7 @@ static void DrawDisplayM0(int scanline)
|
|||
|
||||
// sprites
|
||||
if (!(pv->debug_p & PVD_KILL_S_LO))
|
||||
DrawSpritesTMS(scanline);
|
||||
DrawSpritesTMS();
|
||||
}
|
||||
|
||||
|
||||
|
@ -609,6 +643,7 @@ void PicoFrameStartSMS(void)
|
|||
emu_video_mode_change(loffs, lines, coffs, columns);
|
||||
rendstatus_old = Pico.est.rendstatus;
|
||||
rendlines = lines;
|
||||
sprites = 0;
|
||||
}
|
||||
|
||||
Pico.est.HighCol = HighColBase + screen_offset * HighColIncrement;
|
||||
|
@ -621,6 +656,12 @@ void PicoFrameStartSMS(void)
|
|||
}
|
||||
}
|
||||
|
||||
void PicoParseSATSMS(int line)
|
||||
{
|
||||
if (Pico.video.reg[0] & 0x04) ParseSpritesM4(line);
|
||||
else ParseSpritesTMS(line);
|
||||
}
|
||||
|
||||
void PicoLineSMS(int line)
|
||||
{
|
||||
int skip = skip_next_line;
|
||||
|
|
|
@ -704,6 +704,7 @@ PICO_INTERNAL void PicoFrameFull();
|
|||
|
||||
// mode4.c
|
||||
void PicoFrameStartSMS(void);
|
||||
void PicoParseSATSMS(int line);
|
||||
void PicoLineSMS(int line);
|
||||
void PicoDoHighPal555SMS(void);
|
||||
void PicoDrawSetOutputSMS(pdso_t which);
|
||||
|
|
30
pico/sms.c
30
pico/sms.c
|
@ -20,6 +20,7 @@
|
|||
extern void YM2413_regWrite(unsigned reg);
|
||||
extern void YM2413_dataWrite(unsigned data);
|
||||
|
||||
extern unsigned sprites_status; // TODO put in some hdr file!
|
||||
|
||||
static unsigned char vdp_data_read(void)
|
||||
{
|
||||
|
@ -682,9 +683,15 @@ void PicoFrameMS(void)
|
|||
PicoFrameStartSMS();
|
||||
hint = pv->reg[0x0a];
|
||||
|
||||
// SMS: xscroll:f3 sprovr,vint, vcount:fc, hint:fd
|
||||
// GG: xscroll:f5 sprovr,vint:fd vcount:fe, hint:ff
|
||||
for (y = 0; y < lines; y++)
|
||||
{
|
||||
pv->v_counter = Pico.m.scanline = y;
|
||||
Pico.t.z80c_line_start = Pico.t.z80c_aim;
|
||||
|
||||
// advance the line counter. It is set back at some point in the VBLANK so
|
||||
// that the line count in the active area (-32..lines+1) is contiguous.
|
||||
pv->v_counter = Pico.m.scanline = (u8)y;
|
||||
switch (is_pal ? -lines_vis : lines_vis) {
|
||||
case 192: if (y > 218) pv->v_counter = y - (lines-256); break;
|
||||
case 224: if (y > 234) pv->v_counter = y - (lines-256); break;
|
||||
|
@ -693,14 +700,24 @@ void PicoFrameMS(void)
|
|||
case -240: if (y > 266) pv->v_counter = y - (lines-256); break;
|
||||
}
|
||||
|
||||
// Parse sprites for the next line
|
||||
if (y < lines_vis)
|
||||
PicoParseSATSMS(y-1);
|
||||
else if (y > lines-32)
|
||||
PicoParseSATSMS(y-1-lines);
|
||||
|
||||
// render next line
|
||||
if (y < lines_vis && !skip)
|
||||
PicoLineSMS(y);
|
||||
|
||||
Pico.t.z80c_line_start = Pico.t.z80c_aim;
|
||||
// take over status bits from previously rendered line TODO: cycle exact?
|
||||
pv->status |= sprites_status;
|
||||
sprites_status = 0;
|
||||
|
||||
// Interrupt handling. Simulate interrupt flagged and immediately reset in
|
||||
// same insn by flagging the irq, execute for 1 insn, then checking if the
|
||||
// irq is still pending. (GG Chicago, SMS Back to the Future III)
|
||||
pv->pending_ints &= ~2; // lost if not caught in the same line
|
||||
if (y <= lines_vis)
|
||||
{
|
||||
if (--hint < 0)
|
||||
|
@ -713,11 +730,9 @@ void PicoFrameMS(void)
|
|||
elprintf(EL_INTS, "hint");
|
||||
z80_int_assert(1);
|
||||
}
|
||||
pv->pending_ints &= ~2; // lost if not caught immediately
|
||||
}
|
||||
}
|
||||
else if (y == lines_vis + 1) {
|
||||
pv->pending_ints &= ~2;
|
||||
pv->pending_ints |= 1;
|
||||
z80_exec(Pico.t.z80c_cnt + 1);
|
||||
|
||||
|
@ -736,13 +751,18 @@ void PicoFrameMS(void)
|
|||
|
||||
void PicoFrameDrawOnlyMS(void)
|
||||
{
|
||||
struct PicoVideo *pv = &Pico.video;
|
||||
int lines_vis = 192;
|
||||
int y;
|
||||
|
||||
if ((pv->reg[0] & 6) == 6 && (pv->reg[1] & 0x18))
|
||||
lines_vis = (pv->reg[1] & 0x08) ? 240 : 224;
|
||||
PicoFrameStartSMS();
|
||||
|
||||
for (y = 0; y < lines_vis; y++)
|
||||
for (y = 0; y < lines_vis; y++) {
|
||||
PicoParseSATSMS(y-1);
|
||||
PicoLineSMS(y);
|
||||
}
|
||||
}
|
||||
|
||||
// vim:ts=2:sw=2:expandtab
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue