Add screenshot capability
Jeffrey Pfau jeffrey@endrift.com
Fri, 25 Jul 2014 05:44:20 -0700
6 files changed,
118 insertions(+),
1 deletions(-)
M
CMakeLists.txt
→
CMakeLists.txt
@@ -85,7 +85,7 @@ endif()
source_group("ARM debugger" FILES ${DEBUGGER_SRC}) add_library(${BINARY_NAME} SHARED ${ARM_SRC} ${GBA_SRC} ${DEBUGGER_SRC} ${RENDERER_SRC} ${UTIL_SRC} ${VFS_SRC} ${OS_SRC}) -target_link_libraries(${BINARY_NAME} m ${DEBUGGER_LIB} ${OS_LIB} ${DEPENDENCY_LIB}) +target_link_libraries(${BINARY_NAME} m ${DEBUGGER_LIB} ${OS_LIB} ${DEPENDENCY_LIB} png) if(BUILD_SDL) add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/sdl ${CMAKE_BINARY_DIR}/sdl)
M
src/platform/sdl/gl-main.c
→
src/platform/sdl/gl-main.c
@@ -77,6 +77,7 @@ #if SDL_VERSION_ATLEAST(2, 0, 0)
renderer.events.fullscreen = graphicsOpts.fullscreen; renderer.events.windowUpdated = 0; #endif + renderer.events.renderer = &renderer.d; if (!_GBASDLInit(&renderer)) { freeOptions(&opts);
M
src/platform/sdl/sdl-events.c
→
src/platform/sdl/sdl-events.c
@@ -5,6 +5,9 @@ #include "gba-io.h"
#include "gba-rr.h" #include "gba-serialize.h" #include "gba-video.h" +#include "renderers/video-software.h" +#include "util/png-io.h" +#include "util/vfs.h" #if SDL_VERSION_ATLEAST(2, 0, 0) && defined(__APPLE__) #define GUI_MOD KMOD_GUI@@ -14,6 +17,8 @@ #endif
#define SDL_BINDING_KEY 0x53444C4B #define SDL_BINDING_BUTTON 0x53444C42 + +static void _takeScreenshot(struct GBAThread*, struct GBASDLEvents*); bool GBASDLInitEvents(struct GBASDLEvents* context) { if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {@@ -72,6 +77,13 @@ switch (event->keysym.sym) {
case SDLK_F11: if (event->type == SDL_KEYDOWN && context->debugger) { ARMDebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL); + } + return; + case SDLK_F12: + if (event->type == SDL_KEYDOWN) { + GBAThreadInterrupt(context); + _takeScreenshot(context, sdlContext); + GBAThreadContinue(context); } return; case SDLK_TAB:@@ -249,3 +261,12 @@ case SDL_JOYHATMOTION:
_GBASDLHandleJoyHat(context, &event->jhat); } } + +static void _takeScreenshot(struct GBAThread* context, struct GBASDLEvents* sdlContext) { + struct VFile* vf = context->stateDir->openFile(context->stateDir, "screenshot.png", O_CREAT | O_WRONLY); + png_structp png = PNGWriteOpen(vf); + png_infop info = PNGWriteHeader(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + PNGWritePixels(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 256, sdlContext->renderer->outputBuffer); + PNGWriteClose(png, info); + vf->close(vf); +}
M
src/platform/sdl/sdl-events.h
→
src/platform/sdl/sdl-events.h
@@ -7,8 +7,11 @@ #include "gba-thread.h"
#include <SDL.h> +struct GBAVideoSoftwareRenderer; + struct GBASDLEvents { struct GBAInputMap* bindings; + struct GBAVideoSoftwareRenderer* renderer; SDL_Joystick* joystick; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_Window* window;
A
src/util/png-io.c
@@ -0,0 +1,76 @@
+#include "util/png-io.h" + +#include "vfs.h" + +static void _pngWrite(png_structp png, png_bytep buffer, png_size_t size) { + struct VFile* vf = png_get_io_ptr(png); + size_t written = vf->write(vf, buffer, size); + if (written != size) { + png_error(png, "Could not write PNG"); + } +} + +png_structp PNGWriteOpen(struct VFile* source) { + png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (!png) { + return 0; + } + if (setjmp(png_jmpbuf(png))) { + png_destroy_write_struct(&png, 0); + return 0; + } + png_set_write_fn(png, source, _pngWrite, 0); + return png; +} + +png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height) { + png_infop info = png_create_info_struct(png); + if (!info) { + return 0; + } + png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + png_write_info(png, info); + return info; +} + +bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, void* pixels) { + png_bytep row = malloc(sizeof(png_bytep) * width * 3); + if (!row) { + return false; + } + png_bytep pixelData = pixels; + if (setjmp(png_jmpbuf(png))) { + free(row); + return false; + } + unsigned i; + for (i = 0; i < height; ++i) { + unsigned x; + for (x = 0; x < width; ++x) { + row[x * 3] = pixelData[stride * i * 4 + x * 4]; + row[x * 3 + 1] = pixelData[stride * i * 4 + x * 4 + 1]; + row[x * 3 + 2] = pixelData[stride * i * 4 + x * 4 + 2]; + } + png_write_row(png, row); + } + free(row); + return true; +} + +bool PNGWriteCustomChunk(png_structp png, const char* name, size_t size, void* data) { + char realName[5]; + strncpy(realName, name, 4); + realName[0] = tolower(realName[0]); + realName[1] = tolower(realName[1]); + realName[4] = '\0'; + if (setjmp(png_jmpbuf(png))) { + return false; + } + png_write_chunk(png, (png_const_bytep) realName, data, size); + return true; +} + +void PNGWriteClose(png_structp png, png_infop info) { + png_write_end(png, info); + png_destroy_write_struct(&png, &info); +}
A
src/util/png-io.h
@@ -0,0 +1,16 @@
+#ifndef PNG_IO_H +#define PNG_IO_H + +#include "common.h" + +#include <png.h> + +struct VFile; + +png_structp PNGWriteOpen(struct VFile* source); +png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height); +bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, void* pixels); +bool PNGWriteCustomChunk(png_structp png, const char* name, size_t size, void* data); +void PNGWriteClose(png_structp png, png_infop info); + +#endif