Prepare for new BG processors

This commit is contained in:
Guy Perfect 2024-10-24 10:59:11 -05:00
parent bcd80d291b
commit 67bcb6d508
1 changed files with 161 additions and 120 deletions

View File

@ -54,6 +54,32 @@ static const uint8_t BRIGHT8[] = {
/*********************************** Types ***********************************/
/* World attribtues per eye */
typedef struct {
int32_t bp; /* BG source parallax */
int32_t left, right; /* Window bounds */
int32_t wx; /* World horizontal position */
} EyeAttribs;
/* Parsed world attributes */
typedef struct {
int32_t base; /* Base BG map index */
uint8_t *bg; /* Background template */
int32_t bgm; /* World type */
int32_t bgw, bgh; /* Background dimension masks */
int32_t bottom, top; /* Window bounds */
int32_t gx, gp, gy; /* World screen position */
int32_t mx, mp, my; /* Background scroll */
int32_t over; /* Overplane flag */
uint32_t params; /* Line parameters address */
int32_t scx, scy; /* Background dimensions */
int32_t w, h; /* Window size */
} WorldAttribs;
/***************************** Module Functions ******************************/
/* Retrieve a pointer to character data in host memory */
@ -597,6 +623,88 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) {
/****************************** Pixel Processor ******************************/
/* Parse eye attributes and test window bounds */
static int vipParseEye(WorldAttribs *wttr, EyeAttribs *ettr, int eye) {
/* Validate the world isn't right of frame */
ettr->wx = wttr->gx - (eye == 0 ? wttr->gp : -wttr->gp);
if (ettr->wx > 383)
return 1;
ettr->left = ettr->wx < 0 ? 0 : ettr->wx;
/* Validate the world isn't left of frame */
ettr->right = ettr->wx + wttr->w - 1;
if (ettr->right < 0)
return 1;
if (ettr->right > 383)
ettr->right = 383;
/* BG source parallax */
if (wttr->bgm != 2)
ettr->bp = eye == 0 ? -wttr->mp : wttr->mp;
return 0;
}
/* Parse world attributes and test window bounds */
static int vipParseWorld(VB*sim,uint8_t*world,uint16_t bits,WorldAttribs*attr){
int32_t z; /* Scratch */
/* Validate the world isn't below the frame */
attr->gy = busReadBuffer(world + 6, VB_S16);
if (attr->gy > 223)
return 1;
/* Validate the world isn't above the frame, and height is positive */
attr->bgm = bits >> 12 & 3;
attr->h = busReadBuffer(world + 16, VB_S16) + 1;
z = attr->bgm == 2 ? 0 : 8;
if (attr->h < z)
attr->h = z;
if (attr->h == 0)
return 1;
attr->bottom = attr->gy + attr->h - 1;
attr->top = (int32_t) sim->vip.xp.sbcount << 3;
if (attr->bottom < attr->top)
return 1;
if (attr->bottom > 223)
attr->bottom = 223;
if (attr->top < attr->gy)
attr->top = attr->gy;
/* Validate width is positive */
attr->w = SignExtend(busReadBuffer(world + 14, VB_U16),
attr->bgm == 2 ? 10 : 13) + 1;
if (attr->w < 1)
return 1;
/* Parse attributes */
attr->bg = (uint8_t *) BG_TEMPLATES[bits >> 8 & 15];
attr->gx = SignExtend(busReadBuffer(world + 2, VB_U16), 10);
attr->gp = SignExtend(busReadBuffer(world + 4, VB_U16), 10);
attr->over = bits >> 7 & 1;
attr->scx = bits >> 10 & 3;
attr->scy = bits >> 8 & 3;
attr->bgw = (1 << attr->scx) - 1;
attr->bgh = (1 << attr->scy) - 1;
z = attr->scx + attr->scy;
attr->base = bits & 15 & ~((1 << (z < 3 ? z : 3)) - 1);
if (attr->bgm != 2) {
attr->mx = SignExtend(busReadBuffer(world + 8, VB_U16), 13);
attr->mp = SignExtend(busReadBuffer(world + 10, VB_U16), 15);
attr->my = SignExtend(busReadBuffer(world + 12, VB_U16), 13);
}
if (attr->bgm != 0) {
attr->params =
0x20000 +
(attr->top - attr->gy) * (attr->bgm == 1 ? 4 : 16) +
((uint32_t) busReadBuffer(world + 18, VB_U16) << 1)
;
}
return 0;
}
/* Draw an object group into shadow memory */
static void vipDrawObjects(VB *sim, int group) {
uint8_t *dest; /* Pointer to object position in shadow memory */
@ -687,124 +795,56 @@ static void vipDrawObjects(VB *sim, int group) {
}
/* Draw a background world into shadow memory */
static void vipDrawWorld(VB *sim, uint8_t *world, uint16_t attr) {
uint8_t *bg; /* Background arrangement */
uint16_t bgAttr; /* BG map cell attributes */
int32_t bgh; /* Height of background in BG maps, minus 1 */
int32_t bgw; /* Width of background in BG maps, minus 1 */
int32_t bottom; /* Window bottom edge position */
int32_t bp; /* Eye BG map source parallax */
int32_t bx; /* BG horizontal map source position */
int32_t by; /* BG vertical map source position */
uint8_t *cell; /* Pointer to BG map cell in host memory */
uint8_t *chr; /* Pointer to character data in host memory */
int32_t cx; /* BG cell/character horizontal pixel source position */
int32_t cy; /* BG cell/character vertical pixel source position */
uint8_t *dest; /* Pointer to output in shadow memory */
int32_t left; /* Window left edge position */
uint32_t param; /* Current line parameter address */
int8_t pixel; /* Character pixel value */
int32_t right; /* Window right edge position */
int32_t top; /* Window top edge position */
int32_t wx; /* Eye horizontal position */
int32_t i, x, y; /* Iterators */
static void vipDrawWorld(VB *sim, uint8_t *world, uint16_t bits) {
uint16_t bgAttr; /* BG map cell attributes */
int32_t bx; /* BG source X */
int32_t by; /* BG source Y */
uint8_t *cell; /* Pointer to BG map cell in host memory */
uint8_t *chr; /* Pointer to character data in host memory */
int32_t cx; /* BG cell/character source X */
int32_t cy; /* BG cell/character source Y */
uint8_t *dest; /* Pointer to output in shadow memory */
EyeAttribs ettr; /* Eye attributes */
uint32_t param; /* Current line parameter address */
int8_t pixel; /* Character pixel value */
int32_t i, x, y; /* Iterators */
/* World attributes */
int32_t base; /* BG map base index */
int bgm; /* BG mode */
int32_t dx; /* Affine per-pixel X delta */
int32_t dy; /* Affine per-pixel Y delta */
int16_t gp; /* Window stereo parallax */
int16_t gx; /* Window base horizontal position */
int16_t gy; /* Window vertical position */
int16_t h; /* Window height */
int16_t hofst; /* H-bias shift */
int32_t mp; /* BG map source stereo parallax */
int32_t mx = 0; /* BG map horizontal source */
int32_t my = 0; /* BG map vertical source */
int32_t scx; /* Background width shift amount */
int32_t scy; /* Background height shift amount */
uint8_t *over; /* Pointer to overplane "cell" in host memory */
uint32_t params = 0; /* Base address of line parameters */
int16_t w; /* Window width */
WorldAttribs wttr; /* Common attributes */
int32_t dx; /* Affine per-pixel X delta */
int32_t dy; /* Affine per-pixel Y delta */
int32_t mp; /* BG source parallax */
int32_t mx; /* BG source X */
int32_t my; /* BG source Y */
int16_t hofst; /* H-bias shift */
/* Validate the world isn't below the frame */
gy = busReadBuffer(world + 6, VB_S16);
if (gy > 223)
return;
/* Validate the world isn't above the frame, and height is positive */
bgm = attr >> 12 & 3;
y = bgm == 2 ? 0 : 8;
h = busReadBuffer(world + 16, VB_S16) + 1;
if (h < y)
h = y;
if (h == 0)
return;
bottom = gy + h - 1;
top = (int32_t) sim->vip.xp.sbcount << 3;
if (bottom < top)
return;
if (bottom > 223)
bottom = 223;
if (top < gy)
top = gy;
/* Validate width is positive */
w = SignExtend(busReadBuffer(world + 14, VB_U16), bgm == 2 ? 10 : 13) + 1;
if (w < 1)
return;
/* Working variables */
ettr.bp = wttr.mp = wttr.mx = wttr.my = wttr.params = 0;
/* Parse attributes */
bg = (uint8_t *) BG_TEMPLATES[attr >> 8 & 15];
gx = SignExtend(busReadBuffer(world + 2, VB_U16), 10);
gp = SignExtend(busReadBuffer(world + 4, VB_U16), 10);
over = (attr & 0x0080) ? world + 20 : NULL;
scx = attr >> 10 & 3;
scy = attr >> 8 & 3;
bgw = (1 << scx) - 1;
bgh = (1 << scy) - 1;
base = attr & 15 & ~((1 << (scx + scy < 3 ? scx + scy : 3)) - 1);
if (bgm != 2) {
mx = SignExtend(busReadBuffer(world + 8, VB_U16), 13);
mp = SignExtend(busReadBuffer(world + 10, VB_U16), 15);
my = SignExtend(busReadBuffer(world + 12, VB_U16), 13);
}
if (bgm != 0) {
params = 0x20000 + (top - gy) * (bgm == 1 ? 4 : 16) +
((uint32_t) busReadBuffer(world + 18, VB_U16) << 1);
}
else hofst = 0;
if (vipParseWorld(sim, world, bits, &wttr))
return; /* Window not in frame */
/* Draw the world */
for (i = 0; i < 2; i++) {
/* Validate world is enabled */
if ((attr & (int32_t) 0x8000 >> i) == 0) /* LON, RON */
/* World is not visible */
if ((bits & (int32_t) 0x8000 >> i) == 0) /* LON, RON */
continue;
/* Validate the world isn't right of frame */
wx = gx - (i == 0 ? gp : -gp);
if (wx > 383)
return;
left = wx < 0 ? 0 : wx;
/* Validate the world isn't left of frame */
right = wx + w - 1;
if (right < 0)
return;
if (right > 383)
right = 383;
/* BG source parallax */
if (bgm != 2)
bp = i == 0 ? -mp : mp;
/* Process attributes */
if (vipParseEye(&wttr, &ettr, i))
continue;
/* Draw all rows */
for (y = top, param = params; y <= bottom; y++) {
for (y = wttr.top, param = wttr.params; y <= wttr.bottom; y++) {
/* Parse line parameters */
switch (bgm) {
hofst = 0;
mp = wttr.mp;
mx = wttr.mx;
my = wttr.my;
switch (wttr.bgm) {
case 1: /* H-bias */
hofst = SignExtend(vipParam(param | i << 1), 13);
param += 4;
@ -813,22 +853,22 @@ static void vipDrawWorld(VB *sim, uint8_t *world, uint16_t attr) {
dx = (int32_t) (int16_t) vipParam(param|6) << 7;
dy = (int32_t) (int16_t) vipParam(param|8) << 7;
mp = (int32_t) (int16_t) vipParam(param|2);
mp = left - wx - ((mp < 0) ^ i ? mp : 0);
mp = ettr.left - ettr.wx - ((mp < 0) ^ i ? mp : 0);
mx = ((int32_t) (int16_t) vipParam(param ) << 13) + dx*mp;
my = ((int32_t) (int16_t) vipParam(param|4) << 13) + dy*mp;
param += 16;
}
/* Select output in shadow memory */
dest = &sim->vip.shadow[i][left * 224 + y];
dest = &sim->vip.shadow[i][ettr.left * 224 + y];
/* Draw all columns */
for (x = left; x <= right; x++, dest += 224) {
for (x = ettr.left; x <= ettr.right; x++, dest += 224) {
/* Locate the pixel in the background */
if (bgm != 2) { /* Normal, H-bias */
cx = x - wx + mx + bp + hofst;
cy = y - gy + my;
if (wttr.bgm != 2) { /* Normal, H-bias */
cx = x - ettr.wx + mx + ettr.bp + hofst;
cy = y - wttr.gy + my;
} else { /* Affine */
cx = (int16_t) (mx >> 16);
cy = (int16_t) (my >> 16);
@ -842,23 +882,24 @@ static void vipDrawWorld(VB *sim, uint8_t *world, uint16_t attr) {
cell = NULL;
/* BG map is out of bounds */
if (bx < 0 || bx > bgw || by < 0 || by > bgh) {
if (over == NULL) {
bx &= bgw;
by &= bgh;
}
else {
cell = over;
if (
bx < 0 || bx > wttr.bgw ||
by < 0 || by > wttr.bgh
) {
if (wttr.over)
continue; /* TODO: Research overplane */
}
bx &= wttr.bgw;
by &= wttr.bgh;
}
/* Locate the cell in the BG map */
if (cell == NULL) {
cell = &sim->vip.ram[
0x20000 |
(base + bg[by << scx | bx]) << 13 |
(cy << 4 & 0x1F80) |
0x20000 | ((
wttr.base +
wttr.bg[by << wttr.scx | bx]
) << 13) |
(cy << 4 & 0x1F80) |
(cx >> 2 & 0x007E)
];
}