diff --git a/core/vip.c b/core/vip.c index c4cd2ec..f2295f3 100644 --- a/core/vip.c +++ b/core/vip.c @@ -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) ]; }