bool retro_serialize(void* data, size_t size) { if (size != retro_serialize_size()) { return false; } GBASerialize(core->board, data); return true; }
static bool _savePNGState(struct GBA* gba, struct VFile* vf) { unsigned stride; const void* pixels = 0; gba->video.renderer->getPixels(gba->video.renderer, &stride, &pixels); if (!pixels) { return false; } struct GBASerializedState* state = GBAAllocateState(); if (!state) { return false; } GBASerialize(gba, state); uLongf len = compressBound(sizeof(*state)); void* buffer = malloc(len); if (!buffer) { GBADeallocateState(state); return false; } compress(buffer, &len, (const Bytef*) state, sizeof(*state)); GBADeallocateState(state); png_structp png = PNGWriteOpen(vf); png_infop info = PNGWriteHeader(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); if (!png || !info) { PNGWriteClose(png, info); free(buffer); return false; } PNGWritePixels(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, stride, pixels); PNGWriteCustomChunk(png, "gbAs", len, buffer); PNGWriteClose(png, info); free(buffer); return true; }
bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, bool screenshot) { if (!screenshot) { vf->truncate(vf, sizeof(struct GBASerializedState)); struct GBASerializedState* state = vf->map(vf, sizeof(struct GBASerializedState), MAP_WRITE); if (!state) { return false; } GBASerialize(gba, state); vf->unmap(vf, state, sizeof(struct GBASerializedState)); return true; } #ifdef USE_PNG else { return _savePNGState(gba, vf); } #endif return false; }
void GBARecordFrame(struct GBAThread* thread) { int offset = thread->rewindBufferWriteOffset; struct GBASerializedState* state = thread->rewindBuffer[offset]; if (!state) { state = GBAAllocateState(); thread->rewindBuffer[offset] = state; } GBASerialize(thread->gba, state); if (thread->rewindScreenBuffer) { unsigned stride; const uint8_t* pixels = 0; thread->gba->video.renderer->getPixels(thread->gba->video.renderer, &stride, (const void**) &pixels); if (pixels) { size_t y; for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) { memcpy(&thread->rewindScreenBuffer[(offset * VIDEO_VERTICAL_PIXELS + y) * VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL], &pixels[y * stride * BYTES_PER_PIXEL], VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL); } } } thread->rewindBufferSize = thread->rewindBufferSize == thread->rewindBufferCapacity ? thread->rewindBufferCapacity : thread->rewindBufferSize + 1; thread->rewindBufferWriteOffset = (offset + 1) % thread->rewindBufferCapacity; }