From 67101e29f9aec30482b29f519905f04d65532de9 Mon Sep 17 00:00:00 2001 From: Lauchmelder Date: Tue, 18 Oct 2022 18:43:15 +0200 Subject: [PATCH] added scene abstraction --- src/CMakeLists.txt | 6 ++ src/application.c | 110 +++--------------------------- src/application.h | 10 +-- src/objects/cube.c | 149 +++++++++++++++++++++++++++++++++++++++++ src/objects/cube.h | 15 +++++ src/renderer/buffer.c | 13 ++-- src/renderer/buffer.h | 3 +- src/renderer/camera.c | 2 +- src/renderer/context.c | 2 +- src/renderer/object.c | 44 ++++++++++++ src/renderer/object.h | 32 +++++++++ src/renderer/shader.c | 16 +++-- src/renderer/shader.h | 12 ++-- src/renderer/window.c | 2 + src/scene.c | 48 +++++++++++++ src/scene.h | 21 ++++++ 16 files changed, 362 insertions(+), 123 deletions(-) create mode 100644 src/objects/cube.c create mode 100644 src/objects/cube.h create mode 100644 src/renderer/object.c create mode 100644 src/renderer/object.h create mode 100644 src/scene.c create mode 100644 src/scene.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2628c2d..09b5d97 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,13 +7,19 @@ cmake_minimum_required (VERSION 3.8) add_executable(solver "main.c" "application.c" + "scene.c" "renderer/window.c" "renderer/context.c" "renderer/buffer.c" "renderer/shader.c" "renderer/camera.c" + "objects/cube.c" "renderer/object.c") + +target_include_directories(solver PRIVATE + ${CMAKE_CURRENT_LIST_DIR} ) + target_link_libraries(solver PRIVATE glfw glad diff --git a/src/application.c b/src/application.c index a24a6a4..cc77974 100644 --- a/src/application.c +++ b/src/application.c @@ -3,22 +3,19 @@ #include #include -#include -#include - #include "renderer/context.h" +#include "objects/cube.h" static void on_window_size_change(Application* app, int width, int height) { - set_camera_perspective(&app->camera, 90.0f, (float)width / (float)height); + scene_update_size(app->active_scene, width, height); } static void destroy_application(Application* app) { assert(app); - destroy_vao(app->object); - destroy_window(app->window); + destroy_scene(*app->scenes); } int init_application(Application* app, const char* name) @@ -35,91 +32,14 @@ int init_application(Application* app, const char* name) app->window.user_data = app; app->window.on_size_change = on_window_size_change; - // Create quad for testing - create_vao(&app->object); + app->scenes = (Scene*)malloc(1 * sizeof(Scene)); + app->active_scene = app->scenes; // First scene is active scene - float vertices[] = { - -0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, // front bottom left - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // front top left - 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // front top right - 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, // front bottom right + create_scene(app->scenes); + Cube* obj = (Cube*)malloc(sizeof(Cube)); + create_cube(obj); - -0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, // back bottom left - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, // back top left - 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // back top right - 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, // back bottom right - }; - attach_vertex_buffer(&app->object, vertices, sizeof(vertices)); - - unsigned indices[] = { - 0, 1, 2, // front - 0, 2, 3, - - 3, 2, 6, // right - 3, 6, 7, - - 4, 5, 1, // left - 4, 1, 0, - - 7, 6, 5, // back - 7, 5, 4, - - 1, 5, 6, // top - 1, 6, 2, - - 4, 0, 3, // bottom - 4, 3, 7 - }; - attach_element_buffer(&app->object, indices, sizeof(indices)); - - VertexAttribute layout[] = { - { GL_FLOAT, 3, 3 * sizeof(float) }, - { GL_FLOAT, 3, 3 * sizeof(float) } - }; - set_vertex_layout(&app->object, layout, sizeof(layout) / sizeof(VertexAttribute)); - - app->shader = create_shader( - "#version 460 core\n" - "" - "layout (location = 0) in vec3 pos;" - "layout (location = 1) in vec3 col;" - "" - "out vec3 i_col;" - "" - "uniform mat4 model;" - "uniform mat4 view;" - "uniform mat4 projection;" - "" - "void main() {" - " i_col = col;" - " gl_Position = projection * view * model * vec4(pos, 1.0);" - "}", - - "#version 460 core\n" - "" - "in vec3 i_col;" - "out vec4 FragColor;" - "" - "void main() {" - " FragColor = vec4(i_col, 1.0);" - "}" - ); - if(app->shader == 0) - { - destroy_application(app); - return 1; - } - - if (create_camera(&app->camera) != 0) - { - destroy_application(app); - return 1; - } - - glm_mat4_identity(app->model); - - ctx_enable(GL_DEPTH_TEST); - ctx_front_face(GL_CW); + scene_add_object(app->active_scene, &obj->object); return 0; } @@ -130,17 +50,7 @@ int launch_application(Application* app) { glfwPollEvents(); - // rotate cube - glm_rotate(app->model, 0.03f, (vec3) { 0.0f, 1.0f, 0.0f }); - - ctx_clear_screen(0.3f, 0.1f, 0.8f, 1.0f); - - bind_shader(app->shader); - set_uniform_mat4(app->shader, "model", app->model); - set_uniform_mat4(app->shader, "view", app->camera.view); - set_uniform_mat4(app->shader, "projection", app->camera.projection); - - ctx_draw_elements(&app->object); + render_scene(app->active_scene); glfwSwapBuffers(app->window.window); } diff --git a/src/application.h b/src/application.h index be37e8d..a71a7eb 100644 --- a/src/application.h +++ b/src/application.h @@ -2,18 +2,14 @@ #define APPLICATION_H #include "renderer/window.h" -#include "renderer/buffer.h" -#include "renderer/shader.h" -#include "renderer/camera.h" +#include "scene.h" typedef struct Application { Window window; - VertexArrayObject object; - int shader; - Camera camera; - mat4 model; + Scene* scenes; + Scene* active_scene; } Application; int init_application(Application* app, const char* name); diff --git a/src/objects/cube.c b/src/objects/cube.c new file mode 100644 index 0000000..c9fb10e --- /dev/null +++ b/src/objects/cube.c @@ -0,0 +1,149 @@ +#include "cube.h" + +#include +#include + +static VertexArrayObject* vao = NULL; +static Shader shader = 0; +static size_t num_cubes = 0; + +static int init_cube_object(void) +{ + vao = (VertexArrayObject*) malloc(sizeof(VertexArrayObject)); + if (vao == NULL) + { + fprintf(stderr, "Failed to allocate memory for cube vao\n"); + return 1; + } + + create_vao(vao); + + float cube_vertices[] = { + -1.0f, -1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, + + -1.0f, -1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, + 1.0f, 1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + }; + attach_vertex_buffer(vao, cube_vertices, sizeof(cube_vertices)); + + unsigned cube_indices[] = { + 0, 1, 2, 2, 1, 3, + 1, 5, 6, 1, 6, 2, + 3, 2, 6, 3, 6, 7, + 4, 5, 1, 4, 1, 0, + 4, 0, 3, 4, 3, 7, + 7, 6, 5, 7, 5, 4 + }; + attach_element_buffer(vao, cube_indices, sizeof(cube_indices)); + + VertexAttribute attributes[] = { + { GL_FLOAT, 3, sizeof(float) } + }; + + set_vertex_layout(vao, attributes, sizeof(attributes) / sizeof(VertexAttribute)); + + shader = create_shader( + "#version 460 core\n" + "" + "layout (location = 0) in vec3 pos;" + "" + "uniform mat4 model;" + "uniform mat4 view;" + "uniform mat4 projection;" + "" + "void main() {" + " gl_Position = projection * view * model * vec4(pos, 1.0);" + "}", + + "#version 460 core\n" + "" + "uniform vec3 cube_color;" + "out vec4 FragColor;" + "" + "void main() {" + " FragColor = vec4(cube_color, 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) +{ + set_uniform_vec3(shader, "cube_color", cube->color); +} + +static void on_update(Cube* cube) +{ + cube->object.rotation[1] += 0.05f; + + for (int i = 0; i < 3; i++) + { + cube->color[i] += cube->color_mod[i]; + + if (cube->color[i] > 1.0f) + { + cube->color_mod[i] *= -1.0f; + cube->color[i] = 1.0f; + } + else if (cube->color[i] < 0.0f) + { + cube->color_mod[i] *= -1.0f; + cube->color[i] = 0.0f; + } + } +} + +int create_cube(Cube* cube) +{ + if (vao == NULL || shader == 0) + { + if (init_cube_object() != 0) + { + return 1; + } + } + + init_object(&cube->object); + glm_vec3_one(cube->color); + + cube->color_mod[0] = 0.01f; + cube->color_mod[1] = 0.006f; + cube->color_mod[2] = 0.005f; + + cube->object.vao = vao; + cube->object.shader = shader; + + cube->object.child = cube; + cube->object.on_shader_use = on_shader_bind; + cube->object.on_update = on_update; + cube->object.on_destroy = destroy_cube; + + num_cubes++; +} + +void destroy_cube(Cube* cube) +{ + num_cubes--; + + if (num_cubes == 0) + { + destroy_shader(shader); + shader = 0; + + destroy_vao(*vao); + vao = NULL; + } +} + + diff --git a/src/objects/cube.h b/src/objects/cube.h new file mode 100644 index 0000000..d913566 --- /dev/null +++ b/src/objects/cube.h @@ -0,0 +1,15 @@ +#ifndef OBJ_CUBE_H +#define OBJ_CUBE_H + +#include "renderer/object.h" + +typedef struct Cube { + Object object; + vec3 color; + vec3 color_mod; +} Cube; + +int create_cube(Cube* cube); +void destroy_cube(Cube* cube); + +#endif // OBJ_CUBE_H \ No newline at end of file diff --git a/src/renderer/buffer.c b/src/renderer/buffer.c index 7929cb4..c8c7268 100644 --- a/src/renderer/buffer.c +++ b/src/renderer/buffer.c @@ -50,7 +50,7 @@ void set_vertex_layout(VertexArrayObject* vao, VertexAttribute* attributes, size size_t stride = 0; for (size_t i = 0; i < count; i++) { - stride += attributes[i].size; + stride += attributes[i].size * attributes[i].count; } size_t offset = 0; @@ -58,11 +58,16 @@ void set_vertex_layout(VertexArrayObject* vao, VertexAttribute* attributes, size glVertexAttribPointer(i, attributes[i].count, attributes[i].type, GL_FALSE, stride, (const void*)(offset)); glEnableVertexAttribArray(i); - offset += attributes[i].size; + offset += attributes[i].size * attributes[i].count; } } -void bind_vao(VertexArrayObject vao) +void bind_vao(VertexArrayObject* vao) { - glBindVertexArray(vao.vao); + glBindVertexArray(vao->vao); +} + +void render_vao(VertexArrayObject* vao) +{ + glDrawArrays(GL_TRIANGLES, 0, vao->elements); } diff --git a/src/renderer/buffer.h b/src/renderer/buffer.h index f21d245..cd9186b 100644 --- a/src/renderer/buffer.h +++ b/src/renderer/buffer.h @@ -28,6 +28,7 @@ void attach_element_buffer(VertexArrayObject* vao, const unsigned* data, size_t void set_vertex_layout(VertexArrayObject* vao, VertexAttribute* attributes, size_t count); -void bind_vao(VertexArrayObject vao); +void bind_vao(VertexArrayObject* vao); +void render_vao(VertexArrayObject* vao); #endif // BUFFER_H \ No newline at end of file diff --git a/src/renderer/camera.c b/src/renderer/camera.c index 498f9da..c21da5c 100644 --- a/src/renderer/camera.c +++ b/src/renderer/camera.c @@ -10,7 +10,7 @@ int create_camera(Camera* camera) glm_mat4_identity(camera->view); glm_rotate(camera->view, glm_rad(35.0f), (vec3) { 1.0f, 0.0f, 0.0f }); - glm_translate(camera->view, (vec3) { 0.0f, -1.0f, -2.0f }); + glm_translate(camera->view, (vec3) { 0.0f, -1.5f, -3.0f }); glm_perspective(glm_rad(90.0f), 1.0f, 0.001f, 100.0f, camera->projection); diff --git a/src/renderer/context.c b/src/renderer/context.c index 3a31469..a9ebb4b 100644 --- a/src/renderer/context.c +++ b/src/renderer/context.c @@ -23,7 +23,7 @@ void ctx_clear_screen(float r, float g, float b, float a) void ctx_draw_elements(VertexArrayObject* vao) { - bind_vao(*vao); + bind_vao(vao); glDrawElements(GL_TRIANGLES, vao->elements, GL_UNSIGNED_INT, (void*)0); } diff --git a/src/renderer/object.c b/src/renderer/object.c new file mode 100644 index 0000000..30f281e --- /dev/null +++ b/src/renderer/object.c @@ -0,0 +1,44 @@ +#include "object.h" + +#include +#include "context.h" + +void init_object(Object* obj) +{ + glm_mat4_identity(obj->transform); + glm_vec3_zero(obj->position); + glm_vec3_zero(obj->rotation); + glm_vec3_one(obj->scale); +} + +void update_object(Object* obj) +{ + obj->on_update(obj->child); +} + +void render_object(Object* obj, Camera* camera) +{ + bind_shader(obj->shader); + + glm_mat4_identity(obj->transform); + float angle = glm_vec3_norm(obj->rotation); + vec3 normalized_rot; + glm_vec3_normalize_to(obj->rotation, normalized_rot); + + glm_scale(obj->transform, obj->scale); + 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", camera->view); + set_uniform_mat4(obj->shader, "projection", camera->projection); + + obj->on_shader_use(obj->child); + + ctx_draw_elements(obj->vao); +} + +void destroy_object(Object obj) +{ + obj.on_destroy(obj.child); +} diff --git a/src/renderer/object.h b/src/renderer/object.h new file mode 100644 index 0000000..88783f9 --- /dev/null +++ b/src/renderer/object.h @@ -0,0 +1,32 @@ +#ifndef OBJECT_H +#define OBJECT_H + +#include + +#include "shader.h" +#include "buffer.h" +#include "camera.h" + +typedef struct Object +{ + VertexArrayObject* vao; + Shader shader; + + mat4 transform; + vec3 position; + vec3 rotation; + vec3 scale; + + void* child; + void(*on_shader_use)(void*); + void(*on_update)(void*); + void(*on_destroy)(void*); +} Object; + +void init_object(Object* obj); +void destroy_object(Object obj); + +void update_object(Object* obj); +void render_object(Object* obj, Camera* camera); + +#endif // OBJECT_H \ No newline at end of file diff --git a/src/renderer/shader.c b/src/renderer/shader.c index af17022..bd5c720 100644 --- a/src/renderer/shader.c +++ b/src/renderer/shader.c @@ -32,7 +32,7 @@ static int set_and_compile_shader(GLuint program, GLuint shader, const char* cod return 0; } -int create_shader(const char* vertex_shader_code, const char* fragment_shader_code) +Shader create_shader(const char* vertex_shader_code, const char* fragment_shader_code) { assert(vertex_shader_code && fragment_shader_code); @@ -83,18 +83,24 @@ vertex_failed: return shader; } -void destroy_shader(int shader) +void destroy_shader(Shader shader) { glDeleteProgram(shader); } -void bind_shader(int shader) +void bind_shader(Shader shader) { glUseProgram(shader); } -void set_uniform_mat4(int shader, const char* name, mat4 mat) +void set_uniform_mat4(Shader shader, const char* name, mat4 mat) { int location = glGetUniformLocation(shader, name); glUniformMatrix4fv(location, 1, GL_FALSE, (float*)mat); -} \ No newline at end of file +} + +void set_uniform_vec3(Shader shader, const char* name, vec3 vec) +{ + int location = glGetUniformLocation(shader, name); + glUniform3fv(location, 1, vec); +} diff --git a/src/renderer/shader.h b/src/renderer/shader.h index a77078e..30693cb 100644 --- a/src/renderer/shader.h +++ b/src/renderer/shader.h @@ -3,10 +3,14 @@ #include -int create_shader(const char* vertex_shader_code, const char* fragment_shader_code); -void destroy_shader(int shader); +typedef int Shader; -void bind_shader(int shader); -void set_uniform_mat4(int shader, const char* name, mat4 mat); +Shader create_shader(const char* vertex_shader_code, const char* fragment_shader_code); +void destroy_shader(Shader shader); + +void bind_shader(Shader shader); + +void set_uniform_mat4(Shader shader, const char* name, mat4 mat); +void set_uniform_vec3(Shader shader, const char* name, vec3 vec); #endif // SHADER_H \ No newline at end of file diff --git a/src/renderer/window.c b/src/renderer/window.c index 7ce3301..d5f8fbf 100644 --- a/src/renderer/window.c +++ b/src/renderer/window.c @@ -33,6 +33,8 @@ int create_managed_window(Window* window, const char* title, int width, int heig glfwMakeContextCurrent(window->window); ctx_init(); + ctx_enable(GL_DEPTH_TEST); + ctx_front_face(GL_CW); glfwSetFramebufferSizeCallback(window->window, default_framebuffer_size_callback); diff --git a/src/scene.c b/src/scene.c new file mode 100644 index 0000000..b2f7f8f --- /dev/null +++ b/src/scene.c @@ -0,0 +1,48 @@ +#include "scene.h" + +#include +#include + +#include + +#include "objects/cube.h" + +int create_scene(Scene* scene) +{ + assert(scene); + + if (create_camera(&scene->camera) != 0) + { + fprintf(stderr, "Failed to set up camera for scene\n"); + return 1; + } + + scene->objects = (Object*)malloc(sizeof(Object)); +} + +void destroy_scene(Scene scene) +{ + destroy_object(*(scene.objects)); +} + +void scene_add_object(Scene* scene, Object* object) +{ + assert(scene); + + scene->objects = object; +} + +void scene_update_size(Scene* scene, int width, int height) +{ + assert(scene); + set_camera_perspective(&scene->camera, 90.0f, (float)width / (float)height); +} + +void render_scene(Scene* scene) +{ + assert(scene); + ctx_clear_screen(0.0f, 0.0f, 0.0f, 1.0f); + + update_object(scene->objects); + render_object(scene->objects, &scene->camera); +} diff --git a/src/scene.h b/src/scene.h new file mode 100644 index 0000000..64acafc --- /dev/null +++ b/src/scene.h @@ -0,0 +1,21 @@ +#ifndef SCENE_H +#define SCENE_H + +#include "renderer/camera.h" +#include "renderer/object.h" + +typedef struct Scene +{ + Camera camera; + Object* objects; +} 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 render_scene(Scene* scene); + +#endif \ No newline at end of file