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;
|
||||
// ResidualVM specific method
|
||||
virtual void suggestSideTextures(Graphics::Surface *left, Graphics::Surface *right) = 0;
|
||||
// ResidualVM specific method
|
||||
virtual void saveScreenshot() {}
|
||||
|
||||
virtual int16 getHeight() const = 0;
|
||||
virtual int16 getWidth() const = 0;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "backends/events/sdl/sdl-events.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/file.h"
|
||||
#include "engines/engine.h"
|
||||
#include "graphics/pixelbuffer.h"
|
||||
#include "graphics/opengl/context.h"
|
||||
|
@ -36,6 +37,7 @@
|
|||
#include "graphics/opengl/system_headers.h"
|
||||
#include "graphics/opengl/texture.h"
|
||||
#include "graphics/opengl/tiledsurface.h"
|
||||
#include "image/png.h"
|
||||
|
||||
OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window, const Capabilities &capabilities)
|
||||
:
|
||||
|
@ -652,4 +654,64 @@ void OpenGLSdlGraphicsManager::deinitializeRenderer() {
|
|||
}
|
||||
#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
|
||||
|
|
|
@ -112,6 +112,9 @@ protected:
|
|||
Math::Rect2d computeGameRect(bool renderToFrameBuffer, uint gameWidth, uint gameHeight,
|
||||
uint screenWidth, uint screenHeight);
|
||||
|
||||
// ResVmSdlGraphicsManager API
|
||||
bool saveScreenshot(const Common::String &file) const override;
|
||||
|
||||
int _antialiasing;
|
||||
bool _vsync;
|
||||
|
||||
|
|
|
@ -24,9 +24,11 @@
|
|||
|
||||
#include "backends/platform/sdl/sdl-sys.h"
|
||||
#include "backends/events/sdl/sdl-events.h"
|
||||
#include "backends/platform/sdl/sdl.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/file.h"
|
||||
|
||||
static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
|
||||
{0, 0, 0}
|
||||
|
@ -239,6 +241,10 @@ bool ResVmSdlGraphicsManager::notifyEvent(const Common::Event &event) {
|
|||
//ResidualVM specific:
|
||||
switch ((int)event.type) {
|
||||
case Common::EVENT_KEYDOWN:
|
||||
if (event.kbd.hasFlags(Common::KBD_ALT) && event.kbd.keycode == Common::KEYCODE_s) {
|
||||
saveScreenshot();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Common::EVENT_KEYUP:
|
||||
break;
|
||||
|
@ -260,3 +266,41 @@ bool ResVmSdlGraphicsManager::notifyMousePosition(Common::Point mouse) {
|
|||
//setMousePos(mouse.x, mouse.y);
|
||||
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 fillScreen(uint32 col) override;
|
||||
virtual void setShakePos(int shakeOffset) override;
|
||||
void saveScreenshot() override;
|
||||
|
||||
// GraphicsManager API - Focus Rectangle
|
||||
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 */
|
||||
Common::Rect getPreferredFullscreenResolution();
|
||||
|
||||
/** Save a screenshot to the specified file */
|
||||
virtual bool saveScreenshot(const Common::String &file) const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,9 +27,11 @@
|
|||
#include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
|
||||
#include "backends/events/sdl/sdl-events.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/file.h"
|
||||
#include "engines/engine.h"
|
||||
#include "graphics/pixelbuffer.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "image/png.h"
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
|
|
|
@ -91,6 +91,9 @@ protected:
|
|||
void drawOverlay();
|
||||
void drawSideTextures();
|
||||
void closeOverlay();
|
||||
|
||||
// ResVmSdlGraphicsManager API
|
||||
virtual bool saveScreenshot(const Common::String &file) const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -266,6 +266,10 @@ void ModularBackend::setCursorPalette(const byte *colors, uint start, uint num)
|
|||
_graphicsManager->setCursorPalette(colors, start, num);
|
||||
}
|
||||
|
||||
void ModularBackend::saveScreenshot() {
|
||||
_graphicsManager->saveScreenshot();
|
||||
}
|
||||
|
||||
OSystem::MutexRef ModularBackend::createMutex() {
|
||||
assert(_mutexManager);
|
||||
return _mutexManager->createMutex();
|
||||
|
|
|
@ -84,6 +84,7 @@ public:
|
|||
virtual void suggestSideTextures(Graphics::Surface *left, Graphics::Surface *right); // ResidualVM specific method
|
||||
virtual void initSizeHint(const Graphics::ModeList &modes) override;
|
||||
virtual int getScreenChangeID() const override;
|
||||
virtual void saveScreenshot() override; // ResidualVM specific method
|
||||
|
||||
virtual void beginGFXTransaction() override;
|
||||
virtual OSystem::TransactionError endGFXTransaction() override;
|
||||
|
|
|
@ -1041,6 +1041,13 @@ public:
|
|||
*/
|
||||
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