summaryrefslogtreecommitdiff
path: root/src/shader.c
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-12-11 10:49:50 -0500
committerFreya Murphy <freya@freyacat.org>2025-12-11 10:51:40 -0500
commitfa8fa6784559ed0fc8d780e36880273f77e272c4 (patch)
tree7456a4e9148d47e409ba837bafdc6238b6c757db /src/shader.c
parentadd ubos (diff)
downloadvoxel-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.c246
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);
}