Add Lanczos3 scaling (#9)

"Lanczos filtering tends to yield much better quality (sharper image) than bilinear filtering."
This commit is contained in:
Splendide Imaginarius 2023-05-05 19:39:42 +00:00 committed by GitHub
parent ae6fd075fa
commit f26a9a8e1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 118 additions and 7 deletions

View file

@ -73,6 +73,13 @@
// "smoothScaling": false, // "smoothScaling": false,
// Apply Lanczos3 interpolation when game screen
// is upscaled (typically higher quality than linear)
// (default: disabled)
//
// "lanczos3Scaling": false,
// Sync screen redraws to the monitor refresh rate // Sync screen redraws to the monitor refresh rate
// (default: disabled) // (default: disabled)
// //

48
shader/lanczos3.frag Normal file
View file

@ -0,0 +1,48 @@
// From https://raw.githubusercontent.com/Sentmoraap/doing-sdl-right/93a52a0db0ff2da5066cce12f5b9a2ac62e6f401/assets/lanczos3.frag
// Copyright 2020 Lilian Gimenez (Sentmoraap).
// MIT license.
uniform sampler2D texture;
uniform vec2 sourceSize;
uniform vec2 texSizeInv;
varying vec2 v_texCoord;
float lanczos3(float x)
{
x = max(abs(x), 0.00001);
float val = x * 3.141592654;
return sin(val) * sin(val / 3) / (val * val);
}
void main()
{
vec2 pixel = v_texCoord * sourceSize + 0.5;
vec2 frac = fract(pixel);
vec2 onePixel = texSizeInv;
pixel = floor(pixel) * texSizeInv - onePixel / 2;
float lanczosX[6];
float sum = 0;
for(int x = 0; x < 6; x++)
{
lanczosX[x] = lanczos3(x - 2 - frac.x);
sum += lanczosX[x];
}
for(int x = 0; x < 6; x++) lanczosX[x] /= sum;
sum = 0;
float lanczosY[6];
for(int y = 0; y < 6; y++)
{
lanczosY[y] = lanczos3(y - 2 - frac.y);
sum += lanczosY[y];
}
for(int y = 0; y < 6; y++) lanczosY[y] /= sum;
gl_FragColor = vec4(0);
for(int y = -2; y <= 3; y++)
{
vec4 colour = vec4(0);
for(int x = -2; x <= 3; x++)
colour += texture2D(texture, pixel + vec2(x * onePixel.x, y * onePixel.y)).rgba * lanczosX[x + 2];
gl_FragColor += colour * lanczosY[y + 2];
}
}

View file

@ -15,6 +15,7 @@ embedded_shaders = [
'simpleAlphaUni.frag', 'simpleAlphaUni.frag',
'tilemap.frag', 'tilemap.frag',
'flashMap.frag', 'flashMap.frag',
'lanczos3.frag',
'minimal.vert', 'minimal.vert',
'simple.vert', 'simple.vert',
'simpleColor.vert', 'simpleColor.vert',

View file

@ -134,6 +134,7 @@ void Config::read(int argc, char *argv[]) {
{"fullscreen", false}, {"fullscreen", false},
{"fixedAspectRatio", true}, {"fixedAspectRatio", true},
{"smoothScaling", false}, {"smoothScaling", false},
{"lanczos3Scaling", false},
{"vsync", false}, {"vsync", false},
{"defScreenW", 0}, {"defScreenW", 0},
{"defScreenH", 0}, {"defScreenH", 0},
@ -257,6 +258,7 @@ try { exp } catch (...) {}
SET_OPT(fullscreen, boolean); SET_OPT(fullscreen, boolean);
SET_OPT(fixedAspectRatio, boolean); SET_OPT(fixedAspectRatio, boolean);
SET_OPT(smoothScaling, boolean); SET_OPT(smoothScaling, boolean);
SET_OPT(lanczos3Scaling, boolean);
SET_OPT(winResizable, boolean); SET_OPT(winResizable, boolean);
SET_OPT(vsync, boolean); SET_OPT(vsync, boolean);
SET_STRINGOPT(windowTitle, windowTitle); SET_STRINGOPT(windowTitle, windowTitle);

View file

@ -43,6 +43,7 @@ struct Config {
bool fullscreen; bool fullscreen;
bool fixedAspectRatio; bool fixedAspectRatio;
bool smoothScaling; bool smoothScaling;
bool lanczos3Scaling;
bool vsync; bool vsync;
int defScreenW; int defScreenW;

View file

@ -24,6 +24,7 @@
#include "sharedstate.h" #include "sharedstate.h"
#include "glstate.h" #include "glstate.h"
#include "quad.h" #include "quad.h"
#include "config.h"
namespace GLMeta namespace GLMeta
{ {
@ -144,10 +145,22 @@ static void _blitBegin(FBO::ID fbo, const Vec2i &size)
FBO::bind(fbo); FBO::bind(fbo);
glState.viewport.pushSet(IntRect(0, 0, size.x, size.y)); glState.viewport.pushSet(IntRect(0, 0, size.x, size.y));
SimpleShader &shader = shState->shaders().simple; if (shState->config().lanczos3Scaling)
shader.bind(); {
shader.applyViewportProj(); Lanczos3Shader &shader = shState->shaders().lanczos3;
shader.setTranslation(Vec2i()); shader.bind();
shader.applyViewportProj();
shader.setTranslation(Vec2i());
shader.setTexSize(Vec2i(size.x, size.y));
}
else
{
SimpleShader &shader = shState->shaders().simple;
shader.bind();
shader.applyViewportProj();
shader.setTranslation(Vec2i());
shader.setTexSize(Vec2i(size.x, size.y));
}
} }
} }
@ -169,8 +182,18 @@ void blitSource(TEXFBO &source)
} }
else else
{ {
SimpleShader &shader = shState->shaders().simple; if (shState->config().lanczos3Scaling)
shader.setTexSize(Vec2i(source.width, source.height)); {
Lanczos3Shader &shader = shState->shaders().lanczos3;
shader.bind();
shader.setTexSize(Vec2i(source.width, source.height));
}
else
{
SimpleShader &shader = shState->shaders().simple;
shader.bind();
shader.setTexSize(Vec2i(source.width, source.height));
}
TEX::bind(source.tex); TEX::bind(source.tex);
} }
} }

