From 6d56ff2bb18d9b08e61da6bf9b6d1f8ed0a59d2e Mon Sep 17 00:00:00 2001 From: Shariq Shah Date: Sat, 11 Jul 2015 17:54:34 +0500 Subject: [PATCH] Ported Shader and Geometry code from Project Abstraction. Minor additions to array and string utils --- src/array.c | 6 +- src/array.h | 10 +- src/game.c | 39 +++--- src/geometry.c | 254 +++++++++++++++++++++++++++++++++++++ src/geometry.h | 10 ++ src/input.c | 11 +- src/input.h | 3 +- src/linmath.h | 104 +++++++-------- src/log.c | 10 ++ src/log.h | 1 + src/renderer.c | 40 ++++++ src/renderer.h | 1 + src/shader.c | 309 +++++++++++++++++++++++++++++++++++++++++++++ src/shader.h | 20 +++ src/string_utils.c | 7 - 15 files changed, 731 insertions(+), 94 deletions(-) create mode 100644 src/geometry.c create mode 100644 src/geometry.h create mode 100644 src/shader.c create mode 100644 src/shader.h diff --git a/src/array.c b/src/array.c index 1705556..c01c58e 100644 --- a/src/array.c +++ b/src/array.c @@ -7,13 +7,13 @@ static bool array_reallocate(Array* array); -Array* array_new_(size_t object_size) +Array* array_new_(size_t object_size, int capacity) { Array* newArray = malloc(sizeof(Array)); newArray->object_size = object_size; newArray->length = 0; - newArray->capacity = ARRAY_MIN_CAPACITY; + newArray->capacity = capacity == 0 ? ARRAY_MIN_CAPACITY : capacity; newArray->data = malloc(newArray->object_size * newArray->capacity); return newArray; @@ -60,7 +60,7 @@ void* array_add(Array* array) void array_reset(Array* array, unsigned int length) { - free(array->data); + if(array->data) free(array->data); array->length = length; array->capacity = length < ARRAY_MIN_CAPACITY ? ARRAY_MIN_CAPACITY : length; array->data = malloc(array->object_size * array->capacity); diff --git a/src/array.h b/src/array.h index cd30f4e..fcbcf93 100644 --- a/src/array.h +++ b/src/array.h @@ -12,19 +12,25 @@ typedef struct size_t object_size; // size per element } Array; -Array* array_new_(size_t object_size); -#define array_new(type) array_new_(sizeof(type)); // Use this for array creation +Array* array_new_(size_t object_size, int capacity); +#define array_new(type) array_new_(sizeof(type), 0); // Use this for array creation +#define array_new_cap(type, capacity) array_new_(sizeof(type), capacity); // Use this for array with specific capacity void array_free(Array* array); // All the macros with _val return by value while the function returns pointer void* array_get(Array* array, unsigned int index); #define array_get_val(array, type, index) (*((type*) array_get(array, index))) +#define array_get_last_val(array, type) array_get_val(array, type, array->length - 1) +#define array_get_raw(array, type) (type*) array->data void* array_top(Array* array); #define array_top_val(array, type) (*((type*) array_top(array))) void* array_add(Array* array); #define array_add_val(array, type) (*((type*) array_add(array))) +#define array_push(array, value, type) \ + type* new_val = array_add(array); \ + *new_val = value; void array_reset(Array* array, unsigned int length); // Resize to length objects whose data is unspecified #define array_clear(array) array_reset(array, 0) diff --git a/src/game.c b/src/game.c index 7856b85..2b557b7 100644 --- a/src/game.c +++ b/src/game.c @@ -1,10 +1,13 @@ -#include "game.h" +#include #include "GLFW/glfw3.h" +#include "game.h" #include "window_system.h" #include "input.h" #include "renderer.h" #include "log.h" +#include "file_io.h" +#include "shader.h" void run(void); void update(void); @@ -13,16 +16,22 @@ void render(void); void game_init(void) { GLFWwindow* window = window_get_active(); + /* Init systems */ input_init(window); renderer_init(window); - int keys[2] = {GLFW_KEY_W, GLFW_KEY_UP}; - int keys2[2] = {GLFW_KEY_S, GLFW_KEY_DOWN}; - int keys3[1] = {GLFW_KEY_J}; - int keys4[1] = {GLFW_KEY_K}; + io_file_initialize("/mnt/Dev/Projects/Symmetry/assets/");/* TODO: Implement proper way of getting binary directory */ + shader_initialize(); + + int keys[2] = {'W', GLFW_KEY_UP}; + int keys2[2] = {'S', GLFW_KEY_DOWN}; + int keys3[1] = {'J'}; + int keys4[1] = {'K'}; input_map_create("MoveUp", keys, 2); input_map_create("MoveDown", keys2, 2); input_map_create("Test", keys3, 1); input_map_create("Test2", keys4, 1); + + int shader = shader_create("phong.vert", "phong.frag"); run(); } @@ -39,24 +48,6 @@ void run(void) void update(void) { - if(input_map_state_get("MoveUp", GLFW_RELEASE)) - log_message("MoveUp pressed!"); - - if(input_map_state_get("MoveDown", GLFW_RELEASE)) - log_message("MoveDown pressed!"); - - if(input_map_state_get("Test", GLFW_RELEASE)) - log_message("Test released"); - - if(input_map_state_get("Test2", GLFW_RELEASE)) - { - input_map_name_set("Test2", "NewTest"); - log_message("Test2 released!"); - } - - if(input_map_state_get("NewTest", GLFW_RELEASE)) - log_message("NewTest released"); - input_update(); } @@ -69,4 +60,6 @@ void game_cleanup(void) { input_cleanup(); renderer_cleanup(); + io_file_cleanup(); + shader_cleanup(); } diff --git a/src/geometry.c b/src/geometry.c new file mode 100644 index 0000000..f2874b3 --- /dev/null +++ b/src/geometry.c @@ -0,0 +1,254 @@ +#include "geometry.h" +#include "array.h" +#include "num_types.h" +#include "linmath.h" +#include "string_utils.h" +#include "file_io.h" +#include "log.h" +#include "renderer.h" + +#include "GL/glew.h" +#include "GLFW/glfw3.h" + +#include +#include +#include +#include + +typedef struct +{ + char* filename; + bool draw_indexed; + Array* vertices; + Array* vertex_colors; + Array* normals; + Array* uvs; + Array* indices; + uint vao; + uint vertex_vbo; + uint uv_vbo; + uint normal_vbo; + uint color_vbo; + uint index_vbo; + uint ref_count; + /* BoundingBox boundingBox; */ + /* BoundingSphere boundingSphere; */ +} Geometry; + +/* Data */ +static Array* geometry_list; +static Array* empty_indices; + +/* Function definitions */ +bool load_from_file(Geometry* geometry, const char* filename); +void create_vao(Geometry* geometry); + +void geom_initialize(void) +{ + geometry_list = array_new(Geometry); + empty_indices = array_new(int); +} + +int geom_find(const char* filename) +{ + int index = -1; + for(int i = 0; i < (int)geometry_list->length; i++) + { + Geometry* geometry = array_get(geometry_list, i); + if(strcmp(geometry->filename, filename) == 0) + { + index = i; + break; + } + } + return index; +} + +int geom_create(const char* name) +{ + // check if exists + int index = geom_find(name); + if(index == -1) + { + /* add new geometry object or overwrite existing one */ + Geometry* new_geo = NULL; + int index = -1; + if(empty_indices->length != 0) + { + index = array_get_last_val(empty_indices, int); + array_pop(empty_indices); + new_geo = array_get(geometry_list, index); + } + else + { + new_geo = array_add(geometry_list); + index = geometry_list->length - 1; + } + assert(new_geo); + + + if(load_from_file(new_geo, name)) + { + create_vao(new_geo); + //generateBoundingBox(index); + } + else + { + /* TODO: Some error here, find it and fix it */ + array_pop(geometry_list); + index = -1; + } + } + else + { + Geometry* raw_geom_array = array_get_raw(geometry_list, Geometry); + raw_geom_array[index].ref_count++; + } + return index; +} + +void geom_remove(int index) +{ + if(index >= 0 && index < (int)geometry_list->length) + { + Geometry* geometry = array_get(geometry_list, index); + array_free(geometry->indices); + array_free(geometry->vertices); + array_free(geometry->uvs); + array_free(geometry->normals); + array_free(geometry->vertex_colors); + free(geometry->filename); + array_push(empty_indices, index, int); + } +} + +void geom_cleanup(void) +{ + for(uint i = 0; i < geometry_list->length; i++) + geom_remove(i); + + array_free(geometry_list); + array_free(empty_indices); +} + +bool load_from_file(Geometry* geometry, const char* filename) +{ + assert(filename); + bool success = true; + char* full_path = str_new("models/"); + full_path = str_concat(full_path, filename); + + FILE* file = io_file_open(full_path, "rb"); + free(full_path); + if(file) + { + const uint32 INDEX_SIZE = sizeof(uint32); + const uint32 VEC3_SIZE = sizeof(vec3); + const uint32 VEC2_SIZE = sizeof(vec2); + uint32 header[4]; + size_t bytes_read = 0; + if((bytes_read = fread(header, INDEX_SIZE, 4, file)) <= 0) + { + log_error("geometry:load_from_file", "Read failed"); + success = false; + } + else + { + uint32 indices_count = header[0]; + uint32 vertices_count = header[1]; + uint32 normals_count = header[2]; + uint32 uvs_count = header[3]; + // Indices + geometry->indices = array_new_cap(uint, indices_count); + fread(geometry->indices->data, INDEX_SIZE, indices_count, file); + // Vertices + geometry->vertices = array_new_cap(uint, vertices_count); + fread(geometry->vertices->data, VEC3_SIZE, vertices_count, file); + // Normals + geometry->normals = array_new_cap(uint, normals_count); + fread(&geometry->normals->data, VEC3_SIZE, normals_count, file); + // Uvs + geometry->uvs = array_new_cap(uint, uvs_count); + fread(&geometry->uvs->data, VEC2_SIZE, uvs_count, file); + } + fclose(file); + geometry->filename = str_new(filename); + geometry->draw_indexed = true; + geometry->ref_count++; + } + else + { + success = false; + } + + return success; +} + +void create_vao(Geometry* geometry) +{ + // TODO : Add support for different model formats and interleaving VBO + assert(geometry); + glGenVertexArrays(1, &geometry->vao); + glBindVertexArray(geometry->vao); + + glGenBuffers(1, &geometry->vertex_vbo); + glBindBuffer(GL_ARRAY_BUFFER, geometry->vertex_vbo); + glBufferData(GL_ARRAY_BUFFER, + geometry->vertices->length * sizeof(vec3), + geometry->vertices->data, + GL_STATIC_DRAW); + renderer_check_glerror("Geometry::create_vbo::vertex"); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + + if(geometry->normals->length > 0) + { + glGenBuffers(1, &geometry->normal_vbo); + glBindBuffer(GL_ARRAY_BUFFER, geometry->normal_vbo); + glBufferData(GL_ARRAY_BUFFER, + geometry->normals->length * sizeof(vec3), + geometry->normals->data, + GL_STATIC_DRAW); + renderer_check_glerror("Geometry::create_vbo::normal"); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, 0, 0); + } + + if(geometry->uvs->length > 0) + { + glGenBuffers(1, &geometry->uv_vbo); + glBindBuffer(GL_ARRAY_BUFFER, geometry->uv_vbo); + glBufferData(GL_ARRAY_BUFFER, + geometry->uvs->length * sizeof(vec2), + geometry->uvs->data, + GL_STATIC_DRAW); + renderer_check_glerror("Geometry::create_vbo::uv"); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0); + } + + if(geometry->vertex_colors->length > 0) + { + glGenBuffers(1, &geometry->color_vbo); + glBindBuffer(GL_ARRAY_BUFFER, geometry->color_vbo); + glBufferData(GL_ARRAY_BUFFER, + geometry->vertex_colors->length * sizeof(vec3), + geometry->vertex_colors->data, + GL_STATIC_DRAW); + renderer_check_glerror("Geometry::create_vbo::color"); + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, 0); + } + + if(geometry->indices->length > 0) + { + glGenBuffers(1, &geometry->index_vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->index_vbo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + geometry->indices->length * sizeof(GLuint), + geometry->indices->data, + GL_STATIC_DRAW); + geometry->draw_indexed = true; + } + glBindVertexArray(0); +} diff --git a/src/geometry.h b/src/geometry.h new file mode 100644 index 0000000..2f91238 --- /dev/null +++ b/src/geometry.h @@ -0,0 +1,10 @@ +#ifndef geometry_H +#define geometry_H + +void geom_initialize(void); +int geom_ceate(const char* name); +int geom_find(const char* filename); +void geom_remove(int index); +void geom_cleanup(void); + +#endif diff --git a/src/input.c b/src/input.c index 08b1d6c..b90bbbb 100644 --- a/src/input.c +++ b/src/input.c @@ -22,7 +22,6 @@ void input_init(GLFWwindow* window) glfwSetMouseButtonCallback(window, input_on_mousebutton); glfwSetKeyCallback(window, input_on_key); glfwSetCursorPosCallback(window, input_on_cursor_move); - glfwSetInputMode(window, GLFW_STICKY_KEYS, 1); input_map_list = array_new(Input_Map); } @@ -42,7 +41,7 @@ static void input_on_cursor_move(GLFWwindow* window, double xpos, double ypos) } -void input_get_cursor_pos(double* xpos, double* ypos) +void input_cursor_pos_get(double* xpos, double* ypos) { assert(xpos && ypos); GLFWwindow* window = window_get_active(); @@ -68,7 +67,9 @@ static void input_on_key(GLFWwindow* window, int key, int scancode, int action, static void input_on_mousebutton(GLFWwindow* window, int button, int action, int mods) { - + /* Probably add 'mouse maps', same as input maps for keyvboard but with buttons + Do we even need that? + */ } void input_cursor_mode_set(Cursor_Mode mode) @@ -98,7 +99,7 @@ bool input_map_state_get(const char* map_name, int state) return state == current_state ? true : false; } -bool inputkey_state_get(int key, int state_type) +bool input_key_state_get(int key, int state_type) { GLFWwindow* window = window_get_active(); int current_state = glfwGetKey(window, key); @@ -137,7 +138,7 @@ void input_update(void) } } -bool input_map_remvove(const char* name) +bool input_map_remove(const char* name) { assert(name); bool success = false; diff --git a/src/input.h b/src/input.h index 9becdc8..812cdae 100644 --- a/src/input.h +++ b/src/input.h @@ -13,7 +13,6 @@ typedef enum } Cursor_Mode; - typedef struct { Array* keys; @@ -31,7 +30,7 @@ void input_cursor_mode_set(Cursor_Mode mode); void input_update(void); bool input_map_state_get(const char* map_name, int state); void input_map_create(const char* name, int* keys, size_t num_keys); -bool input_map_remvove(const char* name); +bool input_map_remove(const char* name); bool input_map_keys_set(const char* name, int* keys, int num_keys); bool input_map_name_set(const char* name, const char* new_name); diff --git a/src/linmath.h b/src/linmath.h index 3216cd8..2a5c833 100644 --- a/src/linmath.h +++ b/src/linmath.h @@ -76,9 +76,9 @@ static inline void vec4_reflect(vec4 r, vec4 v, vec4 n) r[i] = v[i] - p*n[i]; } -typedef vec4 mat4x4[4]; +typedef vec4 mat4[4]; -static inline void mat4x4_identity(mat4x4 M) +static inline void mat4_identity(mat4 M) { int i, j; for(i=0; i<4; ++i) @@ -86,7 +86,7 @@ static inline void mat4x4_identity(mat4x4 M) M[i][j] = i==j ? 1.f : 0.f; } -static inline void mat4x4_dup(mat4x4 M, mat4x4 N) +static inline void mat4_dup(mat4 M, mat4 N) { int i, j; for(i=0; i<4; ++i) @@ -94,21 +94,21 @@ static inline void mat4x4_dup(mat4x4 M, mat4x4 N) M[i][j] = N[i][j]; } -static inline void mat4x4_row(vec4 r, mat4x4 M, int i) +static inline void mat4_row(vec4 r, mat4 M, int i) { int k; for(k=0; k<4; ++k) r[k] = M[k][i]; } -static inline void mat4x4_col(vec4 r, mat4x4 M, int i) +static inline void mat4_col(vec4 r, mat4 M, int i) { int k; for(k=0; k<4; ++k) r[k] = M[i][k]; } -static inline void mat4x4_transpose(mat4x4 M, mat4x4 N) +static inline void mat4_transpose(mat4 M, mat4 N) { int i, j; for(j=0; j<4; ++j) @@ -116,28 +116,28 @@ static inline void mat4x4_transpose(mat4x4 M, mat4x4 N) M[i][j] = N[j][i]; } -static inline void mat4x4_add(mat4x4 M, mat4x4 a, mat4x4 b) +static inline void mat4_add(mat4 M, mat4 a, mat4 b) { int i; for(i=0; i<4; ++i) vec4_add(M[i], a[i], b[i]); } -static inline void mat4x4_sub(mat4x4 M, mat4x4 a, mat4x4 b) +static inline void mat4_sub(mat4 M, mat4 a, mat4 b) { int i; for(i=0; i<4; ++i) vec4_sub(M[i], a[i], b[i]); } -static inline void mat4x4_scale(mat4x4 M, mat4x4 a, float k) +static inline void mat4_scale(mat4 M, mat4 a, float k) { int i; for(i=0; i<4; ++i) vec4_scale(M[i], a[i], k); } -static inline void mat4x4_scale_aniso(mat4x4 M, mat4x4 a, float x, float y, float z) +static inline void mat4_scale_aniso(mat4 M, mat4 a, float x, float y, float z) { int i; vec4_scale(M[0], a[0], x); @@ -148,19 +148,19 @@ static inline void mat4x4_scale_aniso(mat4x4 M, mat4x4 a, float x, float y, floa } } -static inline void mat4x4_mul(mat4x4 M, mat4x4 a, mat4x4 b) +static inline void mat4_mul(mat4 M, mat4 a, mat4 b) { - mat4x4 temp; + mat4 temp; int k, r, c; for(c=0; c<4; ++c) for(r=0; r<4; ++r) { temp[c][r] = 0.f; for(k=0; k<4; ++k) temp[c][r] += a[k][r] * b[c][k]; } - mat4x4_dup(M, temp); + mat4_dup(M, temp); } -static inline void mat4x4_mul_vec4(vec4 r, mat4x4 M, vec4 v) +static inline void mat4_mul_vec4(vec4 r, mat4 M, vec4 v) { int i, j; for(j=0; j<4; ++j) { @@ -170,101 +170,101 @@ static inline void mat4x4_mul_vec4(vec4 r, mat4x4 M, vec4 v) } } -static inline void mat4x4_translate(mat4x4 T, float x, float y, float z) +static inline void mat4_translate(mat4 T, float x, float y, float z) { - mat4x4_identity(T); + mat4_identity(T); T[3][0] = x; T[3][1] = y; T[3][2] = z; } -static inline void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z) +static inline void mat4_translate_in_place(mat4 M, float x, float y, float z) { vec4 t = {x, y, z, 0}; vec4 r; int i; for (i = 0; i < 4; ++i) { - mat4x4_row(r, M, i); + mat4_row(r, M, i); M[3][i] += vec4_mul_inner(r, t); } } -static inline void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 a, vec3 b) +static inline void mat4_from_vec3_mul_outer(mat4 M, vec3 a, vec3 b) { int i, j; for(i=0; i<4; ++i) for(j=0; j<4; ++j) M[i][j] = i<3 && j<3 ? a[i] * b[j] : 0.f; } -static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z, float angle) +static inline void mat4_rotate(mat4 R, mat4 M, float x, float y, float z, float angle) { float s = sinf(angle); float c = cosf(angle); vec3 u = {x, y, z}; if(vec3_len(u) > 1e-4) { vec3_norm(u, u); - mat4x4 T; - mat4x4_from_vec3_mul_outer(T, u, u); - mat4x4 S = { + mat4 T; + mat4_from_vec3_mul_outer(T, u, u); + mat4 S = { { 0, u[2], -u[1], 0}, {-u[2], 0, u[0], 0}, { u[1], -u[0], 0, 0}, { 0, 0, 0, 0} }; - mat4x4_scale(S, S, s); - mat4x4 C; - mat4x4_identity(C); - mat4x4_sub(C, C, T); - mat4x4_scale(C, C, c); - mat4x4_add(T, T, C); - mat4x4_add(T, T, S); + mat4_scale(S, S, s); + mat4 C; + mat4_identity(C); + mat4_sub(C, C, T); + mat4_scale(C, C, c); + mat4_add(T, T, C); + mat4_add(T, T, S); T[3][3] = 1.; - mat4x4_mul(R, M, T); + mat4_mul(R, M, T); } else { - mat4x4_dup(R, M); + mat4_dup(R, M); } } -static inline void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle) +static inline void mat4_rotate_X(mat4 Q, mat4 M, float angle) { float s = sinf(angle); float c = cosf(angle); - mat4x4 R = { + mat4 R = { {1.f, 0.f, 0.f, 0.f}, {0.f, c, s, 0.f}, {0.f, -s, c, 0.f}, {0.f, 0.f, 0.f, 1.f} }; - mat4x4_mul(Q, M, R); + mat4_mul(Q, M, R); } -static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle) +static inline void mat4_rotate_Y(mat4 Q, mat4 M, float angle) { float s = sinf(angle); float c = cosf(angle); - mat4x4 R = { + mat4 R = { { c, 0.f, s, 0.f}, { 0.f, 1.f, 0.f, 0.f}, { -s, 0.f, c, 0.f}, { 0.f, 0.f, 0.f, 1.f} }; - mat4x4_mul(Q, M, R); + mat4_mul(Q, M, R); } -static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle) +static inline void mat4_rotate_Z(mat4 Q, mat4 M, float angle) { float s = sinf(angle); float c = cosf(angle); - mat4x4 R = { + mat4 R = { { c, s, 0.f, 0.f}, { -s, c, 0.f, 0.f}, { 0.f, 0.f, 1.f, 0.f}, { 0.f, 0.f, 0.f, 1.f} }; - mat4x4_mul(Q, M, R); + mat4_mul(Q, M, R); } -static inline void mat4x4_invert(mat4x4 T, mat4x4 M) +static inline void mat4_invert(mat4 T, mat4 M) { float s[6]; float c[6]; @@ -300,9 +300,9 @@ static inline void mat4x4_invert(mat4x4 T, mat4x4 M) T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet; } -static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M) +static inline void mat4_orthonormalize(mat4 R, mat4 M) { - mat4x4_dup(R, M); + mat4_dup(R, M); float s = 1.; vec3 h; vec3_norm(R[2], R[2]); @@ -320,7 +320,7 @@ static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M) vec3_norm(R[0], R[0]); } -static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f) +static inline void mat4_frustum(mat4 M, float l, float r, float b, float t, float n, float f) { M[0][0] = 2.f*n/(r-l); M[0][1] = M[0][2] = M[0][3] = 0.f; @@ -334,7 +334,7 @@ static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, M[3][0] = M[3][1] = M[3][3] = 0.f; } -static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f) +static inline void mat4_ortho(mat4 M, float l, float r, float b, float t, float n, float f) { M[0][0] = 2.f/(r-l); M[0][1] = M[0][2] = M[0][3] = 0.f; @@ -348,7 +348,7 @@ static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, fl M[3][3] = 1.f; } -static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f) +static inline void mat4_perspective(mat4 m, float y_fov, float aspect, float n, float f) { /* NOTE: Degrees are an unhandy unit to work with. * linmath.h uses radians for everything! */ @@ -371,7 +371,7 @@ static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float m[3][3] = 0.f; } -static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up) +static inline void mat4_look_at(mat4 m, vec3 eye, vec3 center, vec3 up) { /* Adapted from Android's OpenGL Matrix.java. */ /* See the OpenGL GLUT documentation for gluLookAt for a description */ @@ -402,7 +402,7 @@ static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up) m[3][1] = 0.f; m[3][2] = 0.f; m[3][3] = 1.f; - mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]); + mat4_translate_in_place(m, -eye[0], -eye[1], -eye[2]); } typedef float quat[4]; @@ -482,7 +482,7 @@ static inline void quat_mul_vec3(vec3 r, quat q, vec3 v) quat_mul(r, q, r); } -static inline void mat4x4_from_quat(mat4x4 M, quat q) +static inline void mat4_from_quat(mat4 M, quat q) { float a = q[3]; float b = q[0]; @@ -508,7 +508,7 @@ static inline void mat4x4_from_quat(mat4x4 M, quat q) M[3][3] = 1.f; } -static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q) +static inline void mat4o_mul_quat(mat4 R, mat4 M, quat q) { /* XXX: The way this is written only works for othogonal matrices. */ /* TODO: Take care of non-orthogonal case. */ @@ -519,7 +519,7 @@ static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q) R[3][3] = 1.f; } -static inline void quat_from_mat4x4(quat q, mat4x4 M) +static inline void quat_from_mat4(quat q, mat4 M) { float r=0.f; int i; diff --git a/src/log.c b/src/log.c index 012bb21..9a755f6 100644 --- a/src/log.c +++ b/src/log.c @@ -13,6 +13,16 @@ void log_message(const char* message, ...) printf("\n"); } +void log_warning(const char* message, ...) +{ + printf("WRN : "); + va_list list; + va_start(list, message); + vprintf(message, list); + va_end(list); + printf("\n"); +} + void log_error(const char* context, const char* error, ...) { printf("ERR (%s) : ", context); diff --git a/src/log.h b/src/log.h index d9f939a..50d55b9 100644 --- a/src/log.h +++ b/src/log.h @@ -2,6 +2,7 @@ #define log_H void log_message(const char* message, ...); +void log_warning(const char* message, ...); void log_error(const char* context, const char* error, ...); #endif diff --git a/src/renderer.c b/src/renderer.c index 93d7dc0..8b696de 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -1,6 +1,8 @@ #include "renderer.h" #include "GLFW/glfw3.h" +#include "log.h" + void on_framebuffer_size_change(GLFWwindow* window, int width, int height); void renderer_init(GLFWwindow* window) @@ -28,3 +30,41 @@ void renderer_set_clearcolor(float red, float green, float blue, float alpha) { glClearColor(red, green, blue, alpha); } + +void renderer_check_glerror(const char* context) +{ + GLenum error = glGetError(); + const char* errorString = "No Error"; + switch(error) + { + case GL_INVALID_OPERATION: + errorString = "Invalid Operation"; + break; + case GL_NO_ERROR: + errorString = "No Error"; + break; + case GL_INVALID_ENUM: + errorString = "Invalid ENUM"; + break; + case GL_INVALID_VALUE: + errorString = "Invalid Value"; + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + errorString = "Invalid FrameBuffer Operation"; + break; + case GL_OUT_OF_MEMORY: + errorString = "Out of Memory"; + break; + case GL_STACK_UNDERFLOW: + errorString = "Stack Underflow"; + break; + case GL_STACK_OVERFLOW: + errorString = "Stack Overflow"; + break; + } + + if(error != GL_NO_ERROR) + { + log_error(context, errorString); + } +} diff --git a/src/renderer.h b/src/renderer.h index cf47f4c..97c4000 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -7,5 +7,6 @@ void renderer_init(GLFWwindow* window); void renderer_draw(void); void renderer_cleanup(void); void renderer_set_clearcolor(float r, float g, float b, float a); +void renderer_check_glerror(const char* context); #endif diff --git a/src/shader.c b/src/shader.c new file mode 100644 index 0000000..3363b38 --- /dev/null +++ b/src/shader.c @@ -0,0 +1,309 @@ +#include "shader.h" +#include "file_io.h" +#include "array.h" +#include "num_types.h" +#include "string_utils.h" +#include "log.h" +#include "renderer.h" + +#include +#include +#include +#include + +#include "GL/glew.h" +#include "GLFW/glfw3.h" + +typedef struct +{ + unsigned int vertex_shader; + unsigned int fragment_shader; + unsigned int program; + +} Shader_Object; + + +// Constants for locations of attributes inside all shaders +const int POSITION_LOC = 0; +const int NORMAL_LOC = 1; +const int UV_LOC = 2; +const int COLOR_LOC = 3; + +static Array* shader_list; +static Array* empty_indices; + +void debug_print_shader(const char* shaderText) +{ + size_t len = strlen(shaderText); + int line_count = 1; + printf("%d. ", line_count); + for(uint i = 0; i < len; i++) + { + if(shaderText[i] != '\n') + printf("%c", shaderText[i]); + else + printf("\n%d. ", ++line_count); + } + printf("\n END_DEBUG_PRINT\n\n"); +} + +char* run_preprocessor(char* shader_text) +{ + char* include_loc = strstr(shader_text, "//include"); + if(include_loc) + { + char* line_end = strchr(include_loc, '\n'); + int line_size = line_end - include_loc; + char* inc_line = malloc((sizeof(char) * line_size) + 1); + strncpy(inc_line, include_loc, line_size); + inc_line[line_size] = '\0'; + + char* filename = strtok(inc_line, " "); + while(filename) + { + filename = strtok(NULL, " "); + if(filename) + { + char* path = str_new("shaders/"); + path = str_concat(path, filename); + char* file = io_file_read(path); + char* shader_copy = str_new(shader_text); + char* temp = realloc(shader_text, (strlen(shader_text) + strlen(file) + 2)); + if(temp) + { + shader_text = temp; + strcpy(shader_text, file); + strcat(shader_text, shader_copy); + } + else + { + log_warning("Realloc failed in Shader::run_preprocessor"); + } + + free(path); + free(shader_copy); + free(file); + } + } + free(inc_line); + } + return shader_text; +} + +void shader_initialize(void) +{ + shader_list = array_new(Shader_Object); + empty_indices = array_new(int); +} + +int shader_create(const char* vert_shader_name, const char* frag_shader_name) +{ + char* vs_path = str_new("shaders/"); + vs_path = str_concat(vs_path, vert_shader_name); + char* fs_path = str_new("shaders/"); + fs_path = str_concat(fs_path, frag_shader_name); + + GLuint vert_shader = glCreateShader(GL_VERTEX_SHADER); + GLuint frag_shader = glCreateShader(GL_FRAGMENT_SHADER); + + char* vert_source = io_file_read(vs_path); + char* frag_source = io_file_read(fs_path); + + assert(vert_source != NULL); + assert(frag_source != NULL); + + vert_source = run_preprocessor(vert_source); + frag_source = run_preprocessor(frag_source); + + GLint v_size = (GLint)strlen(vert_source); + GLint f_size = (GLint)strlen(frag_source); + + const char* vert_sourcePtr = vert_source; + const char* frag_sourcePtr = frag_source; + + const GLint* vert_size = &v_size; + const GLint* frag_size = &f_size; + + glShaderSource(vert_shader, 1, &vert_sourcePtr, vert_size); + glShaderSource(frag_shader, 1, &frag_sourcePtr, frag_size); + + glCompileShader(vert_shader); + glCompileShader(frag_shader); + + GLint is_vert_compiled = 0; + GLint is_frag_compiled = 0; + glGetShaderiv(vert_shader, GL_COMPILE_STATUS, &is_vert_compiled); + glGetShaderiv(frag_shader, GL_COMPILE_STATUS, &is_frag_compiled); + + if(!is_vert_compiled) + { + GLint log_size = 0; + glGetShaderiv(vert_shader, GL_INFO_LOG_LENGTH, &log_size); + char* message = (char *)malloc(sizeof(char) * log_size); + glGetShaderInfoLog(vert_shader, log_size, NULL, message); + + log_error("shader:create", "COMPILING VS %s : %s", vert_shader_name, message); + debug_print_shader(vert_source); + free(message); + } + + if(!is_frag_compiled) + { + GLint log_size = 0; + glGetShaderiv(frag_shader, GL_INFO_LOG_LENGTH, &log_size); + char* message = (char *)malloc(sizeof(char) * log_size); + glGetShaderInfoLog(frag_shader, log_size, NULL, message); + + log_error("shader:create", "COMPILING FS %s : %s", frag_shader_name, message); + debug_print_shader(frag_source); + free(message); + } + + free(vert_source); + free(frag_source); + + if(!is_vert_compiled || !is_frag_compiled) + { + glDeleteShader(vert_shader); + glDeleteShader(frag_shader); + return -1; + } + + GLuint program = glCreateProgram(); + glAttachShader(program, vert_shader); + glAttachShader(program, frag_shader); + + // Bind attribute locations + glBindAttribLocation(program, POSITION_LOC, "vPosition"); + glBindAttribLocation(program, NORMAL_LOC, "vNormal"); + glBindAttribLocation(program, UV_LOC, "vUV"); + glBindAttribLocation(program, COLOR_LOC, "vColor"); + renderer_check_glerror("shader:create"); + glLinkProgram(program); + + GLint is_linked = 0; + glGetProgramiv(program, GL_LINK_STATUS, &is_linked); + if(!is_linked) + { + GLint log_size = 0; + glGetProgramiv(program, GL_LINK_STATUS, &log_size); + char* message = (char *)malloc(sizeof(char) * log_size); + glGetProgramInfoLog(program, log_size, NULL, message); + log_error("shader:create", "LINK SHADER : %s", message); + free(message); + + glDeleteProgram(program); + glDeleteShader(vert_shader); + glDeleteShader(frag_shader); + + return -1; + } + + /* add new object or overwrite existing one */ + Shader_Object* new_object = NULL; + int index = -1; + if(empty_indices->length != 0) + { + index = array_get_last_val(empty_indices, int); + array_pop(empty_indices); + new_object = array_get(shader_list, index); + } + else + { + new_object = array_add(shader_list); + index = shader_list->length - 1; + } + assert(new_object); + new_object->vertex_shader = vert_shader; + new_object->fragment_shader = frag_shader; + new_object->program = program; + + log_message("%s, %s compiled into shader program", vert_shader_name, frag_shader_name); + free(vs_path); + free(fs_path); + + return index; +} + +void shader_bind(const int shader_index) +{ + Shader_Object* shader_object = array_get(shader_list, shader_index); + glUseProgram(shader_object->program); +} + +void shader_unbind(void) +{ + glUseProgram(0); +} + +int get_uniform_location(const int shader_index, const char* name) +{ + Shader_Object shader_object = array_get_val(shader_list, Shader_Object, shader_index); + GLint handle = glGetUniformLocation(shader_object.program, name); + + if(handle == -1) + log_error("shader:get_uniform_location", "Invalid uniform %s", name); + + return handle; +} + +void set_uniform_int(const int shader_index, const char* name, const int value) +{ + GLint location = get_uniform_location(shader_index, name); + if(location >= 0) + glUniform1i(location, value); +} + +void set_uniform_float(const int shader_index, const char* name, const float value) +{ + GLint location = get_uniform_location(shader_index, name); + if(location >= 0) + glUniform1f(location, value); +} + +void set_uniform_vec2(const int shader_index, const char* name, const vec2 value) +{ + GLint location = get_uniform_location(shader_index, name); + if(location >= 0) + glUniform2fv(location, 1, value); +} + +void set_uniform_vec3(const int shader_index, const char* name, const vec3 value) +{ + GLint location = get_uniform_location(shader_index, name); + if(location >= 0) + glUniform3fv(location, 1, value); +} + +void set_uniform_vec4(const int shader_index, const char* name, const vec4 value) +{ + GLint location = get_uniform_location(shader_index, name); + if(location >= 0) + glUniform4fv(location, 1, value); +} + +void setUniformMat4(const int shader_index, const char* name, const mat4 value) +{ + GLint location = get_uniform_location(shader_index, name); + if(location >= 0) + glUniformMatrix4fv(location, 1, GL_FALSE, *value); +} + +void shader_remove(const int shader_index) +{ + Shader_Object* shader_object = array_get(shader_list, shader_index); + glDeleteProgram(shader_object->program); + glDeleteShader(shader_object->vertex_shader); + glDeleteShader(shader_object->fragment_shader); + shader_object->fragment_shader = shader_object->vertex_shader = shader_object->program = -1; + array_push(empty_indices, shader_index, int); +} + +void shader_cleanup(void) +{ + for(int i = 0; i < (int)shader_list->length; i++) + shader_remove(i); + + array_free(shader_list); + array_free(empty_indices); +} diff --git a/src/shader.h b/src/shader.h new file mode 100644 index 0000000..3b17cbe --- /dev/null +++ b/src/shader.h @@ -0,0 +1,20 @@ +#ifndef shader_H +#define shader_H + +#include "linmath.h" + +int shader_create(const char* vert_shader_name, const char* frag_shader_name); +void shader_initialize(void); +void shader_bind(const int shader_index); +void shader_remove(const int shader_index); +void shader_unbind(void); +void shader_set_uniform_int(const int shaderIndex, const char* name, const int value); +void shader_set_uniform_float(const int shaderIndex, const char* name, const float value); +void shader_set_uniform_vec2(const int shaderIndex, const char* name, const vec2 value); +void shader_set_uniform_vec3(const int shaderIndex, const char* name, const vec3 value); +void shader_set_uniform_vec4(const int shaderIndex, const char* name, const vec4 value); +void shader_set_uniform_mat4(const int shaderIndex, const char* name, const mat4 value); +void shader_cleanup(void); +int shader_uniform_location_get(const int shader_index, const char* name); + +#endif diff --git a/src/string_utils.c b/src/string_utils.c index 41ee8ae..128070a 100644 --- a/src/string_utils.c +++ b/src/string_utils.c @@ -98,10 +98,3 @@ char* str_replace(char* string, const char* pattern, const char* replacement) return NULL; } } - - - - - - -