diff --git a/src/application.c b/src/application.c index 3a0f915..a923807 100644 --- a/src/application.c +++ b/src/application.c @@ -36,7 +36,10 @@ int init_application(Application* app, const char* name) app->scenes = (Scene*)malloc(1 * sizeof(Scene)); app->active_scene = app->scenes; // First scene is active scene - create_spinning_cubes_scene(&app->window, app->scenes); + if (create_spinning_cubes_scene(&app->window, app->scenes) != 0) + { + return 1; + } return 0; } diff --git a/src/objects/cube.c b/src/objects/cube.c index 9ff5983..a141531 100644 --- a/src/objects/cube.c +++ b/src/objects/cube.c @@ -4,7 +4,6 @@ #include static VertexArrayObject* vao = NULL; -static Shader shader = 0; static size_t num_cubes = 0; static int init_cube_object(void) @@ -78,72 +77,10 @@ static int init_cube_object(void) }; set_vertex_layout(vao, attributes, sizeof(attributes) / sizeof(VertexAttribute)); - shader = create_shader( - "#version 460 core\n" - "" - "layout (location = 0) in vec3 pos;" - "layout (location = 1) in vec3 normal;" - "" - "out vec3 frag_normal;" - "out vec3 frag_pos;" - "" - "uniform mat4 model;" - "uniform mat4 view;" - "uniform mat4 projection;" - "" - "void main() {" - " frag_normal = mat3(transpose(inverse(model))) * normal;" - " frag_pos = vec3(model * vec4(pos, 1.0));" - " gl_Position = projection * view * model * vec4(pos, 1.0);" - "}", - - "#version 460 core\n" - "" - "in vec3 frag_pos;" - "in vec3 frag_normal;" - "" - "uniform vec3 ambient_color = vec3(1.0, 1.0, 1.0);" - "uniform float ambient_intens = 1.0f;" - "" - "uniform vec3 point_pos = vec3(0.0, 0.0, 0.0);" - "uniform vec3 point_col = vec3(1.0, 1.0, 1.0);" - "uniform float point_intens = 1.0f;" - "" - "uniform vec3 cam_pos = vec3(0.0, 0.0, 0.0);" - "float specular_strength = 0.5f;" - "" - "uniform vec3 cube_color;" - "" - "out vec4 FragColor;" - "" - "void main() {" - " vec3 ambient = ambient_intens * ambient_color;" - "" - " vec3 norm = normalize(frag_normal);" - " vec3 light_dir = normalize(point_pos - frag_pos);" - " float diff = max(dot(norm, light_dir), 0.0);" - " vec3 diffuse = diff * point_col;" - "" - " vec3 view_dir = normalize(cam_pos - frag_pos);" - " vec3 reflect_dir = reflect(-light_dir, norm);" - "" - " float spec = pow(max(dot(view_dir, reflect_dir), 0.0), 32);" - " vec3 specular = specular_strength * spec * point_col; " - "" - " vec3 result = (ambient + diffuse + specular) * cube_color;" - " FragColor = vec4(result, 1.0);" - "}" - ); - if (shader == 0) - { - fprintf(stderr, "failed to create shader for cube\n"); - return 1; - } - return 0; } -static void on_shader_bind(Cube* cube) +static void on_shader_bind(Cube* cube, Shader* shader) { set_uniform_vec3(shader, "cube_color", cube->color); } @@ -171,7 +108,7 @@ static void on_update(Cube* cube) int create_cube(Cube* cube) { - if (vao == NULL || shader == 0) + if (vao == NULL) { if (init_cube_object() != 0) { @@ -187,7 +124,6 @@ int create_cube(Cube* cube) cube->color_mod[2] = 0.005f; cube->object.vao = vao; - cube->object.shader = shader; cube->object.child = cube; cube->object.on_shader_use_obj = on_shader_bind; @@ -203,9 +139,6 @@ void destroy_cube(Cube* cube) if (num_cubes == 0) { - destroy_shader(shader); - shader = 0; - destroy_vao(*vao); vao = NULL; } diff --git a/src/renderer/object.c b/src/renderer/object.c index c3f6848..30cd255 100644 --- a/src/renderer/object.c +++ b/src/renderer/object.c @@ -17,10 +17,8 @@ void update_object(Object* obj) obj->on_update(obj->child); } -void render_object(Object* obj, Camera* camera) +void render_object(Object* obj, Shader* shader) { - bind_shader(obj->shader); - glm_mat4_identity(obj->transform); float angle = glm_vec3_norm(obj->rotation); vec3 normalized_rot; @@ -30,12 +28,9 @@ void render_object(Object* obj, Camera* camera) glm_rotate(obj->transform, angle, normalized_rot); glm_scale(obj->transform, obj->scale); - set_uniform_mat4(obj->shader, "model", obj->transform); - set_uniform_mat4(obj->shader, "view", get_camera_view(camera)); - set_uniform_mat4(obj->shader, "projection", camera->projection); + set_uniform_mat4(shader, "model", obj->transform); - obj->on_shader_use_obj(obj->child); - obj->on_shader_use_scene(obj, obj->scene); + obj->on_shader_use_obj(obj->child, shader); ctx_draw_elements(obj->vao); } diff --git a/src/renderer/object.h b/src/renderer/object.h index 100f62f..3150aca 100644 --- a/src/renderer/object.h +++ b/src/renderer/object.h @@ -11,7 +11,6 @@ typedef struct Camera Camera; typedef struct Object { VertexArrayObject* vao; - Shader shader; mat4 transform; vec3 position; @@ -20,8 +19,7 @@ typedef struct Object void* child; void* scene; - void(*on_shader_use_obj)(void*); - void(*on_shader_use_scene)(void*, void*); + void(*on_shader_use_obj)(void*, void*); void(*on_update)(void*); void(*on_destroy)(void*); } Object; @@ -33,6 +31,6 @@ void object_set_position(Object* obj, vec3 position); void object_move(Object* obj, vec3 direction); void update_object(Object* obj); -void render_object(Object* obj, Camera* camera); +void render_object(Object* obj, Shader* shader); #endif // OBJECT_H \ No newline at end of file diff --git a/src/renderer/shader.c b/src/renderer/shader.c index 9462458..8bc41a0 100644 --- a/src/renderer/shader.c +++ b/src/renderer/shader.c @@ -4,8 +4,11 @@ #include #include #include + #include +#include "object.h" + static int set_and_compile_shader(GLuint program, GLuint shader, const char* code, char** error) { int result; @@ -32,47 +35,54 @@ static int set_and_compile_shader(GLuint program, GLuint shader, const char* cod return 0; } -Shader create_shader(const char* vertex_shader_code, const char* fragment_shader_code) +int create_shader(Shader* shader, const char* vertex_shader_code, const char* fragment_shader_code) { + assert(shader); assert(vertex_shader_code && fragment_shader_code); - int shader = glCreateProgram(); + int return_val = 0; + + shader->objects = create_dynamic_array(Object*); + shader->id = glCreateProgram(); char* error; int vertex_shader = glCreateShader(GL_VERTEX_SHADER); - if (set_and_compile_shader(shader, vertex_shader, vertex_shader_code, &error) != 0) + if (set_and_compile_shader(shader->id, vertex_shader, vertex_shader_code, &error) != 0) { fprintf(stderr, "vertex shader compilation failed: %s\n", error); free(error); - glDeleteProgram(shader); - shader = 0; + glDeleteProgram(shader->id); + shader->id = 0; + return_val = 1; goto vertex_failed; } int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - if (set_and_compile_shader(shader, fragment_shader, fragment_shader_code, &error) != 0) + if (set_and_compile_shader(shader->id, fragment_shader, fragment_shader_code, &error) != 0) { fprintf(stderr, "fragment shader compilation failed: %s\n", error); free(error); - glDeleteProgram(shader); - shader = 0; + glDeleteProgram(shader->id); + shader->id = 0; + return_val = 1; goto fragment_failed; } - glLinkProgram(shader); + glLinkProgram(shader->id); int result; glGetProgramiv(shader, GL_LINK_STATUS, &result); if (result == GL_FALSE) { char error[512]; - glGetProgramInfoLog(shader, 512, NULL, error); + glGetProgramInfoLog(shader->id, 512, NULL, error); fprintf(stderr, "shader linking failed: %s\n", error); glDeleteProgram(shader); - shader = 0; + shader->id = 0; + return_val = 1; } fragment_failed: @@ -80,33 +90,49 @@ fragment_failed: vertex_failed: glDeleteShader(vertex_shader); - return shader; + return return_val; } void destroy_shader(Shader shader) { - glDeleteProgram(shader); + destroy_dynamic_array(shader.objects); + glDeleteProgram(shader.id); } -void bind_shader(Shader shader) +void bind_shader(Shader* shader) { - glUseProgram(shader); + dynamic_array_clear(&shader->objects); + glUseProgram(shader->id); } -void set_uniform_mat4(Shader shader, const char* name, mat4 mat) +void shader_add_object(Shader* shader, Object* object) { - int location = glGetUniformLocation(shader, name); + dynamic_array_push(&shader->objects, (void*)&object); +} + +void shader_render(Shader* shader) +{ + for (int i = 0; i < shader->objects.size; i++) + { + Object* obj = *(Object**)dynamic_array_get(&shader->objects, i); + render_object(obj, shader); + } +} + +void set_uniform_mat4(Shader* shader, const char* name, mat4 mat) +{ + int location = glGetUniformLocation(shader->id, name); glUniformMatrix4fv(location, 1, GL_FALSE, (float*)mat); } -void set_uniform_float(Shader shader, const char* name, float val) +void set_uniform_float(Shader* shader, const char* name, float val) { - int location = glGetUniformLocation(shader, name); + int location = glGetUniformLocation(shader->id, name); glUniform1f(location, val); } -void set_uniform_vec3(Shader shader, const char* name, vec3 vec) +void set_uniform_vec3(Shader* shader, const char* name, vec3 vec) { - int location = glGetUniformLocation(shader, name); + int location = glGetUniformLocation(shader->id, name); glUniform3fv(location, 1, vec); } diff --git a/src/renderer/shader.h b/src/renderer/shader.h index 7dab914..fd8e8b5 100644 --- a/src/renderer/shader.h +++ b/src/renderer/shader.h @@ -2,16 +2,25 @@ #define SHADER_H #include +#include "util/dynarray.h" -typedef int Shader; +typedef struct Object Object; -Shader create_shader(const char* vertex_shader_code, const char* fragment_shader_code); +typedef struct Shader +{ + int id; + DynamicArray objects; +} Shader; + +int create_shader(Shader* shader, const char* vertex_shader_code, const char* fragment_shader_code); void destroy_shader(Shader shader); -void bind_shader(Shader shader); +void bind_shader(Shader* shader); +void shader_add_object(Shader* shader, Object* object); +void shader_render(Shader* shader); -void set_uniform_mat4(Shader shader, const char* name, mat4 mat); -void set_uniform_float(Shader shader, const char* name, float val); -void set_uniform_vec3(Shader shader, const char* name, vec3 vec); +void set_uniform_mat4(Shader* shader, const char* name, mat4 mat); +void set_uniform_float(Shader* shader, const char* name, float val); +void set_uniform_vec3(Shader* shader, const char* name, vec3 vec); #endif // SHADER_H \ No newline at end of file diff --git a/src/scene.c b/src/scene.c index 5378996..f405141 100644 --- a/src/scene.c +++ b/src/scene.c @@ -8,20 +8,6 @@ #include "objects/cube.h" -static void set_lighting_uniforms(Object* obj, Scene* scene) -{ - Shader shader = obj->shader; - - set_uniform_vec3(shader, "ambient_color", scene->ambient_light.color); - set_uniform_float(shader, "ambient_intens", scene->ambient_light.intensity); - - set_uniform_vec3(shader, "point_pos", scene->point_light.position); - set_uniform_vec3(shader, "point_col", scene->point_light.color); - set_uniform_float(shader, "point_intens", scene->point_light.intensity); - - set_uniform_vec3(shader, "cam_pos", scene->camera.object.position); -} - int create_scene(Scene* scene) { assert(scene); @@ -32,29 +18,13 @@ int create_scene(Scene* scene) return 1; } - scene->objects = create_dynamic_array(Object*); scene->on_update = NULL; scene->last_frame_start = glfwGetTime(); } void destroy_scene(Scene scene) { - for (size_t i = 0; i < scene.objects.size; i++) - { - Object* obj = *(Object**)dynamic_array_get(&scene.objects, i); - destroy_object(*obj); - } - - destroy_dynamic_array(scene.objects); -} - -void scene_add_object(Scene* scene, Object* object) -{ - assert(scene); - - object->scene = scene; - object->on_shader_use_scene = set_lighting_uniforms; - dynamic_array_push(&scene->objects, (void*)&object); + } void scene_update_size(Scene* scene, int width, int height) @@ -63,6 +33,12 @@ void scene_update_size(Scene* scene, int width, int height) set_camera_perspective(&scene->camera, 90.0f, (float)width / (float)height); } +void scene_set_camera_uniforms(Scene* scene, Shader* shader) +{ + set_uniform_mat4(shader, "view", get_camera_view(&scene->camera)); + set_uniform_mat4(shader, "projection", scene->camera.projection); +} + void update_scene(Scene* scene) { double frametime = glfwGetTime() - scene->last_frame_start; @@ -76,10 +52,5 @@ void render_scene(Scene* scene) assert(scene); ctx_clear_screen(0.0f, 0.0f, 0.0f, 1.0f); - for (size_t i = 0; i < scene->objects.size; i++) - { - Object* obj = *(Object**)dynamic_array_get(&scene->objects, i); - update_object(obj); - render_object(obj, &scene->camera); - } + scene->on_render(scene); } diff --git a/src/scene.h b/src/scene.h index 8640c9b..944d11a 100644 --- a/src/scene.h +++ b/src/scene.h @@ -11,21 +11,18 @@ typedef struct Scene { Camera camera; - DynamicArray objects; - - AmbientLight ambient_light; - PointLight point_light; void* child; void(*on_update)(void*, double); + void(*on_render)(void*); double last_frame_start; } Scene; int create_scene(Scene* scene); void destroy_scene(Scene scene); -void scene_add_object(Scene* scene, Object* object); void scene_update_size(Scene* scene, int width, int height); +void scene_set_camera_uniforms(Scene* scene, Shader* shader); void update_scene(Scene* scene); void render_scene(Scene* scene); diff --git a/src/scenes/spinning_cubes.c b/src/scenes/spinning_cubes.c index 7ca7471..6b90769 100644 --- a/src/scenes/spinning_cubes.c +++ b/src/scenes/spinning_cubes.c @@ -9,9 +9,73 @@ #include "objects/cube.h" #include "application.h" +#include "renderer/object.h" + +static const char* vertex_shader = +"#version 460 core\n" +"" +"layout (location = 0) in vec3 pos;" +"layout (location = 1) in vec3 normal;" +"" +"out vec3 frag_normal;" +"out vec3 frag_pos;" +"" +"uniform mat4 model;" +"uniform mat4 view;" +"uniform mat4 projection;" +"" +"void main() {" +" frag_normal = mat3(transpose(inverse(model))) * normal;" +" frag_pos = vec3(model * vec4(pos, 1.0));" +" gl_Position = projection * view * model * vec4(pos, 1.0);" +"}"; + +static const char* fragment_shader = +"#version 460 core\n" +"" +"in vec3 frag_pos;" +"in vec3 frag_normal;" +"" +"uniform vec3 ambient_color = vec3(1.0, 1.0, 1.0);" +"uniform float ambient_intens = 1.0f;" +"" +"uniform vec3 point_pos = vec3(0.0, 0.0, 0.0);" +"uniform vec3 point_col = vec3(1.0, 1.0, 1.0);" +"uniform float point_intens = 1.0f;" +"" +"uniform vec3 cam_pos = vec3(0.0, 0.0, 0.0);" +"float specular_strength = 0.5f;" +"" +"uniform vec3 cube_color;" +"" +"out vec4 FragColor;" +"" +"void main() {" +" vec3 ambient = ambient_intens * ambient_color;" +"" +" vec3 norm = normalize(frag_normal);" +" vec3 light_dir = normalize(point_pos - frag_pos);" +" float diff = max(dot(norm, light_dir), 0.0);" +" vec3 diffuse = diff * point_col;" +"" +" vec3 view_dir = normalize(cam_pos - frag_pos);" +" vec3 reflect_dir = reflect(-light_dir, norm);" +"" +" float spec = pow(max(dot(view_dir, reflect_dir), 0.0), 32);" +" vec3 specular = specular_strength * spec * point_col; " +"" +" vec3 result = (ambient + diffuse + specular) * cube_color;" +" FragColor = vec4(result, 1.0);" +"}"; typedef struct SpinningCubes { + Shader cube_shader; + DynamicArray objects; + + AmbientLight ambient_light; + PointLight point_light; + struct { double x, y; } last_cursor_pos; @@ -23,6 +87,20 @@ typedef struct SpinningCubes double time; } SpinningCubes; +static void set_lighting_uniforms(Shader* shader, Scene* scene) +{ + SpinningCubes* data = scene->child; + + set_uniform_vec3(shader, "ambient_color", data->ambient_light.color); + set_uniform_float(shader, "ambient_intens", data->ambient_light.intensity); + + set_uniform_vec3(shader, "point_pos", data->point_light.position); + set_uniform_vec3(shader, "point_col", data->point_light.color); + set_uniform_float(shader, "point_intens", data->point_light.intensity); + + set_uniform_vec3(shader, "cam_pos", scene->camera.object.position); +} + static void init_spinning_cubes_data(SpinningCubes* scene) { assert(scene); @@ -31,6 +109,8 @@ static void init_spinning_cubes_data(SpinningCubes* scene) scene->dragging = false; scene->drag_speed = 0.01f; scene->time = 0.0f; + + scene->objects = create_dynamic_array(Object*); } static void get_arcball_vector(vec3 dest, double width, double height, double x, double y) @@ -113,23 +193,48 @@ static void mouse_moved_callback(GLFWwindow* window, double xpos, double ypos) static void on_update(Scene* scene, double frametime) { SpinningCubes* data = scene->child; + + for (int i = 0; i < data->objects.size; i++) + { + Object* obj = *(Object**)dynamic_array_get(&data->objects, i); + update_object(obj); + } + vec3 cam_pos = { 6.0f * sin(2.0f * data->time), 3.5f * cos(data->time), 6.0f * cos(2.0f * data->time)}; object_set_position(&scene->camera.object, cam_pos); data->time += frametime; - glm_vec3_copy(scene->camera.object.position, scene->point_light.position); + glm_vec3_copy(scene->camera.object.position, data->point_light.position); } -void create_spinning_cubes_scene(Window* window, Scene* scene) +static void on_render(Scene* scene) +{ + SpinningCubes* data = scene->child; + + bind_shader(&data->cube_shader); + set_lighting_uniforms(&data->cube_shader, scene); + scene_set_camera_uniforms(scene, &data->cube_shader); + + for (int i = 0; i < data->objects.size; i++) + { + shader_add_object(&data->cube_shader, *(Object**)dynamic_array_get(&data->objects, i)); + } + + shader_render(&data->cube_shader); +} + +int create_spinning_cubes_scene(Window* window, Scene* scene) { assert(scene); create_scene(scene); scene->on_update = on_update; + scene->on_render = on_render; scene->child = malloc(sizeof(SpinningCubes)); init_spinning_cubes_data(scene->child); + SpinningCubes* data = scene->child; for (int i = 0; i < 4; i++) { Cube* obj = (Cube*)malloc(sizeof(Cube)); @@ -140,22 +245,31 @@ void create_spinning_cubes_scene(Window* window, Scene* scene) 0.0f, ((i < 2) ? -1 : 1) * 1.5 }; + object_set_position(&obj->object, position); - scene_add_object(scene, &obj->object); + Object* raw_obj = &obj->object; + dynamic_array_push(&data->objects, (void*)&raw_obj); + } + + if(create_shader(&data->cube_shader, vertex_shader, fragment_shader) != 0) + { + fprintf(stderr, "failed to create shader for cube\n"); + return 1; } vec3 cam_pos = { 0.0f, 3.5f, 3.0 }; object_set_position(&scene->camera.object, cam_pos); glm_vec3_zero(&scene->camera.look_at); + glm_vec3_one(data->ambient_light.color); + data->ambient_light.intensity = 0.1f; - glm_vec3_one(scene->ambient_light.color); - scene->ambient_light.intensity = 0.1f; - - glm_vec3_one(scene->point_light.color); - scene->point_light.intensity = 1.0f; + glm_vec3_one(data->point_light.color); + data->point_light.intensity = 1.0f; glfwSetMouseButtonCallback(window->window, mouse_button_callback); glfwSetCursorPosCallback(window->window, mouse_moved_callback); + + return 0; } diff --git a/src/scenes/spinning_cubes.h b/src/scenes/spinning_cubes.h index a239879..646db46 100644 --- a/src/scenes/spinning_cubes.h +++ b/src/scenes/spinning_cubes.h @@ -4,6 +4,6 @@ #include "scene.h" #include "renderer/window.h" -void create_spinning_cubes_scene(Window* window, Scene* scene); +int create_spinning_cubes_scene(Window* window, Scene* scene); #endif // SCENE_SPINNING_CUBES_H \ No newline at end of file diff --git a/src/util/dynarray.c b/src/util/dynarray.c index 9b9f5f9..0c129d7 100644 --- a/src/util/dynarray.c +++ b/src/util/dynarray.c @@ -36,6 +36,14 @@ void* dynamic_array_get(DynamicArray* array, size_t i) return (void*)((char*)array->data + (i * array->element_size)); } +void dynamic_array_clear(DynamicArray* array) +{ + array->capacity = 5; + array->size = 0; + + array->data = realloc(array->data, array->element_size * array->capacity); +} + void dynamic_array_push(DynamicArray* array, void* element) { assert(array->capacity > 0); diff --git a/src/util/dynarray.h b/src/util/dynarray.h index 3b3cb42..19c565d 100644 --- a/src/util/dynarray.h +++ b/src/util/dynarray.h @@ -18,6 +18,7 @@ DynamicArray create_dynamic_array_from_size(size_t type_size); void destroy_dynamic_array(DynamicArray array); void* dynamic_array_get(DynamicArray* array, size_t i); +void dynamic_array_clear(DynamicArray* array); void dynamic_array_push(DynamicArray* array, void* element); void dynamic_array_pop(DynamicArray* array);