aboutsummaryrefslogtreecommitdiff
path: root/backends/graphics
diff options
context:
space:
mode:
authorColin Snover2017-05-12 12:44:44 -0500
committerColin Snover2017-05-21 15:55:39 -0500
commitfa0bb7dd5a60c8f323ecbd5e190ad705bec3e934 (patch)
tree3d7006e16ca0aeeca20b85c7258e979ed07756cb /backends/graphics
parent71989715d02075ebedfd72e4ec5704b3beb91cca (diff)
downloadscummvm-rg350-fa0bb7dd5a60c8f323ecbd5e190ad705bec3e934.tar.gz
scummvm-rg350-fa0bb7dd5a60c8f323ecbd5e190ad705bec3e934.tar.bz2
scummvm-rg350-fa0bb7dd5a60c8f323ecbd5e190ad705bec3e934.zip
BACKENDS: Compress screenshots using PNG if available
Closes gh-948.
Diffstat (limited to 'backends/graphics')
-rw-r--r--backends/graphics/opengl/opengl-graphics.cpp40
-rw-r--r--backends/graphics/openglsdl/openglsdl-graphics.cpp4
-rw-r--r--backends/graphics/surfacesdl/surfacesdl-graphics.cpp68
3 files changed, 93 insertions, 19 deletions
diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index a595d076db..fc27270648 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -28,6 +28,7 @@
#include "backends/graphics/opengl/pipelines/shader.h"
#include "backends/graphics/opengl/shader.h"
+#include "common/array.h"
#include "common/textconsole.h"
#include "common/translation.h"
#include "common/algorithm.h"
@@ -43,6 +44,10 @@
#include "graphics/font.h"
#endif
+#ifdef USE_PNG
+#include "image/png.h"
+#endif
+
namespace OpenGL {
OpenGLGraphicsManager::OpenGLGraphicsManager()
@@ -1311,33 +1316,35 @@ bool OpenGLGraphicsManager::saveScreenshot(const Common::String &filename) const
// 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).
+ // GL_PACK_ALIGNMENT is 4, so this line padding is required for PNG too
const uint linePaddingSize = width % 4;
const uint lineSize = width * 3 + linePaddingSize;
- // Allocate memory for screenshot
- uint8 *pixels = new uint8[lineSize * height];
+ Common::DumpFile out;
+ if (!out.open(filename)) {
+ return false;
+ }
- // Get pixel data from OpenGL buffer
- GL_CALL(glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels));
+ Common::Array<uint8> pixels;
+ pixels.resize(lineSize * height);
+ GL_CALL(glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, &pixels.front()));
+#ifdef USE_PNG
+ const Graphics::PixelFormat format(3, 8, 8, 8, 0, 16, 8, 0, 0);
+ Graphics::Surface data;
+ data.init(width, height, lineSize, &pixels.front(), format);
+ return Image::writePNG(out, data, true);
+#else
// 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;
+ uint8 *line = &pixels.front() + y * lineSize;
for (uint x = width; x > 0; --x, line += 3) {
SWAP(line[0], line[2]);
}
}
- // Open file
- Common::DumpFile out;
- if (!out.open(filename)) {
- delete[] pixels;
- return false;
- }
-
- // Write BMP header
out.writeByte('B');
out.writeByte('M');
out.writeUint32LE(height * lineSize + 54);
@@ -1354,13 +1361,10 @@ bool OpenGLGraphicsManager::saveScreenshot(const Common::String &filename) const
out.writeUint32LE(0);
out.writeUint32LE(0);
out.writeUint32LE(0);
+ out.write(&pixels.front(), pixels.size());
- // Write pixel data to BMP
- out.write(pixels, lineSize * height);
-
- // Free allocated memory
- delete[] pixels;
return true;
+#endif
}
} // End of namespace OpenGL
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp
index 75e2cf8ef7..e41148062f 100644
--- a/backends/graphics/openglsdl/openglsdl-graphics.cpp
+++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp
@@ -633,7 +633,11 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) {
for (int n = 0;; n++) {
SDL_RWops *file;
+#ifdef USE_PNG
+ filename = Common::String::format("scummvm%05d.png", n);
+#else
filename = Common::String::format("scummvm%05d.bmp", n);
+#endif
file = SDL_RWFromFile((screenshotsPath + filename).c_str(), "r");
diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
index ccfcc94ab3..9594587d88 100644
--- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
+++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
@@ -42,6 +42,10 @@
#include "graphics/scaler/aspect.h"
#include "graphics/surface.h"
#include "gui/EventRecorder.h"
+#ifdef USE_PNG
+#include "common/file.h"
+#include "image/png.h"
+#endif
static const OSystem::GraphicsMode s_supportedShaders[] = {
{"NONE", "Normal (no shader)", 0},
@@ -1321,8 +1325,66 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
bool SurfaceSdlGraphicsManager::saveScreenshot(const char *filename) {
assert(_hwscreen != NULL);
- Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+ Common::StackLock lock(_graphicsMutex);
+#ifdef USE_PNG
+ Common::DumpFile out;
+ if (!out.open(filename)) {
+ return false;
+ }
+
+#if SDL_VERSION_ATLEAST(2, 0, 0)
+ SDL_Surface *rgbScreen = SDL_ConvertSurfaceFormat(_hwscreen, SDL_PIXELFORMAT_RGB24, 0);
+#else
+ // This block of code was taken mostly as-is from SDL 1.2's SDL_SaveBMP_RW
+ SDL_Surface *rgbScreen = SDL_CreateRGBSurface(SDL_SWSURFACE,
+ _hwscreen->w,
+ _hwscreen->h,
+ 24,
+#ifdef SCUMM_LITTLE_ENDIAN
+ 0x0000FF, 0x00FF00, 0xFF0000,
+#else
+ 0xFF0000, 0x00FF00, 0x0000FF,
+#endif
+ 0);
+ if (rgbScreen == nullptr) {
+ warning("Could not create RGB24 surface");
+ return false;
+ }
+
+ SDL_Rect bounds;
+ bounds.x = bounds.y = 0;
+ bounds.w = _hwscreen->w;
+ bounds.h = _hwscreen->h;
+ if (SDL_LowerBlit(_hwscreen, &bounds, rgbScreen, &bounds) < 0) {
+ SDL_FreeSurface(rgbScreen);
+ rgbScreen = nullptr;
+ }
+#endif
+
+ if (rgbScreen == nullptr) {
+ warning("Could not convert hardware surface to RGB24");
+ return false;
+ }
+
+ int result = SDL_LockSurface(rgbScreen);
+ if (result < 0) {
+ warning("Could not lock RGB surface");
+ SDL_FreeSurface(rgbScreen);
+ return false;
+ }
+
+ const Graphics::PixelFormat format(3, 8, 8, 8, 0, 16, 8, 0, 0);
+ Graphics::Surface data;
+ data.init(rgbScreen->w, rgbScreen->h, rgbScreen->pitch, rgbScreen->pixels, format);
+ const bool success = Image::writePNG(out, data);
+
+ SDL_UnlockSurface(rgbScreen);
+ SDL_FreeSurface(rgbScreen);
+
+ return success;
+#else
return SDL_SaveBMP(_hwscreen, filename) == 0;
+#endif
}
void SurfaceSdlGraphicsManager::setFullscreenMode(bool enable) {
@@ -2534,7 +2596,11 @@ bool SurfaceSdlGraphicsManager::notifyEvent(const Common::Event &event) {
for (int n = 0;; n++) {
SDL_RWops *file;
+#ifdef USE_PNG
+ filename = Common::String::format("scummvm%05d.png", n);
+#else
filename = Common::String::format("scummvm%05d.bmp", n);
+#endif
file = SDL_RWFromFile((screenshotsPath + filename).c_str(), "r");