diff options
| author | Freya Murphy <freya@freyacat.org> | 2025-12-11 10:49:50 -0500 |
|---|---|---|
| committer | Freya Murphy <freya@freyacat.org> | 2025-12-11 10:51:40 -0500 |
| commit | fa8fa6784559ed0fc8d780e36880273f77e272c4 (patch) | |
| tree | 7456a4e9148d47e409ba837bafdc6238b6c757db /src/shader.c | |
| parent | add ubos (diff) | |
| download | voxel-fa8fa6784559ed0fc8d780e36880273f77e272c4.tar.gz voxel-fa8fa6784559ed0fc8d780e36880273f77e272c4.tar.bz2 voxel-fa8fa6784559ed0fc8d780e36880273f77e272c4.zip | |
i did a lot
Diffstat (limited to 'src/shader.c')
| -rw-r--r-- | src/shader.c | 246 |
1 files changed, 167 insertions, 79 deletions
diff --git a/src/shader.c b/src/shader.c index 26bb92b..abb62a2 100644 --- a/src/shader.c +++ b/src/shader.c @@ -1,60 +1,28 @@ #include <GL/glew.h> -#include <stdio.h> #include <stdlib.h> #include <string.h> #include "voxel.h" -#include "shader.h" +#include "utils.h" +#include "list.h" +#include "gl.h" -static GLint current_program; - -static char *read_file(const char *filename) +static void print_shader_log(const char *filename, u32 id) { - FILE *file; - long length, read; - char *buffer; - - file = fopen(filename, "r"); - if (file == NULL) { - ERROR("could not read file: %s", filename); - return NULL; - } - - fseek(file, 0, SEEK_END); - length = ftell(file); - fseek(file, 0, SEEK_SET); - - buffer = malloc(length + 1); - read = fread(buffer, 1, length, file); - buffer[length] = 0; - - if (read < length) { - ERROR("could not read file: %s", filename); - free(buffer); - return NULL; - } - - fclose(file); - return buffer; -} - -static void print_shader_log(const char *filename, GLuint id) -{ - GLint log_len; + i32 log_len; char *log; glGetShaderiv(id, GL_INFO_LOG_LENGTH, &log_len); - log = malloc(log_len + 1); + log = xalloc(log_len + 1); glGetShaderInfoLog(id, log_len, &log_len, log); log[log_len] = 0; ERROR("failed to compile shader: '%s'\n%s", filename, log); free(log); } -static int compile_shader(GLuint *out, const char *filename, const char *code, GLenum type) +static GL_RESULT compile_shader(u32 *out, const char *filename, const char *code, u32 type) { - GLuint id; - GLint status; - int code_len; + u32 id; + i32 status, code_len; id = glCreateShader(type); code_len = strlen(code); @@ -64,41 +32,112 @@ static int compile_shader(GLuint *out, const char *filename, const char *code, G if (status == GL_FALSE) { print_shader_log(filename, id); glDeleteShader(id); - return 1; + return GL_ERROR; } *out = id; - return 0; + return GL_OK; } -static void parse_bind_attributes(Shader *shader, char *code) +static void locate_attributes(Shader *shader) { - char *line, *last_line; - char *token, *last_token; - int attribute = 0; + i32 count, max_len; + List names, locations; + + list_init_string(&names); + list_init_i32(&locations); + + glGetProgramiv(shader->program_id, GL_ACTIVE_ATTRIBUTES, &count); + glGetProgramiv(shader->program_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len); + DEBUG("shader %d has %d attributes", shader->program_id, count); - line = strtok_r(code, "\n", &last_line); - for (; line != NULL; line = strtok_r(NULL, "\n", &last_line)) { - token = strtok_r(line, " \t", &last_token); - if (strcmp(token, "in") != 0) - continue; + for (i32 i = 0; i < count; i++) { + i32 size, location; + u32 type; + char *name; - token = strtok_r(NULL, " \t", &last_token); - token = strtok_r(NULL, " \t", &last_token); - *strchr(token, ';') = 0; + name = xalloc(max_len + 1); + glGetActiveAttrib(shader->program_id, i, max_len, NULL, &size, &type, name); - glBindAttribLocation(shader->program_id, attribute, token); - attribute++; + location = glGetAttribLocation(shader->program_id, name); + DEBUG("shader %d located attribute %s at location %d", shader->program_id, name, + location); + + list_push_string(&names, name); + list_push_i32(&locations, location); } + + shader->attribute_names = names; + shader->attribute_locations = locations; } -Shader *shader_init(const char *vertex_file, const char *fragment_file) +static void locate_uniforms(Shader *shader) { - Shader *shader; - char *vertex, *fragment; + i32 count, max_len; + List names, locations; + + list_init_string(&names); + list_init_i32(&locations); + + glGetProgramiv(shader->program_id, GL_ACTIVE_UNIFORMS, &count); + glGetProgramiv(shader->program_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len); + DEBUG("shader %d has %d uniforms", shader->program_id, count); + + for (i32 i = 0; i < count; i++) { + i32 size, location; + u32 type; + char *name; + + name = xalloc(max_len + 1); + glGetActiveUniform(shader->program_id, i, max_len, NULL, &size, &type, name); + + location = glGetUniformLocation(shader->program_id, name); + DEBUG("shader %d located uniform %s at location %d", shader->program_id, name, + location); + + list_push_string(&names, name); + list_push_i32(&locations, location); + } + + shader->uniform_names = names; + shader->uniform_locations = locations; +} + +static void locate_uniform_blocks(Shader *shader) +{ + i32 count; + List names, indicies; + + list_init_string(&names); + list_init_i32(&indicies); + + glGetProgramiv(shader->program_id, GL_ACTIVE_UNIFORM_BLOCKS, &count); + DEBUG("shader %d has %d uniform blocks", shader->program_id, count); + + for (i32 i = 0; i < count; i++) { + i32 index, name_len; + char *name; - shader = malloc(sizeof(Shader)); - memset(shader, 0, sizeof(Shader)); + glGetActiveUniformBlockiv(shader->program_id, i, GL_UNIFORM_BLOCK_NAME_LENGTH, + &name_len); + name = xalloc(name_len + 1); + glGetActiveUniformBlockName(shader->program_id, i, name_len, NULL, name); + + index = glGetUniformBlockIndex(shader->program_id, name); + DEBUG("shader %d located uniform block %s at index %d", shader->program_id, name, + index); + + list_push_string(&names, name); + list_push_i32(&indicies, index); + } + + shader->uniform_block_names = names; + shader->uniform_block_indicies = indicies; +} + +GL_RESULT shader_init(Shader *shader, const char *vertex_file, const char *fragment_file) +{ + char *vertex, *fragment; // read shader code from file vertex = read_file(vertex_file); @@ -109,23 +148,25 @@ Shader *shader_init(const char *vertex_file, const char *fragment_file) // compile shaders if (compile_shader(&shader->vertex_id, vertex_file, vertex, GL_VERTEX_SHADER)) goto failure; - if (compile_shader(&shader->fragment_id, fragment_file, fragment, - GL_FRAGMENT_SHADER)) + if (compile_shader(&shader->fragment_id, fragment_file, fragment, GL_FRAGMENT_SHADER)) goto failure; shader->program_id = glCreateProgram(); glAttachShader(shader->program_id, shader->vertex_id); glAttachShader(shader->program_id, shader->fragment_id); - parse_bind_attributes(shader, vertex); glLinkProgram(shader->program_id); glValidateProgram(shader->program_id); + locate_attributes(shader); + locate_uniforms(shader); + locate_uniform_blocks(shader); + if (vertex) free(vertex); if (fragment) free(fragment); - return shader; + return GL_OK; failure: if (vertex) @@ -133,12 +174,11 @@ failure: if (fragment) free(fragment); free(shader); - return NULL; + return GL_ERROR; } void shader_bind(Shader *shader) { - current_program = shader->program_id; glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); @@ -149,7 +189,6 @@ void shader_bind(Shader *shader) void shader_unbind(void) { - current_program = 0; glDisable(GL_CULL_FACE); glUseProgram(0); } @@ -161,36 +200,85 @@ void shader_free(Shader *shader) glDeleteShader(shader->vertex_id); glDeleteShader(shader->fragment_id); glDeleteProgram(shader->program_id); - free(shader); + for (u32 i = 0; i < shader->attribute_names.len; i++) + free(shader->attribute_names.strings[i]); + list_free(&shader->attribute_names); + list_free(&shader->attribute_locations); + for (u32 i = 0; i < shader->uniform_names.len; i++) + free(shader->uniform_names.strings[i]); + list_free(&shader->uniform_names); + list_free(&shader->uniform_locations); + for (u32 i = 0; i < shader->uniform_block_names.len; i++) + free(shader->uniform_block_names.strings[i]); + list_free(&shader->uniform_block_names); + list_free(&shader->uniform_block_indicies); } -GLint shader_uniform_location(Shader *shader, const char *name) +int shader_attribute_location(Shader *shader, const char *name) { - return glGetUniformLocation(shader->program_id, name); + for (u32 i = 0; i < shader->attribute_names.len; i++) { + const char *attribute = shader->attribute_names.strings[i]; + if (strcmp(attribute, name) == 0) + return shader->attribute_locations.ints[i]; + } + WARN("unknown attribute '%s'", name); + return -1; } -void shader_load_float(GLint location, float value) +int shader_uniform_location(Shader *shader, const char *name) { + for (u32 i = 0; i < shader->uniform_names.len; i++) { + const char *uniform = shader->uniform_names.strings[i]; + if (strcmp(uniform, name) == 0) + return shader->uniform_locations.ints[i]; + } + WARN("unknown uniform '%s'", name); + return -1; +} + +int shader_uniform_block_index(Shader *shader, const char *name) +{ + for (u32 i = 0; i < shader->uniform_block_names.len; i++) { + const char *uniform_block = shader->uniform_block_names.strings[i]; + if (strcmp(uniform_block, name) == 0) + return shader->uniform_block_indicies.ints[i]; + } + WARN("unknown uniform block '%s'", name); + return -1; +} + +void shader_load_float(Shader *shader, const char *name, float value) +{ + int location = shader_uniform_location(shader, name); glUniform1f(location, value); } -void shader_load_int(GLint location, int value) +void shader_load_int(Shader *shader, const char *name, int value) { + int location = shader_uniform_location(shader, name); glUniform1i(location, value); } -void shader_load_vec3(GLint location, vec3 value) +void shader_load_vec3(Shader *shader, const char *name, vec3 value) { + int location = shader_uniform_location(shader, name); glUniform3f(location, value[0], value[1], value[2]); } -void shader_load_mat4(GLint location, mat4 value) +void shader_load_ivec3(Shader *shader, const char *name, ivec3 value) +{ + int location = shader_uniform_location(shader, name); + glUniform3i(location, value[0], value[1], value[2]); +} + +void shader_load_mat4(Shader *shader, const char *name, mat4 value) { + int location = shader_uniform_location(shader, name); glUniformMatrix4fv(location, 1, GL_FALSE, (float *)value); } -void shader_load_ubo(GLint location, GLuint index, Uniform *uniform) +void shader_load_ubo(Shader *shader, const char *name, u32 binding) { - glUniformBlockBinding(current_program, index, location); - glBindBufferBase(GL_UNIFORM_BUFFER, location, uniform->id); + int index = shader_uniform_block_index(shader, name); + glUniformBlockBinding(shader->program_id, index, binding); } |