#include "SDL_internal.h"
#ifdef SDL_VIDEO_RENDER_OGL_ES2
#include <SDL3/SDL_opengles2.h>
#include "SDL_shaders_gles2.h"
static const char GLES2_Fragment_Include_Best_Texture_Precision[] =
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
"#define SDL_TEXCOORD_PRECISION highp\n"
"#else\n"
"#define SDL_TEXCOORD_PRECISION mediump\n"
"#endif\n"
"\n"
"precision mediump float;\n"
"\n"
;
static const char GLES2_Fragment_Include_Medium_Texture_Precision[] =
"#define SDL_TEXCOORD_PRECISION mediump\n"
"precision mediump float;\n"
"\n"
;
static const char GLES2_Fragment_Include_High_Texture_Precision[] =
"#define SDL_TEXCOORD_PRECISION highp\n"
"precision mediump float;\n"
"\n"
;
static const char GLES2_Fragment_Include_Undef_Precision[] =
"#define mediump\n"
"#define highp\n"
"#define lowp\n"
"#define SDL_TEXCOORD_PRECISION\n"
"\n"
;
static const char GLES2_Vertex_Default[] =
"uniform mat4 u_projection;\n"
"attribute vec2 a_position;\n"
"attribute vec4 a_color;\n"
"attribute vec2 a_texCoord;\n"
"varying vec2 v_texCoord;\n"
"varying vec4 v_color;\n"
"\n"
"void main()\n"
"{\n"
" v_texCoord = a_texCoord;\n"
" gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\n"
" gl_PointSize = 1.0;\n"
" v_color = a_color;\n"
"}\n"
;
static const char GLES2_Fragment_Solid[] =
"varying mediump vec4 v_color;\n"
"\n"
"void main()\n"
"{\n"
" gl_FragColor = v_color;\n"
"}\n"
;
#define RGB_SHADER_PROLOGUE \
"uniform sampler2D u_texture;\n" \
"varying mediump vec4 v_color;\n" \
"varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \
#define RGB_PIXELART_SHADER_PROLOGUE \
"uniform sampler2D u_texture;\n" \
"uniform mediump vec4 u_texel_size;\n" \
"varying mediump vec4 v_color;\n" \
"varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \
#define PALETTE_SHADER_PROLOGUE \
"uniform sampler2D u_texture;\n" \
"uniform sampler2D u_palette;\n" \
"uniform mediump vec4 u_texel_size;\n" \
"varying mediump vec4 v_color;\n" \
"varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \
#define PALETTE_SHADER_FUNCTIONS \
"mediump vec4 SamplePaletteNearest(SDL_TEXCOORD_PRECISION vec2 uv)\n" \
"{\n" \
" mediump float index = texture2D(u_texture, uv).r * 255.0;\n" \
" return texture2D(u_palette, vec2((index + 0.5) / 256.0, 0.5));\n" \
"}\n" \
"\n" \
"mediump vec4 SamplePaletteLinear(SDL_TEXCOORD_PRECISION vec2 uv)\n" \
"{\n" \
" // scale & offset uvs to integer values at texel centers\n" \
" SDL_TEXCOORD_PRECISION vec2 uv_texels = uv * u_texel_size.zw + 0.5;\n" \
"\n" \
" // get uvs for the center of the 4 surrounding texels by flooring\n" \
" SDL_TEXCOORD_PRECISION vec4 uv_min_max = vec4((floor(uv_texels) - 0.5) * u_texel_size.xy, (floor(uv_texels) + 0.5) * u_texel_size.xy);\n" \
"\n" \
" // blend factor\n" \
" SDL_TEXCOORD_PRECISION vec2 uv_frac = fract(uv_texels);\n" \
"\n" \
" // sample all 4 texels\n" \
" mediump vec4 texelA = SamplePaletteNearest(uv_min_max.xy);\n" \
" mediump vec4 texelB = SamplePaletteNearest(uv_min_max.xw);\n" \
" mediump vec4 texelC = SamplePaletteNearest(uv_min_max.zy);\n" \
" mediump vec4 texelD = SamplePaletteNearest(uv_min_max.zw);\n" \
"\n" \
" // bilinear interpolation\n" \
" return mix(mix(texelA, texelB, uv_frac.y), mix(texelC, texelD, uv_frac.y), uv_frac.x);\n" \
"}\n" \
"\n"
#ifdef OPENGLES_300
#define PIXELART_SHADER_FUNCTIONS \
"SDL_TEXCOORD_PRECISION vec2 GetPixelArtUV(SDL_TEXCOORD_PRECISION vec2 uv)\n" \
"{\n" \
" SDL_TEXCOORD_PRECISION vec2 boxSize = clamp(fwidth(uv) * u_texel_size.zw, 1e-5, 1.0);\n" \
" SDL_TEXCOORD_PRECISION vec2 tx = uv * u_texel_size.zw - 0.5 * boxSize;\n" \
" SDL_TEXCOORD_PRECISION vec2 txOffset = smoothstep(vec2(1.0) - boxSize, vec2(1.0), fract(tx));\n" \
" return (floor(tx) + 0.5 + txOffset) * u_texel_size.xy;\n" \
"}\n" \
"\n" \
"mediump vec4 GetPixelArtSample(vec2 uv)\n" \
"{\n" \
" return textureGrad(u_texture, GetPixelArtUV(uv), dFdx(v_texCoord), dFdy(v_texCoord));\n" \
"}\n" \
"\n"
#else
#define PIXELART_SHADER_FUNCTIONS \
"mediump vec4 GetPixelArtSample(vec2 uv)\n" \
"{\n" \
" return texture2D(u_texture, uv);\n" \
"}\n" \
"\n"
#endif
static const char GLES2_Fragment_TexturePalette_Nearest[] =
PALETTE_SHADER_PROLOGUE
PALETTE_SHADER_FUNCTIONS
"\n"
"void main()\n"
"{\n"
" mediump vec4 color = SamplePaletteNearest(v_texCoord);\n"
" gl_FragColor = color;\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TexturePalette_Nearest_Colorswap[] =
PALETTE_SHADER_PROLOGUE
PALETTE_SHADER_FUNCTIONS
"\n"
"void main()\n"
"{\n"
" mediump vec4 color = SamplePaletteNearest(v_texCoord);\n"
" gl_FragColor = vec4(color.b, color.g, color.r, color.a);\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TexturePalette_Linear[] =
PALETTE_SHADER_PROLOGUE
PALETTE_SHADER_FUNCTIONS
"\n"
"void main()\n"
"{\n"
" mediump vec4 color = SamplePaletteLinear(v_texCoord);\n"
" gl_FragColor = color;\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TexturePalette_Linear_Colorswap[] =
PALETTE_SHADER_PROLOGUE
PALETTE_SHADER_FUNCTIONS
"\n"
"void main()\n"
"{\n"
" mediump vec4 color = SamplePaletteLinear(v_texCoord);\n"
" gl_FragColor = vec4(color.b, color.g, color.r, color.a);\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TexturePalette_PixelArt[] =
PALETTE_SHADER_PROLOGUE
PALETTE_SHADER_FUNCTIONS
PIXELART_SHADER_FUNCTIONS
"\n"
"void main()\n"
"{\n"
#ifdef OPENGLES_300
" mediump vec4 color = SamplePaletteLinear(GetPixelArtUV(v_texCoord));\n"
#else
" mediump vec4 color = SamplePaletteNearest(v_texCoord);\n"
#endif
" gl_FragColor = color;\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TexturePalette_PixelArt_Colorswap[] =
PALETTE_SHADER_PROLOGUE
PALETTE_SHADER_FUNCTIONS
PIXELART_SHADER_FUNCTIONS
"\n"
"void main()\n"
"{\n"
#ifdef OPENGLES_300
" mediump vec4 color = SamplePaletteLinear(GetPixelArtUV(v_texCoord));\n"
#else
" mediump vec4 color = SamplePaletteNearest(v_texCoord);\n"
#endif
" gl_FragColor = vec4(color.b, color.g, color.r, color.a);\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TextureRGB[] =
RGB_SHADER_PROLOGUE
"\n"
"void main()\n"
"{\n"
" mediump vec4 color = texture2D(u_texture, v_texCoord);\n"
" gl_FragColor = vec4(color.b, color.g, color.r, 1.0);\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TextureRGB_PixelArt[] =
RGB_PIXELART_SHADER_PROLOGUE
PIXELART_SHADER_FUNCTIONS
"\n"
"void main()\n"
"{\n"
" mediump vec4 color = GetPixelArtSample(v_texCoord);\n"
" gl_FragColor = vec4(color.b, color.g, color.r, 1.0);\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TextureBGR[] =
RGB_SHADER_PROLOGUE
"\n"
"void main()\n"
"{\n"
" mediump vec4 color = texture2D(u_texture, v_texCoord);\n"
" gl_FragColor = vec4(color.r, color.g, color.b, 1.0);\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TextureBGR_PixelArt[] =
RGB_PIXELART_SHADER_PROLOGUE
PIXELART_SHADER_FUNCTIONS
"\n"
"void main()\n"
"{\n"
" mediump vec4 color = GetPixelArtSample(v_texCoord);\n"
" gl_FragColor = vec4(color.r, color.g, color.b, 1.0);\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TextureARGB[] =
RGB_SHADER_PROLOGUE
"\n"
"void main()\n"
"{\n"
" mediump vec4 color = texture2D(u_texture, v_texCoord);\n"
" gl_FragColor = vec4(color.b, color.g, color.r, color.a);\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TextureARGB_PixelArt[] =
RGB_PIXELART_SHADER_PROLOGUE
PIXELART_SHADER_FUNCTIONS
"\n"
"void main()\n"
"{\n"
" mediump vec4 color = GetPixelArtSample(v_texCoord);\n"
" gl_FragColor = vec4(color.b, color.g, color.r, color.a);\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TextureABGR[] =
RGB_SHADER_PROLOGUE
"\n"
"void main()\n"
"{\n"
" mediump vec4 color = texture2D(u_texture, v_texCoord);\n"
" gl_FragColor = color;\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
static const char GLES2_Fragment_TextureABGR_PixelArt[] =
RGB_PIXELART_SHADER_PROLOGUE
PIXELART_SHADER_FUNCTIONS
"\n"
"void main()\n"
"{\n"
" mediump vec4 color = GetPixelArtSample(v_texCoord);\n"
" gl_FragColor = color;\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
#ifdef SDL_HAVE_YUV
#define YUV_SHADER_PROLOGUE \
"uniform sampler2D u_texture;\n" \
"uniform sampler2D u_texture_u;\n" \
"uniform sampler2D u_texture_v;\n" \
"uniform vec3 u_offset;\n" \
"uniform mat3 u_matrix;\n" \
"varying mediump vec4 v_color;\n" \
"varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \
"\n" \
#define YUV_SHADER_BODY \
"void main()\n" \
"{\n" \
" mediump vec3 yuv;\n" \
" lowp vec3 rgb;\n" \
"\n" \
" // Get the YUV values \n" \
" yuv.x = texture2D(u_texture, v_texCoord).r;\n" \
" yuv.y = texture2D(u_texture_u, v_texCoord).r;\n" \
" yuv.z = texture2D(u_texture_v, v_texCoord).r;\n" \
"\n" \
" // Do the color transform \n" \
" yuv += u_offset;\n" \
" rgb = yuv * u_matrix;\n" \
"\n" \
" // That was easy. :) \n" \
" gl_FragColor = vec4(rgb, 1);\n" \
" gl_FragColor *= v_color;\n" \
"}" \
#define NV12_RA_SHADER_BODY \
"void main()\n" \
"{\n" \
" mediump vec3 yuv;\n" \
" lowp vec3 rgb;\n" \
"\n" \
" // Get the YUV values \n" \
" yuv.x = texture2D(u_texture, v_texCoord).r;\n" \
" yuv.yz = texture2D(u_texture_u, v_texCoord).ra;\n" \
"\n" \
" // Do the color transform \n" \
" yuv += u_offset;\n" \
" rgb = yuv * u_matrix;\n" \
"\n" \
" // That was easy. :) \n" \
" gl_FragColor = vec4(rgb, 1);\n" \
" gl_FragColor *= v_color;\n" \
"}" \
#define NV12_RG_SHADER_BODY \
"void main()\n" \
"{\n" \
" mediump vec3 yuv;\n" \
" lowp vec3 rgb;\n" \
"\n" \
" // Get the YUV values \n" \
" yuv.x = texture2D(u_texture, v_texCoord).r;\n" \
" yuv.yz = texture2D(u_texture_u, v_texCoord).rg;\n" \
"\n" \
" // Do the color transform \n" \
" yuv += u_offset;\n" \
" rgb = yuv * u_matrix;\n" \
"\n" \
" // That was easy. :) \n" \
" gl_FragColor = vec4(rgb, 1);\n" \
" gl_FragColor *= v_color;\n" \
"}" \
#define NV21_RA_SHADER_BODY \
"void main()\n" \
"{\n" \
" mediump vec3 yuv;\n" \
" lowp vec3 rgb;\n" \
"\n" \
" // Get the YUV values \n" \
" yuv.x = texture2D(u_texture, v_texCoord).r;\n" \
" yuv.yz = texture2D(u_texture_u, v_texCoord).ar;\n" \
"\n" \
" // Do the color transform \n" \
" yuv += u_offset;\n" \
" rgb = yuv * u_matrix;\n" \
"\n" \
" // That was easy. :) \n" \
" gl_FragColor = vec4(rgb, 1);\n" \
" gl_FragColor *= v_color;\n" \
"}" \
#define NV21_RG_SHADER_BODY \
"void main()\n" \
"{\n" \
" mediump vec3 yuv;\n" \
" lowp vec3 rgb;\n" \
"\n" \
" // Get the YUV values \n" \
" yuv.x = texture2D(u_texture, v_texCoord).r;\n" \
" yuv.yz = texture2D(u_texture_u, v_texCoord).gr;\n" \
"\n" \
" // Do the color transform \n" \
" yuv += u_offset;\n" \
" rgb = yuv * u_matrix;\n" \
"\n" \
" // That was easy. :) \n" \
" gl_FragColor = vec4(rgb, 1);\n" \
" gl_FragColor *= v_color;\n" \
"}" \
static const char GLES2_Fragment_TextureYUV[] =
YUV_SHADER_PROLOGUE
YUV_SHADER_BODY
;
static const char GLES2_Fragment_TextureNV12_RA[] =
YUV_SHADER_PROLOGUE
NV12_RA_SHADER_BODY
;
static const char GLES2_Fragment_TextureNV12_RG[] =
YUV_SHADER_PROLOGUE
NV12_RG_SHADER_BODY
;
static const char GLES2_Fragment_TextureNV21_RA[] =
YUV_SHADER_PROLOGUE
NV21_RA_SHADER_BODY
;
static const char GLES2_Fragment_TextureNV21_RG[] =
YUV_SHADER_PROLOGUE
NV21_RG_SHADER_BODY
;
#endif
static const char GLES2_Fragment_TextureExternalOES_Prologue[] =
"#extension GL_OES_EGL_image_external : require\n"
"\n"
;
static const char GLES2_Fragment_TextureExternalOES[] =
"uniform samplerExternalOES u_texture;\n"
"varying mediump vec4 v_color;\n"
"varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n"
"\n"
"void main()\n"
"{\n"
" gl_FragColor = texture2D(u_texture, v_texCoord);\n"
" gl_FragColor *= v_color;\n"
"}\n"
;
const char *GLES2_GetShaderPrologue(GLES2_ShaderType type)
{
switch (type) {
case GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES:
return GLES2_Fragment_TextureExternalOES_Prologue;
default:
return "";
}
}
const char *GLES2_GetShaderInclude(GLES2_ShaderIncludeType type)
{
switch (type) {
case GLES2_SHADER_FRAGMENT_INCLUDE_UNDEF_PRECISION:
return GLES2_Fragment_Include_Undef_Precision;
case GLES2_SHADER_FRAGMENT_INCLUDE_BEST_TEXCOORD_PRECISION:
return GLES2_Fragment_Include_Best_Texture_Precision;
case GLES2_SHADER_FRAGMENT_INCLUDE_MEDIUM_TEXCOORD_PRECISION:
return GLES2_Fragment_Include_Medium_Texture_Precision;
case GLES2_SHADER_FRAGMENT_INCLUDE_HIGH_TEXCOORD_PRECISION:
return GLES2_Fragment_Include_High_Texture_Precision;
default:
return "";
}
}
GLES2_ShaderIncludeType GLES2_GetTexCoordPrecisionEnumFromHint(void)
{
const char *texcoord_hint = SDL_GetHint("SDL_RENDER_OPENGLES2_TEXCOORD_PRECISION");
GLES2_ShaderIncludeType value = GLES2_SHADER_FRAGMENT_INCLUDE_BEST_TEXCOORD_PRECISION;
if (texcoord_hint) {
if (SDL_strcmp(texcoord_hint, "undefined") == 0) {
return GLES2_SHADER_FRAGMENT_INCLUDE_UNDEF_PRECISION;
}
if (SDL_strcmp(texcoord_hint, "high") == 0) {
return GLES2_SHADER_FRAGMENT_INCLUDE_HIGH_TEXCOORD_PRECISION;
}
if (SDL_strcmp(texcoord_hint, "medium") == 0) {
return GLES2_SHADER_FRAGMENT_INCLUDE_MEDIUM_TEXCOORD_PRECISION;
}
}
return value;
}
const char *GLES2_GetShader(GLES2_ShaderType type)
{
switch (type) {
case GLES2_SHADER_VERTEX_DEFAULT:
return GLES2_Vertex_Default;
case GLES2_SHADER_FRAGMENT_SOLID:
return GLES2_Fragment_Solid;
case GLES2_SHADER_FRAGMENT_TEXTURE_PALETTE_NEAREST:
return GLES2_Fragment_TexturePalette_Nearest;
case GLES2_SHADER_FRAGMENT_TEXTURE_PALETTE_LINEAR:
return GLES2_Fragment_TexturePalette_Linear;
case GLES2_SHADER_FRAGMENT_TEXTURE_PALETTE_PIXELART:
return GLES2_Fragment_TexturePalette_PixelArt;
case GLES2_SHADER_FRAGMENT_TEXTURE_PALETTE_NEAREST_COLORSWAP:
return GLES2_Fragment_TexturePalette_Nearest_Colorswap;
case GLES2_SHADER_FRAGMENT_TEXTURE_PALETTE_LINEAR_COLORSWAP:
return GLES2_Fragment_TexturePalette_Linear_Colorswap;
case GLES2_SHADER_FRAGMENT_TEXTURE_PALETTE_PIXELART_COLORSWAP:
return GLES2_Fragment_TexturePalette_PixelArt_Colorswap;
case GLES2_SHADER_FRAGMENT_TEXTURE_RGB:
return GLES2_Fragment_TextureRGB;
case GLES2_SHADER_FRAGMENT_TEXTURE_RGB_PIXELART:
return GLES2_Fragment_TextureRGB_PixelArt;
case GLES2_SHADER_FRAGMENT_TEXTURE_BGR:
return GLES2_Fragment_TextureBGR;
case GLES2_SHADER_FRAGMENT_TEXTURE_BGR_PIXELART:
return GLES2_Fragment_TextureBGR_PixelArt;
case GLES2_SHADER_FRAGMENT_TEXTURE_ARGB:
return GLES2_Fragment_TextureARGB;
case GLES2_SHADER_FRAGMENT_TEXTURE_ARGB_PIXELART:
return GLES2_Fragment_TextureARGB_PixelArt;
case GLES2_SHADER_FRAGMENT_TEXTURE_ABGR:
return GLES2_Fragment_TextureABGR;
case GLES2_SHADER_FRAGMENT_TEXTURE_ABGR_PIXELART:
return GLES2_Fragment_TextureABGR_PixelArt;
#ifdef SDL_HAVE_YUV
case GLES2_SHADER_FRAGMENT_TEXTURE_YUV:
return GLES2_Fragment_TextureYUV;
case GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA:
return GLES2_Fragment_TextureNV12_RA;
case GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG:
return GLES2_Fragment_TextureNV12_RG;
case GLES2_SHADER_FRAGMENT_TEXTURE_NV21_RA:
return GLES2_Fragment_TextureNV21_RA;
case GLES2_SHADER_FRAGMENT_TEXTURE_NV21_RG:
return GLES2_Fragment_TextureNV21_RG;
#endif
case GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES:
return GLES2_Fragment_TextureExternalOES;
default:
return NULL;
}
}
#endif