Restore pixels from PNG when loading savestate

This commit is contained in:
Jeffrey Pfau 2014-07-26 14:06:28 -07:00
parent a872bd3642
commit b4d90e7e84
6 changed files with 58 additions and 3 deletions

View File

@ -130,11 +130,15 @@ static bool _loadPNGState(struct GBA* gba, struct VFile* vf) {
PNGReadClose(png, info, end);
return false;
}
uint32_t pixels[VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4];
PNGInstallChunkHandler(png, gba, _loadPNGChunkHandler, "gbAs");
PNGReadHeader(png, info);
PNGIgnorePixels(png, info);
PNGReadPixels(png, info, &pixels, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, VIDEO_HORIZONTAL_PIXELS);
PNGReadFooter(png, end);
PNGReadClose(png, info, end);
gba->video.renderer->putPixels(gba->video.renderer, VIDEO_HORIZONTAL_PIXELS, pixels);
GBASyncPostFrame(gba->sync);
return true;
}

View File

@ -535,6 +535,10 @@ void GBASyncPostFrame(struct GBASync* sync) {
MutexUnlock(&sync->videoFrameMutex);
struct GBAThread* thread = GBAThreadGetContext();
if (!thread) {
return;
}
if (thread->rewindBuffer) {
--thread->rewindBufferNext;
if (thread->rewindBufferNext <= 0) {
@ -554,10 +558,12 @@ bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip) {
MutexLock(&sync->videoFrameMutex);
ConditionWake(&sync->videoFrameRequiredCond);
if (!sync->videoFrameOn) {
if (!sync->videoFrameOn && !sync->videoFramePending) {
return false;
}
ConditionWait(&sync->videoFrameAvailableCond, &sync->videoFrameMutex);
if (!sync->videoFramePending) {
ConditionWait(&sync->videoFrameAvailableCond, &sync->videoFrameMutex);
}
sync->videoFramePending = 0;
sync->videoFrameSkip = frameskip;
return true;

View File

@ -185,6 +185,7 @@ struct GBAVideoRenderer {
void (*finishFrame)(struct GBAVideoRenderer* renderer);
void (*getPixels)(struct GBAVideoRenderer* renderer, unsigned* stride, void** pixels);
void (*putPixels)(struct GBAVideoRenderer* renderer, unsigned stride, void* pixels);
uint16_t* palette;
uint16_t* vram;

View File

@ -30,6 +30,7 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer);
static void GBAVideoSoftwareRendererGetPixels(struct GBAVideoRenderer* renderer, unsigned* stride, void** pixels);
static void GBAVideoSoftwareRendererPutPixels(struct GBAVideoRenderer* renderer, unsigned stride, void* pixels);
static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRenderer* renderer);
static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* bg, uint16_t value);
@ -69,6 +70,7 @@ void GBAVideoSoftwareRendererCreate(struct GBAVideoSoftwareRenderer* renderer) {
renderer->d.drawScanline = GBAVideoSoftwareRendererDrawScanline;
renderer->d.finishFrame = GBAVideoSoftwareRendererFinishFrame;
renderer->d.getPixels = GBAVideoSoftwareRendererGetPixels;
renderer->d.putPixels = GBAVideoSoftwareRendererPutPixels;
}
static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer) {
@ -510,6 +512,16 @@ static void GBAVideoSoftwareRendererGetPixels(struct GBAVideoRenderer* renderer,
*pixels = softwareRenderer->outputBuffer;
}
static void GBAVideoSoftwareRendererPutPixels(struct GBAVideoRenderer* renderer, unsigned stride, void* pixels) {
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
uint32_t* colorPixels = pixels;
unsigned i;
for (i = 0; i < VIDEO_VERTICAL_PIXELS; ++i) {
memmove(&softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * i], &colorPixels[stride * i], VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL);
}
}
static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRenderer* renderer) {
renderer->bg[0].enabled = renderer->dispcnt.bg0Enable;
renderer->bg[1].enabled = renderer->dispcnt.bg1Enable;

View File

@ -135,6 +135,37 @@ bool PNGIgnorePixels(png_structp png, png_infop info) {
return true;
}
bool PNGReadPixels(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride) {
if (setjmp(png_jmpbuf(png))) {
return false;
}
uint8_t* pixelData = pixels;
unsigned pngHeight = png_get_image_height(png, info);
if (height > pngHeight) {
height = pngHeight;
}
unsigned pngWidth = png_get_image_width(png, info);
if (width > pngWidth) {
width = pngWidth;
}
unsigned i;
png_bytep row = malloc(png_get_rowbytes(png, info));
for (i = 0; i < height; ++i) {
png_read_row(png, row, 0);
unsigned x;
for (x = 0; x < width; ++x) {
pixelData[stride * i * 4 + x * 4] = row[x * 3];
pixelData[stride * i * 4 + x * 4 + 1] = row[x * 3 + 1];
pixelData[stride * i * 4 + x * 4 + 2] = row[x * 3 + 2];
}
}
free(row);
return true;
}
bool PNGReadFooter(png_structp png, png_infop end) {
if (setjmp(png_jmpbuf(png))) {
return false;

View File

@ -23,6 +23,7 @@ bool isPNG(struct VFile* source);
png_structp PNGReadOpen(struct VFile* source, unsigned offset);
bool PNGInstallChunkHandler(png_structp png, void* context, ChunkHandler handler, const char* chunkName);
bool PNGReadHeader(png_structp png, png_infop info);
bool PNGReadPixels(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride);
bool PNGIgnorePixels(png_structp png, png_infop info);
bool PNGReadFooter(png_structp png, png_infop end);
void PNGReadClose(png_structp png, png_infop info, png_infop end);