diff options
author | Ian Romanick <idr@freedesktop.org> | 2010-07-18 17:20:18 -0700 |
---|---|---|
committer | Ian Romanick <idr@freedesktop.org> | 2010-07-18 17:20:18 -0700 |
commit | 4f57c041039e897a3183aa13943f2bac67c937ea (patch) | |
tree | f42ef8793bb87bd4aa44faa44b84ba262138daaf | |
parent | 9a48bdd102c7cc51a8049e5df86c8e538d0f1d13 (diff) |
Add initial version of shading language helper functionsshader_helper
-rw-r--r-- | include/glu3.h | 109 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/shader.c | 261 |
3 files changed, 371 insertions, 1 deletions
diff --git a/include/glu3.h b/include/glu3.h index 98688d3..f93de5f 100644 --- a/include/glu3.h +++ b/include/glu3.h @@ -37,6 +37,8 @@ #include <GL/gl.h> #include <GL/glext.h> +#include <stdbool.h> + #define GLU3_VERSION_0_1 struct GLUmat4; @@ -1219,6 +1221,113 @@ inline GLUmat4 GLUarcball::drag(unsigned end_x, unsigned end_y) } #endif /* __cplusplus */ +#if defined(__cplusplus) +extern "C" { +#endif +/** + * \name Shading language helper functions + */ +/*@{*/ +/** + * Initialize the GLSL compiler infrastructure + * + * This function \b must be called before any of the GLU3 GLSL helper functions + * can be used. On Windows, this function must be called each time a context + * with a different color depth is made current. + * + * It is the responsibility of the caller to verify that the required version + * of GLSL and the required shader targets (e.g., geometry) are supported. + * + * \return + * If GLSL is available, \c true is returned. Otherwise \c false is returned. + */ +extern bool gluInitializeCompiler(void); + +/** + * Compile a shader + * + * Creates a new shader object for the specified target and compiles the + * supplied code into that shader object. If \c log_ptr is not \c NULL, a + * buffer will be allocated and filled with diagnostic messages from the + * shading language compiler. A pointer to this buffer will stored in + * \c log_ptr. + * + * The pointer stored in \c log_ptr must be later released with + * \c gluReleaseInfoLog. + * + * \param target Shader execution unit (e.g., \c GL_VERTEX_SHADER) + * \param code Shader source code + * \param log_ptr Location to store a pointer to the compiler generate info log + * + * \return + * If compilation was successful, the shader object is returned. On failure + * zero is returned. + * + * \sa gluReleaseInfoLog + */ +extern GLint gluCompileShader(GLenum target, const char *code, char **log_ptr); + +/** + * Link a shader program + * + * Links the specified shader program. If \c log_ptr is not \c NULL, a buffer + * will be allocated and filled with diagnostic messages from the shading + * language linker. A pointer to this buffer will stored in \c log_ptr. + * + * The pointer stored in \c log_ptr must be later released with + * \c gluReleaseInfoLog. + * + * \param prog Shading language program to be linked + * \param log_ptr Location to store a pointer to the compiler generate info log + * + * \return + * If linking was successful, \c true is returned. Otherwise \c false is + * returned. + * + * \sa gluReleaseInfoLog + */ +extern bool gluLinkProgram(GLuint prog, char **log_ptr); + +/** + * Attach a list of shader objects to a program + * + * Attaches a zero-terminated list of shader objects to a program object. + * + * \param prog Shading language program to which shaders will be attached + * \param shader First shader to be attached to the program + */ +extern void gluAttachShaders(GLuint prog, GLuint shader, ...); + +/** + * Bind a set of shader program attributes to locations + * + * Bind the locations of a set of attributes. The list of attributes is + * terminate by a \c NULL \c name pointer. + * + * \param prog Shading language program whose attribute locations will + * be set + * \param name Name of the first attribute to set + * \param location Location of the first attribute + */ +extern void gluBindAttributes(GLuint prog, const char *name, unsigned location, + ...); + +/** + * Release an info log + * + * Release an info log generated by a call to \c gluLinkProgram or + * \c gluCompileShader. + * + * \param log Info log buffer to be released + * + * \sa gluCompileShader, gluLinkProgram + */ +extern void gluReleaseInfoLog(char *log); +/*@}*/ +#if defined(__cplusplus) +}; +#endif + #include "glu3_scalar.h" #endif /* __glu3_h__ */ diff --git a/src/Makefile.am b/src/Makefile.am index 624d383..790c30d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,7 +25,7 @@ AM_CFLAGS=-I../include lib_LIBRARIES = libGLU3.a libGLU3_a_SOURCES = matrix.c load_text.c arcball.c revolve.c mesh.c \ - sphere.cpp cube.cpp + sphere.cpp cube.cpp shader.c libGLU3includedir = ${includedir} libGLU3include_HEADERS = ../include/glu3.h ../include/glu3_scalar.h diff --git a/src/shader.c b/src/shader.c new file mode 100644 index 0000000..8e7f271 --- /dev/null +++ b/src/shader.c @@ -0,0 +1,261 @@ +/* + * Copyright © 2009, 2010 Ian D. Romanick + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "config.h" +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <stdbool.h> + +#define GL_GLEXT_PROTOTYPES +#include <GL/gl.h> +#include <GL/glext.h> + +#if defined(HAVE_GLX) +#include <GL/glx.h> +#define GetProcAddress(x) glXGetProcAddress(#x) +#elif defined(HAVE_EGL) +#include <EGL/egl.h> +#define GetProcAddress(x) eglGetProcAddress(#x) +#elif defined(HAVE_WGL) +#include <GL/wgl.h> +#define GetProcAddress(x) wglGetProcAddress(#x) +#else +#define GetProcAddress(x) (x) +#endif + +static PFNGLSHADERSOURCEPROC ShaderSource = NULL; +static PFNGLCREATESHADERPROC CreateShader = NULL; +static PFNGLCOMPILESHADERPROC CompileShader = NULL; +static PFNGLGETSHADERIVPROC GetShaderiv = NULL; +static PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog = NULL; +static PFNGLDELETESHADERPROC DeleteShader = NULL; + +static PFNGLLINKPROGRAMPROC LinkProgram = NULL; +static PFNGLATTACHSHADERPROC AttachShader = NULL; +static PFNGLBINDATTRIBLOCATIONPROC BindAttribLocation = NULL; +static PFNGLGETPROGRAMIVPROC GetProgramiv = NULL; +static PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog = NULL; + +bool +gluInitializeCompiler(void) +{ + /* Determine which set of interfaces are available for accessing GLSL. + * This will either be from OpenGL 2.0+ (or OpenGL ES 2.0) or from + * GL_ARB_shader_objects. + */ + const char *const version_string = glGetString(GL_VERSION); + float version = strtof(version_string, NULL); + + if (version >= 2.0f) { + ShaderSource = (PFNGLSHADERSOURCEPROC) + GetProcAddress(glShaderSource); + CreateShader = (PFNGLCREATESHADERPROC) + GetProcAddress(glCreateShader); + CompileShader = (PFNGLCOMPILESHADERPROC) + GetProcAddress(glCompileShader); + GetShaderiv = (PFNGLGETSHADERIVPROC) + GetProcAddress(glGetShaderiv); + GetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) + GetProcAddress(glGetShaderInfoLog); + DeleteShader = (PFNGLDELETESHADERPROC) + GetProcAddress(glDeleteShader); + + LinkProgram = (PFNGLLINKPROGRAMPROC) + GetProcAddress(glLinkProgram); + AttachShader = (PFNGLATTACHSHADERPROC) + GetProcAddress(glAttachShader); + BindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) + GetProcAddress(glBindAttribLocation); + GetProgramiv = (PFNGLGETPROGRAMIVPROC) + GetProcAddress(glGetProgramiv); + GetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) + GetProcAddress(glGetProgramInfoLog); + } else { + const char *const extension_string = glGetString(GL_EXTENSIONS); + const unsigned len = strlen("GL_ARB_shader_objects"); + const char *x; + + x = extension_string; + while ((x = strstr(x, "GL_ARB_shader_objects")) != NULL) { + if (x[len] == ' ' || x[len] == '\0') + break; + + x += len; + } + + if (strcmp(x, "GL_ARB_shader_objects") != 0) + return false; + + ShaderSource = (PFNGLSHADERSOURCEPROC) + GetProcAddress(glShaderSourceARB); + CreateShader = (PFNGLCREATESHADERPROC) + GetProcAddress(glCreateShaderARB); + CompileShader = (PFNGLCOMPILESHADERPROC) + GetProcAddress(glCompileShaderARB); + DeleteShader = (PFNGLDELETESHADERPROC) + GetProcAddress(glDeleteShaderARB); + + LinkProgram = (PFNGLLINKPROGRAMPROC) + GetProcAddress(glLinkProgramARB); + AttachShader = (PFNGLATTACHSHADERPROC) + GetProcAddress(glAttachShaderARB); + BindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) + GetProcAddress(glBindAttribLocationARB); + + + /* These functions break the mold a little bit. Here the API + * changed between the extension and core GL. For the uses + * internal to this library, we can work around the change by + * using glGetObjectParameterivARB for both glGetShaderiv and + * glGetProgramiv. Likewise glGetInfoLogARB can be used for + * both glGetShaderInfoLog and glGetProgramInfoLog. + */ + GetShaderiv = (PFNGLGETSHADERIVPROC) + GetProcAddress(glGetObjectParameterivARB); + GetProgramiv = (PFNGLGETPROGRAMIVPROC) GetShaderiv; + + GetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) + GetProcAddress(glGetInfoLogARB); + GetProgramInfoLog = (PFNGLGETSHADERIVPROC) GetShaderInfoLog; + } +} + + +void +gluReleaseInfoLog(char *log) +{ + free(log); +} + + +GLint +gluCompileShader(GLenum target, const char *code, char **log_ptr) +{ + GLint status; + GLuint shad = CreateShader(target); + + ShaderSource(shad, 1, &code, NULL); + CompileShader(shad); + + if (log_ptr != NULL) { + GLint len; + + /* The spec says that 0 is returned when no log is available. + * However, Nvidia's drivers like to return a log length of 1, + * and return a log that is just a NUL terminator. + */ + GetShaderiv(shad, GL_INFO_LOG_LENGTH, &len); + if (len > 1) { + char *log = (char *) malloc(len + 1); + + if (log != NULL) { + GetShaderInfoLog(shad, len + 1, NULL, log); + *log_ptr = log; + } + } + } + + GetShaderiv(shad, GL_COMPILE_STATUS, &status); + if (!status) { + DeleteShader(shad); + return 0; + } + + return shad; +} + + +bool +gluLinkProgram(GLuint prog, char **log_ptr) +{ + GLint status; + + LinkProgram(prog); + + if (log_ptr != NULL) { + GLint len; + + /* The spec says that 0 is returned when no log is available. + * However, Nvidia's drivers like to return a log length of 1, + * and return a log that is just a NUL terminator. + */ + GetProgramiv(prog, GL_INFO_LOG_LENGTH, &len); + if (len > 1) { + char *log = (char *) malloc(len + 1); + + if (log != NULL) { + GetProgramInfoLog(prog, len + 1, NULL, log); + *log_ptr = log; + } + } + } + + GetProgramiv(prog, GL_LINK_STATUS, &status); + return status == GL_TRUE; +} + + +void +gluAttachShaders(GLuint prog, GLuint shader, ...) +{ + va_list args; + + AttachShader(prog, shader); + + va_start(args, prog); + + while (true) { + GLuint s = va_arg(args, GLuint); + + if (s == 0) + break; + + AttachShader(prog, s); + } + + va_end(args); +} + + +void +gluBindAttributes(GLuint prog, const char *name, GLuint location, ...) +{ + va_list args; + + BindAttribLocation(prog, location, name); + + va_start(args, prog); + + while (true) { + const char *name = va_arg(args, char *); + GLuint idx; + + if (name == NULL) + break; + + idx = va_arg(args, unsigned); + BindAttribLocation(prog, idx, name); + } + + va_end(args); +} |