mirror of https://github.com/mgba-emu/mgba.git
GBA: Begin working on savestate extra data
This commit is contained in:
parent
f84aadffd2
commit
70b9a1bfe0
|
@ -24,6 +24,10 @@
|
||||||
|
|
||||||
const uint32_t GBA_SAVESTATE_MAGIC = 0x01000000;
|
const uint32_t GBA_SAVESTATE_MAGIC = 0x01000000;
|
||||||
|
|
||||||
|
struct GBAExtdata {
|
||||||
|
struct GBAExtdataItem data[EXTDATA_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
|
void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
|
||||||
STORE_32(GBA_SAVESTATE_MAGIC, 0, &state->versionMagic);
|
STORE_32(GBA_SAVESTATE_MAGIC, 0, &state->versionMagic);
|
||||||
STORE_32(gba->biosChecksum, 0, &state->biosChecksum);
|
STORE_32(gba->biosChecksum, 0, &state->biosChecksum);
|
||||||
|
@ -224,18 +228,13 @@ static int _loadPNGChunkHandler(png_structp png, png_unknown_chunkp chunk) {
|
||||||
if (strcmp((const char*) chunk->name, "gbAs") != 0) {
|
if (strcmp((const char*) chunk->name, "gbAs") != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
struct GBASerializedState* state = GBAAllocateState();
|
struct GBASerializedState* state = png_get_user_chunk_ptr(png);
|
||||||
uLongf len = sizeof(*state);
|
uLongf len = sizeof(*state);
|
||||||
uncompress((Bytef*) state, &len, chunk->data, chunk->size);
|
uncompress((Bytef*) state, &len, chunk->data, chunk->size);
|
||||||
if (!GBADeserialize(png_get_user_chunk_ptr(png), state)) {
|
|
||||||
GBADeallocateState(state);
|
|
||||||
longjmp(png_jmpbuf(png), 1);
|
|
||||||
}
|
|
||||||
GBADeallocateState(state);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _loadPNGState(struct GBA* gba, struct VFile* vf) {
|
static struct GBASerializedState* _loadPNGState(struct VFile* vf, struct GBAExtdata* extdata) {
|
||||||
png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES);
|
png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES);
|
||||||
png_infop info = png_create_info_struct(png);
|
png_infop info = png_create_info_struct(png);
|
||||||
png_infop end = png_create_info_struct(png);
|
png_infop end = png_create_info_struct(png);
|
||||||
|
@ -249,18 +248,27 @@ static bool _loadPNGState(struct GBA* gba, struct VFile* vf) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PNGInstallChunkHandler(png, gba, _loadPNGChunkHandler, "gbAs");
|
struct GBASerializedState* state = GBAAllocateState();
|
||||||
|
|
||||||
|
PNGInstallChunkHandler(png, state, _loadPNGChunkHandler, "gbAs");
|
||||||
bool success = PNGReadHeader(png, info);
|
bool success = PNGReadHeader(png, info);
|
||||||
success = success && PNGReadPixels(png, info, pixels, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, VIDEO_HORIZONTAL_PIXELS);
|
success = success && PNGReadPixels(png, info, pixels, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, VIDEO_HORIZONTAL_PIXELS);
|
||||||
success = success && PNGReadFooter(png, end);
|
success = success && PNGReadFooter(png, end);
|
||||||
PNGReadClose(png, info, end);
|
PNGReadClose(png, info, end);
|
||||||
if (success) {
|
|
||||||
gba->video.renderer->putPixels(gba->video.renderer, VIDEO_HORIZONTAL_PIXELS, pixels);
|
|
||||||
GBASyncForceFrame(gba->sync);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(pixels);
|
if (success && extdata) {
|
||||||
return success;
|
struct GBAExtdataItem item = {
|
||||||
|
.size = VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4,
|
||||||
|
.data = pixels,
|
||||||
|
.clean = free
|
||||||
|
};
|
||||||
|
GBAExtdataPut(extdata, EXTDATA_SCREENSHOT, &item);
|
||||||
|
} else {
|
||||||
|
free(pixels);
|
||||||
|
GBADeallocateState(state);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -349,24 +357,76 @@ bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, bool screenshot) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GBALoadStateNamed(struct GBA* gba, struct VFile* vf) {
|
struct GBASerializedState* GBAExtractState(struct VFile* vf, struct GBAExtdata* extdata) {
|
||||||
#ifdef USE_PNG
|
#ifdef USE_PNG
|
||||||
if (isPNG(vf)) {
|
if (isPNG(vf)) {
|
||||||
return _loadPNGState(gba, vf);
|
return _loadPNGState(vf, extdata);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (vf->size(vf) < (ssize_t) sizeof(struct GBASerializedState)) {
|
if (vf->size(vf) < (ssize_t) sizeof(struct GBASerializedState)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
struct GBASerializedState* state = vf->map(vf, sizeof(struct GBASerializedState), MAP_READ);
|
struct GBASerializedState* state = GBAAllocateState();
|
||||||
|
if (vf->read(vf, state, sizeof(*state)) != sizeof(*state)) {
|
||||||
|
GBADeallocateState(state);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GBALoadStateNamed(struct GBA* gba, struct VFile* vf) {
|
||||||
|
struct GBAExtdata extdata;
|
||||||
|
GBAExtdataInit(&extdata);
|
||||||
|
struct GBASerializedState* state = GBAExtractState(vf, &extdata);
|
||||||
if (!state) {
|
if (!state) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool success = GBADeserialize(gba, state);
|
bool success = GBADeserialize(gba, state);
|
||||||
vf->unmap(vf, state, sizeof(struct GBASerializedState));
|
GBADeallocateState(state);
|
||||||
|
|
||||||
|
struct GBAExtdataItem screenshot;
|
||||||
|
if (GBAExtdataGet(&extdata, EXTDATA_SCREENSHOT, &screenshot)) {
|
||||||
|
gba->video.renderer->putPixels(gba->video.renderer, VIDEO_HORIZONTAL_PIXELS, screenshot.data);
|
||||||
|
GBASyncForceFrame(gba->sync);
|
||||||
|
}
|
||||||
|
GBAExtdataDeinit(&extdata);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GBAExtdataInit(struct GBAExtdata* extdata) {
|
||||||
|
memset(extdata->data, 0, sizeof(extdata->data));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBAExtdataDeinit(struct GBAExtdata* extdata) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 1; i < EXTDATA_MAX; ++i) {
|
||||||
|
if (extdata->data[i].data && extdata->data[i].clean) {
|
||||||
|
extdata->data[i].clean(extdata->data[i].data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBAExtdataPut(struct GBAExtdata* extdata, enum GBAExtdataTag tag, struct GBAExtdataItem* item) {
|
||||||
|
if (tag == EXTDATA_NONE || tag >= EXTDATA_MAX) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extdata->data[tag].data && extdata->data[tag].clean) {
|
||||||
|
extdata->data[tag].clean(extdata->data[tag].data);
|
||||||
|
}
|
||||||
|
extdata->data[tag] = *item;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GBAExtdataGet(struct GBAExtdata* extdata, enum GBAExtdataTag tag, struct GBAExtdataItem* item) {
|
||||||
|
if (tag == EXTDATA_NONE || tag >= EXTDATA_MAX) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*item = extdata->data[tag];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
struct GBASerializedState* GBAAllocateState(void) {
|
struct GBASerializedState* GBAAllocateState(void) {
|
||||||
return anonymousMemoryMap(sizeof(struct GBASerializedState));
|
return anonymousMemoryMap(sizeof(struct GBASerializedState));
|
||||||
}
|
}
|
||||||
|
|
|
@ -330,6 +330,19 @@ struct GBASerializedState {
|
||||||
uint8_t wram[SIZE_WORKING_RAM];
|
uint8_t wram[SIZE_WORKING_RAM];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum GBAExtdataTag {
|
||||||
|
EXTDATA_NONE = 0,
|
||||||
|
EXTDATA_SCREENSHOT = 1,
|
||||||
|
EXTDATA_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GBAExtdata;
|
||||||
|
struct GBAExtdataItem {
|
||||||
|
uint64_t size;
|
||||||
|
void* data;
|
||||||
|
void (*clean)(void*);
|
||||||
|
};
|
||||||
|
|
||||||
struct VDir;
|
struct VDir;
|
||||||
struct GBAThread;
|
struct GBAThread;
|
||||||
|
|
||||||
|
@ -343,6 +356,12 @@ struct VFile* GBAGetState(struct GBA* gba, struct VDir* dir, int slot, bool writ
|
||||||
bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, bool screenshot);
|
bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, bool screenshot);
|
||||||
bool GBALoadStateNamed(struct GBA* gba, struct VFile* vf);
|
bool GBALoadStateNamed(struct GBA* gba, struct VFile* vf);
|
||||||
|
|
||||||
|
bool GBAExtdataInit(struct GBAExtdata*);
|
||||||
|
void GBAExtdataDeinit(struct GBAExtdata*);
|
||||||
|
void GBAExtdataPut(struct GBAExtdata*, enum GBAExtdataTag, struct GBAExtdataItem*);
|
||||||
|
bool GBAExtdataGet(struct GBAExtdata*, enum GBAExtdataTag, struct GBAExtdataItem*);
|
||||||
|
|
||||||
|
struct GBASerializedState* GBAExtractState(struct VFile* vf, struct GBAExtdata* extdata);
|
||||||
struct GBASerializedState* GBAAllocateState(void);
|
struct GBASerializedState* GBAAllocateState(void);
|
||||||
void GBADeallocateState(struct GBASerializedState* state);
|
void GBADeallocateState(struct GBASerializedState* state);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue