|
|
// stb_glprog v0.02 public domain functions to reduce GLSL boilerplate
// http://nothings.org/stb/stb_glprog.h especially with GL1 + ARB extensions
//
// Following defines *before* including have following effects:
//
// STB_GLPROG_IMPLEMENTATION
// creates the implementation
//
// STB_GLPROG_STATIC
// forces the implementation to be static (private to file that creates it)
//
// STB_GLPROG_ARB
// uses ARB extension names for GLSL functions and enumerants instead of core names
//
// STB_GLPROG_ARB_DEFINE_EXTENSIONS
// instantiates function pointers needed, static to implementing file
// to avoid collisions (but will collide if implementing file also
// defines any; best to isolate this to its own file in this case).
// This will try to automatically #include glext.h, but if it's not
// in the default include directories you'll need to include it
// yourself and define the next macro.
//
// STB_GLPROG_SUPPRESS_GLEXT_INCLUDE
// disables the automatic #include of glext.h which is normally
// forced by STB_GLPROG_ARB_DEFINE_EXTENSIONS
//
// So, e.g., sample usage on an old Windows compiler:
//
// #define STB_GLPROG_IMPLEMENTATION
// #define STB_GLPROG_ARB_DEFINE_EXTENSIONS
// #include <windows.h>
// #include "gl/gl.h"
// #include "stb_glprog.h"
//
// Note though that the header-file version of this (when you don't define
// STB_GLPROG_IMPLEMENTATION) still uses GLint and such, so you basically
// can only include it in places where you're already including GL, especially
// on Windows where including "gl.h" requires (some of) "windows.h".
//
// See following comment blocks for function documentation.
//
// Version history:
// 2013-12-08 v0.02 slightly simplified API and reduced GL resource usage (@rygorous)
// 2013-12-08 v0.01 initial release
// header file section starts here
#if !defined(INCLUDE_STB_GLPROG_H)
#define INCLUDE_STB_GLPROG_H
#ifndef STB_GLPROG_STATIC
#ifdef __cplusplus
extern "C" { #endif
//////////////////////////////////////////////////////////////////////////////
///////////// SHADER CREATION
/// EASY API
extern GLuint stbgl_create_program(char const **vertex_source, char const **frag_source, char const **binds, char *error, int error_buflen); // This function returns a compiled program or 0 if there's an error.
// To free the created program, call stbgl_delete_program.
//
// stbgl_create_program(
// char **vertex_source, // NULL or one or more strings with the vertex shader source, with a final NULL
// char **frag_source, // NULL or one or more strings with the fragment shader source, with a final NULL
// char **binds, // NULL or zero or more strings with attribute bind names, with a final NULL
// char *error, // output location where compile error message is placed
// int error_buflen) // length of error output buffer
//
// Returns a GLuint with the GL program object handle.
//
// If an individual bind string is "", no name is bound to that slot (this
// allows you to create binds that aren't continuous integers starting at 0).
//
// If the vertex shader is NULL, then fixed-function vertex pipeline
// is used, if that's legal in your version of GL.
//
// If the fragment shader is NULL, then fixed-function fragment pipeline
// is used, if that's legal in your version of GL.
extern void stgbl_delete_program(GLuint program); // deletes a program created by stbgl_create_program or stbgl_link_program
/// FLEXIBLE API
extern GLuint stbgl_compile_shader(GLenum type, char const **sources, int num_sources, char *error, int error_buflen); // compiles a shader. returns the shader on success or 0 on failure.
//
// type either: GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
// or GL_VERTEX_SHADER_ARB or GL_FRAGMENT_SHADER_ARB
// or STBGL_VERTEX_SHADER or STBGL_FRAGMENT_SHADER
// sources array of strings containing the shader source
// num_sources number of string in sources, or -1 meaning sources is NULL-terminated
// error string to output compiler error to
// error_buflen length of error buffer in chars
extern GLuint stbgl_link_program(GLuint vertex_shader, GLuint fragment_shader, char const **binds, int num_binds, char *error, int error_buflen); // links a shader. returns the linked program on success or 0 on failure.
//
// vertex_shader a compiled vertex shader from stbgl_compile_shader, or 0 for fixed-function (if legal)
// fragment_shader a compiled fragment shader from stbgl_compile_shader, or 0 for fixed-function (if legal)
//
extern void stbgl_delete_shader(GLuint shader); // deletes a shader created by stbgl_compile_shader
///////////// RENDERING WITH SHADERS
extern GLint stbgl_find_uniform(GLuint prog, char *uniform);
extern void stbgl_find_uniforms(GLuint prog, GLint *locations, char const **uniforms, int num_uniforms); // Given the locations array that is num_uniforms long, fills out
// the locations of each of those uniforms for the specified program.
// If num_uniforms is -1, then uniforms[] must be NULL-terminated
// the following functions just wrap the difference in naming between GL2+ and ARB,
// so you don't need them unless you're using both ARB and GL2+ in the same codebase,
// or you're relying on this lib to provide the extensions
extern void stbglUseProgram(GLuint program); extern void stbglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer); extern void stbglEnableVertexAttribArray(GLuint index); extern void stbglDisableVertexAttribArray(GLuint index); extern void stbglUniform1fv(GLint loc, GLsizei count, const GLfloat *v); extern void stbglUniform2fv(GLint loc, GLsizei count, const GLfloat *v); extern void stbglUniform3fv(GLint loc, GLsizei count, const GLfloat *v); extern void stbglUniform4fv(GLint loc, GLsizei count, const GLfloat *v); extern void stbglUniform1iv(GLint loc, GLsizei count, const GLint *v); extern void stbglUniform2iv(GLint loc, GLsizei count, const GLint *v); extern void stbglUniform3iv(GLint loc, GLsizei count, const GLint *v); extern void stbglUniform4iv(GLint loc, GLsizei count, const GLint *v); extern void stbglUniform1f(GLint loc, float v0); extern void stbglUniform2f(GLint loc, float v0, float v1); extern void stbglUniform3f(GLint loc, float v0, float v1, float v2); extern void stbglUniform4f(GLint loc, float v0, float v1, float v2, float v3); extern void stbglUniform1i(GLint loc, GLint v0); extern void stbglUniform2i(GLint loc, GLint v0, GLint v1); extern void stbglUniform3i(GLint loc, GLint v0, GLint v1, GLint v2); extern void stbglUniform4i(GLint loc, GLint v0, GLint v1, GLint v2, GLint v3);
////////////// END OF FUNCTIONS
//////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
} #endif
#endif // STB_GLPROG_STATIC
#ifdef STB_GLPROG_ARB
#define STBGL_VERTEX_SHADER GL_VERTEX_SHADER_ARB
#define STBGL_FRAGMENT_SHADER GL_FRAGMENT_SHADER_ARB
#else
#define STBGL_VERTEX_SHADER GL_VERTEX_SHADER
#define STBGL_FRAGMENT_SHADER GL_FRAGMENT_SHADER
#endif
#endif // INCLUDE_STB_GLPROG_H
///////// header file section ends here
#ifdef STB_GLPROG_IMPLEMENTATION
#include <string.h> // strncpy
#ifdef STB_GLPROG_STATIC
#define STB_GLPROG_DECLARE static
#else
#define STB_GLPROG_DECLARE extern
#endif
// check if user wants this file to define the GL extensions itself
#ifdef STB_GLPROG_ARB_DEFINE_EXTENSIONS
#define STB_GLPROG_ARB // make sure later code uses the extensions
#ifndef STB_GLPROG_SUPPRESS_GLEXT_INCLUDE
#include "glext.h"
#endif
#define STB_GLPROG_EXTENSIONS \
STB_GLPROG_FUNC(ATTACHOBJECT , AttachObject ) \ STB_GLPROG_FUNC(BINDATTRIBLOCATION , BindAttribLocation ) \ STB_GLPROG_FUNC(COMPILESHADER , CompileShader ) \ STB_GLPROG_FUNC(CREATEPROGRAMOBJECT , CreateProgramObject ) \ STB_GLPROG_FUNC(CREATESHADEROBJECT , CreateShaderObject ) \ STB_GLPROG_FUNC(DELETEOBJECT , DeleteObject ) \ STB_GLPROG_FUNC(DETACHOBJECT , DetachObject ) \ STB_GLPROG_FUNC(DISABLEVERTEXATTRIBARRAY, DisableVertexAttribArray) \ STB_GLPROG_FUNC(ENABLEVERTEXATTRIBARRAY, EnableVertexAttribArray ) \ STB_GLPROG_FUNC(GETATTACHEDOBJECTS , GetAttachedObjects ) \ STB_GLPROG_FUNC(GETOBJECTPARAMETERIV, GetObjectParameteriv) \ STB_GLPROG_FUNC(GETINFOLOG , GetInfoLog ) \ STB_GLPROG_FUNC(GETUNIFORMLOCATION , GetUniformLocation ) \ STB_GLPROG_FUNC(LINKPROGRAM , LinkProgram ) \ STB_GLPROG_FUNC(SHADERSOURCE , ShaderSource ) \ STB_GLPROG_FUNC(UNIFORM1F , Uniform1f ) \ STB_GLPROG_FUNC(UNIFORM2F , Uniform2f ) \ STB_GLPROG_FUNC(UNIFORM3F , Uniform3f ) \ STB_GLPROG_FUNC(UNIFORM4F , Uniform4f ) \ STB_GLPROG_FUNC(UNIFORM1I , Uniform1i ) \ STB_GLPROG_FUNC(UNIFORM2I , Uniform2i ) \ STB_GLPROG_FUNC(UNIFORM3I , Uniform3i ) \ STB_GLPROG_FUNC(UNIFORM4I , Uniform4i ) \ STB_GLPROG_FUNC(UNIFORM1FV , Uniform1fv ) \ STB_GLPROG_FUNC(UNIFORM2FV , Uniform2fv ) \ STB_GLPROG_FUNC(UNIFORM3FV , Uniform3fv ) \ STB_GLPROG_FUNC(UNIFORM4FV , Uniform4fv ) \ STB_GLPROG_FUNC(UNIFORM1IV , Uniform1iv ) \ STB_GLPROG_FUNC(UNIFORM2IV , Uniform2iv ) \ STB_GLPROG_FUNC(UNIFORM3IV , Uniform3iv ) \ STB_GLPROG_FUNC(UNIFORM4IV , Uniform4iv ) \ STB_GLPROG_FUNC(USEPROGRAMOBJECT , UseProgramObject ) \ STB_GLPROG_FUNC(VERTEXATTRIBPOINTER , VertexAttribPointer )
// define the static function pointers
#define STB_GLPROG_FUNC(x,y) static PFNGL##x##ARBPROC gl##y##ARB;
STB_GLPROG_EXTENSIONS #undef STB_GLPROG_FUNC
// define the GetProcAddress
#ifdef _WIN32
#ifndef WINGDIAPI
#ifndef STB__HAS_WGLPROC
typedef int (__stdcall *stbgl__voidfunc)(void); static __declspec(dllimport) stbgl__voidfunc wglGetProcAddress(char *); #endif
#endif
#define STBGL__GET_FUNC(x) wglGetProcAddress(x)
#else
#error "need to define how this platform gets extensions"
#endif
// create a function that fills out the function pointers
static void stb_glprog_init(void) { static int initialized = 0; // not thread safe!
if (initialized) return; #define STB_GLPROG_FUNC(x,y) gl##y##ARB = (PFNGL##x##ARBPROC) STBGL__GET_FUNC("gl" #y "ARB");
STB_GLPROG_EXTENSIONS #undef STB_GLPROG_FUNC
} #undef STB_GLPROG_EXTENSIONS
#else
static void stb_glprog_init(void) { } #endif
// define generic names for many of the gl functions or extensions for later use;
// note that in some cases there are two functions in core and one function in ARB
#ifdef STB_GLPROG_ARB
#define stbglCreateShader glCreateShaderObjectARB
#define stbglDeleteShader glDeleteObjectARB
#define stbglAttachShader glAttachObjectARB
#define stbglDetachShader glDetachObjectARB
#define stbglShaderSource glShaderSourceARB
#define stbglCompileShader glCompileShaderARB
#define stbglGetShaderStatus(a,b) glGetObjectParameterivARB(a, GL_OBJECT_COMPILE_STATUS_ARB, b)
#define stbglGetShaderInfoLog glGetInfoLogARB
#define stbglCreateProgram glCreateProgramObjectARB
#define stbglDeleteProgram glDeleteObjectARB
#define stbglLinkProgram glLinkProgramARB
#define stbglGetProgramStatus(a,b) glGetObjectParameterivARB(a, GL_OBJECT_LINK_STATUS_ARB, b)
#define stbglGetProgramInfoLog glGetInfoLogARB
#define stbglGetAttachedShaders glGetAttachedObjectsARB
#define stbglBindAttribLocation glBindAttribLocationARB
#define stbglGetUniformLocation glGetUniformLocationARB
#define stbgl_UseProgram glUseProgramObjectARB
#else
#define stbglCreateShader glCreateShader
#define stbglDeleteShader glDeleteShader
#define stbglAttachShader glAttachShader
#define stbglDetachShader glDetachShader
#define stbglShaderSource glShaderSource
#define stbglCompileShader glCompileShader
#define stbglGetShaderStatus(a,b) glGetShaderiv(a, GL_COMPILE_STATUS, b)
#define stbglGetShaderInfoLog glGetShaderInfoLog
#define stbglCreateProgram glCreateProgram
#define stbglDeleteProgram glDeleteProgram
#define stbglLinkProgram glLinkProgram
#define stbglGetProgramStatus(a,b) glGetProgramiv(a, GL_LINK_STATUS, b)
#define stbglGetProgramInfoLog glGetProgramInfoLog
#define stbglGetAttachedShaders glGetAttachedShaders
#define stbglBindAttribLocation glBindAttribLocation
#define stbglGetUniformLocation glGetUniformLocation
#define stbgl_UseProgram glUseProgram
#endif
// perform a safe strcat of 3 strings, given that we can't rely on portable snprintf
// if you need to break on error, this is the best place to place a breakpoint
static void stb_glprog_error(char *error, int error_buflen, char *str1, char *str2, char *str3) { int n = strlen(str1); strncpy(error, str1, error_buflen); if (n < error_buflen && str2) { strncpy(error+n, str2, error_buflen - n); n += strlen(str2); if (n < error_buflen && str3) { strncpy(error+n, str3, error_buflen - n); } } error[error_buflen-1] = 0; }
STB_GLPROG_DECLARE GLuint stbgl_compile_shader(GLenum type, char const **sources, int num_sources, char *error, int error_buflen) { char *typename = (type == STBGL_VERTEX_SHADER ? "vertex" : "fragment"); int len; GLint result; GLuint shader;
// initialize the extensions if we haven't already
stb_glprog_init();
// allocate
shader = stbglCreateShader(type); if (!shader) { stb_glprog_error(error, error_buflen, "Couldn't allocate shader object in stbgl_compile_shader for ", typename, NULL); return 0; }
// compile
// if num_sources is negative, assume source is NULL-terminated and count the non-NULL ones
if (num_sources < 0) for (num_sources = 0; sources[num_sources] != NULL; ++num_sources) ; stbglShaderSource(shader, num_sources, sources, NULL); stbglCompileShader(shader); stbglGetShaderStatus(shader, &result); if (result) return shader;
// errors
stb_glprog_error(error, error_buflen, "Compile error for ", typename, " shader: "); len = strlen(error); if (len < error_buflen) stbglGetShaderInfoLog(shader, error_buflen-len, NULL, error+len);
stbglDeleteShader(shader); return 0; }
STB_GLPROG_DECLARE GLuint stbgl_link_program(GLuint vertex_shader, GLuint fragment_shader, char const **binds, int num_binds, char *error, int error_buflen) { int len; GLint result;
// allocate
GLuint prog = stbglCreateProgram(); if (!prog) { stb_glprog_error(error, error_buflen, "Couldn't allocate program object in stbgl_link_program", NULL, NULL); return 0; }
// attach
if (vertex_shader) stbglAttachShader(prog, vertex_shader); if (fragment_shader) stbglAttachShader(prog, fragment_shader);
// attribute binds
if (binds) { int i; // if num_binds is negative, then it is NULL terminated
if (num_binds < 0) for (num_binds=0; binds[num_binds]; ++num_binds) ; for (i=0; i < num_binds; ++i) if (binds[i] && binds[i][0]) // empty binds can be NULL or ""
stbglBindAttribLocation(prog, i, binds[i]); }
// link
stbglLinkProgram(prog);
// detach
if (vertex_shader) stbglDetachShader(prog, vertex_shader); if (fragment_shader) stbglDetachShader(prog, fragment_shader);
// errors
stbglGetProgramStatus(prog, &result); if (result) return prog;
stb_glprog_error(error, error_buflen, "Link error: ", NULL, NULL); len = strlen(error); if (len < error_buflen) stbglGetProgramInfoLog(prog, error_buflen-len, NULL, error+len);
stbglDeleteProgram(prog); return 0; }
STB_GLPROG_DECLARE GLuint stbgl_create_program(char const **vertex_source, char const **frag_source, char const **binds, char *error, int error_buflen) { GLuint vertex, fragment, prog=0; vertex = stbgl_compile_shader(STBGL_VERTEX_SHADER, vertex_source, -1, error, error_buflen); if (vertex) { fragment = stbgl_compile_shader(STBGL_FRAGMENT_SHADER, frag_source, -1, error, error_buflen); if (fragment) prog = stbgl_link_program(vertex, fragment, binds, -1, error, error_buflen); if (fragment) stbglDeleteShader(fragment); stbglDeleteShader(vertex); } return prog; }
STB_GLPROG_DECLARE void stbgl_delete_shader(GLuint shader) { stbglDeleteShader(shader); }
STB_GLPROG_DECLARE void stgbl_delete_program(GLuint program) { stbglDeleteProgram(program); }
GLint stbgl_find_uniform(GLuint prog, char *uniform) { return stbglGetUniformLocation(prog, uniform); }
STB_GLPROG_DECLARE void stbgl_find_uniforms(GLuint prog, GLint *locations, char const **uniforms, int num_uniforms) { int i; if (num_uniforms < 0) num_uniforms = 999999; for (i=0; i < num_uniforms && uniforms[i]; ++i) locations[i] = stbglGetUniformLocation(prog, uniforms[i]); }
STB_GLPROG_DECLARE void stbglUseProgram(GLuint program) { stbgl_UseProgram(program); }
#ifdef STB_GLPROG_ARB
#define STBGL_ARBIFY(name) name##ARB
#else
#define STBGL_ARBIFY(name) name
#endif
STB_GLPROG_DECLARE void stbglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer) { STBGL_ARBIFY(glVertexAttribPointer)(index, size, type, normalized, stride, pointer); }
STB_GLPROG_DECLARE void stbglEnableVertexAttribArray (GLuint index) { STBGL_ARBIFY(glEnableVertexAttribArray )(index); } STB_GLPROG_DECLARE void stbglDisableVertexAttribArray(GLuint index) { STBGL_ARBIFY(glDisableVertexAttribArray)(index); }
STB_GLPROG_DECLARE void stbglUniform1fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform1fv)(loc,count,v); } STB_GLPROG_DECLARE void stbglUniform2fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform2fv)(loc,count,v); } STB_GLPROG_DECLARE void stbglUniform3fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform3fv)(loc,count,v); } STB_GLPROG_DECLARE void stbglUniform4fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform4fv)(loc,count,v); }
STB_GLPROG_DECLARE void stbglUniform1iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform1iv)(loc,count,v); } STB_GLPROG_DECLARE void stbglUniform2iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform2iv)(loc,count,v); } STB_GLPROG_DECLARE void stbglUniform3iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform3iv)(loc,count,v); } STB_GLPROG_DECLARE void stbglUniform4iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform4iv)(loc,count,v); }
STB_GLPROG_DECLARE void stbglUniform1f(GLint loc, float v0) { STBGL_ARBIFY(glUniform1f)(loc,v0); } STB_GLPROG_DECLARE void stbglUniform2f(GLint loc, float v0, float v1) { STBGL_ARBIFY(glUniform2f)(loc,v0,v1); } STB_GLPROG_DECLARE void stbglUniform3f(GLint loc, float v0, float v1, float v2) { STBGL_ARBIFY(glUniform3f)(loc,v0,v1,v2); } STB_GLPROG_DECLARE void stbglUniform4f(GLint loc, float v0, float v1, float v2, float v3) { STBGL_ARBIFY(glUniform4f)(loc,v0,v1,v2,v3); }
STB_GLPROG_DECLARE void stbglUniform1i(GLint loc, GLint v0) { STBGL_ARBIFY(glUniform1i)(loc,v0); } STB_GLPROG_DECLARE void stbglUniform2i(GLint loc, GLint v0, GLint v1) { STBGL_ARBIFY(glUniform2i)(loc,v0,v1); } STB_GLPROG_DECLARE void stbglUniform3i(GLint loc, GLint v0, GLint v1, GLint v2) { STBGL_ARBIFY(glUniform3i)(loc,v0,v1,v2); } STB_GLPROG_DECLARE void stbglUniform4i(GLint loc, GLint v0, GLint v1, GLint v2, GLint v3) { STBGL_ARBIFY(glUniform4i)(loc,v0,v1,v2,v3); }
#endif
|