Created
November 10, 2016 17:34
-
-
Save datenwolf/9bdc52a92ac4091220d0b3270dbcf179 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#include "shaderloader.h" | |
#include <stdlib.h> | |
#include <stdio.h> | |
#if defined(_WIN32) | |
#include <windows.h> | |
#define shader_gl_proc(x) wglGetProcAddress(#x) | |
#elif defined(__APPLE__) && defined(__MACH__) | |
#define shader_gl_proc(x) ((void(*)())x) | |
#else | |
#include <GL/glx.h> | |
#define shader_gl_proc(x) glXGetProcAddress(#x) | |
#endif | |
static | |
size_t linecount(char const * str) | |
{ | |
size_t count = 0; | |
for(;*str;str++) { count += ('\n' == *str); } | |
return count; | |
} | |
/* OpenGL function loading -- uses no caching, but shader loading is a | |
* seldomly executed operation and never called from time critical sections. */ | |
typedef void(*shader_func_ptr)(); | |
static | |
shader_func_ptr shader_gl_proc_address(char const * const procname) | |
{ | |
return NULL; | |
} | |
static | |
GLuint shader_glCreateShader(GLenum unit) | |
{ | |
GLuint r = 0; | |
shader_func_ptr const proc = shader_gl_proc(glCreateShader); | |
if( proc ) { r = ((PFNGLCREATESHADERPROC)proc)(unit); } | |
return r; | |
} | |
static | |
void shader_glShaderSource( | |
GLuint shader, | |
GLsizei count, | |
GLchar const * const * const string, | |
GLint const * const lengths) | |
{ | |
shader_func_ptr const proc = shader_gl_proc(glShaderSource); | |
if( proc ) { ((PFNGLSHADERSOURCEPROC)proc)( | |
shader, count, string, lengths); | |
} | |
} | |
static | |
void shader_glCompileShader(GLuint shader) | |
{ | |
shader_func_ptr const proc = shader_gl_proc(glCompileShader); | |
if( proc ) { ((PFNGLCOMPILESHADERPROC)proc)(shader); } | |
} | |
static | |
void shader_glGetShaderiv(GLuint shader, GLenum pname, GLint *params) | |
{ | |
shader_func_ptr const proc = shader_gl_proc(glGetShaderiv); | |
if( proc ) { ((PFNGLGETSHADERIVPROC)proc)(shader, pname, params); } | |
} | |
static | |
void shader_glGetShaderInfoLog( | |
GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) | |
{ | |
shader_func_ptr const proc = shader_gl_proc(glGetShaderInfoLog); | |
if( proc ) { ((PFNGLGETSHADERINFOLOGPROC)proc)( | |
shader, bufSize, length, infoLog); | |
} | |
} | |
static | |
void shader_glDeleteShader(GLuint shader) | |
{ | |
shader_func_ptr const proc = shader_gl_proc(glDeleteShader); | |
if( proc ) { ((PFNGLDELETESHADERPROC)proc)(shader); } | |
} | |
static | |
GLuint shader_glCreateProgram() | |
{ | |
GLuint r = 0; | |
shader_func_ptr const proc = shader_gl_proc(glCreateProgram); | |
if( proc ) { r = ((PFNGLCREATEPROGRAMPROC)proc)(); } | |
return r; | |
} | |
static | |
void shader_glAttachShader(GLuint program, GLuint shader) | |
{ | |
shader_func_ptr const proc = shader_gl_proc(glAttachShader); | |
if( proc ) { ((PFNGLATTACHSHADERPROC)proc)(program, shader); } | |
} | |
static | |
void shader_glLinkProgram(GLuint program) | |
{ | |
shader_func_ptr const proc = shader_gl_proc(glLinkProgram); | |
if( proc ) { ((PFNGLLINKPROGRAMPROC)proc)(program); } | |
} | |
static | |
void shader_glGetProgramiv(GLuint program, GLenum pname, GLint *params) | |
{ | |
shader_func_ptr const proc = shader_gl_proc(glGetProgramiv); | |
if( proc ) { ((PFNGLGETPROGRAMIVPROC)proc)(program, pname, params); } | |
} | |
static | |
void shader_glGetProgramInfoLog( | |
GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) | |
{ | |
shader_func_ptr const proc = shader_gl_proc(glGetProgramInfoLog); | |
if( proc ) { ((PFNGLGETSHADERINFOLOGPROC)proc)( | |
program, bufSize, length, infoLog); | |
} | |
} | |
static | |
void shader_glDeleteProgram(GLuint program) | |
{ | |
shader_func_ptr const proc = shader_gl_proc(glDeleteProgram); | |
if( proc ) { ((PFNGLDELETEPROGRAMPROC)proc)(program); } | |
} | |
/* shader loader functions */ | |
GLuint shader_load_from_files( | |
GLenum shader_unit, | |
char const * const * const filepaths) | |
{ | |
size_t i; | |
size_t n_sources_allocated = 0; | |
GLchar const ** sources = NULL; | |
GLuint * lengths = NULL; | |
GLint shader_status = GL_FALSE; | |
GLuint shader = 0; | |
shader = shader_glCreateShader(shader_unit); | |
if(!shader) { goto failed; } | |
int filecount = 0; | |
while( filepaths[filecount] ) { filecount++; } | |
sources = malloc(sizeof(char*)*(filecount+1)); | |
if(!sources) { goto failed; } | |
sources[filecount] = 0; | |
lengths = malloc(sizeof(GLuint)*(filecount+1)); | |
if(!lengths) { goto failed; } | |
lengths[filecount] = 0; | |
for(i = 0; i < filecount; i++) { | |
size_t length = 0; | |
size_t read_length = 0; | |
GLchar *sourcestring = NULL; | |
FILE *fil = fopen(filepaths[i], "r"); | |
if(!fil) { | |
fprintf(stderr, | |
"could not open file '%s'\n", | |
filepaths[i] ); | |
goto failed; | |
} | |
fseek(fil, 0, SEEK_END); | |
length = ftell(fil); | |
lengths[i] = length; | |
rewind(fil); | |
sourcestring = malloc(length); | |
if( !sourcestring ) { goto failed; } | |
sources[i] = sourcestring; | |
n_sources_allocated = i + 1; | |
read_length = fread(sourcestring, 1, length, fil); | |
fclose(fil); | |
if( length != read_length ) { goto failed; } | |
} | |
shader_glShaderSource(shader, 1, sources, lengths); | |
shader_glCompileShader(shader); | |
shader_glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_status); | |
if( shader_status == GL_FALSE ) { | |
GLint log_length, returned_length; | |
shader_glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); | |
char *shader_infolog = malloc(log_length); | |
if( shader_infolog ) { | |
shader_glGetShaderInfoLog( | |
shader, | |
log_length, | |
&returned_length, | |
shader_infolog ); | |
fprintf(stderr, "shader compilation failed; sources:\n"); | |
for(i = 0; i < filecount; i++) { | |
fprintf(stderr, " %.2u: %s\n", (unsigned)i, filepaths[i]); | |
} | |
fputs("compile log:\n", stderr); | |
fwrite(shader_infolog, returned_length, 1, stderr); | |
free(shader_infolog); | |
} | |
goto failed; | |
} | |
cleanup: | |
free(lengths); | |
for(i = 0; i < n_sources_allocated; ++i) { free((void*)sources[i]); } | |
free(sources); | |
return shader; | |
failed: | |
shader_glDeleteShader(shader); | |
shader = 0; | |
goto cleanup; | |
} | |
GLuint shader_program_load_from_files( | |
shader_program_sources const * const sources ) | |
{ | |
size_t i; | |
size_t n_shaders = 0; | |
GLuint program = 0; | |
GLuint *shaders = NULL; | |
GLint linkStatus; | |
for( n_shaders = 0 | |
; sources[n_shaders].unit && sources[n_shaders].paths | |
; ++n_shaders); | |
if( !n_shaders ) { goto failed; }; | |
shaders = calloc(sizeof(*shaders), n_shaders); | |
if( !shaders ) { goto failed; } | |
program = shader_glCreateProgram(); | |
if(!program) { goto failed; } | |
for( i = 0; i < n_shaders; ++i ) { | |
shaders[i] = | |
shader_load_from_files( | |
sources[i].unit, | |
sources[i].paths ); | |
if( !shaders[i] ) { goto failed; } | |
shader_glAttachShader(program, shaders[i]); | |
} | |
shader_glLinkProgram(program); | |
shader_glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); | |
if( linkStatus == GL_FALSE ) { | |
GLint log_length, returned_length; | |
shader_glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length); | |
char *program_infolog= malloc(log_length); | |
if( program_infolog ) { | |
shader_glGetProgramInfoLog( | |
program, | |
log_length, | |
&returned_length, | |
program_infolog); | |
fwrite(program_infolog, returned_length, 1, stderr); | |
free( program_infolog ); | |
} | |
} | |
cleanup: | |
/* shaders will get actually deleted when program gets deleted */ | |
for( i = 0; i < n_shaders; ++i ) { | |
if( shaders[i] ) { | |
shader_glDeleteShader(shaders[i]); | |
} | |
} | |
free(shaders); | |
return program; | |
failed: | |
shader_glDeleteProgram(program); | |
program = 0; | |
goto cleanup; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment