mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-25 23:25:40 +00:00
Added Screenshot feature (ALT+S).
This commit is contained in:
parent
ca57659fcb
commit
981cdc33f5
|
@ -58,6 +58,7 @@ CInputs::CInputs(CInputSystem *system)
|
||||||
uiToggleFrLimit = AddSwitchInput("UIToggleFrameLimit", "Toggle Frame Limiting", Game::INPUT_UI, "KEY_ALT+KEY_T");
|
uiToggleFrLimit = AddSwitchInput("UIToggleFrameLimit", "Toggle Frame Limiting", Game::INPUT_UI, "KEY_ALT+KEY_T");
|
||||||
uiDumpInpState = AddSwitchInput("UIDumpInputState", "Dump Input State", Game::INPUT_UI, "KEY_ALT+KEY_U");
|
uiDumpInpState = AddSwitchInput("UIDumpInputState", "Dump Input State", Game::INPUT_UI, "KEY_ALT+KEY_U");
|
||||||
uiDumpTimings = AddSwitchInput("UIDumpTimings", "Dump Frame Timings", Game::INPUT_UI, "KEY_ALT+KEY_O");
|
uiDumpTimings = AddSwitchInput("UIDumpTimings", "Dump Frame Timings", Game::INPUT_UI, "KEY_ALT+KEY_O");
|
||||||
|
uiScreenshot = AddSwitchInput("UIScreenShot", "Screenshot", Game::INPUT_UI, "KEY_ALT+KEY_S");
|
||||||
#ifdef SUPERMODEL_DEBUGGER
|
#ifdef SUPERMODEL_DEBUGGER
|
||||||
uiEnterDebugger = AddSwitchInput("UIEnterDebugger", "Enter Debugger", Game::INPUT_UI, "KEY_ALT+KEY_B");
|
uiEnterDebugger = AddSwitchInput("UIEnterDebugger", "Enter Debugger", Game::INPUT_UI, "KEY_ALT+KEY_B");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -105,6 +105,7 @@ public:
|
||||||
CSwitchInput *uiToggleFrLimit;
|
CSwitchInput *uiToggleFrLimit;
|
||||||
CSwitchInput *uiDumpInpState;
|
CSwitchInput *uiDumpInpState;
|
||||||
CSwitchInput *uiDumpTimings;
|
CSwitchInput *uiDumpTimings;
|
||||||
|
CSwitchInput *uiScreenshot;
|
||||||
#ifdef SUPERMODEL_DEBUGGER
|
#ifdef SUPERMODEL_DEBUGGER
|
||||||
CSwitchInput *uiEnterDebugger;
|
CSwitchInput *uiEnterDebugger;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
#include "SDLIncludes.h"
|
#include "SDLIncludes.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "Util/BMPFile.h"
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
@ -195,7 +196,7 @@ static bool CreateGLScreen(const std::string &caption, bool focusWindow, unsigne
|
||||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8);
|
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8);
|
||||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,8);
|
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,8);
|
||||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,24);
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,24);
|
||||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,8);
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,8);
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
|
||||||
|
|
||||||
// Set video mode
|
// Set video mode
|
||||||
|
@ -413,6 +414,27 @@ static void DumpPPCRegisters(IBus *bus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void SaveFrameBuffer(const std::string& file)
|
||||||
|
{
|
||||||
|
std::shared_ptr<uint8_t> pixels(new uint8_t[totalXRes * totalYRes * 4], std::default_delete<uint8_t[]>());
|
||||||
|
glReadPixels(0, 0, totalXRes, totalYRes, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
|
||||||
|
Util::WriteSurfaceToBMP<Util::RGBA8>(file, pixels.get(), totalXRes, totalYRes, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screenshot()
|
||||||
|
{
|
||||||
|
// Make a screenshot
|
||||||
|
char file[128];
|
||||||
|
string info = "Screenshot created: ";
|
||||||
|
time_t now = time(0);
|
||||||
|
tm* ltm = localtime(&now);
|
||||||
|
|
||||||
|
sprintf(file, "Screenshot %.4d-%.2d-%.2d (%.2d-%.2d-%.2d).bmp", 1900 + ltm->tm_year, 1 + ltm->tm_mon, ltm->tm_mday, ltm->tm_hour, ltm->tm_min, ltm->tm_sec);
|
||||||
|
|
||||||
|
info += file;
|
||||||
|
puts(info.c_str());
|
||||||
|
SaveFrameBuffer(file);
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
Render State Analysis
|
Render State Analysis
|
||||||
|
@ -421,17 +443,9 @@ static void DumpPPCRegisters(IBus *bus)
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
||||||
#include "Model3/Model3GraphicsState.h"
|
#include "Model3/Model3GraphicsState.h"
|
||||||
#include "Util/BMPFile.h"
|
|
||||||
#include "OSD/SDL/PolyAnalysis.h"
|
#include "OSD/SDL/PolyAnalysis.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
static void SaveFrameBuffer(const std::string &file)
|
|
||||||
{
|
|
||||||
std::shared_ptr<uint8_t> pixels(new uint8_t[totalXRes*totalYRes*4], std::default_delete<uint8_t[]>());
|
|
||||||
glReadPixels(0, 0, totalXRes, totalYRes, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
|
|
||||||
Util::WriteSurfaceToBMP<Util::RGBA8>(file, pixels.get(), totalXRes, totalYRes, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string s_gfxStatePath;
|
static std::string s_gfxStatePath;
|
||||||
|
|
||||||
static std::string GetFileBaseName(const std::string &file)
|
static std::string GetFileBaseName(const std::string &file)
|
||||||
|
@ -715,91 +729,91 @@ static void PrintGLError(GLenum error)
|
||||||
case GL_NO_ERROR: break;
|
case GL_NO_ERROR: break;
|
||||||
default: printf("unknown error\n"); break;
|
default: printf("unknown error\n"); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void UpdateCrosshairs(uint32_t currentInputs, CInputs *Inputs, unsigned crosshairs)
|
static void UpdateCrosshairs(uint32_t currentInputs, CInputs *Inputs, unsigned crosshairs)
|
||||||
|
|
||||||
{
|
{
|
||||||
bool offscreenTrigger[2];
|
bool offscreenTrigger[2];
|
||||||
float x[2], y[2];
|
float x[2], y[2];
|
||||||
|
|
||||||
crosshairs &= 3;
|
crosshairs &= 3;
|
||||||
if (!crosshairs)
|
if (!crosshairs)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Set up the viewport and orthogonal projection
|
// Set up the viewport and orthogonal projection
|
||||||
glUseProgram(0); // no shaders
|
glUseProgram(0); // no shaders
|
||||||
glViewport(xOffset, yOffset, xRes, yRes);
|
glViewport(xOffset, yOffset, xRes, yRes);
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
gluOrtho2D(0.0, 1.0, 1.0, 0.0);
|
gluOrtho2D(0.0, 1.0, 1.0, 0.0);
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glDisable(GL_TEXTURE_2D); // no texture mapping
|
glDisable(GL_TEXTURE_2D); // no texture mapping
|
||||||
glDisable(GL_BLEND); // no blending
|
glDisable(GL_BLEND); // no blending
|
||||||
glDisable(GL_DEPTH_TEST); // no Z-buffering needed
|
glDisable(GL_DEPTH_TEST); // no Z-buffering needed
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
|
|
||||||
// Convert gun coordinates to viewspace coordinates
|
// Convert gun coordinates to viewspace coordinates
|
||||||
if (currentInputs & Game::INPUT_ANALOG_GUN1)
|
if (currentInputs & Game::INPUT_ANALOG_GUN1)
|
||||||
{
|
{
|
||||||
x[0] = ((float)Inputs->analogGunX[0]->value / 255.0f);
|
x[0] = ((float)Inputs->analogGunX[0]->value / 255.0f);
|
||||||
y[0] = ((255.0f - (float)Inputs->analogGunY[0]->value) / 255.0f);
|
y[0] = ((255.0f - (float)Inputs->analogGunY[0]->value) / 255.0f);
|
||||||
offscreenTrigger[0] = Inputs->analogTriggerLeft[0]->value || Inputs->analogTriggerRight[0]->value;
|
offscreenTrigger[0] = Inputs->analogTriggerLeft[0]->value || Inputs->analogTriggerRight[0]->value;
|
||||||
}
|
}
|
||||||
else if (currentInputs & Game::INPUT_GUN1)
|
else if (currentInputs & Game::INPUT_GUN1)
|
||||||
{
|
{
|
||||||
x[0] = (float)Inputs->gunX[0]->value;
|
x[0] = (float)Inputs->gunX[0]->value;
|
||||||
y[0] = (float)Inputs->gunY[0]->value;
|
y[0] = (float)Inputs->gunY[0]->value;
|
||||||
GunToViewCoords(&x[0], &y[0]);
|
GunToViewCoords(&x[0], &y[0]);
|
||||||
offscreenTrigger[0] = (Inputs->trigger[0]->offscreenValue) > 0;
|
offscreenTrigger[0] = (Inputs->trigger[0]->offscreenValue) > 0;
|
||||||
}
|
}
|
||||||
if (currentInputs & Game::INPUT_ANALOG_GUN2)
|
if (currentInputs & Game::INPUT_ANALOG_GUN2)
|
||||||
{
|
{
|
||||||
x[1] = ((float)Inputs->analogGunX[1]->value / 255.0f);
|
x[1] = ((float)Inputs->analogGunX[1]->value / 255.0f);
|
||||||
y[1] = ((255.0f - (float)Inputs->analogGunY[1]->value) / 255.0f);
|
y[1] = ((255.0f - (float)Inputs->analogGunY[1]->value) / 255.0f);
|
||||||
offscreenTrigger[1] = Inputs->analogTriggerLeft[1]->value || Inputs->analogTriggerRight[1]->value;
|
offscreenTrigger[1] = Inputs->analogTriggerLeft[1]->value || Inputs->analogTriggerRight[1]->value;
|
||||||
}
|
}
|
||||||
else if (currentInputs & Game::INPUT_GUN2)
|
else if (currentInputs & Game::INPUT_GUN2)
|
||||||
{
|
{
|
||||||
x[1] = (float)Inputs->gunX[1]->value;
|
x[1] = (float)Inputs->gunX[1]->value;
|
||||||
y[1] = (float)Inputs->gunY[1]->value;
|
y[1] = (float)Inputs->gunY[1]->value;
|
||||||
GunToViewCoords(&x[1], &y[1]);
|
GunToViewCoords(&x[1], &y[1]);
|
||||||
offscreenTrigger[1] = (Inputs->trigger[1]->offscreenValue) > 0;
|
offscreenTrigger[1] = (Inputs->trigger[1]->offscreenValue) > 0;
|
||||||
}
|
}
|
||||||
// Draw visible crosshairs
|
// Draw visible crosshairs
|
||||||
glBegin(GL_TRIANGLES);
|
glBegin(GL_TRIANGLES);
|
||||||
if ((crosshairs & 1) && !offscreenTrigger[0]) // Player 1
|
if ((crosshairs & 1) && !offscreenTrigger[0]) // Player 1
|
||||||
DrawCrosshair(x[0], y[0], 1.0f, 0.0f, 0.0f);
|
DrawCrosshair(x[0], y[0], 1.0f, 0.0f, 0.0f);
|
||||||
if ((crosshairs & 2) && !offscreenTrigger[1]) // Player 2
|
if ((crosshairs & 2) && !offscreenTrigger[1]) // Player 2
|
||||||
DrawCrosshair(x[1], y[1], 0.0f, 1.0f, 0.0f);
|
DrawCrosshair(x[1], y[1], 0.0f, 1.0f, 0.0f);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
//PrintGLError(glGetError());
|
//PrintGLError(glGetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
Video Callbacks
|
Video Callbacks
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
static CInputs *videoInputs = NULL;
|
static CInputs *videoInputs = NULL;
|
||||||
static uint32_t currentInputs = 0;
|
static uint32_t currentInputs = 0;
|
||||||
|
|
||||||
bool BeginFrameVideo()
|
bool BeginFrameVideo()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EndFrameVideo()
|
void EndFrameVideo()
|
||||||
{
|
{
|
||||||
// Show crosshairs for light gun games
|
// Show crosshairs for light gun games
|
||||||
if (videoInputs)
|
if (videoInputs)
|
||||||
UpdateCrosshairs(currentInputs, videoInputs, s_runtime_config["Crosshairs"].ValueAs<unsigned>());
|
UpdateCrosshairs(currentInputs, videoInputs, s_runtime_config["Crosshairs"].ValueAs<unsigned>());
|
||||||
|
|
||||||
// Swap the buffers
|
// Swap the buffers
|
||||||
SDL_GL_SwapWindow(s_window);
|
SDL_GL_SwapWindow(s_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SuperSleep(UINT32 time)
|
static void SuperSleep(UINT32 time)
|
||||||
|
@ -863,14 +877,14 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
|
||||||
if (OKAY != OpenAudio())
|
if (OKAY != OpenAudio())
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// Hide mouse if fullscreen, enable crosshairs for gun games
|
// Hide mouse if fullscreen, enable crosshairs for gun games
|
||||||
Inputs->GetInputSystem()->SetMouseVisibility(!s_runtime_config["FullScreen"].ValueAs<bool>());
|
Inputs->GetInputSystem()->SetMouseVisibility(!s_runtime_config["FullScreen"].ValueAs<bool>());
|
||||||
gameHasLightguns = !!(game.inputs & (Game::INPUT_GUN1|Game::INPUT_GUN2));
|
gameHasLightguns = !!(game.inputs & (Game::INPUT_GUN1|Game::INPUT_GUN2));
|
||||||
gameHasLightguns |= game.name == "lostwsga";
|
gameHasLightguns |= game.name == "lostwsga";
|
||||||
currentInputs = game.inputs;
|
currentInputs = game.inputs;
|
||||||
if (gameHasLightguns)
|
if (gameHasLightguns)
|
||||||
videoInputs = Inputs;
|
videoInputs = Inputs;
|
||||||
else
|
else
|
||||||
videoInputs = NULL;
|
videoInputs = NULL;
|
||||||
|
|
||||||
// Attach the inputs to the emulator
|
// Attach the inputs to the emulator
|
||||||
|
@ -1175,6 +1189,11 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
|
||||||
s_runtime_config.Get("Throttle").SetValue(!s_runtime_config["Throttle"].ValueAs<bool>());
|
s_runtime_config.Get("Throttle").SetValue(!s_runtime_config["Throttle"].ValueAs<bool>());
|
||||||
printf("Frame limiting: %s\n", s_runtime_config["Throttle"].ValueAs<bool>() ? "On" : "Off");
|
printf("Frame limiting: %s\n", s_runtime_config["Throttle"].ValueAs<bool>() ? "On" : "Off");
|
||||||
}
|
}
|
||||||
|
else if (Inputs->uiScreenshot->Pressed())
|
||||||
|
{
|
||||||
|
// Make a screenshot
|
||||||
|
Screenshot();
|
||||||
|
}
|
||||||
#ifdef SUPERMODEL_DEBUGGER
|
#ifdef SUPERMODEL_DEBUGGER
|
||||||
else if (Debugger != NULL && Inputs->uiEnterDebugger->Pressed())
|
else if (Debugger != NULL && Inputs->uiEnterDebugger->Pressed())
|
||||||
{
|
{
|
||||||
|
@ -1320,16 +1339,16 @@ static void PrintGameList(const std::string &xml_file, const std::map<std::strin
|
||||||
for (auto &v: games)
|
for (auto &v: games)
|
||||||
{
|
{
|
||||||
const Game &game = v.second;
|
const Game &game = v.second;
|
||||||
printf(" %s", game.name.c_str());
|
printf(" %s", game.name.c_str());
|
||||||
for (int i = game.name.length(); i < 9; i++) // pad for alignment (no game ID should be more than 9 letters)
|
for (int i = game.name.length(); i < 9; i++) // pad for alignment (no game ID should be more than 9 letters)
|
||||||
printf(" ");
|
printf(" ");
|
||||||
if (!game.version.empty())
|
if (!game.version.empty())
|
||||||
printf(" %s (%s)\n", game.title.c_str(), game.version.c_str());
|
printf(" %s (%s)\n", game.title.c_str(), game.version.c_str());
|
||||||
else
|
else
|
||||||
printf(" %s\n", game.title.c_str());
|
printf(" %s\n", game.title.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LogConfig(const Util::Config::Node &config)
|
static void LogConfig(const Util::Config::Node &config)
|
||||||
{
|
{
|
||||||
InfoLog("Runtime configuration:");
|
InfoLog("Runtime configuration:");
|
||||||
|
|
Loading…
Reference in a new issue