From 05c347fc8ad8edc990c9d6e7c15a12d93bd8a3a3 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 19 Oct 2013 20:39:01 +0200 Subject: OPENGL/SDL: Add screenshot support. --- backends/graphics/opengl/opengl-graphics.cpp | 63 ++++++++++++++++++++++ backends/graphics/opengl/opengl-graphics.h | 8 +++ backends/graphics/openglsdl/openglsdl-graphics.cpp | 23 +++++++- 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index e3c56dccca..00e8dc358e 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -29,6 +29,7 @@ #include "common/textconsole.h" #include "common/translation.h" #include "common/algorithm.h" +#include "common/file.h" #ifdef USE_OSD #include "common/tokenizer.h" #include "common/rect.h" @@ -849,6 +850,11 @@ void OpenGLGraphicsManager::notifyContextChange(const Graphics::PixelFormat &def GLCALL(glEnable(GL_TEXTURE_2D)); + // We use a "pack" alignment (when reading from textures) to 4 here, + // since the only place where we really use it is the BMP screenshot + // code and that requires the same alignment too. + GLCALL(glPixelStorei(GL_PACK_ALIGNMENT, 4)); + // Query information needed by textures. Texture::queryTextureInformation(); @@ -1082,4 +1088,61 @@ const Graphics::Font *OpenGLGraphicsManager::getFontOSD() { } #endif +void OpenGLGraphicsManager::saveScreenshot(const Common::String &filename) const { + const uint width = _outputScreenWidth; + const uint height = _outputScreenHeight; + + // A line of a BMP image must have a size divisible by 4. + // We calculate the padding bytes needed here. + // Since we use a 3 byte per pixel mode, we can use width % 4 here, since + // it is equal to 4 - (width * 3) % 4. (4 - (width * Bpp) % 4, is the + // usual way of computing the padding bytes required). + const uint linePaddingSize = width % 4; + const uint lineSize = width * 3 + linePaddingSize; + + // Allocate memory for screenshot + uint8 *pixels = new uint8[lineSize * height]; + + // Get pixel data from OpenGL buffer + GLCALL(glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels)); + + // BMP stores as BGR. Since we can't assume that GL_BGR is supported we + // will swap the components from the RGB we read to BGR on our own. + for (uint y = height; y-- > 0;) { + uint8 *line = pixels + y * lineSize; + + for (uint x = width; x > 0; --x, line += 3) { + SWAP(line[0], line[2]); + } + } + + // Open file + Common::DumpFile out; + out.open(filename); + + // Write BMP header + out.writeByte('B'); + out.writeByte('M'); + out.writeUint32LE(height * lineSize + 54); + out.writeUint32LE(0); + out.writeUint32LE(54); + out.writeUint32LE(40); + out.writeUint32LE(width); + out.writeUint32LE(height); + out.writeUint16LE(1); + out.writeUint16LE(24); + out.writeUint32LE(0); + out.writeUint32LE(0); + out.writeUint32LE(0); + out.writeUint32LE(0); + out.writeUint32LE(0); + out.writeUint32LE(0); + + // Write pixel data to BMP + out.write(pixels, lineSize * height); + + // Free allocated memory + delete[] pixels; +} + } // End of namespace OpenGL diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h index 67ad5aa067..ebfe38fb60 100644 --- a/backends/graphics/opengl/opengl-graphics.h +++ b/backends/graphics/opengl/opengl-graphics.h @@ -247,6 +247,14 @@ protected: */ virtual bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format) = 0; + /** + * Save a screenshot of the full display as BMP to the given file. This + * uses Common::DumpFile for writing the screenshot. + * + * @param filename The output filename. + */ + void saveScreenshot(const Common::String &filename) const; + private: // // OpenGL utilities diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp index a1a3e8590a..925237b75e 100644 --- a/backends/graphics/openglsdl/openglsdl-graphics.cpp +++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp @@ -355,6 +355,26 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) { #endif return true; } + + if (event.kbd.keycode == Common::KEYCODE_s) { + // Alt-s creates a screenshot + Common::String filename; + + for (int n = 0;; n++) { + SDL_RWops *file; + + filename = Common::String::format("scummvm%05d.bmp", n); + file = SDL_RWFromFile(filename.c_str(), "r"); + if (!file) + break; + SDL_RWclose(file); + } + + saveScreenshot(filename.c_str()); + debug("Saved screenshot '%s'", filename.c_str()); + + return true; + } } else if (event.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_ALT)) { if ( event.kbd.keycode == Common::KEYCODE_PLUS || event.kbd.keycode == Common::KEYCODE_MINUS || event.kbd.keycode == Common::KEYCODE_KP_PLUS || event.kbd.keycode == Common::KEYCODE_KP_MINUS) { @@ -502,7 +522,8 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) { bool OpenGLSdlGraphicsManager::isHotkey(const Common::Event &event) { if (event.kbd.hasFlags(Common::KBD_ALT)) { return event.kbd.keycode == Common::KEYCODE_RETURN - || event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER; + || event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER + || event.kbd.keycode == Common::KEYCODE_s; } else if (event.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_ALT)) { return event.kbd.keycode == Common::KEYCODE_PLUS || event.kbd.keycode == Common::KEYCODE_MINUS || event.kbd.keycode == Common::KEYCODE_KP_PLUS || event.kbd.keycode == Common::KEYCODE_KP_MINUS -- cgit v1.2.3