diff options
Diffstat (limited to 'mons_3d/src')
-rw-r--r-- | mons_3d/src/color.c | 1 | ||||
-rw-r--r-- | mons_3d/src/mesh.c | 124 | ||||
-rw-r--r-- | mons_3d/src/model.c | 15 | ||||
-rw-r--r-- | mons_3d/src/projection.c | 15 | ||||
-rw-r--r-- | mons_3d/src/shader.c | 185 | ||||
-rw-r--r-- | mons_3d/src/texture.c | 55 | ||||
-rw-r--r-- | mons_3d/src/transform.c | 112 |
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; +} |