View file

@ -44,6 +44,7 @@
#include "simpleAlphaUni.frag.xxd" #include "simpleAlphaUni.frag.xxd"
#include "tilemap.frag.xxd" #include "tilemap.frag.xxd"
#include "flashMap.frag.xxd" #include "flashMap.frag.xxd"
#include "lanczos3.frag.xxd"
#include "minimal.vert.xxd" #include "minimal.vert.xxd"
#include "simple.vert.xxd" #include "simple.vert.xxd"
#include "simpleColor.vert.xxd" #include "simpleColor.vert.xxd"
@ -746,3 +747,19 @@ void BltShader::setOpacity(float value)
{ {
gl.Uniform1f(u_opacity, value); gl.Uniform1f(u_opacity, value);
} }
Lanczos3Shader::Lanczos3Shader()
{
INIT_SHADER(simple, lanczos3, Lanczos3Shader);
ShaderBase::init();
GET_U(texOffsetX);
GET_U(sourceSize);
}
void Lanczos3Shader::setTexSize(const Vec2i &value)
{
ShaderBase::setTexSize(value);
gl.Uniform2f(u_sourceSize, (float)value.x, (float)value.y);
}

View file

@ -113,7 +113,7 @@ public:
void setTexOffsetX(int value); void setTexOffsetX(int value);
private: protected:
GLint u_texOffsetX; GLint u_texOffsetX;
}; };
@ -326,6 +326,17 @@ private:
GLint u_source, u_destination, u_subRect, u_opacity; GLint u_source, u_destination, u_subRect, u_opacity;
}; };
class Lanczos3Shader : public SimpleShader
{
public:
Lanczos3Shader();
void setTexSize(const Vec2i &value);
protected:
GLint u_sourceSize;
};
/* Global object containing all available shaders */ /* Global object containing all available shaders */
struct ShaderSet struct ShaderSet
{ {
@ -347,6 +358,7 @@ struct ShaderSet
SimpleMatrixShader simpleMatrix; SimpleMatrixShader simpleMatrix;
BlurShader blur; BlurShader blur;
TilemapVXShader tilemapVX; TilemapVXShader tilemapVX;
Lanczos3Shader lanczos3;
}; };
#endif // SHADER_H #endif // SHADER_H