aboutsummaryrefslogtreecommitdiff
path: root/mons_3d/src
diff options
context:
space:
mode:
authorLibravatar Silas Bartha <silas@exvacuum.dev>2025-02-07 11:27:18 -0500
committerLibravatar Silas Bartha <silas@exvacuum.dev>2025-02-07 11:27:18 -0500
commit4da7be39827ea5888ef9c97b1aadf61b0d76347c (patch)
tree15d0ff8f8bcb0e871efb1b2e65c2bc8d07b17565 /mons_3d/src
initial commit (lol)
Diffstat (limited to 'mons_3d/src')
-rw-r--r--mons_3d/src/color.c1
-rw-r--r--mons_3d/src/mesh.c124
-rw-r--r--mons_3d/src/model.c15
-rw-r--r--mons_3d/src/projection.c15
-rw-r--r--mons_3d/src/shader.c185
-rw-r--r--mons_3d/src/texture.c55
-rw-r--r--mons_3d/src/transform.c112
7 files changed, 507 insertions, 0 deletions
diff --git a/mons_3d/src/color.c b/mons_3d/src/color.c
new file mode 100644
index 0000000..1b1627d
--- /dev/null
+++ b/mons_3d/src/color.c
@@ -0,0 +1 @@
+#include "color.h"
diff --git a/mons_3d/src/mesh.c b/mons_3d/src/mesh.c
new file mode 100644
index 0000000..213a24c
--- /dev/null
+++ b/mons_3d/src/mesh.c
@@ -0,0 +1,124 @@
+#include "mesh.h"
+#include "vertex.h"
+#include "mikktspace.h"
+
+#include <glad/gl.h>
+#include <stdlib.h>
+
+void compute_tangents(mons_vertex *vertex_array, int vertex_count, int *index_array, int index_count);
+
+mons_mesh mons_create_mesh(mons_vertex *vertex_array, int vertex_count, int *index_array, int index_count) {
+ compute_tangents(vertex_array, vertex_count, index_array, index_count);
+ // VAO & VBO
+ unsigned int vao;
+ glGenVertexArrays(1, &vao);
+ glBindVertexArray(vao);
+ unsigned int vbo;
+ glGenBuffers(1, &vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, vbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(mons_vertex) * vertex_count, vertex_array, GL_STATIC_DRAW);
+ unsigned int ebo;
+ glGenBuffers(1, &ebo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * index_count, index_array, GL_STATIC_DRAW);
+ // Set up vertex attributes
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(mons_vertex), 0);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(mons_vertex), (void*)(sizeof(mons_vec3)));
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(mons_vertex), (void*)(sizeof(mons_vec3) * 2));
+ glEnableVertexAttribArray(2);
+ glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(mons_vertex), (void*)(sizeof(mons_vec3) * 2 + sizeof(mons_vec4)));
+ glEnableVertexAttribArray(3);
+ return (mons_mesh) {
+ .vao = vao,
+ .element_count = index_count,
+ };
+}
+
+struct mesh_data {
+ mons_vertex *vertex_array;
+ int vertex_count;
+ int *index_array;
+ int index_count;
+};
+
+int get_vertex_index(const SMikkTSpaceContext *context, int i_face, int i_vert) {
+ struct mesh_data *mesh_data = context->m_pUserData;
+ int index_index = (i_face * 3) + i_vert;
+ int index = mesh_data->index_array[index_index];
+ return index;
+}
+
+int get_num_faces(const SMikkTSpaceContext *context) {
+ struct mesh_data *mesh_data = context->m_pUserData;
+ return mesh_data->index_count / 3;
+}
+
+int get_num_vertices_of_face(const SMikkTSpaceContext *context, int i_face) {
+ return 3;
+}
+
+void get_position(const SMikkTSpaceContext *context, float *outpos, int i_face, int i_vert) {
+ struct mesh_data *mesh_data = context->m_pUserData;
+ int index = get_vertex_index(context, i_face, i_vert);
+ mons_vertex vertex = mesh_data->vertex_array[index];
+
+ outpos[0] = vertex.position.x;
+ outpos[1] = vertex.position.y;
+ outpos[2] = vertex.position.z;
+}
+
+void get_normal(const SMikkTSpaceContext *context, float *outnormal, int i_face, int i_vert) {
+ struct mesh_data *mesh_data = context->m_pUserData;
+ int index = get_vertex_index(context, i_face, i_vert);
+ mons_vertex vertex = mesh_data->vertex_array[index];
+
+ outnormal[0] = vertex.normal.x;
+ outnormal[1] = vertex.normal.y;
+ outnormal[2] = vertex.normal.z;
+}
+
+void get_tex_coords(const SMikkTSpaceContext *context, float *outuv, int i_face, int i_vert) {
+ struct mesh_data *mesh_data = context->m_pUserData;
+ int index = get_vertex_index(context, i_face, i_vert);
+ mons_vertex vertex = mesh_data->vertex_array[index];
+
+ outuv[0] = vertex.texture_coords.x;
+ outuv[1] = vertex.texture_coords.y;
+}
+
+void set_tspace_basic(const SMikkTSpaceContext *context, const float *tangentu, float f_sign, int i_face, int i_vert) {
+ struct mesh_data *mesh_data = context->m_pUserData;
+ int index = get_vertex_index(context, i_face, i_vert);
+ mons_vertex *vertex = &mesh_data->vertex_array[index];
+
+ vertex->tangent.x = tangentu[0];
+ vertex->tangent.y = tangentu[1];
+ vertex->tangent.z = tangentu[2];
+ vertex->tangent.w = f_sign;
+}
+
+void compute_tangents(mons_vertex *vertex_array, int vertex_count, int *index_array, int index_count) {
+ static SMikkTSpaceInterface iface = {
+ .m_getNumFaces = get_num_faces,
+ .m_getNumVerticesOfFace = get_num_vertices_of_face,
+ .m_getNormal = get_normal,
+ .m_getPosition = get_position,
+ .m_getTexCoord = get_tex_coords,
+ .m_setTSpaceBasic = set_tspace_basic,
+ };
+ struct mesh_data mesh_data = {
+ vertex_array,
+ vertex_count,
+ index_array,
+ index_count,
+ };
+ SMikkTSpaceContext context = {
+ .m_pInterface = &iface,
+ .m_pUserData = &mesh_data,
+ };
+
+ genTangSpaceDefault(&context);
+}
+
diff --git a/mons_3d/src/model.c b/mons_3d/src/model.c
new file mode 100644
index 0000000..ed2e543
--- /dev/null
+++ b/mons_3d/src/model.c
@@ -0,0 +1,15 @@
+#include "model.h"
+#include "texture.h"
+#include "camera.h"
+#include <glad/gl.h>
+
+void mons_model_draw(mons_model model) {
+ glUseProgram(model.shader);
+ mons_shader_apply_global_uniforms(model.shader);
+ mons_shader_set_mat4(model.shader, "transform", mons_transform_matrix(model.transform), GL_TRUE);
+ for (int i = 0; i < model.textures_len; i++) {
+ mons_texture_bind(model.shader, i, model.textures[i]);
+ }
+ glBindVertexArray(model.mesh.vao);
+ glDrawElements(GL_TRIANGLES, model.mesh.element_count, GL_UNSIGNED_INT, 0);
+}
diff --git a/mons_3d/src/projection.c b/mons_3d/src/projection.c
new file mode 100644
index 0000000..287d59e
--- /dev/null
+++ b/mons_3d/src/projection.c
@@ -0,0 +1,15 @@
+#include "projection.h"
+#include <math.h>
+#include "mons_math/mat4.h"
+
+mons_mat4 mons_projection_matrix(mons_projection projection) {
+ float tangent = tanf(projection.fov / 2.0f);
+ float top = projection.near * tangent;
+ float right = top * projection.aspect_ratio;
+ return (mons_mat4){
+ {projection.near / right, 0, 0, 0},
+ {0, projection.near / top, 0, 0},
+ {0, 0, -(projection.far + projection.near) / (projection.far - projection.near), -1},
+ {0, 0, -(2.0f * projection.far * projection.near) / (projection.far - projection.near), 0},
+ };
+}
diff --git a/mons_3d/src/shader.c b/mons_3d/src/shader.c
new file mode 100644
index 0000000..6898a1f
--- /dev/null
+++ b/mons_3d/src/shader.c
@@ -0,0 +1,185 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include "shader.h"
+#include "mons_math/vec4.h"
+#include "mons_math/vec3.h"
+#include "mons_math/vec2.h"
+#include "mons_math/mat4.h"
+#include "hashmap.h"
+#include <stdlib.h>
+
+typedef enum mons_uniform_type {
+ MONS_UNIFORM_INT,
+ MONS_UNIFORM_FLOAT,
+ MONS_UNIFORM_VEC2,
+ MONS_UNIFORM_VEC3,
+ MONS_UNIFORM_VEC4,
+ MONS_UNIFORM_MAT4,
+} mons_uniform_type;
+
+typedef struct mons_uniform_m4 {
+ mons_mat4 matrix;
+ bool transpose;
+} mons_uniform_m4;
+
+typedef union mons_uniform_data {
+ int i;
+ float f;
+ mons_vec2 v2;
+ mons_vec3 v3;
+ mons_vec4 v4;
+ mons_uniform_m4 m4;
+} mons_uniform_data;
+
+typedef struct mons_uniform {
+ mons_uniform_type type;
+ mons_uniform_data data;
+} mons_uniform;
+
+static mons_hashmap *GLOBAL_UNIFORMS = NULL;
+mons_hashmap *get_global_uniforms() {
+ if (GLOBAL_UNIFORMS == NULL) {
+ GLOBAL_UNIFORMS = malloc(sizeof(mons_hashmap));
+ *GLOBAL_UNIFORMS = mons_hashmap_new(sizeof(mons_uniform), 10);
+ }
+ return GLOBAL_UNIFORMS;
+}
+
+void mons_shader_apply_global_uniforms(mons_program shader) {
+ mons_hashmap *global_uniforms = get_global_uniforms();
+ for (int i = 0; i < global_uniforms->len; i++) {
+ mons_hashmap_pair pair;
+ mons_hashmap_at(*global_uniforms, i, &pair);
+ char *name = pair.key;
+ mons_uniform uniform = *(mons_uniform *)pair.value;
+ switch (uniform.type) {
+ case MONS_UNIFORM_INT:
+ // TODO:
+ break;
+ case MONS_UNIFORM_FLOAT:
+ mons_shader_set_float(shader, name, uniform.data.f);
+ break;
+ case MONS_UNIFORM_VEC2:
+ mons_shader_set_vec2(shader, name, uniform.data.v2);
+ break;
+ case MONS_UNIFORM_VEC3:
+ mons_shader_set_vec3(shader, name, uniform.data.v3);
+ break;
+ case MONS_UNIFORM_VEC4:
+ mons_shader_set_vec4(shader, name, uniform.data.v4);
+ break;
+ case MONS_UNIFORM_MAT4:
+ mons_shader_set_mat4(shader, name, uniform.data.m4.matrix, uniform.data.m4.transpose);
+ break;
+ }
+ }
+}
+
+void mons_shader_set_float_global(char *uniform_name, float value) {
+ mons_hashmap *global_uniforms = get_global_uniforms();
+ mons_uniform uniform = {
+ .type = MONS_UNIFORM_FLOAT,
+ .data.f = value,
+ };
+ mons_hashmap_insert(global_uniforms, uniform_name, &uniform);
+}
+
+void mons_shader_set_vec2_global(char *uniform_name, mons_vec2 value) {
+ mons_hashmap *global_uniforms = get_global_uniforms();
+ mons_uniform uniform = {
+ .type = MONS_UNIFORM_VEC2,
+ .data.v2 = value,
+ };
+ mons_hashmap_insert(global_uniforms, uniform_name, &uniform);
+}
+
+void mons_shader_set_vec3_global(char *uniform_name, mons_vec3 value) {
+ mons_hashmap *global_uniforms = get_global_uniforms();
+ mons_uniform uniform = {
+ .type = MONS_UNIFORM_VEC3,
+ .data.v3 = value,
+ };
+ mons_hashmap_insert(global_uniforms, uniform_name, &uniform);
+}
+
+void mons_shader_set_vec4_global(char *uniform_name, mons_vec4 value) {
+ mons_hashmap *global_uniforms = get_global_uniforms();
+ mons_uniform uniform = {
+ .type = MONS_UNIFORM_VEC4,
+ .data.v4 = value,
+ };
+ mons_hashmap_insert(global_uniforms, uniform_name, &uniform);
+}
+
+void mons_shader_set_mat4_global(char *uniform_name, mons_mat4 value, bool transpose) {
+ mons_hashmap *global_uniforms = get_global_uniforms();
+ mons_uniform uniform = {
+ .type = MONS_UNIFORM_MAT4,
+ .data.m4 = {
+ .matrix = value,
+ .transpose = transpose,
+ },
+ };
+ mons_hashmap_insert(global_uniforms, uniform_name, &uniform);
+}
+
+mons_shader mons_create_shader(mons_shader_type shader_type, char *source,
+ int source_length) {
+ unsigned int shader = glCreateShader(shader_type);
+ const char *shader_source = (const char *)source;
+ int shader_len = (int)source_length;
+ glShaderSource(shader, 1, &shader_source, &shader_len);
+ glCompileShader(shader);
+ int success;
+ char info_log[512];
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(shader, 512, NULL, info_log);
+ printf("Shader Compilation Failed: %s\n", info_log);
+ }
+ return shader;
+}
+
+mons_program mons_create_program(mons_shader vertex_shader,
+ mons_shader fragment_shader) {
+ unsigned int shader_program = glCreateProgram();
+ glAttachShader(shader_program, vertex_shader);
+ glAttachShader(shader_program, fragment_shader);
+ glLinkProgram(shader_program);
+ int success;
+ char info_log[512];
+ glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
+ if (!success) {
+ glGetProgramInfoLog(shader_program, 512, NULL, info_log);
+ }
+ return shader_program;
+}
+
+void mons_shader_set_float(mons_program shader, char *uniform_name,
+ float value) {
+ glUniform1f(glGetUniformLocation(shader, uniform_name), value);
+}
+
+void mons_shader_set_vec2(mons_program shader, char *uniform_name,
+ mons_vec2 value) {
+ glUniform2fv(glGetUniformLocation(shader, uniform_name), 1,
+ (float *)&value);
+}
+
+void mons_shader_set_vec3(mons_program shader, char *uniform_name,
+ mons_vec3 value) {
+ glUniform3fv(glGetUniformLocation(shader, uniform_name), 1,
+ (float *)&value);
+}
+
+void mons_shader_set_vec4(mons_program shader, char *uniform_name,
+ mons_vec4 value) {
+ glUniform4fv(glGetUniformLocation(shader, uniform_name), 1,
+ (float *)&value);
+}
+
+void mons_shader_set_mat4(mons_program shader, char *uniform_name,
+ mons_mat4 value, bool transpose) {
+ glUniformMatrix4fv(glGetUniformLocation(shader, uniform_name), 1, transpose,
+ (float *)&value);
+}
diff --git a/mons_3d/src/texture.c b/mons_3d/src/texture.c
new file mode 100644
index 0000000..7b2a478
--- /dev/null
+++ b/mons_3d/src/texture.c
@@ -0,0 +1,55 @@
+#include "texture.h"
+#include "qoi.h"
+
+#include <glad/gl.h>
+
+mons_texture mons_texture_load(FILE *stream) {
+ mons_image image = mons_load_qoi(stream);
+ return mons_texture_from_image(image);
+}
+
+mons_texture mons_texture_from_image(mons_image image) {
+ glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST_MIPMAP_LINEAR);
+ glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ unsigned int texture;
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image.data);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ mons_texture result = {
+ .id = texture,
+ .width = image.width,
+ .height = image.height,
+ };
+ mons_image_free(&image);
+ return result;
+}
+
+char *texure_uniforms[16] = {
+ "base_texture",
+ "normal_texture",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+void mons_texture_bind(mons_program shader, unsigned int unit, mons_texture texture) {
+ glActiveTexture(GL_TEXTURE0 + unit);
+ glUniform1i(glGetUniformLocation(shader, texure_uniforms[unit]), unit);
+ glBindTexture(GL_TEXTURE_2D, texture.id);
+}
diff --git a/mons_3d/src/transform.c b/mons_3d/src/transform.c
new file mode 100644
index 0000000..c4435fc
--- /dev/null
+++ b/mons_3d/src/transform.c
@@ -0,0 +1,112 @@
+#include <math.h>
+#include "transform.h"
+#include "mons_math/vec3.h"
+#include "mons_math/quat.h"
+#include <stdio.h>
+
+mons_mat4 translation_to_mat4(mons_vec3 translation) {
+ mons_mat4 result = MONS_MAT4_IDENTITY;
+ result.m1.w = translation.x;
+ result.m2.w = translation.y;
+ result.m3.w = translation.z;
+ return result;
+}
+
+mons_mat4 scale_to_mat4(mons_vec3 scale) {
+ mons_mat4 result = MONS_MAT4_IDENTITY;
+ result.m1.x = scale.x;
+ result.m2.y = scale.y;
+ result.m3.z = scale.z;
+ return result;
+}
+
+void mons_transform_translate(mons_transform *transform,
+ mons_vec3 translation) {
+ mons_vec3_add_inplace(&transform->translation, translation);
+}
+
+void mons_transform_rotate(mons_transform *transform, mons_quat rotation) {
+ mons_quat_mul_inplace(&transform->rotation, rotation);
+}
+
+void mons_transform_scale(mons_transform *transform, mons_vec3 scale) {
+ mons_vec3_mul_memberwise_inplace(&transform->scale, scale);
+}
+
+mons_mat4 mons_transform_matrix(mons_transform transform) {
+ mons_mat4 translation = translation_to_mat4(transform.translation);
+ mons_mat4 result = translation;
+ mons_mat4_mul_inplace(&result, mons_quat_to_mat4(transform.rotation));
+ mons_mat4_mul_inplace(&result, scale_to_mat4(transform.scale));
+ return result;
+}
+
+mons_vec3 mons_transform_forward(mons_transform transform) {
+ return mons_quat_transform_vec3(transform.rotation, MONS_VEC3_Z);
+}
+
+mons_vec3 mons_transform_up(mons_transform transform) {
+ return mons_quat_transform_vec3(transform.rotation, MONS_VEC3_Y);
+}
+
+mons_vec3 mons_transform_right(mons_transform transform) {
+ return mons_quat_transform_vec3(transform.rotation, MONS_VEC3_X);
+}
+
+void mons_transform_look_at(mons_transform *transform, mons_vec3 point, mons_vec3 up) {
+ mons_vec3 forward = mons_vec3_normalize(mons_vec3_sub(transform->translation, point));
+ mons_vec3 right = mons_vec3_normalize(mons_vec3_cross(up, forward));
+ mons_vec3 new_up = mons_vec3_cross(forward, right);
+ float m00 = right.x;
+ float m01 = right.y;
+ float m02 = right.z;
+ float m10 = new_up.x;
+ float m11 = new_up.y;
+ float m12 = new_up.z;
+ float m20 = forward.x;
+ float m21 = forward.y;
+ float m22 = forward.z;
+
+ float num8 = (m00 + m11) + m22;
+ mons_quat quaternion = {0};
+ if (num8 > 0.0f) {
+ float num = sqrt(num8 + 1.0f);
+ quaternion.w = num * 0.5f;
+ num = 0.5f / num;
+ quaternion.x = (m12 - m21) * num;
+ quaternion.y = (m20 - m02) * num;
+ quaternion.z = (m01 - m10) * num;
+ transform->rotation = quaternion;
+ return;
+ }
+ if ((m00 >= m11) && (m00 >= m22))
+ {
+ float num7 = (float)sqrt(((1.0f + m00) - m11) - m22);
+ float num4 = 0.5f / num7;
+ quaternion.x = 0.5f * num7;
+ quaternion.y = (m01 + m10) * num4;
+ quaternion.z = (m02 + m20) * num4;
+ quaternion.w = (m12 - m21) * num4;
+ transform->rotation = quaternion;
+ return;
+ }
+ if (m11 > m22)
+ {
+ float num6 = (float)sqrt(((1.0f + m11) - m00) - m22);
+ float num3 = 0.5f / num6;
+ quaternion.x = (m10 + m01) * num3;
+ quaternion.y = 0.5f * num6;
+ quaternion.z = (m21 + m12) * num3;
+ quaternion.w = (m20 - m02) * num3;
+ transform->rotation = quaternion;
+ return;
+ }
+ float num5 = (float)sqrt(((1.0f + m22) - m00) - m11);
+ float num2 = 0.5f / num5;
+ quaternion.x = (m20 + m02) * num2;
+ quaternion.y = (m21 + m12) * num2;
+ quaternion.z = 0.5f * num5;
+ quaternion.w = (m01 - m10) * num2;
+ transform->rotation = quaternion;
+ return;
+}