This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Beginning of a framework for OpenGL shaders
- Loading branch information
Showing
3 changed files
with
377 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,304 @@ | ||
/* | ||
SDL - Simple DirectMedia Layer | ||
Copyright (C) 1997-2010 Sam Lantinga | ||
This library is free software; you can redistribute it and/or | ||
modify it under the terms of the GNU Lesser General Public | ||
License as published by the Free Software Foundation; either | ||
version 2.1 of the License, or (at your option) any later version. | ||
This library is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
Lesser General Public License for more details. | ||
You should have received a copy of the GNU Lesser General Public | ||
License along with this library; if not, write to the Free Software | ||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
Sam Lantinga | ||
slouken@libsdl.org | ||
*/ | ||
#include "SDL_config.h" | ||
|
||
#if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED | ||
|
||
#include "SDL_stdinc.h" | ||
#include "SDL_log.h" | ||
#include "SDL_opengl.h" | ||
#include "SDL_video.h" | ||
#include "SDL_shaders_gl.h" | ||
|
||
/* OpenGL shader implementation */ | ||
|
||
typedef struct | ||
{ | ||
GLenum program; | ||
GLenum vert_shader; | ||
GLenum frag_shader; | ||
} GL_ShaderData; | ||
|
||
struct GL_ShaderContext | ||
{ | ||
GLenum (*glGetError)(void); | ||
|
||
PFNGLATTACHOBJECTARBPROC glAttachObjectARB; | ||
PFNGLCOMPILESHADERARBPROC glCompileShaderARB; | ||
PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB; | ||
PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB; | ||
PFNGLDELETEOBJECTARBPROC glDeleteObjectARB; | ||
PFNGLGETINFOLOGARBPROC glGetInfoLogARB; | ||
PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; | ||
PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB; | ||
PFNGLLINKPROGRAMARBPROC glLinkProgramARB; | ||
PFNGLSHADERSOURCEARBPROC glShaderSourceARB; | ||
PFNGLUNIFORM1IARBPROC glUniform1iARB; | ||
PFNGLUNIFORM1FARBPROC glUniform1fARB; | ||
PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; | ||
|
||
GL_Shader current_shader; | ||
GL_ShaderData shaders[NUM_SHADERS]; | ||
}; | ||
|
||
static const char *shader_source[NUM_SHADERS][2] = | ||
{ | ||
/* SHADER_NONE */ | ||
{ NULL, NULL }, | ||
|
||
/* SHADER_SOLID */ | ||
{ | ||
/* vertex shader */ | ||
" \ | ||
varying vec4 v_color; \ | ||
\ | ||
void main() \ | ||
{ \ | ||
gl_Position = ftransform(); \ | ||
v_color = gl_Color; \ | ||
} \ | ||
", | ||
/* fragment shader */ | ||
" \ | ||
varying vec4 v_color; \ | ||
\ | ||
void main() \ | ||
{ \ | ||
gl_FragColor = v_color; \ | ||
} \ | ||
" | ||
}, | ||
|
||
/* SHADER_RGB */ | ||
{ | ||
/* vertex shader */ | ||
" \ | ||
varying vec4 v_color; \ | ||
varying vec2 v_texCoord; \ | ||
\ | ||
void main() \ | ||
{ \ | ||
gl_Position = ftransform(); \ | ||
v_color = gl_Color; \ | ||
v_texCoord = vec2(gl_MultiTexCoord0); \ | ||
} \ | ||
", | ||
/* fragment shader */ | ||
" \ | ||
varying vec4 v_color; \ | ||
varying vec2 v_texCoord; \ | ||
uniform sampler2D tex0; \ | ||
\ | ||
void main() \ | ||
{ \ | ||
gl_FragColor = texture2D(tex0, v_texCoord) * v_color; \ | ||
} \ | ||
" | ||
}, | ||
}; | ||
|
||
static SDL_bool | ||
CompileShader(GL_ShaderContext *ctx, GLenum shader, const char *source) | ||
{ | ||
GLint status; | ||
|
||
ctx->glShaderSourceARB(shader, 1, &source, NULL); | ||
ctx->glCompileShaderARB(shader); | ||
ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status); | ||
if (status == 0) { | ||
GLint length; | ||
char *info; | ||
|
||
ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); | ||
info = SDL_stack_alloc(char, length+1); | ||
ctx->glGetInfoLogARB(shader, length, NULL, info); | ||
SDL_LogError(SDL_LOG_CATEGORY_RENDER, | ||
"Failed to compile shader:\n%s\n%s", source, info); | ||
fprintf(stderr, "Failed to compile shader:\n%s\n%s", source, info); | ||
SDL_stack_free(info); | ||
|
||
return SDL_FALSE; | ||
} else { | ||
return SDL_TRUE; | ||
} | ||
} | ||
|
||
static SDL_bool | ||
CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data) | ||
{ | ||
const int num_tmus_bound = 4; | ||
GLint status; | ||
int i; | ||
GLint location; | ||
|
||
if (index == SHADER_NONE) { | ||
return SDL_TRUE; | ||
} | ||
|
||
ctx->glGetError(); | ||
|
||
/* Create one program object to rule them all */ | ||
data->program = ctx->glCreateProgramObjectARB(); | ||
|
||
/* Create the vertex shader */ | ||
data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); | ||
if (!CompileShader(ctx, data->vert_shader, shader_source[index][0])) { | ||
return SDL_FALSE; | ||
} | ||
|
||
/* Create the fragment shader */ | ||
data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); | ||
if (!CompileShader(ctx, data->frag_shader, shader_source[index][1])) { | ||
return SDL_FALSE; | ||
} | ||
|
||
/* ... and in the darkness bind them */ | ||
ctx->glAttachObjectARB(data->program, data->vert_shader); | ||
ctx->glAttachObjectARB(data->program, data->frag_shader); | ||
ctx->glLinkProgramARB(data->program); | ||
|
||
/* Set up some uniform variables */ | ||
ctx->glUseProgramObjectARB(data->program); | ||
for (i = 0; i < num_tmus_bound; ++i) { | ||
char tex_name[5]; | ||
SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i); | ||
location = ctx->glGetUniformLocationARB(data->program, tex_name); | ||
if (location >= 0) { | ||
ctx->glUniform1iARB(location, 1); | ||
} | ||
} | ||
ctx->glUseProgramObjectARB(0); | ||
|
||
return (ctx->glGetError() == GL_NO_ERROR); | ||
} | ||
|
||
static void | ||
DestroyShaderProgram(GL_ShaderContext *ctx, GL_ShaderData *data) | ||
{ | ||
if (index == SHADER_NONE) { | ||
return; | ||
} | ||
|
||
ctx->glDeleteObjectARB(data->vert_shader); | ||
ctx->glDeleteObjectARB(data->frag_shader); | ||
ctx->glDeleteObjectARB(data->program); | ||
} | ||
|
||
GL_ShaderContext * | ||
GL_CreateShaderContext() | ||
{ | ||
GL_ShaderContext *ctx; | ||
SDL_bool shaders_supported; | ||
int i; | ||
|
||
ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx)); | ||
if (!ctx) { | ||
return NULL; | ||
} | ||
|
||
/* Check for shader support */ | ||
shaders_supported = SDL_FALSE; | ||
if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") && | ||
SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") && | ||
SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") && | ||
SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) { | ||
ctx->glGetError = (GLenum (*)(void)) SDL_GL_GetProcAddress("glGetError"); | ||
ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB"); | ||
ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB"); | ||
ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB"); | ||
ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB"); | ||
ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB"); | ||
ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB"); | ||
ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB"); | ||
ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB"); | ||
ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB"); | ||
ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB"); | ||
ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB"); | ||
ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB"); | ||
ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB"); | ||
if (ctx->glGetError && | ||
ctx->glAttachObjectARB && | ||
ctx->glCompileShaderARB && | ||
ctx->glCreateProgramObjectARB && | ||
ctx->glCreateShaderObjectARB && | ||
ctx->glDeleteObjectARB && | ||
ctx->glGetInfoLogARB && | ||
ctx->glGetObjectParameterivARB && | ||
ctx->glGetUniformLocationARB && | ||
ctx->glLinkProgramARB && | ||
ctx->glShaderSourceARB && | ||
ctx->glUniform1iARB && | ||
ctx->glUniform1fARB && | ||
ctx->glUseProgramObjectARB) { | ||
shaders_supported = SDL_TRUE; | ||
} | ||
} | ||
|
||
if (!shaders_supported) { | ||
GL_DestroyShaderContext(ctx); | ||
return NULL; | ||
} | ||
|
||
/* Compile all the shaders */ | ||
for (i = 0; i < NUM_SHADERS; ++i) { | ||
if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) { | ||
fprintf(stderr, "Unable to compile shader!\n"); | ||
GL_DestroyShaderContext(ctx); | ||
return NULL; | ||
} | ||
} | ||
|
||
/* We're done! */ | ||
return ctx; | ||
} | ||
|
||
void | ||
GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader) | ||
{ | ||
/* Nothing to do if there's no shader support */ | ||
if (!ctx) { | ||
return; | ||
} | ||
|
||
/* Nothing to do if there's no shader change */ | ||
if (shader == ctx->current_shader) { | ||
return; | ||
} | ||
|
||
ctx->glUseProgramObjectARB(ctx->shaders[shader].program); | ||
ctx->current_shader = shader; | ||
} | ||
|
||
void | ||
GL_DestroyShaderContext(GL_ShaderContext *ctx) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < NUM_SHADERS; ++i) { | ||
DestroyShaderProgram(ctx, &ctx->shaders[i]); | ||
} | ||
SDL_free(ctx); | ||
} | ||
|
||
#endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */ | ||
|
||
/* vi: set ts=4 sw=4 expandtab: */ |
Oops, something went wrong.