Crosshair: use actual adjusted viewport resolution (configuration resolution is not the same thing). Fixes crosshair alignment for resolutions with non-Model 3 aspect.

This commit is contained in:
Bart Trzynadlowski 2023-03-17 23:00:44 -07:00 committed by trzy
parent 95fc08e0a3
commit 87de86f7d1
3 changed files with 315 additions and 312 deletions

View file

@ -1,7 +1,7 @@
/** /**
** Supermodel ** Supermodel
** A Sega Model 3 Arcade Emulator. ** A Sega Model 3 Arcade Emulator.
** Copyright 2003-2022 The Supermodel Team ** Copyright 2003-2023 The Supermodel Team
** **
** This file is part of Supermodel. ** This file is part of Supermodel.
** **
@ -45,10 +45,6 @@ bool CCrosshair::Init()
m_isBitmapCrosshair = false; m_isBitmapCrosshair = false;
} }
m_xRes = m_config["XResolution"].ValueAs<unsigned>();
m_yRes = m_config["YResolution"].ValueAs<unsigned>();
m_a = (float)m_xRes / (float)m_yRes;
SDL_Surface* surfaceCrosshairP1 = SDL_LoadBMP(p1CrosshairFile.c_str()); SDL_Surface* surfaceCrosshairP1 = SDL_LoadBMP(p1CrosshairFile.c_str());
SDL_Surface* surfaceCrosshairP2 = SDL_LoadBMP(p2CrosshairFile.c_str()); SDL_Surface* surfaceCrosshairP2 = SDL_LoadBMP(p2CrosshairFile.c_str());
if (surfaceCrosshairP1 == NULL || surfaceCrosshairP2 == NULL) if (surfaceCrosshairP1 == NULL || surfaceCrosshairP2 == NULL)
@ -88,31 +84,6 @@ bool CCrosshair::Init()
m_uvCoord.emplace_back(1.0f, 1.0f); m_uvCoord.emplace_back(1.0f, 1.0f);
m_uvCoord.emplace_back(0.0f, 1.0f); m_uvCoord.emplace_back(0.0f, 1.0f);
if (!m_isBitmapCrosshair)
{
m_verts.emplace_back(0.0f, m_dist); // bottom triangle
m_verts.emplace_back(m_base / 2.0f, (m_dist + m_height) * m_a);
m_verts.emplace_back(-m_base / 2.0f, (m_dist + m_height) * m_a);
m_verts.emplace_back(0.0f, -m_dist); // top triangle
m_verts.emplace_back(-m_base / 2.0f, -(m_dist + m_height) * m_a);
m_verts.emplace_back(m_base / 2.0f, -(m_dist + m_height) * m_a);
m_verts.emplace_back(-m_dist, 0.0f); // left triangle
m_verts.emplace_back(-m_dist - m_height, (m_base / 2.0f) * m_a);
m_verts.emplace_back(-m_dist - m_height, -(m_base / 2.0f) * m_a);
m_verts.emplace_back(m_dist, 0.0f); // right triangle
m_verts.emplace_back(m_dist + m_height, -(m_base / 2.0f) * m_a);
m_verts.emplace_back(m_dist + m_height, (m_base / 2.0f) * m_a);
}
else
{
m_verts.emplace_back(-m_squareSize / 2.0f, -m_squareSize / 2.0f * m_a);
m_verts.emplace_back(m_squareSize / 2.0f, -m_squareSize / 2.0f * m_a);
m_verts.emplace_back(m_squareSize / 2.0f, m_squareSize / 2.0f * m_a);
m_verts.emplace_back(-m_squareSize / 2.0f, -m_squareSize / 2.0f * m_a);
m_verts.emplace_back(m_squareSize / 2.0f, m_squareSize / 2.0f * m_a);
m_verts.emplace_back(-m_squareSize / 2.0f, m_squareSize / 2.0f * m_a);
}
m_vertexShader = R"glsl( m_vertexShader = R"glsl(
#version 410 core #version 410 core
@ -178,12 +149,45 @@ bool CCrosshair::Init()
return OKAY; return OKAY;
} }
void CCrosshair::DrawCrosshair(New3D::Mat4 matrix, float x, float y, int player) void CCrosshair::BuildCrosshairVertices(unsigned int xRes, unsigned int yRes)
{ {
float aspect = (float)xRes / (float)yRes;
m_verts.clear();
if (!m_isBitmapCrosshair)
{
m_verts.emplace_back(0.0f, m_dist); // bottom triangle
m_verts.emplace_back(m_base / 2.0f, (m_dist + m_height) * aspect);
m_verts.emplace_back(-m_base / 2.0f, (m_dist + m_height) * aspect);
m_verts.emplace_back(0.0f, -m_dist); // top triangle
m_verts.emplace_back(-m_base / 2.0f, -(m_dist + m_height) * aspect);
m_verts.emplace_back(m_base / 2.0f, -(m_dist + m_height) * aspect);
m_verts.emplace_back(-m_dist, 0.0f); // left triangle
m_verts.emplace_back(-m_dist - m_height, (m_base / 2.0f) * aspect);
m_verts.emplace_back(-m_dist - m_height, -(m_base / 2.0f) * aspect);
m_verts.emplace_back(m_dist, 0.0f); // right triangle
m_verts.emplace_back(m_dist + m_height, -(m_base / 2.0f) * aspect);
m_verts.emplace_back(m_dist + m_height, (m_base / 2.0f) * aspect);
}
else
{
m_verts.emplace_back(-m_squareSize / 2.0f, -m_squareSize / 2.0f * aspect);
m_verts.emplace_back(m_squareSize / 2.0f, -m_squareSize / 2.0f * aspect);
m_verts.emplace_back(m_squareSize / 2.0f, m_squareSize / 2.0f * aspect);
m_verts.emplace_back(-m_squareSize / 2.0f, -m_squareSize / 2.0f * aspect);
m_verts.emplace_back(m_squareSize / 2.0f, m_squareSize / 2.0f * aspect);
m_verts.emplace_back(-m_squareSize / 2.0f, m_squareSize / 2.0f * aspect);
}
}
void CCrosshair::DrawCrosshair(New3D::Mat4 matrix, float x, float y, int player, unsigned int xRes, unsigned int yRes)
{
BuildCrosshairVertices(xRes, yRes);
float r=0.0f, g=0.0f, b=0.0f; float r=0.0f, g=0.0f, b=0.0f;
int count = (int)m_verts.size(); int count = (int)m_verts.size();
if (count > MaxVerts) { if (count > MaxVerts)
{
count = MaxVerts; // maybe we could error out somehow count = MaxVerts; // maybe we could error out somehow
} }
@ -248,7 +252,7 @@ void CCrosshair::DrawCrosshair(New3D::Mat4 matrix, float x, float y, int player)
m_shader.DisableShader(); m_shader.DisableShader();
} }
void CCrosshair::Update(uint32_t currentInputs, CInputs* Inputs, unsigned int xOffset, unsigned int yOffset) void CCrosshair::Update(uint32_t currentInputs, CInputs* Inputs, unsigned int xOffset, unsigned int yOffset, unsigned int xRes, unsigned int yRes)
{ {
bool offscreenTrigger[2]{false}; bool offscreenTrigger[2]{false};
float x[2]{ 0.0f }, y[2]{ 0.0f }; float x[2]{ 0.0f }, y[2]{ 0.0f };
@ -261,7 +265,7 @@ void CCrosshair::Update(uint32_t currentInputs, CInputs* Inputs, unsigned int xO
// 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, m_xRes, m_yRes); glViewport(xOffset, yOffset, xRes, yRes);
glDisable(GL_DEPTH_TEST); // no Z-buffering needed glDisable(GL_DEPTH_TEST); // no Z-buffering needed
if (!m_isBitmapCrosshair) if (!m_isBitmapCrosshair)
@ -310,11 +314,11 @@ void CCrosshair::Update(uint32_t currentInputs, CInputs* Inputs, unsigned int xO
if ((crosshairs & 1) && !offscreenTrigger[0]) // Player 1 if ((crosshairs & 1) && !offscreenTrigger[0]) // Player 1
{ {
DrawCrosshair(m, x[0], y[0], 0); DrawCrosshair(m, x[0], y[0], 0, xRes, yRes);
} }
if ((crosshairs & 2) && !offscreenTrigger[1]) // Player 2 if ((crosshairs & 2) && !offscreenTrigger[1]) // Player 2
{ {
DrawCrosshair(m, x[1], y[1], 1); DrawCrosshair(m, x[1], y[1], 1, xRes, yRes);
} }
//PrintGLError(glGetError()); //PrintGLError(glGetError());
@ -326,10 +330,11 @@ void CCrosshair::GunToViewCoords(float* x, float* y)
*y = (*y - 80.0f) / (465.0f - 80.0f); // Scale [80,465] -> [0.0,1.0] *y = (*y - 80.0f) / (465.0f - 80.0f); // Scale [80,465] -> [0.0,1.0]
} }
CCrosshair::CCrosshair(const Util::Config::Node& config) : m_config(config),m_xRes(0),m_yRes(0) CCrosshair::CCrosshair(const Util::Config::Node& config)
: m_config(config),
m_vertexShader(nullptr),
m_fragmentShader(nullptr)
{ {
m_vertexShader = nullptr;
m_fragmentShader = nullptr;
} }
CCrosshair::~CCrosshair() CCrosshair::~CCrosshair()

View file

@ -1,7 +1,7 @@
/** /**
** Supermodel ** Supermodel
** A Sega Model 3 Arcade Emulator. ** A Sega Model 3 Arcade Emulator.
** Copyright 2003-2022 The Supermodel Team ** Copyright 2003-2023 The Supermodel Team
** **
** This file is part of Supermodel. ** This file is part of Supermodel.
** **
@ -35,11 +35,8 @@ private:
GLuint m_crosshairTexId[2] = { 0 }; GLuint m_crosshairTexId[2] = { 0 };
int m_p1CrosshairW = 0, m_p1CrosshairH = 0, m_p2CrosshairW = 0, m_p2CrosshairH = 0; int m_p1CrosshairW = 0, m_p1CrosshairH = 0, m_p2CrosshairW = 0, m_p2CrosshairH = 0;
float m_diagDpi = 0.0f, m_hDpi = 0.0f, m_vDpi = 0.0f; float m_diagDpi = 0.0f, m_hDpi = 0.0f, m_vDpi = 0.0f;
unsigned int m_xRes=0;
unsigned int m_yRes=0;
const float m_base = 0.01f, m_height = 0.02f; // geometric parameters of each triangle const float m_base = 0.01f, m_height = 0.02f; // geometric parameters of each triangle
const float m_dist = 0.004f; // distance of triangle tip from center const float m_dist = 0.004f; // distance of triangle tip from center
float m_a = 0.0f; // aspect ratio (to square the crosshair)
const float m_squareSize = 1.0f; const float m_squareSize = 1.0f;
const float m_standardDpi = 96.0f; // normal dpi for usual monitor (full hd) const float m_standardDpi = 96.0f; // normal dpi for usual monitor (full hd)
float m_dpiMultiplicator = 0.0f; float m_dpiMultiplicator = 0.0f;
@ -71,14 +68,15 @@ private:
const int MaxVerts = 1024; // per draw call const int MaxVerts = 1024; // per draw call
void DrawCrosshair(New3D::Mat4 matrix, float x, float y, int player); 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); void GunToViewCoords(float* x, float* y);
public: public:
CCrosshair(const Util::Config::Node& config); CCrosshair(const Util::Config::Node& config);
~CCrosshair(); ~CCrosshair();
bool Init(); bool Init();
void Update(uint32_t currentInputs, CInputs* Inputs, unsigned int, unsigned int); void Update(uint32_t currentInputs, CInputs* Inputs, unsigned int xOffset, unsigned int yOffset, unsigned int xRes, unsigned int yRes);
}; };
#endif #endif

View file

@ -1,7 +1,7 @@
/** /**
** Supermodel ** Supermodel
** A Sega Model 3 Arcade Emulator. ** A Sega Model 3 Arcade Emulator.
** Copyright 2003-2022 The Supermodel Team ** Copyright 2003-2023 The Supermodel Team
** **
** This file is part of Supermodel. ** This file is part of Supermodel.
** **
@ -815,7 +815,7 @@ void EndFrameVideo()
{ {
// Show crosshairs for light gun games // Show crosshairs for light gun games
if (videoInputs) if (videoInputs)
s_crosshair->Update(currentInputs, videoInputs, xOffset, yOffset); s_crosshair->Update(currentInputs, videoInputs, xOffset, yOffset, xRes, yRes);
// Swap the buffers // Swap the buffers
SDL_GL_SwapWindow(s_window); SDL_GL_SwapWindow(s_window);
@ -1515,7 +1515,7 @@ static Util::Config::Node DefaultConfig()
static void Title(void) static void Title(void)
{ {
puts("Supermodel: A Sega Model 3 Arcade Emulator (Version " SUPERMODEL_VERSION ")"); puts("Supermodel: A Sega Model 3 Arcade Emulator (Version " SUPERMODEL_VERSION ")");
puts("Copyright 2003-2022 by The Supermodel Team"); puts("Copyright 2003-2023 by The Supermodel Team");
} }
static void Help(void) static void Help(void)