mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-27 08:05:41 +00:00
6595b9320e
Some games update the tilegen after the ping_ping bit has flipped at 66% of the frame, so we need to split the tilegen drawing up into two stages to get some effects to work. So having the tilegen draw independantly of the 3d chip can make this happen.
163 lines
3.9 KiB
C++
163 lines
3.9 KiB
C++
#include "R3DScrollFog.h"
|
|
#include "Graphics/Shader.h"
|
|
|
|
namespace New3D {
|
|
|
|
static const char *vertexShaderFog = R"glsl(
|
|
|
|
#version 410 core
|
|
|
|
void main(void)
|
|
{
|
|
const vec4 vertices[] = vec4[](vec4(-1.0, -1.0, 0.0, 1.0),
|
|
vec4(-1.0, 1.0, 0.0, 1.0),
|
|
vec4( 1.0, -1.0, 0.0, 1.0),
|
|
vec4( 1.0, 1.0, 0.0, 1.0));
|
|
|
|
gl_Position = vertices[gl_VertexID % 4];
|
|
}
|
|
|
|
)glsl";
|
|
|
|
static const char *fragmentShaderFog = R"glsl(
|
|
|
|
#version 410 core
|
|
|
|
uniform float fogAttenuation;
|
|
uniform float fogAmbient;
|
|
uniform vec4 fogColour;
|
|
uniform vec3 spotFogColor;
|
|
uniform vec4 spotEllipse;
|
|
|
|
// Spotlight on fog
|
|
float ellipse;
|
|
vec2 position, size;
|
|
vec3 lSpotFogColor;
|
|
|
|
// Scroll fog
|
|
float lfogAttenuation;
|
|
vec3 lFogColor;
|
|
vec4 scrollFog;
|
|
|
|
// outputs
|
|
layout(location = 0) out vec4 out0; // opaque
|
|
layout(location = 1) out vec4 out1; // trans layer 1
|
|
layout(location = 2) out vec4 out2; // trans layer 2
|
|
|
|
void WriteOutputs(vec4 colour)
|
|
{
|
|
vec4 blank = vec4(0.0);
|
|
|
|
if(colour.a < 1.0) { // some transparency
|
|
out0 = blank;
|
|
out1 = colour;
|
|
out2 = blank;
|
|
}
|
|
else { // opaque
|
|
out0 = colour;
|
|
out1 = blank;
|
|
out2 = blank;
|
|
}
|
|
}
|
|
|
|
void main()
|
|
{
|
|
// Scroll fog base color
|
|
lFogColor = fogColour.rgb * fogAmbient;
|
|
|
|
// Spotlight on fog (area)
|
|
position = spotEllipse.xy;
|
|
size = spotEllipse.zw;
|
|
ellipse = length((gl_FragCoord.xy - position) / size);
|
|
ellipse = ellipse * ellipse; // decay rate = square of distance from center
|
|
ellipse = 1.0 - ellipse; // invert
|
|
ellipse = max(0.0, ellipse); // clamp
|
|
|
|
// Spotlight on fog (color)
|
|
lSpotFogColor = mix(spotFogColor * ellipse * fogColour.rgb, vec3(0.0), fogAttenuation);
|
|
|
|
// Scroll fog density
|
|
scrollFog = vec4(lFogColor + lSpotFogColor, fogColour.a);
|
|
|
|
// Final Color
|
|
WriteOutputs(scrollFog);
|
|
}
|
|
|
|
)glsl";
|
|
|
|
|
|
R3DScrollFog::R3DScrollFog(const Util::Config::Node &config)
|
|
: m_config(config),
|
|
m_vao(0)
|
|
{
|
|
m_shaderProgram = 0;
|
|
m_vertexShader = 0;
|
|
m_fragmentShader = 0;
|
|
|
|
AllocResources();
|
|
|
|
glGenVertexArrays(1, &m_vao);
|
|
glBindVertexArray(m_vao);
|
|
// no states needed since we do it in the shader
|
|
glBindVertexArray(0);
|
|
}
|
|
|
|
R3DScrollFog::~R3DScrollFog()
|
|
{
|
|
DeallocResources();
|
|
|
|
if (m_vao) {
|
|
glDeleteVertexArrays(1, &m_vao);
|
|
m_vao = 0;
|
|
}
|
|
}
|
|
|
|
void R3DScrollFog::DrawScrollFog(float rgba[4], float attenuation, float ambient, float *spotRGB, float *spotEllipse)
|
|
{
|
|
// some ogl states
|
|
glDepthMask (GL_FALSE); // disable z writes
|
|
glDisable (GL_DEPTH_TEST); // disable depth testing
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glBindVertexArray (m_vao);
|
|
glUseProgram (m_shaderProgram);
|
|
glUniform4fv (m_locFogColour, 1, rgba);
|
|
glUniform1f (m_locFogAttenuation, attenuation);
|
|
glUniform1f (m_locFogAmbient, ambient);
|
|
glUniform3fv (m_locSpotFogColor, 1, spotRGB);
|
|
glUniform4fv (m_locSpotEllipse, 1, spotEllipse);
|
|
|
|
glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
|
|
|
|
glUseProgram (0);
|
|
glBindVertexArray (0);
|
|
|
|
glDisable (GL_BLEND);
|
|
glDepthMask (GL_TRUE);
|
|
}
|
|
|
|
void R3DScrollFog::AllocResources()
|
|
{
|
|
bool success = LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, m_config["VertexShaderFog"].ValueAs<std::string>(), m_config["FragmentShaderFog"].ValueAs<std::string>(), vertexShaderFog, fragmentShaderFog);
|
|
|
|
m_locFogColour = glGetUniformLocation(m_shaderProgram, "fogColour");
|
|
m_locFogAttenuation = glGetUniformLocation(m_shaderProgram, "fogAttenuation");
|
|
m_locFogAmbient = glGetUniformLocation(m_shaderProgram, "fogAmbient");
|
|
m_locSpotFogColor = glGetUniformLocation(m_shaderProgram, "spotFogColor");
|
|
m_locSpotEllipse = glGetUniformLocation(m_shaderProgram, "spotEllipse");
|
|
}
|
|
|
|
void R3DScrollFog::DeallocResources()
|
|
{
|
|
if (m_shaderProgram) {
|
|
DestroyShaderProgram(m_shaderProgram, m_vertexShader, m_fragmentShader);
|
|
}
|
|
|
|
m_shaderProgram = 0;
|
|
m_vertexShader = 0;
|
|
m_fragmentShader = 0;
|
|
}
|
|
|
|
}
|