mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-05-01 14:17:58 +03:00
glrage: make .jpg screenshots
This commit is contained in:
parent
6402a325d6
commit
b3d5703b92
18 changed files with 90 additions and 126 deletions
|
@ -221,7 +221,6 @@ sources = [
|
||||||
'src/glrage/ContextImpl.cpp',
|
'src/glrage/ContextImpl.cpp',
|
||||||
'src/glrage/GLRage.cpp',
|
'src/glrage/GLRage.cpp',
|
||||||
'src/glrage/Interop.cpp',
|
'src/glrage/Interop.cpp',
|
||||||
'src/glrage/Screenshot.cpp',
|
|
||||||
'src/glrage_gl/Buffer.cpp',
|
'src/glrage_gl/Buffer.cpp',
|
||||||
'src/glrage_gl/Program.cpp',
|
'src/glrage_gl/Program.cpp',
|
||||||
'src/glrage_gl/Sampler.cpp',
|
'src/glrage_gl/Sampler.cpp',
|
||||||
|
|
|
@ -83,7 +83,7 @@ HRESULT DirectDrawSurface::Blt(
|
||||||
|
|
||||||
gl::Screenshot::capture(
|
gl::Screenshot::capture(
|
||||||
buffer, width, height, depth, GL_BGRA,
|
buffer, width, height, depth, GL_BGRA,
|
||||||
GL_UNSIGNED_INT_8_8_8_8_REV);
|
GL_UNSIGNED_INT_8_8_8_8_REV, false);
|
||||||
|
|
||||||
Blitter::Rect srcRect { 0, height, width, 0 };
|
Blitter::Rect srcRect { 0, height, width, 0 };
|
||||||
|
|
||||||
|
|
|
@ -856,3 +856,8 @@ void Output_ApplyWaterEffect(float *r, float *g, float *b)
|
||||||
*b *= m_WaterColor.b;
|
*b *= m_WaterColor.b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Output_MakeScreenshot(const char *path)
|
||||||
|
{
|
||||||
|
return S_Output_MakeScreenshot(path);
|
||||||
|
}
|
||||||
|
|
|
@ -71,4 +71,6 @@ void Output_AnimateTextures(int32_t ticks);
|
||||||
|
|
||||||
void Output_ApplyWaterEffect(float *r, float *g, float *b);
|
void Output_ApplyWaterEffect(float *r, float *g, float *b);
|
||||||
|
|
||||||
|
bool Output_MakeScreenshot(const char *path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "3dsystem/phd_math.h"
|
#include "3dsystem/phd_math.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "filesystem.h"
|
||||||
#include "game/clock.h"
|
#include "game/clock.h"
|
||||||
#include "game/demo.h"
|
#include "game/demo.h"
|
||||||
#include "game/fmv.h"
|
#include "game/fmv.h"
|
||||||
|
@ -186,3 +187,16 @@ void Shell_Wait(int nticks)
|
||||||
Input_Update();
|
Input_Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Shell_MakeScreenshot()
|
||||||
|
{
|
||||||
|
char path[20];
|
||||||
|
for (int i = 0; i < 10000; i++) {
|
||||||
|
sprintf(path, "screenshot%04d.jpg", i);
|
||||||
|
if (File_Exists(path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return Output_MakeScreenshot(path);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#ifndef T1M_GAME_SHELL_H
|
#ifndef T1M_GAME_SHELL_H
|
||||||
#define T1M_GAME_SHELL_H
|
#define T1M_GAME_SHELL_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
void Shell_Main();
|
void Shell_Main();
|
||||||
void Shell_ExitSystem(const char *message);
|
void Shell_ExitSystem(const char *message);
|
||||||
void Shell_ExitSystemFmt(const char *fmt, ...);
|
void Shell_ExitSystemFmt(const char *fmt, ...);
|
||||||
void Shell_Wait(int nticks);
|
void Shell_Wait(int nticks);
|
||||||
|
bool Shell_MakeScreenshot();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,6 +28,7 @@ public:
|
||||||
virtual bool isRendered() = 0;
|
virtual bool isRendered() = 0;
|
||||||
virtual HWND getHWnd() = 0;
|
virtual HWND getHWnd() = 0;
|
||||||
virtual std::string getBasePath() = 0;
|
virtual std::string getBasePath() = 0;
|
||||||
|
virtual void scheduleScreenshot(const std::string &path) = 0;
|
||||||
|
|
||||||
virtual ~Context() = default;
|
virtual ~Context() = default;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "glrage/ContextImpl.hpp"
|
#include "glrage/ContextImpl.hpp"
|
||||||
|
|
||||||
|
#include "glrage_gl/Screenshot.hpp"
|
||||||
#include "glrage_gl/gl_core_3_3.h"
|
#include "glrage_gl/gl_core_3_3.h"
|
||||||
#include "glrage_gl/wgl_ext.h"
|
#include "glrage_gl/wgl_ext.h"
|
||||||
#include "glrage_util/ErrorUtils.hpp"
|
#include "glrage_util/ErrorUtils.hpp"
|
||||||
|
@ -109,17 +110,6 @@ LRESULT
|
||||||
ContextImpl::windowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
ContextImpl::windowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
// Printscreen on Windows with OpenGL doesn't work in fullscreen, so
|
|
||||||
// hook the key and implement screenshot saving to files.
|
|
||||||
// For some reason, VK_SNAPSHOT doesn't generate WM_KEYDOWN events but
|
|
||||||
// only WM_KEYUP. Works just as well, though.
|
|
||||||
case WM_KEYUP:
|
|
||||||
if (wParam == VK_SNAPSHOT) {
|
|
||||||
m_screenshot.schedule(true);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// force default handling for some window messages when in windowed
|
// force default handling for some window messages when in windowed
|
||||||
// mode, especially important for Tomb Raider
|
// mode, especially important for Tomb Raider
|
||||||
case WM_MOVE:
|
case WM_MOVE:
|
||||||
|
@ -223,11 +213,9 @@ void ContextImpl::swapBuffers()
|
||||||
{
|
{
|
||||||
glFinish();
|
glFinish();
|
||||||
|
|
||||||
try {
|
if (!m_screenshotScheduledPath.empty()) {
|
||||||
m_screenshot.captureScheduled();
|
gl::Screenshot::capture(m_screenshotScheduledPath);
|
||||||
} catch (const std::exception &ex) {
|
m_screenshotScheduledPath.clear();
|
||||||
ErrorUtils::warning("Can't capture screenshot", ex);
|
|
||||||
m_screenshot.schedule(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SwapBuffers(m_hdc);
|
SwapBuffers(m_hdc);
|
||||||
|
@ -270,4 +258,9 @@ std::string ContextImpl::getBasePath()
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContextImpl::scheduleScreenshot(const std::string &path)
|
||||||
|
{
|
||||||
|
m_screenshotScheduledPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "glrage/Context.hpp"
|
#include "glrage/Context.hpp"
|
||||||
#include "glrage/Screenshot.hpp"
|
|
||||||
|
|
||||||
namespace glrage {
|
namespace glrage {
|
||||||
|
|
||||||
|
@ -30,6 +29,7 @@ public:
|
||||||
bool isRendered();
|
bool isRendered();
|
||||||
HWND getHWnd();
|
HWND getHWnd();
|
||||||
std::string getBasePath();
|
std::string getBasePath();
|
||||||
|
void scheduleScreenshot(const std::string &path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ContextImpl();
|
ContextImpl();
|
||||||
|
@ -66,9 +66,6 @@ private:
|
||||||
// rendering flag
|
// rendering flag
|
||||||
bool m_render = false;
|
bool m_render = false;
|
||||||
|
|
||||||
// screenshot object
|
|
||||||
Screenshot m_screenshot;
|
|
||||||
|
|
||||||
// DirectDraw display mode
|
// DirectDraw display mode
|
||||||
int32_t m_displayWidth = 0;
|
int32_t m_displayWidth = 0;
|
||||||
int32_t m_displayHeight = 0;
|
int32_t m_displayHeight = 0;
|
||||||
|
@ -80,6 +77,9 @@ private:
|
||||||
// Window size, controlled by SDL
|
// Window size, controlled by SDL
|
||||||
int32_t m_windowWidth = 0;
|
int32_t m_windowWidth = 0;
|
||||||
int32_t m_windowHeight = 0;
|
int32_t m_windowHeight = 0;
|
||||||
|
|
||||||
|
// whether to capture screenshot on next redraw
|
||||||
|
std::string m_screenshotScheduledPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,3 +27,10 @@ void GLRage_SetWindowSize(int width, int height)
|
||||||
auto &context = GLRage::getContext();
|
auto &context = GLRage::getContext();
|
||||||
context.setWindowSize(width, height);
|
context.setWindowSize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GLRage_MakeScreenshot(const char *path)
|
||||||
|
{
|
||||||
|
auto &context = GLRage::getContext();
|
||||||
|
context.scheduleScreenshot(std::string(path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ void GLRage_Detach();
|
||||||
void GLRage_SetFullscreen(bool fullscreen);
|
void GLRage_SetFullscreen(bool fullscreen);
|
||||||
void GLRage_SetWindowSize(int width, int height);
|
void GLRage_SetWindowSize(int width, int height);
|
||||||
|
|
||||||
|
bool GLRage_MakeScreenshot(const char *path);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
#include "glrage/Screenshot.hpp"
|
|
||||||
|
|
||||||
#include "glrage/ContextImpl.hpp"
|
|
||||||
#include "glrage_gl/Screenshot.hpp"
|
|
||||||
#include "glrage_util/StringUtils.hpp"
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <exception>
|
|
||||||
#include <fstream>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace glrage {
|
|
||||||
|
|
||||||
void Screenshot::schedule(bool schedule)
|
|
||||||
{
|
|
||||||
m_schedule = schedule;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screenshot::captureScheduled()
|
|
||||||
{
|
|
||||||
if (m_schedule) {
|
|
||||||
capture();
|
|
||||||
m_schedule = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screenshot::capture()
|
|
||||||
{
|
|
||||||
// find unused screenshot file name
|
|
||||||
std::string basePath = ContextImpl::instance().getBasePath();
|
|
||||||
std::string path;
|
|
||||||
DWORD dwAttrib;
|
|
||||||
do {
|
|
||||||
std::string fileName =
|
|
||||||
StringUtils::format("screenshot%04d.tga", m_index++);
|
|
||||||
path = basePath + "\\" + fileName;
|
|
||||||
dwAttrib = GetFileAttributes(path.c_str());
|
|
||||||
} while (dwAttrib != INVALID_FILE_ATTRIBUTES && m_index < 9999);
|
|
||||||
|
|
||||||
// rather unlikely, but better safe than sorry
|
|
||||||
if (dwAttrib != INVALID_FILE_ATTRIBUTES) {
|
|
||||||
throw std::runtime_error("All available screenshot slots are used up!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// actual capture
|
|
||||||
gl::Screenshot::capture(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace glrage {
|
|
||||||
|
|
||||||
class Screenshot {
|
|
||||||
public:
|
|
||||||
void schedule(bool schedule);
|
|
||||||
void captureScheduled();
|
|
||||||
void capture();
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t m_index = 0;
|
|
||||||
bool m_schedule = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -3,6 +3,11 @@
|
||||||
#include "glrage_util/ErrorUtils.hpp"
|
#include "glrage_util/ErrorUtils.hpp"
|
||||||
#include "glrage_util/StringUtils.hpp"
|
#include "glrage_util/StringUtils.hpp"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "memory.h"
|
||||||
|
#include "game/picture.h"
|
||||||
|
}
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
@ -14,46 +19,34 @@
|
||||||
namespace glrage {
|
namespace glrage {
|
||||||
namespace gl {
|
namespace gl {
|
||||||
|
|
||||||
// heavily simplified Targa header struct for raw BGR(A) data
|
bool Screenshot::capture(const std::string &path)
|
||||||
struct TGAHeader {
|
|
||||||
uint8_t blank1[2];
|
|
||||||
uint8_t format;
|
|
||||||
uint8_t blank2[9];
|
|
||||||
uint16_t width;
|
|
||||||
uint16_t height;
|
|
||||||
uint8_t depth;
|
|
||||||
uint8_t blank3;
|
|
||||||
};
|
|
||||||
|
|
||||||
void Screenshot::capture(const std::string &path)
|
|
||||||
{
|
{
|
||||||
// open screenshot file
|
bool ret = false;
|
||||||
std::ofstream file(path, std::ofstream::binary);
|
|
||||||
if (!file.good()) {
|
|
||||||
throw std::runtime_error(
|
|
||||||
"Can't open screenshot file '" + path
|
|
||||||
+ "': " + ErrorUtils::getSystemErrorString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy framebuffer to local buffer
|
|
||||||
GLint width;
|
GLint width;
|
||||||
GLint height;
|
GLint height;
|
||||||
GLint depth = 3;
|
|
||||||
|
|
||||||
std::vector<uint8_t> buffer;
|
std::vector<uint8_t> buffer;
|
||||||
capture(buffer, width, height, depth, GL_BGR, GL_UNSIGNED_BYTE, false);
|
|
||||||
|
|
||||||
// create Targa header
|
Screenshot::capture(
|
||||||
TGAHeader tgaHeader = { { 0, 0 }, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 0,
|
buffer, width, height, 3, GL_RGB, GL_UNSIGNED_BYTE, true);
|
||||||
0, 0 };
|
|
||||||
tgaHeader.format = 2;
|
|
||||||
tgaHeader.width = width;
|
|
||||||
tgaHeader.height = height;
|
|
||||||
tgaHeader.depth = depth * 8;
|
|
||||||
|
|
||||||
file.write(reinterpret_cast<char *>(&tgaHeader), sizeof(TGAHeader));
|
PICTURE *pic = Picture_Create();
|
||||||
file.write(reinterpret_cast<char *>(&buffer[0]), buffer.size());
|
if (!pic) {
|
||||||
file.close();
|
goto cleanup;
|
||||||
|
}
|
||||||
|
pic->width = width;
|
||||||
|
pic->height = height;
|
||||||
|
pic->data = static_cast<RGB888 *>(Memory_Alloc(width * height * 3));
|
||||||
|
std::copy(
|
||||||
|
buffer.begin(), buffer.end(), reinterpret_cast<uint8_t *>(pic->data));
|
||||||
|
|
||||||
|
ret = Picture_SaveToFile(pic, path.c_str());
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (pic) {
|
||||||
|
Picture_Free(pic);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screenshot::capture(
|
void Screenshot::capture(
|
||||||
|
|
|
@ -11,10 +11,10 @@ namespace gl {
|
||||||
|
|
||||||
class Screenshot {
|
class Screenshot {
|
||||||
public:
|
public:
|
||||||
static void capture(const std::string &path);
|
static bool capture(const std::string &path);
|
||||||
static void capture(
|
static void capture(
|
||||||
std::vector<uint8_t> &buffer, GLint &width, GLint &height, GLint depth,
|
std::vector<uint8_t> &buffer, GLint &width, GLint &height, GLint depth,
|
||||||
GLenum format, GLenum type, bool vflip = false);
|
GLenum format, GLenum type, bool vflip);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1543,3 +1543,8 @@ void S_Output_DownloadTextures(int32_t pages)
|
||||||
|
|
||||||
m_SelectedTexture = -1;
|
m_SelectedTexture = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool S_Output_MakeScreenshot(const char *path)
|
||||||
|
{
|
||||||
|
return GLRage_MakeScreenshot(path);
|
||||||
|
}
|
||||||
|
|
|
@ -54,4 +54,6 @@ void S_Output_DrawLightningSegment(
|
||||||
int x1, int y1, int z1, int thickness1, int x2, int y2, int z2,
|
int x1, int y1, int z1, int thickness1, int x2, int y2, int z2,
|
||||||
int thickness2);
|
int thickness2);
|
||||||
|
|
||||||
|
bool S_Output_MakeScreenshot(const char *path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -87,6 +87,13 @@ void S_Shell_SpinMessageLoop()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SDL_KEYUP:
|
||||||
|
if (event.key.keysym.sym == SDLK_PRINTSCREEN) {
|
||||||
|
Shell_MakeScreenshot();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_WINDOWEVENT:
|
||||||
switch (event.window.event) {
|
switch (event.window.event) {
|
||||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue