diff --git a/Src/OSD/SDL/Crosshair.cpp b/Src/OSD/SDL/Crosshair.cpp index d5354b57..94a9e1b7 100644 --- a/Src/OSD/SDL/Crosshair.cpp +++ b/Src/OSD/SDL/Crosshair.cpp @@ -331,10 +331,10 @@ void CCrosshair::GunToViewCoords(float* x, float* y) } CCrosshair::CCrosshair(const Util::Config::Node& config) - : m_config(config), - m_vertexShader(nullptr), - m_fragmentShader(nullptr) + : m_config(config) { + m_vertexShader = nullptr; + m_fragmentShader = nullptr; } CCrosshair::~CCrosshair() diff --git a/Src/OSD/SDL/Crosshair.h b/Src/OSD/SDL/Crosshair.h index 0bb1fd07..d487dd8d 100644 --- a/Src/OSD/SDL/Crosshair.h +++ b/Src/OSD/SDL/Crosshair.h @@ -25,8 +25,9 @@ #include "Supermodel.h" #include "Graphics/New3D/New3D.h" #include "Inputs/Inputs.h" +#include "basicDrawable.h" -class CCrosshair +class CCrosshair : public CBasicDrawable { private: const Util::Config::Node& m_config; @@ -42,32 +43,6 @@ class CCrosshair float m_dpiMultiplicator = 0.0f; const float m_scaleBitmap = 0.1f; - struct BasicVertex - { - BasicVertex(float x, float y, float z) : x(x), y(y), z(z) {} - BasicVertex(float x, float y) : x(x), y(y), z(0.0f) {} - float x, y, z; - }; - - struct UVCoords - { - UVCoords(float x, float y) : x(x), y(y) {} - float x, y; - }; - - std::vector m_verts; - std::vector m_uvCoord; - - GLSLShader m_shader; - VBO m_vbo; - VBO m_textvbo; - GLuint m_vao = 0; - int m_textureCoordsCount = 0; - const char* m_vertexShader; - const char* m_fragmentShader; - - const int MaxVerts = 1024; // per draw call - void BuildCrosshairVertices(unsigned int xRes, unsigned int yRes); void DrawCrosshair(New3D::Mat4 matrix, float x, float y, int player, unsigned int xRes, unsigned int yRes); void GunToViewCoords(float* x, float* y); diff --git a/Src/OSD/SDL/Main.cpp b/Src/OSD/SDL/Main.cpp index d9b3c320..38c9b066 100644 --- a/Src/OSD/SDL/Main.cpp +++ b/Src/OSD/SDL/Main.cpp @@ -82,6 +82,7 @@ #include "Util/BMPFile.h" #include "Crosshair.h" +#include "WhiteBorder.h" /****************************************************************************** Global Run-time Config @@ -110,6 +111,7 @@ static unsigned totalXRes, totalYRes; // total resolution (the whole GL viewpo * Crosshair stuff */ static CCrosshair* s_crosshair = nullptr; +static CWhiteBorder* s_whiteBorder = nullptr; static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *xResPtr, unsigned *yResPtr, unsigned *totalXResPtr, unsigned *totalYResPtr, bool keepAspectRatio) { @@ -123,6 +125,16 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned * // If required, fix the aspect ratio of the resolution that the user passed to match Model 3 ratio float xRes = float(*xResPtr); float yRes = float(*yResPtr); + + //if we want to draw a white border, we have also to put a black border around it so we are sure lightgun will find it... + if (s_whiteBorder->IsEnabled()) + { + int blackborder = s_whiteBorder->Width(); + int whiteBorder = s_whiteBorder->Width(); //50px borders + xRes -= (whiteBorder + blackborder); + yRes -= (whiteBorder + blackborder); + } + if (keepAspectRatio) { float model3Ratio = float(496.0/384.0); @@ -174,6 +186,7 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned * { glScissor(*xOffsetPtr + correction, *yOffsetPtr + correction, *xResPtr - (correction * 2), *yResPtr - (correction * 2)); } + return OKAY; } @@ -780,7 +793,6 @@ static void LoadNVRAM(IEmulator *Model3) DebugLog("Loaded NVRAM from '%s'.\n", file_path.c_str()); } - /* static void PrintGLError(GLenum error) { @@ -817,6 +829,8 @@ void EndFrameVideo() if (videoInputs) s_crosshair->Update(currentInputs, videoInputs, xOffset, yOffset, xRes, yRes); + //Update whiteborders + s_whiteBorder->Update(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes); // Swap the buffers SDL_GL_SwapWindow(s_window); } @@ -1460,6 +1474,7 @@ static Util::Config::Node DefaultConfig() config.SetEmpty("WindowYPosition"); config.Set("FullScreen", false); config.Set("BorderlessWindow", false); + config.Set("DrawWhiteBorder", false); config.Set("WideScreen", false); config.Set("Stretch", false); @@ -1543,6 +1558,7 @@ static void Help(void) puts(" -window-pos=, Window position [Default: centered]"); puts(" -window Windowed mode [Default]"); puts(" -borderless Windowed mode with no border"); + puts(" -draw-white-border Draw a whiteborder around image: usefull for some lightgun type (Sinden LightGun)"); puts(" -fullscreen Full screen mode"); puts(" -wide-screen Expand 3D field of view to screen width"); puts(" -wide-bg When wide-screen mode is enabled, also expand the 2D"); @@ -1667,6 +1683,7 @@ static ParsedCommandLine ParseCommandLine(int argc, char **argv) { "-window", { "FullScreen", false } }, { "-fullscreen", { "FullScreen", true } }, { "-borderless", { "BorderlessWindow", true } }, + { "-draw-white-border", { "DrawWhiteBorder", true } }, { "-no-wide-screen", { "WideScreen", false } }, { "-wide-screen", { "WideScreen", true } }, { "-stretch", { "Stretch", true } }, @@ -1943,6 +1960,8 @@ int main(int argc, char **argv) std::shared_ptr Debugger; #endif // SUPERMODEL_DEBUGGER std::string selectedInputSystem = s_runtime_config["InputSystem"].ValueAs(); + s_crosshair = new CCrosshair(s_runtime_config); + s_whiteBorder = new CWhiteBorder(s_runtime_config); // Create a window xRes = 496; @@ -1954,7 +1973,6 @@ int main(int argc, char **argv) } // Create Crosshair - s_crosshair = new CCrosshair(s_runtime_config); if (s_crosshair->Init() != OKAY) { ErrorLog("Unable to load bitmap crosshair texture\n"); @@ -1962,6 +1980,16 @@ int main(int argc, char **argv) goto Exit; } + // Create WhiteBorder + if (s_whiteBorder->Init() != OKAY) + { + ErrorLog("Unable to create whiteborder\n"); + exitCode = 1; + goto Exit; + } + + + // Create Model 3 emulator #ifdef DEBUG Model3 = s_gfxStatePath.empty() ? static_cast(new CModel3(s_runtime_config)) : static_cast(new CModel3GraphicsState(s_runtime_config, s_gfxStatePath)); @@ -2064,7 +2092,9 @@ int main(int argc, char **argv) if (Outputs != NULL) delete Outputs; if (s_crosshair != NULL) - delete s_crosshair; + delete s_crosshair; + if (s_whiteBorder != NULL) + delete s_whiteBorder; DestroyGLScreen(); SDL_Quit(); diff --git a/Src/OSD/SDL/WhiteBorder.cpp b/Src/OSD/SDL/WhiteBorder.cpp new file mode 100644 index 00000000..cc7cc088 --- /dev/null +++ b/Src/OSD/SDL/WhiteBorder.cpp @@ -0,0 +1,176 @@ +/** + ** Supermodel + ** A Sega Model 3 Arcade Emulator. + ** Copyright 2003-2023 The Supermodel Team + ** + ** This file is part of Supermodel. + ** + ** Supermodel is free software: you can redistribute it and/or modify it under + ** the terms of the GNU General Public License as published by the Free + ** Software Foundation, either version 3 of the License, or (at your option) + ** any later version. + ** + ** Supermodel is distributed in the hope that it will be useful, but WITHOUT + ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + ** more details. + ** + ** You should have received a copy of the GNU General Public License along + ** with Supermodel. If not, see . + **/ + +#include "WhiteBorder.h" +#include "Supermodel.h" +#include "Graphics/New3D/New3D.h" +#include "OSD/FileSystemPath.h" +#include "SDLIncludes.h" +#include +#include +#include "Inputs/Inputs.h" +#include "Util/Format.h" + + +bool CWhiteBorder::Init() +{ + //whiteBorders must change during runtime when resolution is chnaging + if (m_drawWhiteBorder) + { + m_vertexShader = R"glsl( + + #version 410 core + + uniform mat4 mvp; + layout(location = 0) in vec3 inVertices; + + void main(void) + { + gl_Position = mvp * vec4(inVertices,1.0); + } + )glsl"; + + m_fragmentShader = R"glsl( + + #version 410 core + + uniform vec4 colour; + out vec4 fragColour; + + void main(void) + { + fragColour = colour; + } + )glsl"; + + m_shader.LoadShaders(m_vertexShader, m_fragmentShader); + m_shader.GetUniformLocationMap("mvp"); + m_shader.GetUniformLocationMap("colour"); + m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(BasicVertex) * (MaxVerts)); + m_vbo.Bind(true); + + + glGenVertexArrays(1, &m_vao); + glBindVertexArray(m_vao); + + m_vbo.Bind(true); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(BasicVertex), 0); + m_vbo.Bind(false); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + + glBindVertexArray(0); + m_drawWhiteBorder = true; + } + return OKAY; +} + +void CWhiteBorder::GenQuad(std::vector &verts, unsigned int x, unsigned int y, unsigned int w, unsigned int h) +{ + verts.emplace_back(float(x), float(y)); + verts.emplace_back(float(x), float(y + h)); + verts.emplace_back(float(x + w), float(y + h)); + verts.emplace_back(float(x), float(y)); + verts.emplace_back(float(x + w), float(y + h)); + verts.emplace_back(float(x + w), float(y)); +} + + +void CWhiteBorder::Update(unsigned int xOffset, unsigned int yOffset, unsigned int xRes, unsigned int yRes, unsigned int totalXRes, unsigned int totalYRes) +{ + //white border + if (m_drawWhiteBorder) + { + if(m_xRes != xRes || + m_yRes != yRes || + m_xOffset != xOffset || + m_yOffset != yOffset ) + { + m_xRes = xRes ; + m_yRes = yRes ; + m_xOffset = xOffset; + m_yOffset = yOffset; + int whiteBorder = m_width; + int internalWhiteBorder = m_width / 2; + //generate border geometry + m_verts.clear(); + GenQuad(m_verts, m_xOffset - internalWhiteBorder, m_yOffset - internalWhiteBorder, internalWhiteBorder, m_yRes + internalWhiteBorder * 2); + GenQuad(m_verts, m_xOffset + m_xRes, m_yOffset - internalWhiteBorder, internalWhiteBorder, m_yRes + internalWhiteBorder * 2); + GenQuad(m_verts, m_xOffset, m_yOffset - internalWhiteBorder, m_xRes , internalWhiteBorder); + GenQuad(m_verts, m_xOffset, m_yOffset + m_yRes, m_xRes, internalWhiteBorder); + + // update vbo mem + m_vbo.Bind(true); + m_vbo.BufferSubData(0, m_verts.size() * sizeof(BasicVertex), m_verts.data()); + } + + glUseProgram(0); + glViewport(0, 0, totalXRes, totalYRes); + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + + New3D::Mat4 mvpMatrix; + mvpMatrix.Ortho(0.0, float(totalXRes), float(totalYRes), 0.0, -1.0f, 1.0f); + + m_shader.EnableShader(); + + // update uniform memory + glUniformMatrix4fv(m_shader.uniformLocMap["mvp"], 1, GL_FALSE, mvpMatrix); + glUniform4f(m_shader.uniformLocMap["colour"], 1.0f, 1.0f, 1.0f, 1.0f); + + glBindVertexArray(m_vao); + glDrawArrays(GL_TRIANGLES, 0, GLsizei(m_verts.size())); + glBindVertexArray(0); + + m_shader.DisableShader(); + + glEnable(GL_SCISSOR_TEST); + } +} + +bool CWhiteBorder::IsEnabled() +{ + return m_drawWhiteBorder; +} + +unsigned int CWhiteBorder::Width() +{ + return m_width; +} + + +CWhiteBorder::CWhiteBorder(const Util::Config::Node& config) : m_config(config) +{ + m_drawWhiteBorder = m_config["DrawWhiteBorder"].ValueAs(); + m_vertexShader = nullptr; + m_fragmentShader = nullptr; + m_xRes = 0; + m_yRes = 0; + m_xOffset = 0; + m_yOffset = 0; + m_width = 50; +} + +CWhiteBorder::~CWhiteBorder() +{ +} diff --git a/Src/OSD/SDL/WhiteBorder.h b/Src/OSD/SDL/WhiteBorder.h new file mode 100644 index 00000000..c1661215 --- /dev/null +++ b/Src/OSD/SDL/WhiteBorder.h @@ -0,0 +1,53 @@ +/** + ** Supermodel + ** A Sega Model 3 Arcade Emulator. + ** Copyright 2003-2023 The Supermodel Team + ** + ** This file is part of Supermodel. + ** + ** Supermodel is free software: you can redistribute it and/or modify it under + ** the terms of the GNU General Public License as published by the Free + ** Software Foundation, either version 3 of the License, or (at your option) + ** any later version. + ** + ** Supermodel is distributed in the hope that it will be useful, but WITHOUT + ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + ** more details. + ** + ** You should have received a copy of the GNU General Public License along + ** with Supermodel. If not, see . + **/ + +#ifndef INCLUDED_WHITEBORDER_H +#define INCLUDED_WHITEBORDER_H + +#include "Supermodel.h" +#include "Graphics/New3D/New3D.h" +#include "Inputs/Inputs.h" +#include "basicDrawable.h" + + +class CWhiteBorder : public CBasicDrawable +{ +private: + const Util::Config::Node& m_config; + bool m_drawWhiteBorder; + unsigned int m_xRes; + unsigned int m_yRes; + unsigned int m_xOffset; + unsigned int m_yOffset; + unsigned int m_width; + + void GenQuad(std::vector& verts, unsigned int x, unsigned int y, unsigned int w, unsigned int h); +public: + CWhiteBorder(const Util::Config::Node& config); + ~CWhiteBorder(); + bool Init(); + void Update(unsigned int xOffset, unsigned int yOffset, unsigned int xRes, unsigned int yRes, unsigned int totalXRes, unsigned int totalYRes); + bool IsEnabled(); + unsigned int Width(); +}; + +#endif + diff --git a/Src/OSD/SDL/basicDrawable.h b/Src/OSD/SDL/basicDrawable.h new file mode 100644 index 00000000..cc6411d8 --- /dev/null +++ b/Src/OSD/SDL/basicDrawable.h @@ -0,0 +1,58 @@ +/** + ** Supermodel + ** A Sega Model 3 Arcade Emulator. + ** Copyright 2003-2023 The Supermodel Team + ** + ** This file is part of Supermodel. + ** + ** Supermodel is free software: you can redistribute it and/or modify it under + ** the terms of the GNU General Public License as published by the Free + ** Software Foundation, either version 3 of the License, or (at your option) + ** any later version. + ** + ** Supermodel is distributed in the hope that it will be useful, but WITHOUT + ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + ** more details. + ** + ** You should have received a copy of the GNU General Public License along + ** with Supermodel. If not, see . + **/ + +#ifndef INCLUDED_BASICDRAWABLE_H +#define INCLUDED_BASICDRAWABLE_H + +class CBasicDrawable +{ +protected: + struct BasicVertex + { + BasicVertex(float x, float y, float z) : x(x), y(y), z(z) {} + BasicVertex(float x, float y) : x(x), y(y), z(0.0f) {} + float x, y, z; + }; + + struct UVCoords + { + UVCoords(float x, float y) : x(x), y(y) {} + float x, y; + }; + + std::vector m_verts; + std::vector m_uvCoord; + + GLSLShader m_shader; + VBO m_vbo; + VBO m_textvbo; + GLuint m_vao = 0; + int m_textureCoordsCount = 0; + const char* m_vertexShader; + const char* m_fragmentShader; + + const int MaxVerts = 1024; // per draw call + + +}; + +#endif + diff --git a/VS2008/Supermodel.vcxproj b/VS2008/Supermodel.vcxproj index d755d81b..4d761866 100644 --- a/VS2008/Supermodel.vcxproj +++ b/VS2008/Supermodel.vcxproj @@ -359,6 +359,7 @@ xcopy /D /Y "$(ProjectDir)..\Assets\*" "$(TargetDir)Assets" + @@ -532,10 +533,12 @@ xcopy /D /Y "$(ProjectDir)..\Assets\*" "$(TargetDir)Assets" + + diff --git a/VS2008/Supermodel.vcxproj.filters b/VS2008/Supermodel.vcxproj.filters index e554f3d9..52c4c977 100644 --- a/VS2008/Supermodel.vcxproj.filters +++ b/VS2008/Supermodel.vcxproj.filters @@ -467,6 +467,9 @@ Source Files\OSD\SDL + + Source Files\OSD\SDL + @@ -847,6 +850,12 @@ Header Files\OSD\SDL + + Header Files\OSD\SDL + + + Header Files\OSD\SDL +