cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_shaders_gl.c (13945B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21#include "../../SDL_internal.h"
     22
     23#if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED
     24
     25#include "SDL_stdinc.h"
     26#include "SDL_log.h"
     27#include "SDL_opengl.h"
     28#include "SDL_video.h"
     29#include "SDL_shaders_gl.h"
     30
     31/* OpenGL shader implementation */
     32
     33/* #define DEBUG_SHADERS */
     34
     35typedef struct
     36{
     37    GLhandleARB program;
     38    GLhandleARB vert_shader;
     39    GLhandleARB frag_shader;
     40} GL_ShaderData;
     41
     42struct GL_ShaderContext
     43{
     44    GLenum (*glGetError)(void);
     45
     46    PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
     47    PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
     48    PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
     49    PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
     50    PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
     51    PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
     52    PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
     53    PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
     54    PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
     55    PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
     56    PFNGLUNIFORM1IARBPROC glUniform1iARB;
     57    PFNGLUNIFORM1FARBPROC glUniform1fARB;
     58    PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
     59
     60    SDL_bool GL_ARB_texture_rectangle_supported;
     61
     62    GL_ShaderData shaders[NUM_SHADERS];
     63};
     64
     65/*
     66 * NOTE: Always use sampler2D, etc here. We'll #define them to the
     67 *  texture_rectangle versions if we choose to use that extension.
     68 */
     69static const char *shader_source[NUM_SHADERS][2] =
     70{
     71    /* SHADER_NONE */
     72    { NULL, NULL },
     73
     74    /* SHADER_SOLID */
     75    {
     76        /* vertex shader */
     77"varying vec4 v_color;\n"
     78"\n"
     79"void main()\n"
     80"{\n"
     81"    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
     82"    v_color = gl_Color;\n"
     83"}",
     84        /* fragment shader */
     85"varying vec4 v_color;\n"
     86"\n"
     87"void main()\n"
     88"{\n"
     89"    gl_FragColor = v_color;\n"
     90"}"
     91    },
     92
     93    /* SHADER_RGB */
     94    {
     95        /* vertex shader */
     96"varying vec4 v_color;\n"
     97"varying vec2 v_texCoord;\n"
     98"\n"
     99"void main()\n"
    100"{\n"
    101"    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
    102"    v_color = gl_Color;\n"
    103"    v_texCoord = vec2(gl_MultiTexCoord0);\n"
    104"}",
    105        /* fragment shader */
    106"varying vec4 v_color;\n"
    107"varying vec2 v_texCoord;\n"
    108"uniform sampler2D tex0;\n"
    109"\n"
    110"void main()\n"
    111"{\n"
    112"    gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n"
    113"}"
    114    },
    115
    116    /* SHADER_YUV */
    117    {
    118        /* vertex shader */
    119"varying vec4 v_color;\n"
    120"varying vec2 v_texCoord;\n"
    121"\n"
    122"void main()\n"
    123"{\n"
    124"    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
    125"    v_color = gl_Color;\n"
    126"    v_texCoord = vec2(gl_MultiTexCoord0);\n"
    127"}",
    128        /* fragment shader */
    129"varying vec4 v_color;\n"
    130"varying vec2 v_texCoord;\n"
    131"uniform sampler2D tex0; // Y \n"
    132"uniform sampler2D tex1; // U \n"
    133"uniform sampler2D tex2; // V \n"
    134"\n"
    135"// YUV offset \n"
    136"const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n"
    137"\n"
    138"// RGB coefficients \n"
    139"const vec3 Rcoeff = vec3(1.164,  0.000,  1.596);\n"
    140"const vec3 Gcoeff = vec3(1.164, -0.391, -0.813);\n"
    141"const vec3 Bcoeff = vec3(1.164,  2.018,  0.000);\n"
    142"\n"
    143"void main()\n"
    144"{\n"
    145"    vec2 tcoord;\n"
    146"    vec3 yuv, rgb;\n"
    147"\n"
    148"    // Get the Y value \n"
    149"    tcoord = v_texCoord;\n"
    150"    yuv.x = texture2D(tex0, tcoord).r;\n"
    151"\n"
    152"    // Get the U and V values \n"
    153"    tcoord *= UVCoordScale;\n"
    154"    yuv.y = texture2D(tex1, tcoord).r;\n"
    155"    yuv.z = texture2D(tex2, tcoord).r;\n"
    156"\n"
    157"    // Do the color transform \n"
    158"    yuv += offset;\n"
    159"    rgb.r = dot(yuv, Rcoeff);\n"
    160"    rgb.g = dot(yuv, Gcoeff);\n"
    161"    rgb.b = dot(yuv, Bcoeff);\n"
    162"\n"
    163"    // That was easy. :) \n"
    164"    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
    165"}"
    166    },
    167
    168    /* SHADER_NV12 */
    169    {
    170        /* vertex shader */
    171"varying vec4 v_color;\n"
    172"varying vec2 v_texCoord;\n"
    173"\n"
    174"void main()\n"
    175"{\n"
    176"    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
    177"    v_color = gl_Color;\n"
    178"    v_texCoord = vec2(gl_MultiTexCoord0);\n"
    179"}",
    180        /* fragment shader */
    181"varying vec4 v_color;\n"
    182"varying vec2 v_texCoord;\n"
    183"uniform sampler2D tex0; // Y \n"
    184"uniform sampler2D tex1; // U/V \n"
    185"\n"
    186"// YUV offset \n"
    187"const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n"
    188"\n"
    189"// RGB coefficients \n"
    190"const vec3 Rcoeff = vec3(1.164,  0.000,  1.596);\n"
    191"const vec3 Gcoeff = vec3(1.164, -0.391, -0.813);\n"
    192"const vec3 Bcoeff = vec3(1.164,  2.018,  0.000);\n"
    193"\n"
    194"void main()\n"
    195"{\n"
    196"    vec2 tcoord;\n"
    197"    vec3 yuv, rgb;\n"
    198"\n"
    199"    // Get the Y value \n"
    200"    tcoord = v_texCoord;\n"
    201"    yuv.x = texture2D(tex0, tcoord).r;\n"
    202"\n"
    203"    // Get the U and V values \n"
    204"    tcoord *= UVCoordScale;\n"
    205"    yuv.yz = texture2D(tex1, tcoord).ra;\n"
    206"\n"
    207"    // Do the color transform \n"
    208"    yuv += offset;\n"
    209"    rgb.r = dot(yuv, Rcoeff);\n"
    210"    rgb.g = dot(yuv, Gcoeff);\n"
    211"    rgb.b = dot(yuv, Bcoeff);\n"
    212"\n"
    213"    // That was easy. :) \n"
    214"    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
    215"}"
    216    },
    217
    218    /* SHADER_NV21 */
    219    {
    220        /* vertex shader */
    221"varying vec4 v_color;\n"
    222"varying vec2 v_texCoord;\n"
    223"\n"
    224"void main()\n"
    225"{\n"
    226"    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
    227"    v_color = gl_Color;\n"
    228"    v_texCoord = vec2(gl_MultiTexCoord0);\n"
    229"}",
    230        /* fragment shader */
    231"varying vec4 v_color;\n"
    232"varying vec2 v_texCoord;\n"
    233"uniform sampler2D tex0; // Y \n"
    234"uniform sampler2D tex1; // U/V \n"
    235"\n"
    236"// YUV offset \n"
    237"const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n"
    238"\n"
    239"// RGB coefficients \n"
    240"const vec3 Rcoeff = vec3(1.164,  0.000,  1.596);\n"
    241"const vec3 Gcoeff = vec3(1.164, -0.391, -0.813);\n"
    242"const vec3 Bcoeff = vec3(1.164,  2.018,  0.000);\n"
    243"\n"
    244"void main()\n"
    245"{\n"
    246"    vec2 tcoord;\n"
    247"    vec3 yuv, rgb;\n"
    248"\n"
    249"    // Get the Y value \n"
    250"    tcoord = v_texCoord;\n"
    251"    yuv.x = texture2D(tex0, tcoord).r;\n"
    252"\n"
    253"    // Get the U and V values \n"
    254"    tcoord *= UVCoordScale;\n"
    255"    yuv.yz = texture2D(tex1, tcoord).ar;\n"
    256"\n"
    257"    // Do the color transform \n"
    258"    yuv += offset;\n"
    259"    rgb.r = dot(yuv, Rcoeff);\n"
    260"    rgb.g = dot(yuv, Gcoeff);\n"
    261"    rgb.b = dot(yuv, Bcoeff);\n"
    262"\n"
    263"    // That was easy. :) \n"
    264"    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
    265"}"
    266    },
    267};
    268
    269static SDL_bool
    270CompileShader(GL_ShaderContext *ctx, GLhandleARB shader, const char *defines, const char *source)
    271{
    272    GLint status;
    273    const char *sources[2];
    274
    275    sources[0] = defines;
    276    sources[1] = source;
    277
    278    ctx->glShaderSourceARB(shader, SDL_arraysize(sources), sources, NULL);
    279    ctx->glCompileShaderARB(shader);
    280    ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
    281    if (status == 0) {
    282        GLint length;
    283        char *info;
    284
    285        ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
    286        info = SDL_stack_alloc(char, length+1);
    287        ctx->glGetInfoLogARB(shader, length, NULL, info);
    288        SDL_LogError(SDL_LOG_CATEGORY_RENDER,
    289            "Failed to compile shader:\n%s%s\n%s", defines, source, info);
    290#ifdef DEBUG_SHADERS
    291        fprintf(stderr,
    292            "Failed to compile shader:\n%s%s\n%s", defines, source, info);
    293#endif
    294        SDL_stack_free(info);
    295
    296        return SDL_FALSE;
    297    } else {
    298        return SDL_TRUE;
    299    }
    300}
    301
    302static SDL_bool
    303CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data)
    304{
    305    const int num_tmus_bound = 4;
    306    const char *vert_defines = "";
    307    const char *frag_defines = "";
    308    int i;
    309    GLint location;
    310
    311    if (index == SHADER_NONE) {
    312        return SDL_TRUE;
    313    }
    314
    315    ctx->glGetError();
    316
    317    /* Make sure we use the correct sampler type for our texture type */
    318    if (ctx->GL_ARB_texture_rectangle_supported) {
    319        frag_defines =
    320"#define sampler2D sampler2DRect\n"
    321"#define texture2D texture2DRect\n"
    322"#define UVCoordScale 0.5\n";
    323    } else {
    324        frag_defines = 
    325"#define UVCoordScale 1.0\n";
    326    }
    327
    328    /* Create one program object to rule them all */
    329    data->program = ctx->glCreateProgramObjectARB();
    330
    331    /* Create the vertex shader */
    332    data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
    333    if (!CompileShader(ctx, data->vert_shader, vert_defines, shader_source[index][0])) {
    334        return SDL_FALSE;
    335    }
    336
    337    /* Create the fragment shader */
    338    data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
    339    if (!CompileShader(ctx, data->frag_shader, frag_defines, shader_source[index][1])) {
    340        return SDL_FALSE;
    341    }
    342
    343    /* ... and in the darkness bind them */
    344    ctx->glAttachObjectARB(data->program, data->vert_shader);
    345    ctx->glAttachObjectARB(data->program, data->frag_shader);
    346    ctx->glLinkProgramARB(data->program);
    347
    348    /* Set up some uniform variables */
    349    ctx->glUseProgramObjectARB(data->program);
    350    for (i = 0; i < num_tmus_bound; ++i) {
    351        char tex_name[10];
    352        SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);
    353        location = ctx->glGetUniformLocationARB(data->program, tex_name);
    354        if (location >= 0) {
    355            ctx->glUniform1iARB(location, i);
    356        }
    357    }
    358    ctx->glUseProgramObjectARB(0);
    359
    360    return (ctx->glGetError() == GL_NO_ERROR);
    361}
    362
    363static void
    364DestroyShaderProgram(GL_ShaderContext *ctx, GL_ShaderData *data)
    365{
    366    ctx->glDeleteObjectARB(data->vert_shader);
    367    ctx->glDeleteObjectARB(data->frag_shader);
    368    ctx->glDeleteObjectARB(data->program);
    369}
    370
    371GL_ShaderContext *
    372GL_CreateShaderContext()
    373{
    374    GL_ShaderContext *ctx;
    375    SDL_bool shaders_supported;
    376    int i;
    377
    378    ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx));
    379    if (!ctx) {
    380        return NULL;
    381    }
    382
    383    if (!SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two") &&
    384        (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
    385         SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle"))) {
    386        ctx->GL_ARB_texture_rectangle_supported = SDL_TRUE;
    387    }
    388
    389    /* Check for shader support */
    390    shaders_supported = SDL_FALSE;
    391    if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") &&
    392        SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&
    393        SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&
    394        SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) {
    395        ctx->glGetError = (GLenum (*)(void)) SDL_GL_GetProcAddress("glGetError");
    396        ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
    397        ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
    398        ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
    399        ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
    400        ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
    401        ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
    402        ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
    403        ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
    404        ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
    405        ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
    406        ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
    407        ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB");
    408        ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");
    409        if (ctx->glGetError &&
    410            ctx->glAttachObjectARB &&
    411            ctx->glCompileShaderARB &&
    412            ctx->glCreateProgramObjectARB &&
    413            ctx->glCreateShaderObjectARB &&
    414            ctx->glDeleteObjectARB &&
    415            ctx->glGetInfoLogARB &&
    416            ctx->glGetObjectParameterivARB &&
    417            ctx->glGetUniformLocationARB &&
    418            ctx->glLinkProgramARB &&
    419            ctx->glShaderSourceARB &&
    420            ctx->glUniform1iARB &&
    421            ctx->glUniform1fARB &&
    422            ctx->glUseProgramObjectARB) {
    423            shaders_supported = SDL_TRUE;
    424        }
    425    }
    426
    427    if (!shaders_supported) {
    428        SDL_free(ctx);
    429        return NULL;
    430    }
    431
    432    /* Compile all the shaders */
    433    for (i = 0; i < NUM_SHADERS; ++i) {
    434        if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) {
    435            GL_DestroyShaderContext(ctx);
    436            return NULL;
    437        }
    438    }
    439
    440    /* We're done! */
    441    return ctx;
    442}
    443
    444void
    445GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader)
    446{
    447    ctx->glUseProgramObjectARB(ctx->shaders[shader].program);
    448}
    449
    450void
    451GL_DestroyShaderContext(GL_ShaderContext *ctx)
    452{
    453    int i;
    454
    455    for (i = 0; i < NUM_SHADERS; ++i) {
    456        DestroyShaderProgram(ctx, &ctx->shaders[i]);
    457    }
    458    SDL_free(ctx);
    459}
    460
    461#endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
    462
    463/* vi: set ts=4 sw=4 expandtab: */