diff --git a/source/snes9x/snapshot.cpp b/source/snes9x/snapshot.cpp index 5c88a4b..7d396fd 100644 --- a/source/snes9x/snapshot.cpp +++ b/source/snes9x/snapshot.cpp @@ -1069,6 +1069,38 @@ int S9xUnfreezeGameMem (const uint8 *buf, uint32 bufSize) return result; } +void S9xMessageFromResult(int result, const char* base) +{ + switch(result) + { + case WRONG_FORMAT: + S9xMessage(S9X_ERROR, S9X_WRONG_FORMAT, SAVE_ERR_WRONG_FORMAT); + break; + + case WRONG_VERSION: + S9xMessage(S9X_ERROR, S9X_WRONG_VERSION, SAVE_ERR_WRONG_VERSION); + break; + + case WRONG_MOVIE_SNAPSHOT: + S9xMessage(S9X_ERROR, S9X_WRONG_MOVIE_SNAPSHOT, MOVIE_ERR_SNAPSHOT_WRONG_MOVIE); + break; + + case NOT_A_MOVIE_SNAPSHOT: + S9xMessage(S9X_ERROR, S9X_NOT_A_MOVIE_SNAPSHOT, MOVIE_ERR_SNAPSHOT_NOT_MOVIE); + break; + + case SNAPSHOT_INCONSISTENT: + S9xMessage(S9X_ERROR, S9X_SNAPSHOT_INCONSISTENT, MOVIE_ERR_SNAPSHOT_INCONSISTENT); + break; + + case FILE_NOT_FOUND: + default: + sprintf(String, SAVE_ERR_ROM_NOT_FOUND, base); + S9xMessage(S9X_ERROR, S9X_ROM_NOT_FOUND, String); + break; + } +} + bool8 S9xUnfreezeGame (const char *filename) { STREAM stream = NULL; @@ -1088,35 +1120,7 @@ bool8 S9xUnfreezeGame (const char *filename) if (result != SUCCESS) { - switch (result) - { - case WRONG_FORMAT: - S9xMessage(S9X_ERROR, S9X_WRONG_FORMAT, SAVE_ERR_WRONG_FORMAT); - break; - - case WRONG_VERSION: - S9xMessage(S9X_ERROR, S9X_WRONG_VERSION, SAVE_ERR_WRONG_VERSION); - break; - - case WRONG_MOVIE_SNAPSHOT: - S9xMessage(S9X_ERROR, S9X_WRONG_MOVIE_SNAPSHOT, MOVIE_ERR_SNAPSHOT_WRONG_MOVIE); - break; - - case NOT_A_MOVIE_SNAPSHOT: - S9xMessage(S9X_ERROR, S9X_NOT_A_MOVIE_SNAPSHOT, MOVIE_ERR_SNAPSHOT_NOT_MOVIE); - break; - - case SNAPSHOT_INCONSISTENT: - S9xMessage(S9X_ERROR, S9X_SNAPSHOT_INCONSISTENT, MOVIE_ERR_SNAPSHOT_INCONSISTENT); - break; - - case FILE_NOT_FOUND: - default: - sprintf(String, SAVE_ERR_ROM_NOT_FOUND, base); - S9xMessage(S9X_ERROR, S9X_ROM_NOT_FOUND, String); - break; - } - + S9xMessageFromResult(result, base); return (FALSE); } @@ -1141,6 +1145,34 @@ bool8 S9xUnfreezeGame (const char *filename) return (FALSE); } +bool8 S9xUnfreezeScreenshot(const char *filename, uint16 **image_buffer, int &width, int &height) +{ + STREAM stream = NULL; + + const char *base = S9xBasename(filename); + + if(S9xOpenSnapshotFile(filename, TRUE, &stream)) + { + int result; + + result = S9xUnfreezeScreenshotFromStream(stream, image_buffer, width, height); + S9xCloseSnapshotFile(stream); + + if(result != SUCCESS) + { + S9xMessageFromResult(result, base); + return (FALSE); + } + + return (TRUE); + } + + sprintf(String, SAVE_ERR_SAVE_NOT_FOUND, base); + S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, String); + + return (FALSE); +} + void S9xFreezeToStream (STREAM stream) { char buffer[8192]; @@ -1797,6 +1829,96 @@ int S9xUnfreezeFromStream (STREAM stream) return (result); } +// load screenshot from file, allocating memory for it +int S9xUnfreezeScreenshotFromStream(STREAM stream, uint16 **image_buffer, int &width, int &height) +{ + int result = SUCCESS; + int version, len; + char buffer[PATH_MAX + 1]; + + len = strlen(SNAPSHOT_MAGIC) + 1 + 4 + 1; + if(READ_STREAM(buffer, len, stream) != (unsigned int)len) + return (WRONG_FORMAT); + + if(strncmp(buffer, SNAPSHOT_MAGIC, strlen(SNAPSHOT_MAGIC)) != 0) + return (WRONG_FORMAT); + + version = atoi(&buffer[strlen(SNAPSHOT_MAGIC) + 1]); + if(version > SNAPSHOT_VERSION) + return (WRONG_VERSION); + + result = UnfreezeBlock(stream, "NAM", (uint8 *)buffer, PATH_MAX); + if(result != SUCCESS) + return (result); + + uint8 *local_screenshot = NULL; + + // skip all blocks until screenshot + SkipBlockWithName(stream, "CPU"); + SkipBlockWithName(stream, "REG"); + SkipBlockWithName(stream, "PPU"); + SkipBlockWithName(stream, "DMA"); + SkipBlockWithName(stream, "VRA"); + SkipBlockWithName(stream, "RAM"); + SkipBlockWithName(stream, "SRA"); + SkipBlockWithName(stream, "FIL"); + SkipBlockWithName(stream, "SND"); + SkipBlockWithName(stream, "CTL"); + SkipBlockWithName(stream, "TIM"); + SkipBlockWithName(stream, "SFX"); + SkipBlockWithName(stream, "SA1"); + SkipBlockWithName(stream, "SAR"); + SkipBlockWithName(stream, "DP1"); + SkipBlockWithName(stream, "DP2"); + SkipBlockWithName(stream, "DP4"); + SkipBlockWithName(stream, "CX4"); + SkipBlockWithName(stream, "ST0"); + SkipBlockWithName(stream, "OBC"); + SkipBlockWithName(stream, "OBM"); + SkipBlockWithName(stream, "S71"); + SkipBlockWithName(stream, "SRT"); + SkipBlockWithName(stream, "CLK"); + SkipBlockWithName(stream, "BSX"); + SkipBlockWithName(stream, "MSU"); + result = UnfreezeStructCopy(stream, "SHO", &local_screenshot, SnapScreenshot, COUNT(SnapScreenshot), version); + + + if(result == SUCCESS && local_screenshot) + { + SnapshotScreenshotInfo *ssi = new SnapshotScreenshotInfo; + + UnfreezeStructFromCopy(ssi, SnapScreenshot, COUNT(SnapScreenshot), local_screenshot, version); + + width = min(ssi->Width, IMAGE_WIDTH); + height = min(ssi->Height, IMAGE_HEIGHT); + + *image_buffer = (uint16 *)malloc(width * height * sizeof(uint16)); + + uint8 *rowpix = ssi->Data; + uint16 *screen = (*image_buffer); + + for(int y = 0; y < height; y++, screen += width) + { + for(int x = 0; x < width; x++) + { + uint32 r, g, b; + + r = *(rowpix++); + g = *(rowpix++); + b = *(rowpix++); + + screen[x] = BUILD_PIXEL(r, g, b); + } + } + + delete ssi; + } + + if(local_screenshot) delete[] local_screenshot; + + return (result); +} + static int FreezeSize (int size, int type) { switch (type) diff --git a/source/snes9x/snapshot.h b/source/snes9x/snapshot.h index f1a5ecc..03e5985 100644 --- a/source/snes9x/snapshot.h +++ b/source/snes9x/snapshot.h @@ -31,5 +31,7 @@ bool8 S9xUnfreezeGame (const char *); int S9xUnfreezeGameMem (const uint8 *,uint32); void S9xFreezeToStream (STREAM); int S9xUnfreezeFromStream (STREAM); +bool8 S9xUnfreezeScreenshot(const char *filename, uint16 **image_buffer, int &width, int &height); +int S9xUnfreezeScreenshotFromStream(STREAM stream, uint16 **image_buffer, int &width, int &height); #endif