SDL: Implement screenshot saving
This commit is contained in:
parent
203577d66b
commit
d4d6e6203b
10 changed files with 185 additions and 0 deletions
|
@ -78,6 +78,8 @@ public:
|
||||||
virtual Graphics::PixelBuffer getScreenPixelBuffer() = 0;
|
virtual Graphics::PixelBuffer getScreenPixelBuffer() = 0;
|
||||||
// ResidualVM specific method
|
// ResidualVM specific method
|
||||||
virtual void suggestSideTextures(Graphics::Surface *left, Graphics::Surface *right) = 0;
|
virtual void suggestSideTextures(Graphics::Surface *left, Graphics::Surface *right) = 0;
|
||||||
|
// ResidualVM specific method
|
||||||
|
virtual void saveScreenshot() {}
|
||||||
|
|
||||||
virtual int16 getHeight() const = 0;
|
virtual int16 getHeight() const = 0;
|
||||||
virtual int16 getWidth() const = 0;
|
virtual int16 getWidth() const = 0;
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "backends/events/sdl/sdl-events.h"
|
#include "backends/events/sdl/sdl-events.h"
|
||||||
#include "common/config-manager.h"
|
#include "common/config-manager.h"
|
||||||
|
#include "common/file.h"
|
||||||
#include "engines/engine.h"
|
#include "engines/engine.h"
|
||||||
#include "graphics/pixelbuffer.h"
|
#include "graphics/pixelbuffer.h"
|
||||||
#include "graphics/opengl/context.h"
|
#include "graphics/opengl/context.h"
|
||||||
|
@ -36,6 +37,7 @@
|
||||||
#include "graphics/opengl/system_headers.h"
|
#include "graphics/opengl/system_headers.h"
|
||||||
#include "graphics/opengl/texture.h"
|
#include "graphics/opengl/texture.h"
|
||||||
#include "graphics/opengl/tiledsurface.h"
|
#include "graphics/opengl/tiledsurface.h"
|
||||||
|
#include "image/png.h"
|
||||||
|
|
||||||
OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window, const Capabilities &capabilities)
|
OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window, const Capabilities &capabilities)
|
||||||
:
|
:
|
||||||
|
@ -652,4 +654,64 @@ void OpenGLSdlGraphicsManager::deinitializeRenderer() {
|
||||||
}
|
}
|
||||||
#endif // SDL_VERSION_ATLEAST(2, 0, 0)
|
#endif // SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
|
|
||||||
|
bool OpenGLSdlGraphicsManager::saveScreenshot(const Common::String &file) const {
|
||||||
|
// Largely based on the implementation from ScummVM
|
||||||
|
uint width = _overlayScreen->getWidth();
|
||||||
|
uint height = _overlayScreen->getHeight();
|
||||||
|
|
||||||
|
uint linePaddingSize = width % 4;
|
||||||
|
uint lineSize = width * 3 + linePaddingSize;
|
||||||
|
|
||||||
|
Common::DumpFile out;
|
||||||
|
if (!out.open(file)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Array<uint8> pixels;
|
||||||
|
pixels.resize(lineSize * height);
|
||||||
|
|
||||||
|
if (_frameBuffer) {
|
||||||
|
_frameBuffer->detach();
|
||||||
|
}
|
||||||
|
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, &pixels.front());
|
||||||
|
if (_frameBuffer) {
|
||||||
|
_frameBuffer->attach();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_PNG
|
||||||
|
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
|
||||||
|
for (uint y = height; y-- > 0;) {
|
||||||
|
uint8 *line = &pixels.front() + y * lineSize;
|
||||||
|
|
||||||
|
for (uint x = width; x > 0; --x, line += 3) {
|
||||||
|
SWAP(line[0], line[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
out.write(&pixels.front(), pixels.size());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -112,6 +112,9 @@ protected:
|
||||||
Math::Rect2d computeGameRect(bool renderToFrameBuffer, uint gameWidth, uint gameHeight,
|
Math::Rect2d computeGameRect(bool renderToFrameBuffer, uint gameWidth, uint gameHeight,
|
||||||
uint screenWidth, uint screenHeight);
|
uint screenWidth, uint screenHeight);
|
||||||
|
|
||||||
|
// ResVmSdlGraphicsManager API
|
||||||
|
bool saveScreenshot(const Common::String &file) const override;
|
||||||
|
|
||||||
int _antialiasing;
|
int _antialiasing;
|
||||||
bool _vsync;
|
bool _vsync;
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,11 @@
|
||||||
|
|
||||||
#include "backends/platform/sdl/sdl-sys.h"
|
#include "backends/platform/sdl/sdl-sys.h"
|
||||||
#include "backends/events/sdl/sdl-events.h"
|
#include "backends/events/sdl/sdl-events.h"
|
||||||
|
#include "backends/platform/sdl/sdl.h"
|
||||||
|
|
||||||
#include "common/config-manager.h"
|
#include "common/config-manager.h"
|
||||||
#include "common/textconsole.h"
|
#include "common/textconsole.h"
|
||||||
|
#include "common/file.h"
|
||||||
|
|
||||||
static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
|
static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
|
||||||
{0, 0, 0}
|
{0, 0, 0}
|
||||||
|
@ -239,6 +241,10 @@ bool ResVmSdlGraphicsManager::notifyEvent(const Common::Event &event) {
|
||||||
//ResidualVM specific:
|
//ResidualVM specific:
|
||||||
switch ((int)event.type) {
|
switch ((int)event.type) {
|
||||||
case Common::EVENT_KEYDOWN:
|
case Common::EVENT_KEYDOWN:
|
||||||
|
if (event.kbd.hasFlags(Common::KBD_ALT) && event.kbd.keycode == Common::KEYCODE_s) {
|
||||||
|
saveScreenshot();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Common::EVENT_KEYUP:
|
case Common::EVENT_KEYUP:
|
||||||
break;
|
break;
|
||||||
|
@ -260,3 +266,41 @@ bool ResVmSdlGraphicsManager::notifyMousePosition(Common::Point mouse) {
|
||||||
//setMousePos(mouse.x, mouse.y);
|
//setMousePos(mouse.x, mouse.y);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResVmSdlGraphicsManager::saveScreenshot() {
|
||||||
|
OSystem_SDL *g_systemSdl = dynamic_cast<OSystem_SDL*>(g_system);
|
||||||
|
|
||||||
|
if (g_systemSdl) {
|
||||||
|
Common::String filename;
|
||||||
|
Common::String path = g_systemSdl->getScreenshotsPath();
|
||||||
|
|
||||||
|
// Find unused filename
|
||||||
|
int n = 0;
|
||||||
|
while (true) {
|
||||||
|
#ifdef USE_PNG
|
||||||
|
filename = Common::String::format("residualvm%05d.png", n);
|
||||||
|
#else
|
||||||
|
filename = Common::String::format("residualvm%05d.bmp", n);
|
||||||
|
#endif
|
||||||
|
SDL_RWops *file = SDL_RWFromFile((path + filename).c_str(), "r");
|
||||||
|
if (!file) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SDL_RWclose(file);
|
||||||
|
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (saveScreenshot(path + filename)) {
|
||||||
|
if (path.empty())
|
||||||
|
debug("Saved screenshot '%s' in current directory", filename.c_str());
|
||||||
|
else
|
||||||
|
debug("Saved screenshot '%s' in directory '%s'", filename.c_str(), path.c_str());
|
||||||
|
} else {
|
||||||
|
if (path.empty())
|
||||||
|
warning("Could not save screenshot in current directory");
|
||||||
|
else
|
||||||
|
warning("Could not save screenshot in directory '%s'", path.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -99,6 +99,7 @@ public:
|
||||||
virtual void unlockScreen() override;
|
virtual void unlockScreen() override;
|
||||||
virtual void fillScreen(uint32 col) override;
|
virtual void fillScreen(uint32 col) override;
|
||||||
virtual void setShakePos(int shakeOffset) override;
|
virtual void setShakePos(int shakeOffset) override;
|
||||||
|
void saveScreenshot() override;
|
||||||
|
|
||||||
// GraphicsManager API - Focus Rectangle
|
// GraphicsManager API - Focus Rectangle
|
||||||
virtual void setFocusRectangle(const Common::Rect& rect) override;
|
virtual void setFocusRectangle(const Common::Rect& rect) override;
|
||||||
|
@ -145,6 +146,9 @@ protected:
|
||||||
|
|
||||||
/** Obtain the user configured fullscreen resolution, or default to the desktop resolution */
|
/** Obtain the user configured fullscreen resolution, or default to the desktop resolution */
|
||||||
Common::Rect getPreferredFullscreenResolution();
|
Common::Rect getPreferredFullscreenResolution();
|
||||||
|
|
||||||
|
/** Save a screenshot to the specified file */
|
||||||
|
virtual bool saveScreenshot(const Common::String &file) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -27,9 +27,11 @@
|
||||||
#include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
|
#include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
|
||||||
#include "backends/events/sdl/sdl-events.h"
|
#include "backends/events/sdl/sdl-events.h"
|
||||||
#include "common/config-manager.h"
|
#include "common/config-manager.h"
|
||||||
|
#include "common/file.h"
|
||||||
#include "engines/engine.h"
|
#include "engines/engine.h"
|
||||||
#include "graphics/pixelbuffer.h"
|
#include "graphics/pixelbuffer.h"
|
||||||
#include "graphics/surface.h"
|
#include "graphics/surface.h"
|
||||||
|
#include "image/png.h"
|
||||||
|
|
||||||
SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window, const Capabilities &capabilities)
|
SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window, const Capabilities &capabilities)
|
||||||
:
|
:
|
||||||
|
@ -468,4 +470,57 @@ SDL_Surface *SurfaceSdlGraphicsManager::SDL_SetVideoMode(int width, int height,
|
||||||
}
|
}
|
||||||
#endif // SDL_VERSION_ATLEAST(2, 0, 0)
|
#endif // SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
|
|
||||||
|
bool SurfaceSdlGraphicsManager::saveScreenshot(const Common::String &file) const {
|
||||||
|
// Based on the implementation from ScummVM
|
||||||
|
bool success;
|
||||||
|
SDL_Surface *screen = nullptr;
|
||||||
|
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
|
int width, height;
|
||||||
|
SDL_GetRendererOutputSize(_renderer, &width, &height);
|
||||||
|
|
||||||
|
screen = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
24,
|
||||||
|
#ifdef SCUMM_LITTLE_ENDIAN
|
||||||
|
0x0000FF, 0x00FF00, 0xFF0000,
|
||||||
|
#else
|
||||||
|
0xFF0000, 0x00FF00, 0x0000FF,
|
||||||
|
#endif // SCUMM_LITTLE_ENDIAN
|
||||||
|
0);
|
||||||
|
|
||||||
|
SDL_RenderReadPixels(_renderer, nullptr, SDL_PIXELFORMAT_RGB24, screen->pixels, screen->pitch);
|
||||||
|
#else
|
||||||
|
screen = _screen;
|
||||||
|
#endif // SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
|
|
||||||
|
#ifdef USE_PNG
|
||||||
|
Common::DumpFile out;
|
||||||
|
if (!out.open(file)) {
|
||||||
|
success = false;
|
||||||
|
} else {
|
||||||
|
if (SDL_LockSurface(screen) < 0) {
|
||||||
|
warning("Could not lock the screen surface");
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Graphics::PixelFormat format(3, 8, 8, 8, 0, 16, 8, 0, 0);
|
||||||
|
Graphics::Surface data;
|
||||||
|
data.init(width, height, screen->pitch, screen->pixels, format);
|
||||||
|
success = Image::writePNG(out, data);
|
||||||
|
|
||||||
|
SDL_UnlockSurface(screen);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
success = SDL_SaveBMP(screen, file.c_str()) == 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (screen && screen != _screen) {
|
||||||
|
SDL_FreeSurface(screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -91,6 +91,9 @@ protected:
|
||||||
void drawOverlay();
|
void drawOverlay();
|
||||||
void drawSideTextures();
|
void drawSideTextures();
|
||||||
void closeOverlay();
|
void closeOverlay();
|
||||||
|
|
||||||
|
// ResVmSdlGraphicsManager API
|
||||||
|
virtual bool saveScreenshot(const Common::String &file) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -266,6 +266,10 @@ void ModularBackend::setCursorPalette(const byte *colors, uint start, uint num)
|
||||||
_graphicsManager->setCursorPalette(colors, start, num);
|
_graphicsManager->setCursorPalette(colors, start, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModularBackend::saveScreenshot() {
|
||||||
|
_graphicsManager->saveScreenshot();
|
||||||
|
}
|
||||||
|
|
||||||
OSystem::MutexRef ModularBackend::createMutex() {
|
OSystem::MutexRef ModularBackend::createMutex() {
|
||||||
assert(_mutexManager);
|
assert(_mutexManager);
|
||||||
return _mutexManager->createMutex();
|
return _mutexManager->createMutex();
|
||||||
|
|
|
@ -84,6 +84,7 @@ public:
|
||||||
virtual void suggestSideTextures(Graphics::Surface *left, Graphics::Surface *right); // ResidualVM specific method
|
virtual void suggestSideTextures(Graphics::Surface *left, Graphics::Surface *right); // ResidualVM specific method
|
||||||
virtual void initSizeHint(const Graphics::ModeList &modes) override;
|
virtual void initSizeHint(const Graphics::ModeList &modes) override;
|
||||||
virtual int getScreenChangeID() const override;
|
virtual int getScreenChangeID() const override;
|
||||||
|
virtual void saveScreenshot() override; // ResidualVM specific method
|
||||||
|
|
||||||
virtual void beginGFXTransaction() override;
|
virtual void beginGFXTransaction() override;
|
||||||
virtual OSystem::TransactionError endGFXTransaction() override;
|
virtual OSystem::TransactionError endGFXTransaction() override;
|
||||||
|
|
|
@ -1041,6 +1041,13 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void clearFocusRectangle() {}
|
virtual void clearFocusRectangle() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* !!! ResidualVM specific method !!!
|
||||||
|
* Instruct the backend to capture a screenshot of the current screen.
|
||||||
|
*
|
||||||
|
* The backend can persist it the way it considers appropriate.
|
||||||
|
*/
|
||||||
|
virtual void saveScreenshot() {}
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue