Added SDL_SCALEMODE_PIXELART

This is based on the algorithm presented by t3ssel8r:
https://www.youtube.com/watch?v=d6tp43wZqps
This commit is contained in:
Sam Lantinga
2025-03-12 08:45:25 -07:00
parent 853375da61
commit 3e9e22f17d
63 changed files with 15968 additions and 13125 deletions

View File

@@ -68,6 +68,7 @@ typedef struct
int drawableh;
SDL_BlendMode blend;
GL_Shader shader;
float texel_size[4];
const float *shader_params;
bool cliprect_enabled_dirty;
bool cliprect_enabled;
@@ -133,6 +134,7 @@ typedef struct
GLenum format;
GLenum formattype;
GL_Shader shader;
float texel_size[4];
const float *shader_params;
void *pixels;
int pitch;
@@ -627,6 +629,11 @@ static bool GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_P
data->shader = SHADER_RGB;
}
data->texel_size[2] = texture->w;
data->texel_size[3] = texture->h;
data->texel_size[0] = 1.0f / data->texel_size[2];
data->texel_size[1] = 1.0f / data->texel_size[3];
#ifdef SDL_HAVE_YUV
if (data->yuv || data->nv12) {
if (data->yuv) {
@@ -1081,6 +1088,7 @@ static bool SetTextureScaleMode(GL_RenderData *data, GLenum textype, SDL_ScaleMo
data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
case SDL_SCALEMODE_PIXELART: // Uses linear sampling
case SDL_SCALEMODE_LINEAR:
data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -1113,8 +1121,24 @@ static bool SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd)
SDL_Texture *texture = cmd->data.draw.texture;
GL_TextureData *texturedata = (GL_TextureData *)texture->internal;
const GLenum textype = data->textype;
GL_Shader shader = texturedata->shader;
const float *shader_params = texturedata->shader_params;
SetDrawState(data, cmd, texturedata->shader, texturedata->shader_params);
if (cmd->data.draw.texture_scale_mode == SDL_SCALEMODE_PIXELART) {
switch (shader) {
case SHADER_RGB:
shader = SHADER_RGB_PIXELART;
shader_params = texturedata->texel_size;
break;
case SHADER_RGBA:
shader = SHADER_RGBA_PIXELART;
shader_params = texturedata->texel_size;
break;
default:
break;
}
}
SetDrawState(data, cmd, shader, shader_params);
if (texture != data->drawstate.texture) {
#ifdef SDL_HAVE_YUV

View File

@@ -53,6 +53,7 @@ struct GL_ShaderContext
PFNGLUNIFORM1IARBPROC glUniform1iARB;
PFNGLUNIFORM1FARBPROC glUniform1fARB;
PFNGLUNIFORM3FARBPROC glUniform3fARB;
PFNGLUNIFORM4FARBPROC glUniform4fARB;
PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
bool GL_ARB_texture_rectangle_supported;
@@ -261,6 +262,7 @@ static const char *shader_source[NUM_SHADERS][2] = {
"varying vec4 v_color;\n"
"varying vec2 v_texCoord;\n"
"uniform sampler2D tex0;\n"
"uniform vec4 texel_size; // texel size (xy: texel size, zw: texture dimensions)\n"
"\n"
"void main()\n"
"{\n"
@@ -284,6 +286,50 @@ static const char *shader_source[NUM_SHADERS][2] = {
" gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n"
"}"
},
// SHADER_RGB_PIXELART
{
// vertex shader
TEXTURE_VERTEX_SHADER,
// fragment shader
"varying vec4 v_color;\n"
"varying vec2 v_texCoord;\n"
"uniform sampler2D tex0;\n"
"uniform vec4 texel_size;\n"
"\n"
"void main()\n"
"{\n"
" vec2 boxSize = clamp(fwidth(v_texCoord) * texel_size.zw, 1e-5, 1.0);\n"
" vec2 tx = v_texCoord * texel_size.zw - 0.5 * boxSize;\n"
" vec2 txOffset = smoothstep(vec2(1.0) - boxSize, vec2(1.0), fract(tx));\n"
" vec2 uv = (floor(tx) + 0.5 + txOffset) * texel_size.xy;\n"
" gl_FragColor = textureGrad(tex0, uv, dFdx(v_texCoord), dFdy(v_texCoord));\n"
" gl_FragColor.a = 1.0;\n"
" gl_FragColor *= v_color;\n"
"}"
},
// SHADER_RGBA_PIXELART
{
// vertex shader
TEXTURE_VERTEX_SHADER,
// fragment shader
"varying vec4 v_color;\n"
"varying vec2 v_texCoord;\n"
"uniform sampler2D tex0;\n"
"uniform vec4 texel_size;\n"
"\n"
"void main()\n"
"{\n"
" vec2 boxSize = clamp(fwidth(v_texCoord) * texel_size.zw, 1e-5, 1.0);\n"
" vec2 tx = v_texCoord * texel_size.zw - 0.5 * boxSize;\n"
" vec2 txOffset = smoothstep(vec2(1.0) - boxSize, vec2(1.0), fract(tx));\n"
" vec2 uv = (floor(tx) + 0.5 + txOffset) * texel_size.xy;\n"
" gl_FragColor = textureGrad(tex0, uv, dFdx(v_texCoord), dFdy(v_texCoord));\n"
" gl_FragColor *= v_color;\n"
"}"
},
#ifdef SDL_HAVE_YUV
// SHADER_YUV
{
@@ -466,6 +512,7 @@ GL_ShaderContext *GL_CreateShaderContext(void)
ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC)SDL_GL_GetProcAddress("glUniform1iARB");
ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC)SDL_GL_GetProcAddress("glUniform1fARB");
ctx->glUniform3fARB = (PFNGLUNIFORM3FARBPROC)SDL_GL_GetProcAddress("glUniform3fARB");
ctx->glUniform4fARB = (PFNGLUNIFORM4FARBPROC)SDL_GL_GetProcAddress("glUniform4fARB");
ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glUseProgramObjectARB");
if (ctx->glGetError &&
ctx->glAttachObjectARB &&
@@ -511,23 +558,36 @@ void GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader, const float *shade
ctx->glUseProgramObjectARB(program);
if (shader_params && shader_params != ctx->shader_params[shader]) {
// YUV shader params are Yoffset, 0, Rcoeff, 0, Gcoeff, 0, Bcoeff, 0
location = ctx->glGetUniformLocationARB(program, "Yoffset");
if (location >= 0) {
ctx->glUniform3fARB(location, shader_params[0], shader_params[1], shader_params[2]);
if (shader == SHADER_RGB_PIXELART ||
shader == SHADER_RGBA_PIXELART) {
location = ctx->glGetUniformLocationARB(program, "texel_size");
if (location >= 0) {
ctx->glUniform4fARB(location, shader_params[0], shader_params[1], shader_params[2], shader_params[3]);
}
}
location = ctx->glGetUniformLocationARB(program, "Rcoeff");
if (location >= 0) {
ctx->glUniform3fARB(location, shader_params[4], shader_params[5], shader_params[6]);
}
location = ctx->glGetUniformLocationARB(program, "Gcoeff");
if (location >= 0) {
ctx->glUniform3fARB(location, shader_params[8], shader_params[9], shader_params[10]);
}
location = ctx->glGetUniformLocationARB(program, "Bcoeff");
if (location >= 0) {
ctx->glUniform3fARB(location, shader_params[12], shader_params[13], shader_params[14]);
#ifdef SDL_HAVE_YUV
if (shader >= SHADER_YUV) {
// YUV shader params are Yoffset, 0, Rcoeff, 0, Gcoeff, 0, Bcoeff, 0
location = ctx->glGetUniformLocationARB(program, "Yoffset");
if (location >= 0) {
ctx->glUniform3fARB(location, shader_params[0], shader_params[1], shader_params[2]);
}
location = ctx->glGetUniformLocationARB(program, "Rcoeff");
if (location >= 0) {
ctx->glUniform3fARB(location, shader_params[4], shader_params[5], shader_params[6]);
}
location = ctx->glGetUniformLocationARB(program, "Gcoeff");
if (location >= 0) {
ctx->glUniform3fARB(location, shader_params[8], shader_params[9], shader_params[10]);
}
location = ctx->glGetUniformLocationARB(program, "Bcoeff");
if (location >= 0) {
ctx->glUniform3fARB(location, shader_params[12], shader_params[13], shader_params[14]);
}
}
#endif // SDL_HAVE_YUV
ctx->shader_params[shader] = shader_params;
}
}

View File

@@ -33,6 +33,8 @@ typedef enum
SHADER_SOLID,
SHADER_RGB,
SHADER_RGBA,
SHADER_RGB_PIXELART,
SHADER_RGBA_PIXELART,
#ifdef SDL_HAVE_YUV
SHADER_YUV,
SHADER_NV12_RA,