diff options
Diffstat (limited to 'src/shader')
-rw-r--r-- | src/shader/shader.c | 224 | ||||
-rw-r--r-- | src/shader/shader.h | 117 |
2 files changed, 341 insertions, 0 deletions
diff --git a/src/shader/shader.c b/src/shader/shader.c new file mode 100644 index 0000000..817d451 --- /dev/null +++ b/src/shader/shader.c @@ -0,0 +1,224 @@ +#include "shader.h" + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +static honey_result read_file(char** destination, char* file_path) { + FILE* f = fopen(file_path, "r"); + if (f == NULL) { + honey_error_set_string1(file_path); + return HONEY_FILE_READ_ERROR; + } + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + *destination = malloc(fsize + 1); + if (*destination == NULL) { + return HONEY_MEMORY_ALLOCATION_ERROR; + } + fread(*destination, 1, fsize, f); + fclose(f); + + (*destination)[fsize] = 0; + + return HONEY_OK; +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +honey_result honey_shader_load(honey_shader* shader, + char* vertex_shader_path, + char* fragment_shader_path) { + /* load vertex shader code */ + char* vertex_shader_code; + honey_result result = read_file(&vertex_shader_code, + vertex_shader_path); + if (result != HONEY_OK) + return result; + + /* load fragment shader code */ + char* fragment_shader_code; + result = read_file(&fragment_shader_code, + fragment_shader_path); + if (result != HONEY_OK) + return result; + + result = honey_shader_new(shader, + vertex_shader_code, + fragment_shader_code); + + if (result == HONEY_VERTEX_SHADER_COMPILATION_ERROR) + honey_error_set_string2(vertex_shader_path); + + if (result == HONEY_FRAGMENT_SHADER_COMPILATION_ERROR) + honey_error_set_string2(fragment_shader_path); + + free(vertex_shader_code); + free(fragment_shader_code); + + return result; +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +honey_result honey_shader_new(honey_shader* shader, + char* vertex_shader_code, + char* fragment_shader_code) { + /* compile shaders */ + int success; + char error[512]; + + int vertex_shader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex_shader, 1, ((const char**)&vertex_shader_code), NULL); + glCompileShader(vertex_shader); + glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success); + if (!success) { + honey_error_clear_strings(); + char compiler_error[HONEY_ERROR_DATA_STRING_LENGTH]; + glGetShaderInfoLog(vertex_shader, HONEY_ERROR_DATA_STRING_LENGTH, NULL, compiler_error); + honey_error_set_string1(compiler_error); + return HONEY_VERTEX_SHADER_COMPILATION_ERROR; + } + + int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment_shader, 1, ((const char**)&fragment_shader_code), NULL); + glCompileShader(fragment_shader); + glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success); + if (!success) { + honey_error_clear_strings(); + char compiler_error[HONEY_ERROR_DATA_STRING_LENGTH]; + glGetShaderInfoLog(fragment_shader, HONEY_ERROR_DATA_STRING_LENGTH, NULL, compiler_error); + honey_error_set_string1(compiler_error); + return HONEY_FRAGMENT_SHADER_COMPILATION_ERROR; + } + + /* link shaders */ + *shader = glCreateProgram(); + glAttachShader(*shader, vertex_shader); + glAttachShader(*shader, fragment_shader); + glLinkProgram(*shader); + glGetShaderiv(*shader, GL_LINK_STATUS, &success); + if (!success) { + honey_error_clear_strings(); + char compiler_error[HONEY_ERROR_DATA_STRING_LENGTH]; + glGetShaderInfoLog(vertex_shader, HONEY_ERROR_DATA_STRING_LENGTH, NULL, compiler_error); + honey_error_set_string1(compiler_error); + return HONEY_SHADER_LINK_ERROR; + } + + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + + return HONEY_OK; +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +void honey_shader_set_int(honey_shader shader, + char* int_name, + int value) { + honey_shader_use(shader); + unsigned int int_location = glGetUniformLocation(shader, int_name); + glUniform1i(int_location, value); +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +void honey_shader_set_float(honey_shader shader, + char* float_name, + float value) { + honey_shader_use(shader); + unsigned int float_location = glGetUniformLocation(shader, float_name); + glUniform1f(float_location, value); +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +void honey_shader_set_vec3(honey_shader shader, + char* vector_name, + vec3 value) { + honey_shader_use(shader); + unsigned int vector_location = glGetUniformLocation(shader, vector_name); + glUniform3fv(vector_location, 1, (float*) value); +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +void honey_shader_set_mat3(honey_shader shader, + char* matrix_name, + mat3 value) { + glUseProgram(shader); + unsigned int matrix_location = glGetUniformLocation(shader, matrix_name); + glUniformMatrix3fv(matrix_location, 1, GL_FALSE, (float*) value); +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +void honey_shader_set_mat4(honey_shader shader, + char* matrix_name, + mat4 value) { + glUseProgram(shader); + unsigned int matrix_location = glGetUniformLocation(shader, matrix_name); + glUniformMatrix4fv(matrix_location, 1, GL_FALSE, (float*) value); +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +void honey_shader_set_point_light(honey_shader shader, + int point_light_index, + honey_point_light light) { + char name[HONEY_MAX_LIGHT_NAME_LENGTH]; + + snprintf(name, + HONEY_MAX_LIGHT_NAME_LENGTH, + "point_lights[%d].position", + point_light_index); + honey_shader_set_vec3(shader, name, light.position); + + snprintf(name, + HONEY_MAX_LIGHT_NAME_LENGTH, + "point_lights[%d].color", + point_light_index); + honey_shader_set_vec3(shader, name, light.color); + + snprintf(name, + HONEY_MAX_LIGHT_NAME_LENGTH, + "point_lights[%d].constant", + point_light_index); + honey_shader_set_float(shader, name, light.constant); + + snprintf(name, + HONEY_MAX_LIGHT_NAME_LENGTH, + "point_lights[%d].linear", + point_light_index); + honey_shader_set_float(shader, name, light.linear); + + snprintf(name, + HONEY_MAX_LIGHT_NAME_LENGTH, + "point_lights[%d].quadratic", + point_light_index); + honey_shader_set_float(shader, name, light.quadratic); +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +void honey_shader_set_directional_light(honey_shader shader, + int directional_light_index, + honey_directional_light light) { + char name[HONEY_MAX_LIGHT_NAME_LENGTH]; + + snprintf(name, + HONEY_MAX_LIGHT_NAME_LENGTH, + "directional_lights[%d].direction", + directional_light_index); + honey_shader_set_vec3(shader, name, light.direction); + + snprintf(name, + HONEY_MAX_LIGHT_NAME_LENGTH, + "directional_lights[%d].color", + directional_light_index); + honey_shader_set_vec3(shader, name, light.color); +} + + diff --git a/src/shader/shader.h b/src/shader/shader.h new file mode 100644 index 0000000..07cc22d --- /dev/null +++ b/src/shader/shader.h @@ -0,0 +1,117 @@ +/** @file shader.h + * + * @brief Functions to create, manipulate, and destroy GLSL shaders. + */ + +#ifndef HONEY_SHADER_H +#define HONEY_SHADER_H + +#include "../common.h" +#include "../light/light.h" + +typedef int honey_shader; + +/** @brief Load a shader. + * + * @param[out] shader Pointer to the shader destination + * + * @param[in] vertex_shader_path The path to the vertex shader source code + * @param[in] fragment_shader_path The path to the fragment shader source code + * + * @return The result of the shader load. + */ +honey_result honey_shader_load(honey_shader* shader, + char* vertex_shader_path, + char* fragment_shader_path); + +/** @brief Create a shader from code strings. + * + * @param[out] shader Pointer to the shader destination. + * @param[in] vertex_shader_code Zero-terminated string containing the vertex shader code to compile + * @param[in] fragment_shader_code Zero-terminated string containing the fragment shader code to compile + * + * @return The result of the shader creation. + */ +honey_result honey_shader_new(honey_shader* shader, + char* vertex_shader_code, + char* fragment_shader_code); + +/** @brief Set an integer uniform. + * + * @param[in] shader The shader to which the uniform belongs + * @param[in] int_name The name of the integer uniform + * @param[in] value The value of the integer uniform + */ +void honey_shader_set_int(honey_shader shader, + char* int_name, + int value); + +/** @brief Set a float uniform. + * + * @param[in] shader The shader to which the uniform belongs + * @param[in] float_name The name of the float uniform + * @param[in] value The value of the float uniform + */ +void honey_shader_set_float(honey_shader shader, + char* float_name, + float value); + +/** @brief Set a vec3 uniform. + * @param[in] shader The shader to which the uniform belongs + * @param[in] vector_name The name of the vec3 uniform + * @param[in] value The value of the vector uniform + */ +void honey_shader_set_vec3(honey_shader shader, + char* vector_name, + vec3 value); + + +/** @brief Set a mat3 uniform. + * + * @param[in] shader The shader to which the uniform belongs + * @param[in] matrix_name The name of the matrix uniform + * @param[in] value The value of the matrix uniform + */ +void honey_shader_set_mat3(honey_shader shader, + char* matrix_name, + mat3 value); + +/** @brief Set a mat4 uniform. + * + * @param[in] shader The shader to which the uniform belongs + * @param[in] matrix_name The name of the matrix uniform + * @param[in] value The value of the matrix uniform + */ +void honey_shader_set_mat4(honey_shader shader, + char* matrix_name, + mat4 value); + +/** @brief Set a point_light uniform. + * + * @param[in] shader The shader to which the uniform belongs + * @param[in] point_light_index The index of the light to set + * @param[in] light The honey_point_light to set + */ +void honey_shader_set_point_light(honey_shader shader, + int point_light_index, + honey_point_light light); + +/** @brief Set a directional_light uniform. + * + * @param[in] shader The shader to which the uniform belongs + * @param[in] directional_light_index The index of the light to set + * @param[in] light The honey_directional_light to set + */ +void honey_shader_set_directional_light(honey_shader shader, + int directional_light_index, + honey_directional_light light); + +/** @brief Use a shader. + */ +#define honey_shader_use glUseProgram + +/** @brief delete a shader. + */ +#define honey_shader_delete glDeleteProgram + +#endif |