diff options
Diffstat (limited to 'src/shader.c')
-rw-r--r-- | src/shader.c | 75 |
1 files changed, 67 insertions, 8 deletions
diff --git a/src/shader.c b/src/shader.c index 1cadc7f..83df512 100644 --- a/src/shader.c +++ b/src/shader.c @@ -22,16 +22,20 @@ #include "glad.h" #include "macros.h" +#include "shader.h" + typedef struct shader_t { - unsigned program, refcnt; - unsigned n_uniforms, n_attributes; - const char **uniforms, **attributes; - int *uniform_locations, *attribute_locations; - const char *vs_path, *fs_path; - struct timespec vs_mtime, fs_mtime; - - int locations[]; + unsigned program, refcnt; + unsigned n_uniforms, n_attributes; + const char **uniforms, **attributes; + int *uniform_locations, *attribute_locations; + const char *vs_path, *fs_path; + struct timespec vs_mtime, fs_mtime; + shader_uniform_t *active_uniforms; + int n_active_uniforms; + + int locations[]; } shader_t; @@ -81,6 +85,58 @@ unsigned int shader_pair_new_bare(const char *vs_src, const char *fs_src) return shader; } + +/* query a shader for its active uniforms, returns results in res_uniforms + * the returned results are owned by the shader, do not free them, they will be + * cleaned up with shader_free() or reallocated by shader_reload_files() + */ +void shader_active_uniforms(shader_t *shader, int *res_n_uniforms, const shader_uniform_t **res_uniforms) +{ + assert(shader); + assert(res_n_uniforms); + assert(res_uniforms); + + *res_n_uniforms = shader->n_active_uniforms; + *res_uniforms = shader->active_uniforms; +} + + +static void refresh_active_uniforms(shader_t *shader) +{ + int n, maxlen; + + assert(shader); + + if (shader->active_uniforms) { + for (int i = 0; i < shader->n_active_uniforms; i++) + free(shader->active_uniforms[i].name); + free(shader->active_uniforms); + shader->active_uniforms = NULL; + shader->n_active_uniforms = 0; + } + + glGetProgramiv(shader->program, GL_ACTIVE_UNIFORMS, &n); + glGetProgramiv(shader->program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxlen); + + /* FIXME: this is currently written such that allocation failures just cut the + * active uniforms short instead of throwing an error, but should probably + * be rewritten to fail and report the ENOMEM errors. + */ + shader->active_uniforms = calloc(n, sizeof(shader_uniform_t)); + if (shader->active_uniforms) { + for (int i = 0; i < n; i++) { + shader->active_uniforms[i].name = calloc(maxlen, sizeof(char)); + if (!shader->active_uniforms[i].name) + break; + + glGetActiveUniform(shader->program, i, maxlen, /* length */ NULL, /* size */ NULL, &shader->active_uniforms[i].type, shader->active_uniforms[i].name); + shader->active_uniforms[i].location = glGetUniformLocation(shader->program, shader->active_uniforms[i].name); + shader->n_active_uniforms++; + } + } +} + + static void get_locations(shader_t *shader) { for (unsigned i = 0; i < shader->n_uniforms; i++) @@ -90,6 +146,7 @@ static void get_locations(shader_t *shader) shader->attribute_locations[i] = glGetAttribLocation(shader->program, shader->attributes[i]); } + shader_t * shader_pair_new(const char *vs_src, const char *fs_src, unsigned n_uniforms, const char **uniforms, unsigned n_attributes, const char **attributes) { shader_t *shader; @@ -112,6 +169,7 @@ shader_t * shader_pair_new(const char *vs_src, const char *fs_src, unsigned n_un shader->attribute_locations = &shader->locations[n_uniforms]; get_locations(shader); + refresh_active_uniforms(shader); return shader; } @@ -178,6 +236,7 @@ int shader_reload_files(shader_t *shader) free(fs_src); get_locations(shader); + refresh_active_uniforms(shader); return ret; } |