diff --git a/src/core/core.c b/src/core/core.c index 7bcc2a3b7..460997432 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -9,6 +9,8 @@ #include "util/vfs.h" #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +#include "util/png-io.h" + bool mCoreLoadFile(struct mCore* core, const char* path) { struct VFile* rom = mDirectorySetOpenPath(&core->dirs, path, core->isROM); if (!rom) { @@ -75,6 +77,32 @@ void mCoreDeleteState(struct mCore* core, int slot) { snprintf(name, sizeof(name), "%s.ss%i", core->dirs.baseName, slot); core->dirs.state->deleteFile(core->dirs.state, name); } + +void mCoreTakeScreenshot(struct mCore* core) { +#ifdef USE_PNG + size_t stride; + color_t* pixels = 0; + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + struct VFile* vf = VDirFindNextAvailable(core->dirs.screenshot, core->dirs.baseName, "-", ".png", O_CREAT | O_TRUNC | O_WRONLY); + bool success = false; + if (vf) { + core->getVideoBuffer(core, &pixels, &stride); + png_structp png = PNGWriteOpen(vf); + png_infop info = PNGWriteHeader(png, width, height); + success = PNGWritePixels(png, width, height, stride, pixels); + PNGWriteClose(png, info); + vf->close(vf); + } + if (success) { + mLOG(STATUS, INFO, "Screenshot saved"); + return; + } +#else + UNUSED(core); +#endif + mLOG(STATUS, WARN, "Failed to take screenshot"); +} #endif void mCoreInitConfig(struct mCore* core, const char* port) { diff --git a/src/core/core.h b/src/core/core.h index 40d090efc..9559d389f 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -51,6 +51,7 @@ struct mCore { void (*desiredVideoDimensions)(struct mCore*, unsigned* width, unsigned* height); void (*setVideoBuffer)(struct mCore*, color_t* buffer, size_t stride); + void (*getVideoBuffer)(struct mCore*, color_t** buffer, size_t* stride); struct blip_t* (*getAudioChannel)(struct mCore*, int ch); @@ -93,6 +94,8 @@ bool mCoreSaveState(struct mCore* core, int slot, int flags); bool mCoreLoadState(struct mCore* core, int slot, int flags); struct VFile* mCoreGetState(struct mCore* core, int slot, bool write); void mCoreDeleteState(struct mCore* core, int slot); + +void mCoreTakeScreenshot(struct mCore* core); #endif void mCoreInitConfig(struct mCore* core, const char* port); diff --git a/src/gb/core.c b/src/gb/core.c index a78caac8e..b38f74e89 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -77,6 +77,12 @@ static void _GBCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t st gbcore->renderer.outputBufferStride = stride; } +static void _GBCoreGetVideoBuffer(struct mCore* core, color_t** buffer, size_t* stride) { + struct GBCore* gbcore = (struct GBCore*) core; + *buffer = gbcore->renderer.outputBuffer; + *stride = gbcore->renderer.outputBufferStride; +} + static struct blip_t* _GBCoreGetAudioChannel(struct mCore* core, int ch) { struct GB* gb = core->board; switch (ch) { @@ -200,6 +206,7 @@ struct mCore* GBCoreCreate(void) { core->loadConfig = _GBCoreLoadConfig; core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions; core->setVideoBuffer = _GBCoreSetVideoBuffer; + core->getVideoBuffer = _GBCoreGetVideoBuffer; core->getAudioChannel = _GBCoreGetAudioChannel; core->isROM = GBIsROM; core->loadROM = _GBCoreLoadROM; diff --git a/src/gba/core.c b/src/gba/core.c index 88d1ba1d1..77a039d6d 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -104,6 +104,12 @@ static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t s gbacore->renderer.outputBufferStride = stride; } +static void _GBACoreGetVideoBuffer(struct mCore* core, color_t** buffer, size_t* stride) { + struct GBACore* gbacore = (struct GBACore*) core; + *buffer = gbacore->renderer.outputBuffer; + *stride = gbacore->renderer.outputBufferStride; +} + static struct blip_t* _GBACoreGetAudioChannel(struct mCore* core, int ch) { struct GBA* gba = core->board; switch (ch) { @@ -243,6 +249,7 @@ struct mCore* GBACoreCreate(void) { core->loadConfig = _GBACoreLoadConfig; core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions; core->setVideoBuffer = _GBACoreSetVideoBuffer; + core->getVideoBuffer = _GBACoreGetVideoBuffer; core->getAudioChannel = _GBACoreGetAudioChannel; core->isROM = GBAIsROM; core->loadROM = _GBACoreLoadROM; diff --git a/src/gba/gui/gui-runner.c b/src/gba/gui/gui-runner.c index 2f157d5ed..e0d3e028e 100644 --- a/src/gba/gui/gui-runner.c +++ b/src/gba/gui/gui-runner.c @@ -342,7 +342,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { mCoreLoadState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT); break; case RUNNER_SCREENSHOT: - // TODO: Put back screenshots + mCoreTakeScreenshot(runner->core); break; case RUNNER_CONFIG: mGUIShowConfig(runner, runner->configExtra, runner->nConfigExtra); diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 0ac4778df..80ffd04d2 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -561,7 +561,7 @@ static void _mSDLHandleKeypress(struct mCoreThread* context, struct mSDLPlayer* return; #ifdef USE_PNG case SDLK_F12: - // TODO: Put back screenshots + mCoreTakeScreenshot(context->core); return; #endif case SDLK_BACKSLASH: