From 981cdc33f5a0537c762e3fc43c3120e8f92aff03 Mon Sep 17 00:00:00 2001 From: SpinDizzy Date: Sat, 19 Sep 2020 07:54:26 +0000 Subject: [PATCH] Added Screenshot feature (ALT+S). --- Src/Inputs/Inputs.cpp | 1 + Src/Inputs/Inputs.h | 1 + Src/OSD/SDL/Main.cpp | 217 +++++++++++++++++++++++------------------- 3 files changed, 120 insertions(+), 99 deletions(-) diff --git a/Src/Inputs/Inputs.cpp b/Src/Inputs/Inputs.cpp index 5eb0bc3..4aece0f 100644 --- a/Src/Inputs/Inputs.cpp +++ b/Src/Inputs/Inputs.cpp @@ -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 diff --git a/Src/Inputs/Inputs.h b/Src/Inputs/Inputs.h index 209a1eb..45abfe7 100644 --- a/Src/Inputs/Inputs.h +++ b/Src/Inputs/Inputs.h @@ -105,6 +105,7 @@ public: CSwitchInput *uiToggleFrLimit; CSwitchInput *uiDumpInpState; CSwitchInput *uiDumpTimings; + CSwitchInput *uiScreenshot; #ifdef SUPERMODEL_DEBUGGER CSwitchInput *uiEnterDebugger; #endif diff --git a/Src/OSD/SDL/Main.cpp b/Src/OSD/SDL/Main.cpp index 2f97b1c..06e8b77 100644 --- a/Src/OSD/SDL/Main.cpp +++ b/Src/OSD/SDL/Main.cpp @@ -71,6 +71,7 @@ #include "SDLIncludes.h" #include +#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 pixels(new uint8_t[totalXRes * totalYRes * 4], std::default_delete()); + glReadPixels(0, 0, totalXRes, totalYRes, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get()); + Util::WriteSurfaceToBMP(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 -static void SaveFrameBuffer(const std::string &file) -{ - std::shared_ptr pixels(new uint8_t[totalXRes*totalYRes*4], std::default_delete()); - glReadPixels(0, 0, totalXRes, totalYRes, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get()); - Util::WriteSurfaceToBMP(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()); - - // Swap the buffers - SDL_GL_SwapWindow(s_window); +{ + // Show crosshairs for light gun games + if (videoInputs) + UpdateCrosshairs(currentInputs, videoInputs, s_runtime_config["Crosshairs"].ValueAs()); + + // 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()); - 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()); + 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()); printf("Frame limiting: %s\n", s_runtime_config["Throttle"].ValueAs() ? "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