Added Screenshot feature (ALT+S).

This commit is contained in:
SpinDizzy 2020-09-19 07:54:26 +00:00
parent ca57659fcb
commit 981cdc33f5
3 changed files with 120 additions and 99 deletions

View file

@ -58,6 +58,7 @@ CInputs::CInputs(CInputSystem *system)
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");
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
uiEnterDebugger = AddSwitchInput("UIEnterDebugger", "Enter Debugger", Game::INPUT_UI, "KEY_ALT+KEY_B");
#endif

View file

@ -105,6 +105,7 @@ public:
CSwitchInput *uiToggleFrLimit;
CSwitchInput *uiDumpInpState;
CSwitchInput *uiDumpTimings;
CSwitchInput *uiScreenshot;
#ifdef SUPERMODEL_DEBUGGER
CSwitchInput *uiEnterDebugger;
#endif

View file

@ -71,6 +71,7 @@
#include "SDLIncludes.h"
#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_BLUE_SIZE,8);
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);
// Set video mode
@ -413,6 +414,27 @@ static void DumpPPCRegisters(IBus *bus)
}
#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
@ -421,17 +443,9 @@ static void DumpPPCRegisters(IBus *bus)
#ifdef DEBUG
#include "Model3/Model3GraphicsState.h"
#include "Util/BMPFile.h"
#include "OSD/SDL/PolyAnalysis.h"
#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 GetFileBaseName(const std::string &file)
@ -715,91 +729,91 @@ static void PrintGLError(GLenum error)
case GL_NO_ERROR: break;
default: printf("unknown error\n"); break;
}
}
*/
static void UpdateCrosshairs(uint32_t currentInputs, CInputs *Inputs, unsigned crosshairs)
{
bool offscreenTrigger[2];
float x[2], y[2];
crosshairs &= 3;
if (!crosshairs)
return;
// Set up the viewport and orthogonal projection
glUseProgram(0); // no shaders
glViewport(xOffset, yOffset, xRes, yRes);
}
*/
static void UpdateCrosshairs(uint32_t currentInputs, CInputs *Inputs, unsigned crosshairs)
{
bool offscreenTrigger[2];
float x[2], y[2];
crosshairs &= 3;
if (!crosshairs)
return;
// Set up the viewport and orthogonal projection
glUseProgram(0); // no shaders
glViewport(xOffset, yOffset, xRes, yRes);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_TEXTURE_2D); // no texture mapping
glDisable(GL_BLEND); // no blending
glDisable(GL_DEPTH_TEST); // no Z-buffering needed
glDisable(GL_LIGHTING);
// Convert gun coordinates to viewspace coordinates
if (currentInputs & Game::INPUT_ANALOG_GUN1)
{
x[0] = ((float)Inputs->analogGunX[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;
}
else if (currentInputs & Game::INPUT_GUN1)
{
x[0] = (float)Inputs->gunX[0]->value;
y[0] = (float)Inputs->gunY[0]->value;
GunToViewCoords(&x[0], &y[0]);
offscreenTrigger[0] = (Inputs->trigger[0]->offscreenValue) > 0;
}
if (currentInputs & Game::INPUT_ANALOG_GUN2)
{
x[1] = ((float)Inputs->analogGunX[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;
}
else if (currentInputs & Game::INPUT_GUN2)
{
x[1] = (float)Inputs->gunX[1]->value;
y[1] = (float)Inputs->gunY[1]->value;
GunToViewCoords(&x[1], &y[1]);
offscreenTrigger[1] = (Inputs->trigger[1]->offscreenValue) > 0;
}
// Draw visible crosshairs
glBegin(GL_TRIANGLES);
if ((crosshairs & 1) && !offscreenTrigger[0]) // Player 1
DrawCrosshair(x[0], y[0], 1.0f, 0.0f, 0.0f);
if ((crosshairs & 2) && !offscreenTrigger[1]) // Player 2
DrawCrosshair(x[1], y[1], 0.0f, 1.0f, 0.0f);
glEnd();
//PrintGLError(glGetError());
}
glDisable(GL_BLEND); // no blending
glDisable(GL_DEPTH_TEST); // no Z-buffering needed
glDisable(GL_LIGHTING);
// Convert gun coordinates to viewspace coordinates
if (currentInputs & Game::INPUT_ANALOG_GUN1)
{
x[0] = ((float)Inputs->analogGunX[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;
}
else if (currentInputs & Game::INPUT_GUN1)
{
x[0] = (float)Inputs->gunX[0]->value;
y[0] = (float)Inputs->gunY[0]->value;
GunToViewCoords(&x[0], &y[0]);
offscreenTrigger[0] = (Inputs->trigger[0]->offscreenValue) > 0;
}
if (currentInputs & Game::INPUT_ANALOG_GUN2)
{
x[1] = ((float)Inputs->analogGunX[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;
}
else if (currentInputs & Game::INPUT_GUN2)
{
x[1] = (float)Inputs->gunX[1]->value;
y[1] = (float)Inputs->gunY[1]->value;
GunToViewCoords(&x[1], &y[1]);
offscreenTrigger[1] = (Inputs->trigger[1]->offscreenValue) > 0;
}
// Draw visible crosshairs
glBegin(GL_TRIANGLES);
if ((crosshairs & 1) && !offscreenTrigger[0]) // Player 1
DrawCrosshair(x[0], y[0], 1.0f, 0.0f, 0.0f);
if ((crosshairs & 2) && !offscreenTrigger[1]) // Player 2
DrawCrosshair(x[1], y[1], 0.0f, 1.0f, 0.0f);
glEnd();
//PrintGLError(glGetError());
}
/******************************************************************************
Video Callbacks
******************************************************************************/
static CInputs *videoInputs = NULL;
static uint32_t currentInputs = 0;
bool BeginFrameVideo()
{
******************************************************************************/
static CInputs *videoInputs = NULL;
static uint32_t currentInputs = 0;
bool BeginFrameVideo()
{
return true;
}
void EndFrameVideo()
{
// Show crosshairs for light gun games
if (videoInputs)
UpdateCrosshairs(currentInputs, videoInputs, s_runtime_config["Crosshairs"].ValueAs<unsigned>());
// Swap the buffers
SDL_GL_SwapWindow(s_window);
{
// Show crosshairs for light gun games
if (videoInputs)
UpdateCrosshairs(currentInputs, videoInputs, s_runtime_config["Crosshairs"].ValueAs<unsigned>());
// Swap the buffers
SDL_GL_SwapWindow(s_window);
}
static void SuperSleep(UINT32 time)
@ -863,14 +877,14 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
if (OKAY != OpenAudio())
return 1;
// Hide mouse if fullscreen, enable crosshairs for gun games
Inputs->GetInputSystem()->SetMouseVisibility(!s_runtime_config["FullScreen"].ValueAs<bool>());
gameHasLightguns = !!(game.inputs & (Game::INPUT_GUN1|Game::INPUT_GUN2));
gameHasLightguns |= game.name == "lostwsga";
currentInputs = game.inputs;
if (gameHasLightguns)
videoInputs = Inputs;
else
// Hide mouse if fullscreen, enable crosshairs for gun games
Inputs->GetInputSystem()->SetMouseVisibility(!s_runtime_config["FullScreen"].ValueAs<bool>());
gameHasLightguns = !!(game.inputs & (Game::INPUT_GUN1|Game::INPUT_GUN2));
gameHasLightguns |= game.name == "lostwsga";
currentInputs = game.inputs;
if (gameHasLightguns)
videoInputs = Inputs;
else
videoInputs = NULL;
// 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>());
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
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)
{
const Game &game = v.second;
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)
printf(" ");
if (!game.version.empty())
printf(" %s (%s)\n", game.title.c_str(), game.version.c_str());
else
printf(" %s\n", game.title.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)
printf(" ");
if (!game.version.empty())
printf(" %s (%s)\n", game.title.c_str(), game.version.c_str());
else
printf(" %s\n", game.title.c_str());
}
}
static void LogConfig(const Util::Config::Node &config)
{
InfoLog("Runtime configuration:");