mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-28 16:45:41 +00:00
c039d08c03
Late christmas present. Due to the way alpha works on the model3 adding regular anti-aliasing doesn't really work. Supersampling is very much a brute force solution, render the scene at a higher resolution and mipmap it. It's enabled via command line with the -ss option, for example -ss=4 for 4x supersampling or by adding Supersampling = 4 in the config file. Note non power of two values work as well, so 3 gives a very good balance between speed and quality. 8 will make your GPU bleed, since it is essentially rendering 64 pixels for every visible pixel on the screen.
138 lines
2.9 KiB
C++
138 lines
2.9 KiB
C++
#include "SuperAA.h"
|
|
#include <string>
|
|
|
|
SuperAA::SuperAA(int aaValue) :
|
|
m_aa(aaValue),
|
|
m_vao(0),
|
|
m_width(0),
|
|
m_height(0)
|
|
{
|
|
if (aaValue > 1) {
|
|
|
|
const char* vertexShader = R"glsl(
|
|
|
|
#version 410 core
|
|
|
|
// outputs
|
|
out vec2 fsTexCoord;
|
|
|
|
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));
|
|
|
|
fsTexCoord = (vertices[gl_VertexID % 4].xy + 1.0) / 2.0;
|
|
gl_Position = vertices[gl_VertexID % 4];
|
|
}
|
|
|
|
)glsl";
|
|
|
|
|
|
std::string fragmentShaderVersion = R"glsl(
|
|
#version 410 core
|
|
|
|
)glsl";
|
|
|
|
std::string aaString = "const int aa = ";
|
|
aaString += std::to_string(aaValue);
|
|
aaString += ";\n";
|
|
|
|
std::string fragmentShader = R"glsl(
|
|
|
|
// inputs
|
|
uniform sampler2D tex1; // base tex
|
|
in vec2 fsTexCoord;
|
|
|
|
// outputs
|
|
out vec4 fragColor;
|
|
|
|
vec4 GetTextureValue(sampler2D s, vec2 texCoord)
|
|
{
|
|
vec2 size = vec2(textureSize(s,0)); // want the values as floats
|
|
ivec2 texPos = ivec2(size * texCoord);
|
|
vec4 texColour = vec4(0.0);
|
|
|
|
for(int i=0; i < aa; i++) {
|
|
for(int j=0; j < aa; j++) {
|
|
texColour += texelFetch(s,ivec2(texPos.x+i,texPos.y+j),0);
|
|
}
|
|
}
|
|
|
|
texColour /= float(aa * aa);
|
|
|
|
return texColour;
|
|
}
|
|
|
|
void main()
|
|
{
|
|
fragColor = GetTextureValue(tex1, fsTexCoord);
|
|
}
|
|
|
|
)glsl";
|
|
|
|
std::string fragmentShaderString = fragmentShaderVersion + aaString + fragmentShader;
|
|
|
|
// load shaders
|
|
m_shader.LoadShaders(vertexShader, fragmentShaderString.c_str());
|
|
m_shader.GetUniformLocationMap("tex1");
|
|
|
|
// setup uniform memory
|
|
m_shader.EnableShader();
|
|
glUniform1i(m_shader.attribLocMap["tex1"], 0); // texture will be bound to unit zero
|
|
m_shader.DisableShader();
|
|
|
|
glGenVertexArrays(1, &m_vao);
|
|
glBindVertexArray(m_vao);
|
|
// no states needed since we do it in the shader
|
|
glBindVertexArray(0);
|
|
}
|
|
}
|
|
|
|
// need an active context bound to the current thread to destroy our objects
|
|
SuperAA::~SuperAA()
|
|
{
|
|
m_shader.UnloadShaders();
|
|
m_fbo.Destroy();
|
|
|
|
if (m_vao) {
|
|
glDeleteVertexArrays(1, &m_vao);
|
|
m_vao = 0;
|
|
}
|
|
}
|
|
|
|
void SuperAA::Init(int width, int height)
|
|
{
|
|
if (m_aa > 1) {
|
|
m_fbo.Destroy();
|
|
m_fbo.Create(width * m_aa, height * m_aa);
|
|
|
|
m_width = width;
|
|
m_height = height;
|
|
}
|
|
}
|
|
|
|
void SuperAA::Draw()
|
|
{
|
|
if (m_aa > 1) {
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_STENCIL_TEST);
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glDisable(GL_BLEND);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, m_fbo.GetTextureID());
|
|
glBindVertexArray(m_vao);
|
|
glViewport(0, 0, m_width, m_height);
|
|
m_shader.EnableShader();
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
m_shader.DisableShader();
|
|
glBindVertexArray(0);
|
|
}
|
|
}
|
|
|
|
GLuint SuperAA::GetTargetID()
|
|
{
|
|
return m_fbo.GetFBOID(); // will return 0 if no render target which will be our default frame buffer (back buffer)
|
|
}
|