From 2ca04fbe7985ee944f3fa6302886a252a51add0c Mon Sep 17 00:00:00 2001 From: Wolfgang Draxinger Date: Sun, 24 Apr 2016 23:52:45 +0200 Subject: initial commit --- shaderloader/shaderloader.c | 287 ++++++++++++++++++++++++++++++++++++++++++++ shaderloader/shaderloader.h | 22 ++++ 2 files changed, 309 insertions(+) create mode 100644 shaderloader/shaderloader.c create mode 100644 shaderloader/shaderloader.h (limited to 'shaderloader') diff --git a/shaderloader/shaderloader.c b/shaderloader/shaderloader.c new file mode 100644 index 0000000..2454316 --- /dev/null +++ b/shaderloader/shaderloader.c @@ -0,0 +1,287 @@ +#include "shaderloader.h" + +#include +#include + +#if defined(_WIN32) +#include +#define shader_gl_proc(x) wglGetProcAddress(#x) +#elif defined(__APPLE__) && defined(__MACH__) +#define shader_gl_proc(x) ((void(*)())x) +#else +#include +#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(int i = 0; i < filecount; i++) { + fprintf(stderr, " %.2d: %s\n", 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; +} diff --git a/shaderloader/shaderloader.h b/shaderloader/shaderloader.h new file mode 100644 index 0000000..b57fa8a --- /dev/null +++ b/shaderloader/shaderloader.h @@ -0,0 +1,22 @@ +#pragma once +#ifndef SHADERLOADER_H +#define SHADERLOADER_H + +#if defined(_WIN32) +#include +#endif +#include + +GLuint shader_load_from_files( + GLenum shader_unit, + char const * const * const filepaths ); + +typedef struct shader_program_sources { + GLenum unit; + char const * const * paths; +} shader_program_sources; + +GLuint shader_program_load_from_files( + shader_program_sources const * const sources ); + +#endif/*SHADERLOADER_H*/ -- cgit v1.2.3