mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-03-06 14:27:44 +00:00
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:
parent
95fc08e0a3
commit
87de86f7d1
Src/OSD/SDL
|
@ -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.
|
||||||
**
|
**
|
||||||
|
@ -31,305 +31,310 @@
|
||||||
|
|
||||||
bool CCrosshair::Init()
|
bool CCrosshair::Init()
|
||||||
{
|
{
|
||||||
const std::string p1CrosshairFile = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Assets) << "p1crosshair.bmp";
|
const std::string p1CrosshairFile = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Assets) << "p1crosshair.bmp";
|
||||||
const std::string p2CrosshairFile = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Assets) << "p2crosshair.bmp";
|
const std::string p2CrosshairFile = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Assets) << "p2crosshair.bmp";
|
||||||
|
|
||||||
m_crosshairStyle = Util::ToLower(m_config["CrosshairStyle"].ValueAs<std::string>());
|
m_crosshairStyle = Util::ToLower(m_config["CrosshairStyle"].ValueAs<std::string>());
|
||||||
if (m_crosshairStyle == "bmp")
|
if (m_crosshairStyle == "bmp")
|
||||||
m_isBitmapCrosshair = true;
|
m_isBitmapCrosshair = true;
|
||||||
else if (m_crosshairStyle == "vector")
|
else if (m_crosshairStyle == "vector")
|
||||||
m_isBitmapCrosshair = false;
|
m_isBitmapCrosshair = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ErrorLog("Invalid crosshair style '%s', must be 'vector' or 'bmp'. Reverting to 'vector'.\n", m_crosshairStyle.c_str());
|
||||||
|
m_isBitmapCrosshair = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Surface* surfaceCrosshairP1 = SDL_LoadBMP(p1CrosshairFile.c_str());
|
||||||
|
SDL_Surface* surfaceCrosshairP2 = SDL_LoadBMP(p2CrosshairFile.c_str());
|
||||||
|
if (surfaceCrosshairP1 == NULL || surfaceCrosshairP2 == NULL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
m_p1CrosshairW = surfaceCrosshairP1->w;
|
||||||
|
m_p1CrosshairH = surfaceCrosshairP1->h;
|
||||||
|
m_p2CrosshairW = surfaceCrosshairP2->w;
|
||||||
|
m_p2CrosshairH = surfaceCrosshairP2->h;
|
||||||
|
|
||||||
|
glGenTextures(2, m_crosshairTexId);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_crosshairTexId[0]);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_p1CrosshairW, m_p1CrosshairH, 0, GL_BGRA, GL_UNSIGNED_BYTE, surfaceCrosshairP1->pixels);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_crosshairTexId[1]);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_p1CrosshairW, m_p1CrosshairH, 0, GL_BGRA, GL_UNSIGNED_BYTE, surfaceCrosshairP2->pixels);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
SDL_FreeSurface(surfaceCrosshairP1);
|
||||||
|
SDL_FreeSurface(surfaceCrosshairP2);
|
||||||
|
|
||||||
|
// Get DPI
|
||||||
|
SDL_GetDisplayDPI(0, &m_diagDpi, &m_hDpi, &m_vDpi);
|
||||||
|
m_dpiMultiplicator = m_hDpi / m_standardDpi; // note : on linux VM diagdpi returns 0
|
||||||
|
|
||||||
|
// 3d obj
|
||||||
|
m_uvCoord.emplace_back(0.0f, 0.0f);
|
||||||
|
m_uvCoord.emplace_back(1.0f, 0.0f);
|
||||||
|
m_uvCoord.emplace_back(1.0f, 1.0f);
|
||||||
|
m_uvCoord.emplace_back(0.0f, 0.0f);
|
||||||
|
m_uvCoord.emplace_back(1.0f, 1.0f);
|
||||||
|
m_uvCoord.emplace_back(0.0f, 1.0f);
|
||||||
|
|
||||||
|
m_vertexShader = R"glsl(
|
||||||
|
|
||||||
|
#version 410 core
|
||||||
|
|
||||||
|
uniform mat4 mvp;
|
||||||
|
layout(location = 0) in vec3 inVertices;
|
||||||
|
layout(location = 1) in vec2 vertexUV;
|
||||||
|
out vec2 UV;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
gl_Position = mvp * vec4(inVertices,1.0);
|
||||||
|
UV = vertexUV;
|
||||||
|
}
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
m_fragmentShader = R"glsl(
|
||||||
|
|
||||||
|
#version 410 core
|
||||||
|
|
||||||
|
uniform vec4 colour;
|
||||||
|
uniform sampler2D CrosshairTexture;
|
||||||
|
uniform bool isBitmap;
|
||||||
|
out vec4 fragColour;
|
||||||
|
in vec2 UV;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
if (!isBitmap)
|
||||||
|
fragColour = colour;
|
||||||
else
|
else
|
||||||
|
fragColour = colour * texture(CrosshairTexture, UV);
|
||||||
|
}
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
m_shader.LoadShaders(m_vertexShader, m_fragmentShader);
|
||||||
|
m_shader.GetUniformLocationMap("mvp");
|
||||||
|
m_shader.GetUniformLocationMap("CrosshairTexture");
|
||||||
|
m_shader.GetUniformLocationMap("colour");
|
||||||
|
m_shader.GetUniformLocationMap("isBitmap");
|
||||||
|
|
||||||
|
m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(BasicVertex) * (MaxVerts));
|
||||||
|
m_vbo.Bind(true);
|
||||||
|
m_textvbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(UVCoords) * (int)m_uvCoord.size());
|
||||||
|
m_textvbo.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);
|
||||||
|
|
||||||
|
m_textvbo.Bind(true);
|
||||||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(UVCoords), 0);
|
||||||
|
m_textvbo.Bind(false);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
return OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
int count = (int)m_verts.size();
|
||||||
|
|
||||||
|
if (count > MaxVerts)
|
||||||
|
{
|
||||||
|
count = MaxVerts; // maybe we could error out somehow
|
||||||
|
}
|
||||||
|
|
||||||
|
m_shader.EnableShader();
|
||||||
|
matrix.Translate(x, y, 0);
|
||||||
|
|
||||||
|
if (!m_isBitmapCrosshair)
|
||||||
|
{
|
||||||
|
switch (player)
|
||||||
{
|
{
|
||||||
ErrorLog("Invalid crosshair style '%s', must be 'vector' or 'bmp'. Reverting to 'vector'.\n", m_crosshairStyle.c_str());
|
case 0: // P1 red color
|
||||||
m_isBitmapCrosshair = false;
|
r = 1.0f;
|
||||||
|
g = 0.0f;
|
||||||
|
b = 0.0f;
|
||||||
|
break;
|
||||||
|
case 1: // P2 green color
|
||||||
|
r = 0.0f;
|
||||||
|
g = 1.0f;
|
||||||
|
b = 0.0f;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_xRes = m_config["XResolution"].ValueAs<unsigned>();
|
matrix.Scale(m_dpiMultiplicator, m_dpiMultiplicator, 0);
|
||||||
m_yRes = m_config["YResolution"].ValueAs<unsigned>();
|
|
||||||
m_a = (float)m_xRes / (float)m_yRes;
|
|
||||||
|
|
||||||
SDL_Surface* surfaceCrosshairP1 = SDL_LoadBMP(p1CrosshairFile.c_str());
|
// update uniform memory
|
||||||
SDL_Surface* surfaceCrosshairP2 = SDL_LoadBMP(p2CrosshairFile.c_str());
|
glUniformMatrix4fv(m_shader.uniformLocMap["mvp"], 1, GL_FALSE, matrix);
|
||||||
if (surfaceCrosshairP1 == NULL || surfaceCrosshairP2 == NULL)
|
glUniform4f(m_shader.uniformLocMap["colour"], r, g, b, 1.0f);
|
||||||
return FAIL;
|
glUniform1i(m_shader.uniformLocMap["isBitmap"], false);
|
||||||
|
|
||||||
m_p1CrosshairW = surfaceCrosshairP1->w;
|
// update vbo mem
|
||||||
m_p1CrosshairH = surfaceCrosshairP1->h;
|
|
||||||
m_p2CrosshairW = surfaceCrosshairP2->w;
|
|
||||||
m_p2CrosshairH = surfaceCrosshairP2->h;
|
|
||||||
|
|
||||||
glGenTextures(2, m_crosshairTexId);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, m_crosshairTexId[0]);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_p1CrosshairW, m_p1CrosshairH, 0, GL_BGRA, GL_UNSIGNED_BYTE, surfaceCrosshairP1->pixels);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, m_crosshairTexId[1]);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_p1CrosshairW, m_p1CrosshairH, 0, GL_BGRA, GL_UNSIGNED_BYTE, surfaceCrosshairP2->pixels);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
|
|
||||||
SDL_FreeSurface(surfaceCrosshairP1);
|
|
||||||
SDL_FreeSurface(surfaceCrosshairP2);
|
|
||||||
|
|
||||||
// Get DPI
|
|
||||||
SDL_GetDisplayDPI(0, &m_diagDpi, &m_hDpi, &m_vDpi);
|
|
||||||
m_dpiMultiplicator = m_hDpi / m_standardDpi; // note : on linux VM diagdpi returns 0
|
|
||||||
|
|
||||||
// 3d obj
|
|
||||||
m_uvCoord.emplace_back(0.0f, 0.0f);
|
|
||||||
m_uvCoord.emplace_back(1.0f, 0.0f);
|
|
||||||
m_uvCoord.emplace_back(1.0f, 1.0f);
|
|
||||||
m_uvCoord.emplace_back(0.0f, 0.0f);
|
|
||||||
m_uvCoord.emplace_back(1.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(
|
|
||||||
|
|
||||||
#version 410 core
|
|
||||||
|
|
||||||
uniform mat4 mvp;
|
|
||||||
layout(location = 0) in vec3 inVertices;
|
|
||||||
layout(location = 1) in vec2 vertexUV;
|
|
||||||
out vec2 UV;
|
|
||||||
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
gl_Position = mvp * vec4(inVertices,1.0);
|
|
||||||
UV = vertexUV;
|
|
||||||
}
|
|
||||||
)glsl";
|
|
||||||
|
|
||||||
m_fragmentShader = R"glsl(
|
|
||||||
|
|
||||||
#version 410 core
|
|
||||||
|
|
||||||
uniform vec4 colour;
|
|
||||||
uniform sampler2D CrosshairTexture;
|
|
||||||
uniform bool isBitmap;
|
|
||||||
out vec4 fragColour;
|
|
||||||
in vec2 UV;
|
|
||||||
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
if (!isBitmap)
|
|
||||||
fragColour = colour;
|
|
||||||
else
|
|
||||||
fragColour = colour * texture(CrosshairTexture, UV);
|
|
||||||
}
|
|
||||||
)glsl";
|
|
||||||
|
|
||||||
m_shader.LoadShaders(m_vertexShader, m_fragmentShader);
|
|
||||||
m_shader.GetUniformLocationMap("mvp");
|
|
||||||
m_shader.GetUniformLocationMap("CrosshairTexture");
|
|
||||||
m_shader.GetUniformLocationMap("colour");
|
|
||||||
m_shader.GetUniformLocationMap("isBitmap");
|
|
||||||
|
|
||||||
m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(BasicVertex) * (MaxVerts));
|
|
||||||
m_vbo.Bind(true);
|
m_vbo.Bind(true);
|
||||||
m_textvbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(UVCoords) * (int)m_uvCoord.size());
|
m_vbo.BufferSubData(0, count * sizeof(BasicVertex), m_verts.data());
|
||||||
m_textvbo.Bind(true);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_crosshairTexId[player]);
|
||||||
|
|
||||||
glGenVertexArrays(1, &m_vao);
|
m_textureCoordsCount = (int)m_uvCoord.size();
|
||||||
glBindVertexArray(m_vao);
|
|
||||||
|
|
||||||
|
matrix.Scale(m_dpiMultiplicator * m_scaleBitmap, m_dpiMultiplicator * m_scaleBitmap, 0);
|
||||||
|
|
||||||
|
// update uniform memory
|
||||||
|
glUniformMatrix4fv(m_shader.uniformLocMap["mvp"], 1, GL_FALSE, matrix);
|
||||||
|
glUniform1i(m_shader.uniformLocMap["CrosshairTexture"], 0); // 0 or 1 or GL_TEXTURE0 GL_TEXTURE1
|
||||||
|
glUniform4f(m_shader.uniformLocMap["colour"], 1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
glUniform1i(m_shader.uniformLocMap["isBitmap"], true);
|
||||||
|
|
||||||
|
// update vbo mem
|
||||||
m_vbo.Bind(true);
|
m_vbo.Bind(true);
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(BasicVertex), 0);
|
m_vbo.BufferSubData(0, count * sizeof(BasicVertex), m_verts.data());
|
||||||
m_vbo.Bind(false);
|
m_vbo.Bind(false);
|
||||||
|
|
||||||
m_textvbo.Bind(true);
|
m_textvbo.Bind(true);
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(UVCoords), 0);
|
m_textvbo.BufferSubData(0, m_textureCoordsCount * sizeof(UVCoords), m_uvCoord.data());
|
||||||
m_textvbo.Bind(false);
|
m_textvbo.Bind(false);
|
||||||
|
}
|
||||||
|
|
||||||
glEnableVertexAttribArray(0);
|
glBindVertexArray(m_vao);
|
||||||
glEnableVertexAttribArray(1);
|
glDrawArrays(GL_TRIANGLES, 0, count);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
glBindVertexArray(0);
|
m_shader.DisableShader();
|
||||||
|
|
||||||
return OKAY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCrosshair::DrawCrosshair(New3D::Mat4 matrix, float x, float y, int player)
|
void CCrosshair::Update(uint32_t currentInputs, CInputs* Inputs, unsigned int xOffset, unsigned int yOffset, unsigned int xRes, unsigned int yRes)
|
||||||
{
|
{
|
||||||
float r=0.0f, g=0.0f, b=0.0f;
|
bool offscreenTrigger[2]{false};
|
||||||
int count = (int)m_verts.size();
|
float x[2]{ 0.0f }, y[2]{ 0.0f };
|
||||||
|
|
||||||
if (count > MaxVerts) {
|
// Crosshairs can be enabled/disabled at run-tim
|
||||||
count = MaxVerts; // maybe we could error out somehow
|
unsigned crosshairs = m_config["Crosshairs"].ValueAs<unsigned>();
|
||||||
}
|
crosshairs &= 3;
|
||||||
|
if (!crosshairs)
|
||||||
|
return;
|
||||||
|
|
||||||
m_shader.EnableShader();
|
// Set up the viewport and orthogonal projection
|
||||||
matrix.Translate(x, y, 0);
|
glUseProgram(0); // no shaders
|
||||||
|
glViewport(xOffset, yOffset, xRes, yRes);
|
||||||
|
glDisable(GL_DEPTH_TEST); // no Z-buffering needed
|
||||||
|
|
||||||
if (!m_isBitmapCrosshair)
|
if (!m_isBitmapCrosshair)
|
||||||
{
|
{
|
||||||
switch (player)
|
glDisable(GL_BLEND); // no blending
|
||||||
{
|
}
|
||||||
case 0: // P1 red color
|
else
|
||||||
r = 1.0f;
|
{
|
||||||
g = 0.0f;
|
glEnable(GL_TEXTURE_2D); // enable texture mapping, blending and alpha chanel
|
||||||
b = 0.0f;
|
glEnable(GL_BLEND);
|
||||||
break;
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
case 1: // P2 green color
|
}
|
||||||
r = 0.0f;
|
|
||||||
g = 1.0f;
|
|
||||||
b = 0.0f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
matrix.Scale(m_dpiMultiplicator, m_dpiMultiplicator, 0);
|
New3D::Mat4 m;
|
||||||
|
m.Ortho(0.0, 1.0, 1.0, 0.0, -1.0f, 1.0f);
|
||||||
|
|
||||||
// update uniform memory
|
// Convert gun coordinates to viewspace coordinates
|
||||||
glUniformMatrix4fv(m_shader.uniformLocMap["mvp"], 1, GL_FALSE, matrix);
|
if (currentInputs & Game::INPUT_ANALOG_GUN1)
|
||||||
glUniform4f(m_shader.uniformLocMap["colour"], r, g, b, 1.0f);
|
{
|
||||||
glUniform1i(m_shader.uniformLocMap["isBitmap"], false);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
// update vbo mem
|
// Draw visible crosshairs
|
||||||
m_vbo.Bind(true);
|
|
||||||
m_vbo.BufferSubData(0, count * sizeof(BasicVertex), m_verts.data());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, m_crosshairTexId[player]);
|
|
||||||
|
|
||||||
m_textureCoordsCount = (int)m_uvCoord.size();
|
if ((crosshairs & 1) && !offscreenTrigger[0]) // Player 1
|
||||||
|
{
|
||||||
|
DrawCrosshair(m, x[0], y[0], 0, xRes, yRes);
|
||||||
|
}
|
||||||
|
if ((crosshairs & 2) && !offscreenTrigger[1]) // Player 2
|
||||||
|
{
|
||||||
|
DrawCrosshair(m, x[1], y[1], 1, xRes, yRes);
|
||||||
|
}
|
||||||
|
|
||||||
matrix.Scale(m_dpiMultiplicator * m_scaleBitmap, m_dpiMultiplicator * m_scaleBitmap, 0);
|
//PrintGLError(glGetError());
|
||||||
|
|
||||||
// update uniform memory
|
|
||||||
glUniformMatrix4fv(m_shader.uniformLocMap["mvp"], 1, GL_FALSE, matrix);
|
|
||||||
glUniform1i(m_shader.uniformLocMap["CrosshairTexture"], 0); // 0 or 1 or GL_TEXTURE0 GL_TEXTURE1
|
|
||||||
glUniform4f(m_shader.uniformLocMap["colour"], 1.0f, 1.0f, 1.0f, 1.0f);
|
|
||||||
glUniform1i(m_shader.uniformLocMap["isBitmap"], true);
|
|
||||||
|
|
||||||
// update vbo mem
|
|
||||||
m_vbo.Bind(true);
|
|
||||||
m_vbo.BufferSubData(0, count * sizeof(BasicVertex), m_verts.data());
|
|
||||||
m_vbo.Bind(false);
|
|
||||||
m_textvbo.Bind(true);
|
|
||||||
m_textvbo.BufferSubData(0, m_textureCoordsCount * sizeof(UVCoords), m_uvCoord.data());
|
|
||||||
m_textvbo.Bind(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindVertexArray(m_vao);
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, count);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
|
|
||||||
m_shader.DisableShader();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCrosshair::Update(uint32_t currentInputs, CInputs* Inputs, unsigned int xOffset, unsigned int yOffset)
|
|
||||||
{
|
|
||||||
bool offscreenTrigger[2]{false};
|
|
||||||
float x[2]{ 0.0f }, y[2]{ 0.0f };
|
|
||||||
|
|
||||||
// Crosshairs can be enabled/disabled at run-tim
|
|
||||||
unsigned crosshairs = m_config["Crosshairs"].ValueAs<unsigned>();
|
|
||||||
crosshairs &= 3;
|
|
||||||
if (!crosshairs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Set up the viewport and orthogonal projection
|
|
||||||
glUseProgram(0); // no shaders
|
|
||||||
glViewport(xOffset, yOffset, m_xRes, m_yRes);
|
|
||||||
glDisable(GL_DEPTH_TEST); // no Z-buffering needed
|
|
||||||
|
|
||||||
if (!m_isBitmapCrosshair)
|
|
||||||
{
|
|
||||||
glDisable(GL_BLEND); // no blending
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glEnable(GL_TEXTURE_2D); // enable texture mapping, blending and alpha chanel
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
New3D::Mat4 m;
|
|
||||||
m.Ortho(0.0, 1.0, 1.0, 0.0, -1.0f, 1.0f);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
if ((crosshairs & 1) && !offscreenTrigger[0]) // Player 1
|
|
||||||
{
|
|
||||||
DrawCrosshair(m, x[0], y[0], 0);
|
|
||||||
}
|
|
||||||
if ((crosshairs & 2) && !offscreenTrigger[1]) // Player 2
|
|
||||||
{
|
|
||||||
DrawCrosshair(m, x[1], y[1], 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//PrintGLError(glGetError());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCrosshair::GunToViewCoords(float* x, float* y)
|
void CCrosshair::GunToViewCoords(float* x, float* y)
|
||||||
{
|
{
|
||||||
*x = (*x - 150.0f) / (651.0f - 150.0f); // Scale [150,651] -> [0.0,1.0]
|
*x = (*x - 150.0f) / (651.0f - 150.0f); // Scale [150,651] -> [0.0,1.0]
|
||||||
*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()
|
||||||
|
|
|
@ -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.
|
||||||
**
|
**
|
||||||
|
@ -29,56 +29,54 @@
|
||||||
class CCrosshair
|
class CCrosshair
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const Util::Config::Node& m_config;
|
const Util::Config::Node& m_config;
|
||||||
bool m_isBitmapCrosshair = false;
|
bool m_isBitmapCrosshair = false;
|
||||||
std::string m_crosshairStyle = "";
|
std::string m_crosshairStyle = "";
|
||||||
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;
|
const float m_base = 0.01f, m_height = 0.02f; // geometric parameters of each triangle
|
||||||
unsigned int m_yRes=0;
|
const float m_dist = 0.004f; // distance of triangle tip from center
|
||||||
const float m_base = 0.01f, m_height = 0.02f; // geometric parameters of each triangle
|
const float m_squareSize = 1.0f;
|
||||||
const float m_dist = 0.004f; // distance of triangle tip from center
|
const float m_standardDpi = 96.0f; // normal dpi for usual monitor (full hd)
|
||||||
float m_a = 0.0f; // aspect ratio (to square the crosshair)
|
float m_dpiMultiplicator = 0.0f;
|
||||||
const float m_squareSize = 1.0f;
|
const float m_scaleBitmap = 0.1f;
|
||||||
const float m_standardDpi = 96.0f; // normal dpi for usual monitor (full hd)
|
|
||||||
float m_dpiMultiplicator = 0.0f;
|
|
||||||
const float m_scaleBitmap = 0.1f;
|
|
||||||
|
|
||||||
struct BasicVertex
|
struct BasicVertex
|
||||||
{
|
{
|
||||||
BasicVertex(float x, float y, float z) : x(x), y(y), z(z) {}
|
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) {}
|
BasicVertex(float x, float y) : x(x), y(y), z(0.0f) {}
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UVCoords
|
struct UVCoords
|
||||||
{
|
{
|
||||||
UVCoords(float x, float y) : x(x), y(y) {}
|
UVCoords(float x, float y) : x(x), y(y) {}
|
||||||
float x, y;
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<BasicVertex> m_verts;
|
std::vector<BasicVertex> m_verts;
|
||||||
std::vector<UVCoords> m_uvCoord;
|
std::vector<UVCoords> m_uvCoord;
|
||||||
|
|
||||||
GLSLShader m_shader;
|
GLSLShader m_shader;
|
||||||
VBO m_vbo;
|
VBO m_vbo;
|
||||||
VBO m_textvbo;
|
VBO m_textvbo;
|
||||||
GLuint m_vao = 0;
|
GLuint m_vao = 0;
|
||||||
int m_textureCoordsCount = 0;
|
int m_textureCoordsCount = 0;
|
||||||
const char* m_vertexShader;
|
const char* m_vertexShader;
|
||||||
const char* m_fragmentShader;
|
const char* m_fragmentShader;
|
||||||
|
|
||||||
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 GunToViewCoords(float* x, float* y);
|
void DrawCrosshair(New3D::Mat4 matrix, float x, float y, int player, unsigned int xRes, unsigned int yRes);
|
||||||
|
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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue