Lots of fixes. Maybe.
This commit is contained in:
parent
c80610747a
commit
4fdb757671
4 changed files with 424 additions and 247 deletions
17
agi.c
17
agi.c
|
|
@ -152,7 +152,10 @@ static jlSurfaceT *gBackdrop;
|
|||
static jlSurfaceT *gStage;
|
||||
static AgiVmT gVm;
|
||||
static LogicCacheSlotT gLogicCache[AGI_MAX_RESOURCES];
|
||||
static ViewCacheSlotT gViewCache[AGI_MAX_RESOURCES];
|
||||
// View cache: 256 slots of ~5 KB each (~1.3 MB). Far too large for the
|
||||
// IIgs bank-0 BSS, so it is jlAlloc'd at startup (Memory Manager handle
|
||||
// on the IIgs, malloc elsewhere) rather than declared as a static array.
|
||||
static ViewCacheSlotT *gViewCache;
|
||||
static bool gPicReady;
|
||||
static uint8_t gOverrideRoom;
|
||||
static bool gOverrideRoomActive;
|
||||
|
|
@ -1729,6 +1732,16 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
// The view cache is too large for bank-0 BSS on the IIgs; pull it
|
||||
// from the platform's large-allocator. jlAlloc does not zero its
|
||||
// result, so clear it so every slot starts with loaded == false.
|
||||
gViewCache = (ViewCacheSlotT *)jlAlloc(sizeof(ViewCacheSlotT) * AGI_MAX_RESOURCES);
|
||||
if (gViewCache == NULL) {
|
||||
jlShutdown();
|
||||
return 1;
|
||||
}
|
||||
memset(gViewCache, 0, sizeof(ViewCacheSlotT) * AGI_MAX_RESOURCES);
|
||||
|
||||
gameDir = resolveGameDir(argc, argv);
|
||||
startingRoom = resolveStartingRoom(argc, argv);
|
||||
gOverrideRoom = startingRoom;
|
||||
|
|
@ -1858,6 +1871,8 @@ int main(int argc, char **argv) {
|
|||
jlAudioShutdown();
|
||||
releaseLogicCache();
|
||||
releaseViewCache();
|
||||
jlFree(gViewCache);
|
||||
gViewCache = NULL;
|
||||
if (gBackdrop != NULL) {
|
||||
jlSurfaceDestroy(gBackdrop);
|
||||
}
|
||||
|
|
|
|||
9
agiPic.c
9
agiPic.c
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "agi.h"
|
||||
|
||||
#include "joey/core.h"
|
||||
#include "joey/draw.h"
|
||||
#include "surfaceInternal.h"
|
||||
|
||||
|
|
@ -408,8 +409,8 @@ static void plot(AgiPicT *pic, const PicStateT *state, int16_t x, int16_t y) {
|
|||
// ----- Public API (alphabetical) -----
|
||||
|
||||
bool agiPicAlloc(AgiPicT *pic) {
|
||||
pic->visual = (uint8_t *)malloc(AGI_PIC_PIXELS);
|
||||
pic->priority = (uint8_t *)malloc(AGI_PIC_PIXELS);
|
||||
pic->visual = (uint8_t *)jlAlloc(AGI_PIC_PIXELS);
|
||||
pic->priority = (uint8_t *)jlAlloc(AGI_PIC_PIXELS);
|
||||
if (pic->visual == NULL || pic->priority == NULL) {
|
||||
agiPicFree(pic);
|
||||
return false;
|
||||
|
|
@ -651,11 +652,11 @@ void agiPicAddView(AgiPicT *pic, const AgiViewT *view,
|
|||
|
||||
void agiPicFree(AgiPicT *pic) {
|
||||
if (pic->visual != NULL) {
|
||||
free(pic->visual);
|
||||
jlFree(pic->visual);
|
||||
pic->visual = NULL;
|
||||
}
|
||||
if (pic->priority != NULL) {
|
||||
free(pic->priority);
|
||||
jlFree(pic->priority);
|
||||
pic->priority = NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
256
agiView.c
256
agiView.c
|
|
@ -43,14 +43,157 @@
|
|||
#endif
|
||||
|
||||
|
||||
// ----- File-local types -----
|
||||
|
||||
// Per-draw invariants for one cel blit, grouped so they live in memory
|
||||
// rather than competing for the w65816's tiny register file. Passing a
|
||||
// pointer to this keeps the hot blit helpers under the backend's
|
||||
// register-allocation ceiling.
|
||||
typedef struct {
|
||||
const uint8_t *picPriority;
|
||||
int16_t x;
|
||||
int16_t width;
|
||||
uint8_t actorPri;
|
||||
uint8_t transparent;
|
||||
bool mirrored;
|
||||
} AgiCelBlitT;
|
||||
|
||||
|
||||
// ----- Prototypes -----
|
||||
|
||||
static void blitPlanar(const AgiCelBlitT *blit, const uint8_t *rle, int16_t height, int16_t topY, jlSurfaceT *stage, int16_t destY);
|
||||
static const uint8_t *blitRowChunky(const AgiCelBlitT *blit, const uint8_t *rle, const uint8_t *priRow, uint8_t *stageRow);
|
||||
static void markCelDirty(jlSurfaceT *stage, int16_t x, int16_t width, int16_t destY, int16_t topY, int16_t height);
|
||||
static bool parseLoop(AgiLoopInfoT *loop, const uint8_t *loopStart, uint16_t maxBytes);
|
||||
static const AgiCelInfoT *resolveMirror(const AgiViewT *view, uint8_t loopIdx, uint8_t celIdx, bool *outMirrored);
|
||||
|
||||
|
||||
// ----- Internal helpers (alphabetical) -----
|
||||
|
||||
// Planar fallback row walker (stage->pixels == NULL). Routes every
|
||||
// opaque, visible pixel through jlDrawPixel so the port's c2p /
|
||||
// plane-sync path stays correct. Split out of agiViewDraw so its
|
||||
// locals don't pile onto the chunky path's register budget.
|
||||
static void blitPlanar(const AgiCelBlitT *blit, const uint8_t *rle, int16_t height, int16_t topY, jlSurfaceT *stage, int16_t destY) {
|
||||
int16_t width;
|
||||
int16_t cy;
|
||||
int16_t cx;
|
||||
int16_t drawCx;
|
||||
int16_t agiX;
|
||||
int16_t agiY;
|
||||
int16_t stageX;
|
||||
int16_t stageY;
|
||||
uint8_t rleByte;
|
||||
uint8_t color;
|
||||
uint8_t runLen;
|
||||
uint8_t r;
|
||||
uint8_t picPri;
|
||||
|
||||
width = blit->width;
|
||||
for (cy = 0; cy < height; cy++) {
|
||||
cx = 0;
|
||||
for (;;) {
|
||||
rleByte = *rle++;
|
||||
if (rleByte == 0u) { break; }
|
||||
color = (uint8_t)(rleByte >> 4);
|
||||
runLen = (uint8_t)(rleByte & 0x0Fu);
|
||||
for (r = 0u; r < runLen; r++) {
|
||||
if (cx >= width) { break; }
|
||||
if (color != blit->transparent) {
|
||||
drawCx = blit->mirrored ? (int16_t)(width - 1 - cx) : cx;
|
||||
agiX = (int16_t)(blit->x + drawCx);
|
||||
agiY = (int16_t)(topY + cy);
|
||||
if (agiX >= 0 && agiX < (int16_t)AGI_PIC_WIDTH && agiY >= 0 && agiY < (int16_t)AGI_PIC_HEIGHT) {
|
||||
picPri = blit->picPriority[agiY * (int16_t)AGI_PIC_WIDTH + agiX];
|
||||
if (picPri <= blit->actorPri) {
|
||||
stageX = (int16_t)(agiX << 1);
|
||||
stageY = (int16_t)(destY + agiY);
|
||||
jlDrawPixel(stage, stageX, stageY, color);
|
||||
jlDrawPixel(stage, (int16_t)(stageX + 1), stageY, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
cx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Chunky fast-path walker for one source row. Consumes the cel's RLE
|
||||
// stream from `rle`, writing pixel-doubled bytes into `stageRow` where
|
||||
// the picture priority allows it, and returns the advanced RLE pointer
|
||||
// so the caller can hand it to the next row. A NULL priRow / stageRow
|
||||
// means the row is clipped out vertically: the RLE is still walked (so
|
||||
// the pointer lands correctly for later rows) but nothing is drawn.
|
||||
static const uint8_t *blitRowChunky(const AgiCelBlitT *blit, const uint8_t *rle, const uint8_t *priRow, uint8_t *stageRow) {
|
||||
int16_t width;
|
||||
int16_t cx;
|
||||
int16_t drawCx;
|
||||
int16_t agiX;
|
||||
uint8_t rleByte;
|
||||
uint8_t color;
|
||||
uint8_t runLen;
|
||||
uint8_t packed;
|
||||
uint8_t r;
|
||||
|
||||
width = blit->width;
|
||||
cx = 0;
|
||||
for (;;) {
|
||||
rleByte = *rle++;
|
||||
if (rleByte == 0u) { break; }
|
||||
color = (uint8_t)(rleByte >> 4);
|
||||
runLen = (uint8_t)(rleByte & 0x0Fu);
|
||||
// Transparent runs and vertically-clipped rows both just skip
|
||||
// ahead by runLen without touching the stage.
|
||||
if (color == blit->transparent || priRow == NULL) {
|
||||
cx = (int16_t)(cx + runLen);
|
||||
if (cx > width) { cx = width; }
|
||||
continue;
|
||||
}
|
||||
packed = (uint8_t)((color << 4) | color);
|
||||
for (r = 0u; r < runLen; r++) {
|
||||
if (cx >= width) { break; }
|
||||
drawCx = blit->mirrored ? (int16_t)(width - 1 - cx) : cx;
|
||||
agiX = (int16_t)(blit->x + drawCx);
|
||||
if (agiX >= 0 && agiX < (int16_t)AGI_PIC_WIDTH) {
|
||||
if (priRow[agiX] <= blit->actorPri) {
|
||||
stageRow[agiX] = packed;
|
||||
}
|
||||
}
|
||||
cx++;
|
||||
}
|
||||
}
|
||||
return rle;
|
||||
}
|
||||
|
||||
|
||||
// Mark the cel's stage bounding box dirty once after a chunky blit.
|
||||
// Computes the pixel-doubled bbox from the source rect, clips it to the
|
||||
// stage so the surface marker doesn't reject the whole rect for an
|
||||
// off-screen edge, and records it if any of it is on-screen.
|
||||
static void markCelDirty(jlSurfaceT *stage, int16_t x, int16_t width, int16_t destY, int16_t topY, int16_t height) {
|
||||
int16_t minStageX;
|
||||
int16_t maxStageX;
|
||||
int16_t minStageY;
|
||||
int16_t maxStageY;
|
||||
|
||||
minStageX = (int16_t)(x << 1);
|
||||
maxStageX = (int16_t)((x + width) << 1);
|
||||
minStageY = (int16_t)(destY + topY);
|
||||
maxStageY = (int16_t)(destY + topY + height);
|
||||
if (minStageX < 0) { minStageX = 0; }
|
||||
if (minStageY < 0) { minStageY = 0; }
|
||||
if (maxStageX > (int16_t)SURFACE_WIDTH) { maxStageX = (int16_t)SURFACE_WIDTH; }
|
||||
if (maxStageY > (int16_t)SURFACE_HEIGHT) { maxStageY = (int16_t)SURFACE_HEIGHT; }
|
||||
if (maxStageX > minStageX && maxStageY > minStageY) {
|
||||
surfaceMarkDirtyRect(stage, minStageX, minStageY,
|
||||
(int16_t)(maxStageX - minStageX),
|
||||
(int16_t)(maxStageY - minStageY));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool parseLoop(AgiLoopInfoT *loop, const uint8_t *loopStart, uint16_t maxBytes) {
|
||||
uint8_t celCount;
|
||||
uint8_t i;
|
||||
|
|
@ -149,37 +292,27 @@ void agiViewDraw(const AgiViewT *view, uint8_t loopIdx, uint8_t celIdx,
|
|||
const uint8_t *picPriority,
|
||||
jlSurfaceT *stage, int16_t destY) {
|
||||
const AgiCelInfoT *cel;
|
||||
AgiCelBlitT blit;
|
||||
const uint8_t *rle;
|
||||
bool mirrored;
|
||||
int16_t width;
|
||||
int16_t height;
|
||||
uint8_t transparent;
|
||||
int16_t topY;
|
||||
int16_t cy;
|
||||
int16_t cx;
|
||||
int16_t drawCx;
|
||||
int16_t agiX;
|
||||
int16_t agiY;
|
||||
int16_t stageX;
|
||||
int16_t stageY;
|
||||
uint8_t rleByte;
|
||||
uint8_t color;
|
||||
uint8_t packed;
|
||||
uint8_t runLen;
|
||||
uint8_t r;
|
||||
uint8_t picPri;
|
||||
uint8_t *stagePixels;
|
||||
uint8_t *stagePixels;
|
||||
|
||||
cel = resolveMirror(view, loopIdx, celIdx, &mirrored);
|
||||
if (cel == NULL) {
|
||||
return;
|
||||
}
|
||||
width = (int16_t)cel->width;
|
||||
height = (int16_t)cel->height;
|
||||
transparent = cel->transparentColor;
|
||||
rle = cel->rleData;
|
||||
topY = (int16_t)(y - height + 1);
|
||||
stagePixels = (stage != NULL) ? stage->pixels : NULL;
|
||||
height = (int16_t)cel->height;
|
||||
blit.picPriority = picPriority;
|
||||
blit.x = x;
|
||||
blit.width = (int16_t)cel->width;
|
||||
blit.actorPri = actorPri;
|
||||
blit.transparent = cel->transparentColor;
|
||||
blit.mirrored = mirrored;
|
||||
rle = cel->rleData;
|
||||
topY = (int16_t)(y - height + 1);
|
||||
stagePixels = (stage != NULL) ? stage->pixels : NULL;
|
||||
|
||||
// Per-pixel chunky fast path: pixel-doubled output means each
|
||||
// source pixel maps to exactly one stage byte (both nibbles =
|
||||
|
|
@ -187,10 +320,8 @@ void agiViewDraw(const AgiViewT *view, uint8_t loopIdx, uint8_t celIdx,
|
|||
// direct, marking the cel bbox dirty once at the end. ~80x
|
||||
// faster on DOSBox @ 386SX-equivalent CPU cycles.
|
||||
if (stagePixels != NULL) {
|
||||
int16_t minStageX = (int16_t)(x << 1);
|
||||
int16_t maxStageX = (int16_t)((x + width) << 1);
|
||||
int16_t minStageY = (int16_t)(destY + topY);
|
||||
int16_t maxStageY = (int16_t)(destY + topY + height);
|
||||
int16_t cy;
|
||||
int16_t agiY;
|
||||
const uint8_t *priRow;
|
||||
uint8_t *stageRow;
|
||||
|
||||
|
|
@ -208,82 +339,15 @@ void agiViewDraw(const AgiViewT *view, uint8_t loopIdx, uint8_t celIdx,
|
|||
stageRow = stagePixels +
|
||||
(int32_t)(destY + agiY) * (int32_t)SURFACE_BYTES_PER_ROW;
|
||||
}
|
||||
cx = 0;
|
||||
for (;;) {
|
||||
rleByte = *rle++;
|
||||
if (rleByte == 0u) { break; }
|
||||
color = (uint8_t)(rleByte >> 4);
|
||||
runLen = (uint8_t)(rleByte & 0x0Fu);
|
||||
if (color == transparent) {
|
||||
cx = (int16_t)(cx + runLen);
|
||||
if (cx > width) { cx = width; }
|
||||
continue;
|
||||
}
|
||||
if (priRow == NULL) {
|
||||
cx = (int16_t)(cx + runLen);
|
||||
if (cx > width) { cx = width; }
|
||||
continue;
|
||||
}
|
||||
packed = (uint8_t)((color << 4) | color);
|
||||
for (r = 0u; r < runLen; r++) {
|
||||
if (cx >= width) { break; }
|
||||
drawCx = mirrored ? (int16_t)(width - 1 - cx) : cx;
|
||||
agiX = (int16_t)(x + drawCx);
|
||||
if (agiX >= 0 && agiX < (int16_t)AGI_PIC_WIDTH) {
|
||||
if (priRow[agiX] <= actorPri) {
|
||||
stageRow[agiX] = packed;
|
||||
}
|
||||
}
|
||||
cx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Dirty-rect tracking at the cel level only: we know the
|
||||
// bbox a priori (the cel's stage rect), and per-pixel tight
|
||||
// bounds aren't worth the inner-loop cost on a 386. Clip to
|
||||
// the stage so the surface marker doesn't reject the whole
|
||||
// rect for an off-screen edge.
|
||||
if (minStageX < 0) { minStageX = 0; }
|
||||
if (minStageY < 0) { minStageY = 0; }
|
||||
if (maxStageX > (int16_t)SURFACE_WIDTH) { maxStageX = (int16_t)SURFACE_WIDTH; }
|
||||
if (maxStageY > (int16_t)SURFACE_HEIGHT) { maxStageY = (int16_t)SURFACE_HEIGHT; }
|
||||
if (maxStageX > minStageX && maxStageY > minStageY) {
|
||||
surfaceMarkDirtyRect(stage, minStageX, minStageY,
|
||||
(int16_t)(maxStageX - minStageX),
|
||||
(int16_t)(maxStageY - minStageY));
|
||||
rle = blitRowChunky(&blit, rle, priRow, stageRow);
|
||||
}
|
||||
markCelDirty(stage, x, blit.width, destY, topY, height);
|
||||
return;
|
||||
}
|
||||
|
||||
// Planar fallback (s->pixels NULL: Amiga Phase 9). Goes through
|
||||
// jlDrawPixel so the port's c2p / plane-sync path stays correct.
|
||||
for (cy = 0; cy < height; cy++) {
|
||||
cx = 0;
|
||||
for (;;) {
|
||||
rleByte = *rle++;
|
||||
if (rleByte == 0u) { break; }
|
||||
color = (uint8_t)(rleByte >> 4);
|
||||
runLen = (uint8_t)(rleByte & 0x0Fu);
|
||||
for (r = 0u; r < runLen; r++) {
|
||||
if (cx >= width) { break; }
|
||||
if (color != transparent) {
|
||||
drawCx = mirrored ? (int16_t)(width - 1 - cx) : cx;
|
||||
agiX = (int16_t)(x + drawCx);
|
||||
agiY = (int16_t)(topY + cy);
|
||||
if (agiX >= 0 && agiX < (int16_t)AGI_PIC_WIDTH && agiY >= 0 && agiY < (int16_t)AGI_PIC_HEIGHT) {
|
||||
picPri = picPriority[agiY * (int16_t)AGI_PIC_WIDTH + agiX];
|
||||
if (picPri <= actorPri) {
|
||||
stageX = (int16_t)(agiX << 1);
|
||||
stageY = (int16_t)(destY + agiY);
|
||||
jlDrawPixel(stage, stageX, stageY, color);
|
||||
jlDrawPixel(stage, (int16_t)(stageX + 1), stageY, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
cx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
blitPlanar(&blit, rle, height, topY, stage, destY);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue