src/render/opengl/SDL_shaders_gl.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 08 Feb 2011 16:50:51 -0800
changeset 5229 c015d3e63631
parent 5228 811beeb698f9
child 5230 8efa43b915be
permissions -rw-r--r--
Fixed setting the texture unit, still doesn't work.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED
    25 
    26 #include "SDL_stdinc.h"
    27 #include "SDL_log.h"
    28 #include "SDL_opengl.h"
    29 #include "SDL_video.h"
    30 #include "SDL_shaders_gl.h"
    31 
    32 /* OpenGL shader implementation */
    33 
    34 typedef struct
    35 {
    36     GLenum program;
    37     GLenum vert_shader;
    38     GLenum frag_shader;
    39 } GL_ShaderData;
    40 
    41 struct GL_ShaderContext
    42 {
    43     GLenum (*glGetError)(void);
    44 
    45     PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
    46     PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
    47     PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
    48     PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
    49     PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
    50     PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
    51     PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
    52     PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
    53     PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
    54     PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
    55     PFNGLUNIFORM1IARBPROC glUniform1iARB;
    56     PFNGLUNIFORM1FARBPROC glUniform1fARB;
    57     PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
    58 
    59     GL_Shader current_shader;
    60     GL_ShaderData shaders[NUM_SHADERS];
    61 };
    62 
    63 static const char *shader_source[NUM_SHADERS][2] =
    64 {
    65     /* SHADER_NONE */
    66     { NULL, NULL },
    67 
    68     /* SHADER_SOLID */
    69     {
    70         /* vertex shader */
    71         " \
    72 varying vec4 v_color; \
    73  \
    74 void main() \
    75 { \
    76     gl_Position = ftransform(); \
    77     v_color = gl_Color; \
    78 } \
    79 ",
    80         /* fragment shader */
    81         " \
    82 varying vec4 v_color; \
    83  \
    84 void main() \
    85 { \
    86     gl_FragColor = v_color; \
    87 } \
    88 "
    89     },
    90 
    91     /* SHADER_RGB */
    92     {
    93         /* vertex shader */
    94         " \
    95 varying vec4 v_color; \
    96 varying vec2 v_texCoord; \
    97  \
    98 void main() \
    99 { \
   100     gl_Position = ftransform(); \
   101     v_color = gl_Color; \
   102     v_texCoord = vec2(gl_MultiTexCoord0); \
   103 } \
   104 ",
   105         /* fragment shader */
   106         " \
   107 varying vec4 v_color; \
   108 varying vec2 v_texCoord; \
   109 uniform sampler2D tex0; \
   110  \
   111 void main() \
   112 { \
   113     gl_FragColor = texture2D(tex0, v_texCoord) * v_color; \
   114 } \
   115 "
   116     },
   117 };
   118 
   119 static SDL_bool
   120 CompileShader(GL_ShaderContext *ctx, GLenum shader, const char *source)
   121 {
   122     GLint status;
   123 
   124     ctx->glShaderSourceARB(shader, 1, &source, NULL);
   125     ctx->glCompileShaderARB(shader);
   126     ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
   127     if (status == 0) {
   128         GLint length;
   129         char *info;
   130 
   131         ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
   132         info = SDL_stack_alloc(char, length+1);
   133         ctx->glGetInfoLogARB(shader, length, NULL, info);
   134         SDL_LogError(SDL_LOG_CATEGORY_RENDER,
   135             "Failed to compile shader:\n%s\n%s", source, info);
   136 fprintf(stderr, "Failed to compile shader:\n%s\n%s", source, info);
   137         SDL_stack_free(info);
   138 
   139         return SDL_FALSE;
   140     } else {
   141         return SDL_TRUE;
   142     }
   143 }
   144 
   145 static SDL_bool
   146 CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data)
   147 {
   148     const int num_tmus_bound = 4;
   149     GLint status;
   150     int i;
   151     GLint location;
   152 
   153     if (index == SHADER_NONE) {
   154         return SDL_TRUE;
   155     }
   156 
   157     ctx->glGetError();
   158 
   159     /* Create one program object to rule them all */
   160     data->program = ctx->glCreateProgramObjectARB();
   161 
   162     /* Create the vertex shader */
   163     data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
   164     if (!CompileShader(ctx, data->vert_shader, shader_source[index][0])) {
   165         return SDL_FALSE;
   166     }
   167 
   168     /* Create the fragment shader */
   169     data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
   170     if (!CompileShader(ctx, data->frag_shader, shader_source[index][1])) {
   171         return SDL_FALSE;
   172     }
   173 
   174     /* ... and in the darkness bind them */
   175     ctx->glAttachObjectARB(data->program, data->vert_shader);
   176     ctx->glAttachObjectARB(data->program, data->frag_shader);
   177     ctx->glLinkProgramARB(data->program);
   178 
   179     /* Set up some uniform variables */
   180     ctx->glUseProgramObjectARB(data->program);
   181     for (i = 0; i < num_tmus_bound; ++i) {
   182         char tex_name[5];
   183         SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);
   184         location = ctx->glGetUniformLocationARB(data->program, tex_name);
   185         if (location >= 0) {
   186             ctx->glUniform1iARB(location, i);
   187         }
   188     }
   189     ctx->glUseProgramObjectARB(0);
   190     
   191     return (ctx->glGetError() == GL_NO_ERROR);
   192 }
   193 
   194 static void
   195 DestroyShaderProgram(GL_ShaderContext *ctx, GL_ShaderData *data)
   196 {
   197     if (index == SHADER_NONE) {
   198         return;
   199     }
   200 
   201     ctx->glDeleteObjectARB(data->vert_shader);
   202     ctx->glDeleteObjectARB(data->frag_shader);
   203     ctx->glDeleteObjectARB(data->program);
   204 }
   205 
   206 GL_ShaderContext *
   207 GL_CreateShaderContext()
   208 {
   209     GL_ShaderContext *ctx;
   210     SDL_bool shaders_supported;
   211     int i;
   212 
   213     ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx));
   214     if (!ctx) {
   215         return NULL;
   216     }
   217 
   218     /* Check for shader support */
   219     shaders_supported = SDL_FALSE;
   220     if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") &&
   221         SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&
   222         SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&
   223         SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) {
   224         ctx->glGetError = (GLenum (*)(void)) SDL_GL_GetProcAddress("glGetError");
   225         ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
   226         ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
   227         ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
   228         ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
   229         ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
   230         ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
   231         ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
   232         ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
   233         ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
   234         ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
   235         ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
   236         ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB");
   237         ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");
   238         if (ctx->glGetError &&
   239             ctx->glAttachObjectARB &&
   240             ctx->glCompileShaderARB &&
   241             ctx->glCreateProgramObjectARB &&
   242             ctx->glCreateShaderObjectARB &&
   243             ctx->glDeleteObjectARB &&
   244             ctx->glGetInfoLogARB &&
   245             ctx->glGetObjectParameterivARB &&
   246             ctx->glGetUniformLocationARB &&
   247             ctx->glLinkProgramARB &&
   248             ctx->glShaderSourceARB &&
   249             ctx->glUniform1iARB &&
   250             ctx->glUniform1fARB &&
   251             ctx->glUseProgramObjectARB) {
   252             shaders_supported = SDL_TRUE;
   253         }
   254     }
   255 
   256     if (!shaders_supported) {
   257         GL_DestroyShaderContext(ctx);
   258         return NULL;
   259     }
   260 
   261     /* Compile all the shaders */
   262     for (i = 0; i < NUM_SHADERS; ++i) {
   263         if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) {
   264 fprintf(stderr, "Unable to compile shader!\n");
   265             GL_DestroyShaderContext(ctx);
   266             return NULL;
   267         }
   268     }
   269 
   270     /* We're done! */
   271     return ctx;
   272 }
   273 
   274 void
   275 GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader)
   276 {
   277     /* Nothing to do if there's no shader support */
   278     if (!ctx) {
   279         return;
   280     }
   281 
   282     /* Nothing to do if there's no shader change */
   283     if (shader == ctx->current_shader) {
   284         return;
   285     }
   286 
   287     ctx->glUseProgramObjectARB(ctx->shaders[shader].program);
   288     ctx->current_shader = shader;
   289 }
   290 
   291 void
   292 GL_DestroyShaderContext(GL_ShaderContext *ctx)
   293 {
   294     int i;
   295 
   296     for (i = 0; i < NUM_SHADERS; ++i) {
   297         DestroyShaderProgram(ctx, &ctx->shaders[i]);
   298     }
   299     SDL_free(ctx);
   300 }
   301 
   302 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
   303 
   304 /* vi: set ts=4 sw=4 expandtab: */