From 5ba261c72c4c11700810f4fa4b6b7418515149b0 Mon Sep 17 00:00:00 2001 From: Lauchmelder Date: Sun, 16 Oct 2022 23:43:22 +0200 Subject: [PATCH] implemented basic renderer --- src/CMakeLists.txt | 2 + src/application.c | 65 +++++++++++++++++++++++++++++ src/application.h | 5 +++ src/renderer/buffer.c | 68 ++++++++++++++++++++++++++++++ src/renderer/buffer.h | 33 +++++++++++++++ src/renderer/context.c | 8 ++++ src/renderer/context.h | 3 ++ src/renderer/shader.c | 94 ++++++++++++++++++++++++++++++++++++++++++ src/renderer/shader.h | 9 ++++ src/renderer/window.c | 9 +++- src/renderer/window.h | 1 + 11 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 src/renderer/buffer.c create mode 100644 src/renderer/buffer.h create mode 100644 src/renderer/shader.c create mode 100644 src/renderer/shader.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6c5adde..e39a4c0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,6 +9,8 @@ add_executable(solver "application.c" "renderer/window.c" "renderer/context.c" + "renderer/buffer.c" + "renderer/shader.c" ) target_link_libraries(solver PRIVATE diff --git a/src/application.c b/src/application.c index 76b4f04..9b7eb80 100644 --- a/src/application.c +++ b/src/application.c @@ -7,6 +7,14 @@ #include "renderer/context.h" +static void destroy_application(Application* app) +{ + assert(app); + + destroy_vao(app->object); + destroy_window(app->window); +} + int init_application(Application* app, const char* name) { assert(app); @@ -17,6 +25,57 @@ int init_application(Application* app, const char* name) return 1; } + // Create quad for testing + create_vao(&app->object); + + float vertices[] = { + -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, + -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f + }; + attach_vertex_buffer(&app->object, vertices, sizeof(vertices)); + + unsigned indices[] = { + 0, 1, 2, + 0, 2, 3 + }; + 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;" + "" + "void main() {" + " i_col = col;" + " gl_Position = 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; + } + return 0; } @@ -27,6 +86,12 @@ int launch_application(Application* app) glfwPollEvents(); ctx_clear_screen(0.3f, 0.1f, 0.8f, 1.0f); + + bind_shader(app->shader); + ctx_draw_elements(&app->object); + glfwSwapBuffers(app->window); } + + destroy_application(app); } \ No newline at end of file diff --git a/src/application.h b/src/application.h index 82782d5..ae454a4 100644 --- a/src/application.h +++ b/src/application.h @@ -2,10 +2,15 @@ #define APPLICATION_H #include "renderer/window.h" +#include "renderer/buffer.h" +#include "renderer/shader.h" typedef struct Application { GLFWwindow* window; + + VertexArrayObject object; + int shader; } Application; int init_application(Application* app, const char* name); diff --git a/src/renderer/buffer.c b/src/renderer/buffer.c new file mode 100644 index 0000000..7929cb4 --- /dev/null +++ b/src/renderer/buffer.c @@ -0,0 +1,68 @@ +#include "buffer.h" + +#include +#include + +void create_vao(VertexArrayObject* vao) +{ + assert(vao); + glGenVertexArrays(1, &vao->vao); +} + +void destroy_vao(VertexArrayObject vao) +{ + glDeleteBuffers(1, &vao.ebo); + glDeleteBuffers(1, &vao.vbo); + + glDeleteVertexArrays(1, &vao.vao); +} + +void attach_vertex_buffer(VertexArrayObject* vao, const float* data, size_t size) +{ + assert(vao); + glBindVertexArray(vao->vao); + + glGenBuffers(1, &vao->vbo); + glBindBuffer(GL_ARRAY_BUFFER, vao->vbo); + + glBufferData(GL_ARRAY_BUFFER, size, (const void*)data, GL_STATIC_DRAW); +} + +void attach_element_buffer(VertexArrayObject* vao, const unsigned* data, size_t size) +{ + assert(vao); + glBindVertexArray(vao->vao); + + glGenBuffers(1, &vao->ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->ebo); + + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, (const void*)data, GL_STATIC_DRAW); + + vao->elements = size / sizeof(unsigned); +} + +void set_vertex_layout(VertexArrayObject* vao, VertexAttribute* attributes, size_t count) +{ + assert(vao); + assert(attributes); + + glBindVertexArray(vao->vao); + + size_t stride = 0; + for (size_t i = 0; i < count; i++) { + stride += attributes[i].size; + } + + size_t offset = 0; + for (size_t i = 0; i < count; i++) { + glVertexAttribPointer(i, attributes[i].count, attributes[i].type, GL_FALSE, stride, (const void*)(offset)); + glEnableVertexAttribArray(i); + + offset += attributes[i].size; + } +} + +void bind_vao(VertexArrayObject vao) +{ + glBindVertexArray(vao.vao); +} diff --git a/src/renderer/buffer.h b/src/renderer/buffer.h new file mode 100644 index 0000000..f21d245 --- /dev/null +++ b/src/renderer/buffer.h @@ -0,0 +1,33 @@ +#ifndef BUFFER_H +#define BUFFER_H + +#include + +typedef struct VertexArrayObject +{ + int vao; + + int vbo; + int ebo; + + size_t elements; +} VertexArrayObject; + +typedef struct VertexAttribute +{ + int type; + int count; + size_t size; +} VertexAttribute; + +void create_vao(VertexArrayObject* vao); +void destroy_vao(VertexArrayObject vao); + +void attach_vertex_buffer(VertexArrayObject* vao, const float* data, size_t size); +void attach_element_buffer(VertexArrayObject* vao, const unsigned* data, size_t size); + +void set_vertex_layout(VertexArrayObject* vao, VertexAttribute* attributes, size_t count); + +void bind_vao(VertexArrayObject vao); + +#endif // BUFFER_H \ No newline at end of file diff --git a/src/renderer/context.c b/src/renderer/context.c index 287b8dc..45969ff 100644 --- a/src/renderer/context.c +++ b/src/renderer/context.c @@ -3,6 +3,8 @@ #include #include +#include "buffer.h" + int ctx_init() { gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); @@ -18,3 +20,9 @@ void ctx_clear_screen(float r, float g, float b, float a) glClearColor(r, g, b, a); glClear(GL_COLOR_BUFFER_BIT); } + +void ctx_draw_elements(VertexArrayObject* vao) +{ + bind_vao(*vao); + glDrawElements(GL_TRIANGLES, vao->elements, GL_UNSIGNED_INT, (void*)0); +} diff --git a/src/renderer/context.h b/src/renderer/context.h index e695276..4a6d9e5 100644 --- a/src/renderer/context.h +++ b/src/renderer/context.h @@ -1,10 +1,13 @@ #ifndef CONTEXT_H #define CONTEXT_H +typedef struct VertexArrayObject VertexArrayObject; + int ctx_init(); void ctx_viewport(int x, int y, int w, int h); void ctx_clear_screen(float r, float g, float b, float a); +void ctx_draw_elements(VertexArrayObject* vao); #endif // CONTEXT_H \ No newline at end of file diff --git a/src/renderer/shader.c b/src/renderer/shader.c new file mode 100644 index 0000000..627465b --- /dev/null +++ b/src/renderer/shader.c @@ -0,0 +1,94 @@ +#include "shader.h" + +#include +#include +#include +#include +#include + +static int set_and_compile_shader(GLuint program, GLuint shader, const char* code, char** error) +{ + int result; + + glShaderSource(shader, 1, &code, NULL); + glCompileShader(shader); + + glGetShaderiv(shader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + *error = (char*)malloc(1024); + if (*error == NULL) { + fprintf(stderr, "(shader) memory allocation for error buffer failed\n"); + return -ENOMEM; + } + + glGetShaderInfoLog(shader, 1024, NULL, *error); + (*error)[1023] = NULL; + return 1; + } + + glAttachShader(program, shader); + + return 0; +} + +int create_shader(const char* vertex_shader_code, const char* fragment_shader_code) +{ + assert(vertex_shader_code && fragment_shader_code); + + int shader = glCreateProgram(); + + char* error; + int vertex_shader = glCreateShader(GL_VERTEX_SHADER); + if (set_and_compile_shader(shader, vertex_shader, vertex_shader_code, &error) != 0) + { + fprintf(stderr, "vertex shader compilation failed: %s\n", error); + free(error); + glDeleteProgram(shader); + shader = 0; + + goto vertex_failed; + } + + int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + if (set_and_compile_shader(shader, fragment_shader, fragment_shader_code, &error) != 0) + { + fprintf(stderr, "fragment shader compilation failed: %s\n", error); + free(error); + glDeleteProgram(shader); + shader = 0; + + goto fragment_failed; + } + + glLinkProgram(shader); + + int result; + glGetProgramiv(shader, GL_LINK_STATUS, &result); + if (result == GL_FALSE) + { + char error[512]; + glGetProgramInfoLog(shader, 512, NULL, error); + + fprintf(stderr, "shader linking failed: %s\n", error); + glDeleteProgram(shader); + shader = 0; + } + +fragment_failed: + glDeleteShader(fragment_shader); +vertex_failed: + glDeleteShader(vertex_shader); + + return shader; +} + +void destroy_shader(int shader) +{ + glDeleteProgram(shader); +} + +void bind_shader(int shader) +{ + glUseProgram(shader); +} \ No newline at end of file diff --git a/src/renderer/shader.h b/src/renderer/shader.h new file mode 100644 index 0000000..7032fc9 --- /dev/null +++ b/src/renderer/shader.h @@ -0,0 +1,9 @@ +#ifndef SHADER_H +#define SHADER_H + +int create_shader(const char* vertex_shader_code, const char* fragment_shader_code); +void destroy_shader(int shader); + +void bind_shader(int shader); + +#endif // SHADER_H \ No newline at end of file diff --git a/src/renderer/window.c b/src/renderer/window.c index d843c63..33767e7 100644 --- a/src/renderer/window.c +++ b/src/renderer/window.c @@ -5,7 +5,7 @@ #include "context.h" -void default_framebuffer_size_callback(int vw, int vh) +void default_framebuffer_size_callback(GLFWwindow* window, int vw, int vh) { ctx_viewport(0, 0, vw, vh); } @@ -27,4 +27,9 @@ GLFWwindow* create_managed_window(const char* title, int width, int height) glfwSetFramebufferSizeCallback(window, default_framebuffer_size_callback); return window; -} \ No newline at end of file +} + +void destroy_window(GLFWwindow* window) +{ + glfwDestroyWindow(window); +} diff --git a/src/renderer/window.h b/src/renderer/window.h index b9b34d8..8be835f 100644 --- a/src/renderer/window.h +++ b/src/renderer/window.h @@ -4,5 +4,6 @@ typedef struct GLFWwindow GLFWwindow; GLFWwindow* create_managed_window(const char* title, int width, int height); +void destroy_window(GLFWwindow* window); #endif // WINDOW_H \ No newline at end of file