summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoromniscient <17525998+omnisci3nce@users.noreply.github.com>2024-03-09 16:34:46 +1100
committeromniscient <17525998+omnisci3nce@users.noreply.github.com>2024-03-09 16:34:46 +1100
commitc7fabc44e62152c877b565c1da27a2e1d6f584f3 (patch)
treebbbf35b596c611645eb2f3051ec718bb15721c91
parent91f5f362e4a4abd6840755500d8e2c84a50501ac (diff)
renderer functions necessary for model drawing
-rw-r--r--src/renderer/backends/backend_opengl.c82
-rw-r--r--src/renderer/render.c139
-rw-r--r--src/renderer/render.h17
-rw-r--r--src/renderer/render_backend.h7
-rw-r--r--src/renderer/render_types.h2
5 files changed, 247 insertions, 0 deletions
diff --git a/src/renderer/backends/backend_opengl.c b/src/renderer/backends/backend_opengl.c
index 6022dbf..ea6cb00 100644
--- a/src/renderer/backends/backend_opengl.c
+++ b/src/renderer/backends/backend_opengl.c
@@ -2,6 +2,7 @@
#define CEL_PLATFORM_LINUX
#include "defines.h"
+#include "file.h"
#include "log.h"
#include "maths_types.h"
#include "render_types.h"
@@ -59,4 +60,85 @@ void clear_screen(vec3 colour) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
+void bind_texture(shader s, texture *tex, u32 slot) {
+ // printf("bind texture slot %d with texture id %d \n", slot, tex->texture_id);
+ glActiveTexture(GL_TEXTURE0 + slot);
+ glBindTexture(GL_TEXTURE_2D, tex->texture_id);
+}
+
+void bind_mesh_vertex_buffer(void *_backend, mesh *mesh) { glBindVertexArray(mesh->vao); }
+
+static inline GLenum to_gl_prim_topology(enum cel_primitive_topology primitive) {
+ switch (primitive) {
+ case CEL_PRIMITIVE_TOPOLOGY_TRIANGLE:
+ return GL_TRIANGLES;
+ case CEL_PRIMITIVE_TOPOLOGY_POINT:
+ case CEL_PRIMITIVE_TOPOLOGY_LINE:
+ case CEL_PRIMITIVE_TOPOLOGY_LINE_STRIP:
+ case CEL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
+ case CEL_PRIMITIVE_TOPOLOGY_COUNT:
+ break;
+ }
+}
+
+void draw_primitives(cel_primitive_topology primitive, u32 start_index, u32 count) {
+ u32 gl_primitive = to_gl_prim_topology(primitive);
+ glDrawArrays(gl_primitive, start_index, count);
+}
+
+shader shader_create_separate(const char *vert_shader, const char *frag_shader) {
+ INFO("Load shaders at %s and %s", vert_shader, frag_shader);
+ int success;
+ char info_log[512];
+
+ u32 vertex = glCreateShader(GL_VERTEX_SHADER);
+ const char *vertex_shader_src = string_from_file(vert_shader);
+ if (vertex_shader_src == NULL) {
+ ERROR("EXIT: couldnt load shader");
+ exit(-1);
+ }
+ glShaderSource(vertex, 1, &vertex_shader_src, NULL);
+ glCompileShader(vertex);
+ glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(vertex, 512, NULL, info_log);
+ printf("%s\n", info_log);
+ ERROR("EXIT: vertex shader compilation failed");
+ exit(-1);
+ }
+
+ // fragment shader
+ u32 fragment = glCreateShader(GL_FRAGMENT_SHADER);
+ const char *fragment_shader_src = string_from_file(frag_shader);
+ if (fragment_shader_src == NULL) {
+ ERROR("EXIT: couldnt load shader");
+ exit(-1);
+ }
+ glShaderSource(fragment, 1, &fragment_shader_src, NULL);
+ glCompileShader(fragment);
+ glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(fragment, 512, NULL, info_log);
+ printf("%s\n", info_log);
+ ERROR("EXIT: fragment shader compilation failed");
+ exit(-1);
+ }
+
+ u32 shader_prog;
+ shader_prog = glCreateProgram();
+
+ glAttachShader(shader_prog, vertex);
+ glAttachShader(shader_prog, fragment);
+ glLinkProgram(shader_prog);
+ glDeleteShader(vertex);
+ glDeleteShader(fragment);
+ free((char *)vertex_shader_src);
+ free((char *)fragment_shader_src);
+
+ shader s = { .program_id = shader_prog };
+ return s;
+}
+
+void set_shader(shader s) { glUseProgram(s.program_id); }
+
#endif \ No newline at end of file
diff --git a/src/renderer/render.c b/src/renderer/render.c
index a0cc559..dc541d2 100644
--- a/src/renderer/render.c
+++ b/src/renderer/render.c
@@ -5,13 +5,21 @@
#include <stb_truetype.h>
#include "render.h"
+#include "render_types.h"
#include <glad/glad.h>
#include <glfw3.h>
+#include "defines.h"
#include "log.h"
+#include "maths.h"
#include "render_backend.h"
+// FIXME: get rid of these and store dynamic screen realestate
+// in renderer
+#define SCR_WIDTH 1080
+#define SCR_HEIGHT 800
+
material DEFAULT_MATERIAL = { 0 };
bool renderer_init(renderer* ren) {
@@ -20,6 +28,12 @@ bool renderer_init(renderer* ren) {
// NOTE: all platforms use GLFW at the moment but thats subject to change
glfwInit();
+ DEBUG("init graphics api (OpenGL) backend");
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+
// glfw window creation
GLFWwindow* window = glfwCreateWindow(ren->config.scr_width, ren->config.scr_height,
ren->config.window_name, NULL, NULL);
@@ -37,6 +51,9 @@ bool renderer_init(renderer* ren) {
return false;
}
+ ren->blinn_phong =
+ shader_create_separate("assets/shaders/blinn_phong.vert", "assets/shaders/blinn_phong.frag");
+
return true;
}
@@ -63,6 +80,128 @@ void default_material_init() {
texture_data_upload(&DEFAULT_MATERIAL.specular_texture);
}
+void draw_model(renderer* ren, camera* camera, model* model, transform tf) {
+ // TRACE("Drawing model: %s", model->name);
+ mat4 view;
+ mat4 proj;
+ camera_view_projection(camera, SCR_HEIGHT, SCR_WIDTH, &view, &proj);
+
+ set_shader(ren->blinn_phong);
+
+ for (size_t i = 0; i < mesh_darray_len(model->meshes); i++) {
+ mesh* m = &model->meshes->data[i];
+ if (vertex_darray_len(m->vertices) == 0) {
+ continue;
+ }
+ // TRACE("Drawing mesh %d", i);
+ draw_mesh(ren, m, tf, &(DEFAULT_MATERIAL), &view, &proj);
+ }
+}
+
+void draw_mesh(renderer* ren, mesh* mesh, transform tf, material* mat, mat4* view, mat4* proj) {
+ shader lighting_shader = ren->blinn_phong;
+
+ // bind buffer
+ bind_mesh_vertex_buffer(ren->backend_state, mesh);
+
+ // bind textures
+ bind_texture(lighting_shader, &mat->diffuse_texture, 0); // bind to slot 0
+ bind_texture(lighting_shader, &mat->specular_texture, 1); // bind to slot 1
+ uniform_f32(lighting_shader.program_id, "material.shininess", 32.);
+
+ // upload model transform
+ mat4 trans = mat4_translation(tf.position);
+ mat4 rot = mat4_rotation(tf.rotation);
+ mat4 scale = mat4_scale(tf.scale);
+ mat4 model_tf = mat4_mult(trans, mat4_mult(rot, scale));
+
+ uniform_mat4f(lighting_shader.program_id, "model", &model_tf);
+ // upload view & projection matrices
+ uniform_mat4f(lighting_shader.program_id, "view", view);
+ uniform_mat4f(lighting_shader.program_id, "projection", proj);
+
+ // draw triangles
+ u32 num_vertices = vertex_darray_len(mesh->vertices);
+ draw_primitives(CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, 0, num_vertices);
+}
+
+void model_upload_meshes(renderer* ren, model* model) {
+ INFO("Upload mesh vertex data to GPU for model %s", model->name);
+ // DEBUG("Loading model with handle %d", model_handle.raw);
+ // model m = models->data[model_handle.raw];
+
+ size_t num_meshes = mesh_darray_len(model->meshes);
+ u32 VBOs[num_meshes];
+ u32 VAOs[num_meshes];
+ glGenBuffers(num_meshes, VBOs);
+ glGenVertexArrays(num_meshes, VAOs);
+
+ u64 total_verts = 0;
+
+ TRACE("num meshes %d", num_meshes);
+
+ // upload each mesh to the GPU
+ for (int mesh_i = 0; mesh_i < num_meshes; mesh_i++) {
+ model->meshes->data[mesh_i].vao = VAOs[mesh_i];
+ model->meshes->data[mesh_i].vbo = VBOs[mesh_i];
+ // 3. bind buffers
+ glBindBuffer(GL_ARRAY_BUFFER, VBOs[mesh_i]);
+
+ size_t num_vertices = vertex_darray_len(model->meshes->data[mesh_i].vertices);
+ TRACE("Uploading vertex array data: %d verts", num_vertices);
+ total_verts += num_vertices;
+
+ // TODO: convert this garbage into a function
+ f32 verts[num_vertices * 8];
+ // for each face
+ for (int i = 0; i < (num_vertices / 3); i++) {
+ // for each vert in face
+ for (int j = 0; j < 3; j++) {
+ size_t stride = (i * 24) + j * 8;
+ // printf("i: %d, stride: %ld, loc %d\n", i, stride, i * 3 + j);
+ vertex vert = model->meshes->data[mesh_i].vertices->data[i];
+ // printf("pos %f %f %f\n", vert.position.x, vert.position.y, vert.position.z);
+ // printf("norm %f %f %f\n", vert.normal.x, vert.normal.y, vert.normal.z);
+ // printf("tex %f %f\n", vert.uv.x, vert.uv.y);
+ verts[stride + 0] =
+ ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.x;
+ verts[stride + 1] =
+ ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.y;
+ verts[stride + 2] =
+ ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.z;
+ verts[stride + 3] =
+ ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.x;
+ verts[stride + 4] =
+ ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.y;
+ verts[stride + 5] =
+ ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.z;
+ verts[stride + 6] = ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].uv.x;
+ verts[stride + 7] = ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].uv.y;
+ }
+ }
+
+ // 4. upload data
+ glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
+
+ // 5. cont. set mesh vertex layout
+ glBindVertexArray(model->meshes->data[mesh_i].vao);
+ // position attribute
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
+ glEnableVertexAttribArray(0);
+ // normal vector attribute
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
+ glEnableVertexAttribArray(1);
+ // tex coords
+ glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
+ glEnableVertexAttribArray(2);
+ }
+
+ INFO("Uploaded %d submeshes with a total of %d vertices\n", num_meshes, total_verts);
+
+ // 6. reset buffer
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
texture texture_data_load(const char* path, bool invert_y) {
TRACE("Load texture %s", path);
diff --git a/src/renderer/render.h b/src/renderer/render.h
index e095e1c..65ace4e 100644
--- a/src/renderer/render.h
+++ b/src/renderer/render.h
@@ -1,5 +1,6 @@
#pragma once
+#include "camera.h"
#include "loaders.h"
#include "render_types.h"
@@ -14,6 +15,22 @@ void renderer_shutdown(renderer* ren);
void render_frame_begin(renderer* ren);
void render_frame_end(renderer* ren);
+// --- models meshes
+void model_upload_meshes(renderer* ren, model* model);
+void draw_model(renderer* ren, camera* camera, model* model, transform tf);
+void draw_mesh(renderer* ren, mesh* mesh, transform tf, material* mat, mat4* view, mat4* proj);
+
// ---
texture texture_data_load(const char* path, bool invert_y); // #frontend
void texture_data_upload(texture* tex); // #backend
+
+// --- Uniforms
+
+/** @brief upload a vec3 of f32 to a uniform */
+void uniform_vec3f(u32 program_id, const char *uniform_name, vec3 *value);
+/** @brief upload a single f32 to a uniform */
+void uniform_f32(u32 program_id, const char *uniform_name, f32 value);
+/** @brief upload a integer to a uniform */
+void uniform_i32(u32 program_id, const char *uniform_name, i32 value);
+/** @brief upload a mat4 of f32 to a uniform */
+void uniform_mat4f(u32 program_id, const char *uniform_name, mat4 *value); \ No newline at end of file
diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h
index 61c7ab5..a524f7f 100644
--- a/src/renderer/render_backend.h
+++ b/src/renderer/render_backend.h
@@ -12,4 +12,11 @@ void gfx_backend_shutdown(renderer* ren);
void clear_screen(vec3 colour);
+void bind_texture(shader s, texture *tex, u32 slot);
+void bind_mesh_vertex_buffer(void* backend, mesh* mesh);
+void draw_primitives(cel_primitive_topology primitive, u32 start_index, u32 count);
+
+shader shader_create_separate(const char *vert_shader, const char *frag_shader);
+void set_shader(shader s);
+
// --- Uniforms
diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h
index 12b912d..746dfce 100644
--- a/src/renderer/render_types.h
+++ b/src/renderer/render_types.h
@@ -38,6 +38,8 @@ typedef struct renderer {
struct GLFWwindow *window; /** Currently all platforms use GLFW*/
void *backend_state; /** Graphics API-specific state */
renderer_config config;
+ // shaders
+ shader blinn_phong;
} renderer;
// --- Lighting & Materials