summaryrefslogtreecommitdiff
path: root/src/maths
diff options
context:
space:
mode:
Diffstat (limited to 'src/maths')
-rw-r--r--src/maths/maths.h157
-rw-r--r--src/maths/maths_types.h10
-rw-r--r--src/maths/primitives.h163
3 files changed, 323 insertions, 7 deletions
diff --git a/src/maths/maths.h b/src/maths/maths.h
index 7352aeb..e0d39d7 100644
--- a/src/maths/maths.h
+++ b/src/maths/maths.h
@@ -9,12 +9,19 @@
#pragma once
#include <math.h>
+#include <stdio.h>
#include "maths_types.h"
+// --- Helpers
+#define deg_to_rad(x) (x * 3.14 / 180.0)
+#define min(a, b) (a < b ? a : b)
+#define max(a, b) (a > b ? a : b)
+
// --- Vector Implementations
// Dimension 3
static inline vec3 vec3_create(f32 x, f32 y, f32 z) { return (vec3){ x, y, z }; }
+#define vec3(x, y, z) (vec3_create(x, y, z))
static inline vec3 vec3_add(vec3 a, vec3 b) { return (vec3){ a.x + b.x, a.y + b.y, a.z + b.z }; }
static inline vec3 vec3_sub(vec3 a, vec3 b) { return (vec3){ a.x - b.x, a.y - b.y, a.z - b.z }; }
static inline vec3 vec3_mult(vec3 a, f32 s) { return (vec3){ a.x * s, a.y * s, a.z * s }; }
@@ -42,12 +49,86 @@ static inline vec3 vec3_cross(vec3 a, vec3 b) {
#define VEC3_Z ((vec3){ .x = 0.0, .y = 0.0, .z = 1.0 })
#define VEC3_NEG_Z ((vec3){ .x = 0.0, .y = 0.0, .z = -1.0 })
+static inline void print_vec3(vec3 v) { printf("{ x: %f, y: %f, z: %f )\n", v.x, v.y, v.z); }
+
// TODO: Dimension 2
static inline vec2 vec2_create(f32 x, f32 y) { return (vec2){ x, y }; }
// TODO: Dimension 4
+static inline vec4 vec4_create(f32 x, f32 y, f32 z, f32 w) { return (vec4){ x, y, z, w }; }
+#define vec4(x, y, z, w) (vec4_create(x, y, z, w))
#define VEC4_ZERO ((vec4){ .x = 0.0, .y = 0.0, .z = 0.0, .w = 0.0 })
+// --- Quaternion Implementations
+
+static inline f32 quat_dot(quat a, quat b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; }
+
+static inline quat quat_normalise(quat a) {
+ f32 length = sqrtf(quat_dot(a, a)); // same as len squared
+
+ return (quat){ a.x / length, a.y / length, a.z / length, a.w / length };
+}
+
+static inline quat quat_ident() { return (quat){ .x = 0.0, .y = 0.0, .z = 0.0, .w = 1.0 }; }
+
+static quat quat_from_axis_angle(vec3 axis, f32 angle, bool normalize) {
+ const f32 half_angle = 0.5f * angle;
+ f32 s = sinf(half_angle);
+ f32 c = cosf(half_angle);
+
+ quat q = (quat){ s * axis.x, s * axis.y, s * axis.z, c };
+ if (normalize) {
+ return quat_normalise(q);
+ }
+ return q;
+}
+
+// TODO: grok this.
+static inline quat quat_slerp(quat a, quat b, f32 percentage) {
+ quat out_quaternion;
+
+ quat q0 = quat_normalise(a);
+ quat q1 = quat_normalise(b);
+
+ // Compute the cosine of the angle between the two vectors.
+ f32 dot = quat_dot(q0, q1);
+
+ // If the dot product is negative, slerp won't take
+ // the shorter path. Note that v1 and -v1 are equivalent when
+ // the negation is applied to all four components. Fix by
+ // reversing one quaternion.
+ if (dot < 0.0f) {
+ q1.x = -q1.x;
+ q1.y = -q1.y;
+ q1.z = -q1.z;
+ q1.w = -q1.w;
+ dot = -dot;
+ }
+
+ const f32 DOT_THRESHOLD = 0.9995f;
+ if (dot > DOT_THRESHOLD) {
+ // If the inputs are too close for comfort, linearly interpolate
+ // and normalize the result.
+ out_quaternion =
+ (quat){ q0.x + ((q1.x - q0.x) * percentage), q0.y + ((q1.y - q0.y) * percentage),
+ q0.z + ((q1.z - q0.z) * percentage), q0.w + ((q1.w - q0.w) * percentage) };
+
+ return quat_normalise(out_quaternion);
+ }
+
+ // Since dot is in range [0, DOT_THRESHOLD], acos is safe
+ f32 theta_0 = cos(dot); // theta_0 = angle between input vectors
+ f32 theta = theta_0 * percentage; // theta = angle between v0 and result
+ f32 sin_theta = sin(theta); // compute this value only once
+ f32 sin_theta_0 = sin(theta_0); // compute this value only once
+
+ f32 s0 = cos(theta) - dot * sin_theta / sin_theta_0; // == sin(theta_0 - theta) / sin(theta_0)
+ f32 s1 = sin_theta / sin_theta_0;
+
+ return (quat){ (q0.x * s0) + (q1.x * s1), (q0.y * s0) + (q1.y * s1), (q0.z * s0) + (q1.z * s1),
+ (q0.w * s0) + (q1.w * s1) };
+}
+
// --- Matrix Implementations
static inline mat4 mat4_ident() {
@@ -70,6 +151,26 @@ static inline mat4 mat4_scale(f32 scale) {
return out_matrix;
}
+// TODO: double check this
+static inline mat4 mat4_rotation(quat rotation) {
+ mat4 out_matrix = mat4_ident();
+ quat n = quat_normalise(rotation);
+
+ out_matrix.data[0] = 1.0f - 2.0f * n.y * n.y - 2.0f * n.z * n.z;
+ out_matrix.data[1] = 2.0f * n.x * n.y - 2.0f * n.z * n.w;
+ out_matrix.data[2] = 2.0f * n.x * n.z + 2.0f * n.y * n.w;
+
+ out_matrix.data[4] = 2.0f * n.x * n.y + 2.0f * n.z * n.w;
+ out_matrix.data[5] = 1.0f - 2.0f * n.x * n.x - 2.0f * n.z * n.z;
+ out_matrix.data[6] = 2.0f * n.y * n.z - 2.0f * n.x * n.w;
+
+ out_matrix.data[8] = 2.0f * n.x * n.z - 2.0f * n.y * n.w;
+ out_matrix.data[9] = 2.0f * n.y * n.z + 2.0f * n.x * n.w;
+ out_matrix.data[10] = 1.0f - 2.0f * n.x * n.x - 2.0f * n.y * n.y;
+
+ return out_matrix;
+}
+
static inline mat4 mat4_mult(mat4 lhs, mat4 rhs) {
mat4 out_matrix = mat4_ident();
@@ -89,6 +190,43 @@ static inline mat4 mat4_mult(mat4 lhs, mat4 rhs) {
return out_matrix;
}
+static mat4 mat4_transposed(mat4 matrix) {
+ mat4 out_matrix = mat4_ident();
+ out_matrix.data[0] = matrix.data[0];
+ out_matrix.data[1] = matrix.data[4];
+ out_matrix.data[2] = matrix.data[8];
+ out_matrix.data[3] = matrix.data[12];
+ out_matrix.data[4] = matrix.data[1];
+ out_matrix.data[5] = matrix.data[5];
+ out_matrix.data[6] = matrix.data[9];
+ out_matrix.data[7] = matrix.data[13];
+ out_matrix.data[8] = matrix.data[2];
+ out_matrix.data[9] = matrix.data[6];
+ out_matrix.data[10] = matrix.data[10];
+ out_matrix.data[11] = matrix.data[14];
+ out_matrix.data[12] = matrix.data[3];
+ out_matrix.data[13] = matrix.data[7];
+ out_matrix.data[14] = matrix.data[11];
+ out_matrix.data[15] = matrix.data[15];
+ return out_matrix;
+}
+
+#if defined(CEL_REND_BACKEND_VULKAN)
+/** @brief Creates a perspective projection matrix compatible with Vulkan */
+static inline mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip,
+ f32 far_clip) {
+ f32 half_tan_fov = tanf(fov_radians * 0.5f);
+ mat4 out_matrix = { .data = { 0 } };
+
+ out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov);
+ out_matrix.data[5] = -1.0f / half_tan_fov; // Flip Y-axis for Vulkan
+ out_matrix.data[10] = -((far_clip + near_clip) / (far_clip - near_clip));
+ out_matrix.data[11] = -1.0f;
+ out_matrix.data[14] = -((2.0f * far_clip * near_clip) / (far_clip - near_clip));
+
+ return out_matrix;
+}
+#else
/** @brief Creates a perspective projection matrix */
static inline mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip,
f32 far_clip) {
@@ -101,6 +239,7 @@ static inline mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_
out_matrix.data[14] = -((2.0f * far_clip * near_clip) / (far_clip - near_clip));
return out_matrix;
}
+#endif
/** @brief Creates an orthographic projection matrix */
static inline mat4 mat4_orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 near_clip,
@@ -156,23 +295,23 @@ static inline mat4 mat4_look_at(vec3 position, vec3 target, vec3 up) {
// ...
-// --- Quaternion Implementations
-
// --- Transform Implementations
#define TRANSFORM_DEFAULT \
((transform){ .position = VEC3_ZERO, \
- .rotation = (quat){ .x = 0., .y = 0., .z = 0., .w = 0. }, \
+ .rotation = (quat){ .x = 0., .y = 0., .z = 0., .w = 1. }, \
.scale = 1.0, \
.is_dirty = false })
static transform transform_create(vec3 pos, quat rot, f32 scale) {
- return (transform){ .position = pos, .rotation = rot, .scale = scale, .is_dirty = false };
+ return (transform){ .position = pos, .rotation = rot, .scale = scale, .is_dirty = true };
}
static inline mat4 transform_to_mat(transform *tf) {
- // TODO: rotation
- return mat4_mult(mat4_translation(tf->position), mat4_scale(tf->scale));
+ mat4 scale = mat4_scale(tf->scale);
+ mat4 rotation = mat4_rotation(tf->rotation);
+ mat4 translation = mat4_translation(tf->position);
+ return mat4_mult(translation, mat4_mult(rotation, scale));
}
// --- Sizing asserts
@@ -198,3 +337,9 @@ typedef struct u32x3 {
};
} u32x3;
#define u32x3(x, y, z) ((u32x3){ x, y, z })
+
+typedef struct u32x2 {
+ u32 x;
+ u32 y;
+} u32x2;
+#define u32x2(x, y) ((u32x3){ x, y }) \ No newline at end of file
diff --git a/src/maths/maths_types.h b/src/maths/maths_types.h
index ba741b9..53cac55 100644
--- a/src/maths/maths_types.h
+++ b/src/maths/maths_types.h
@@ -60,4 +60,12 @@ typedef struct transform {
quat rotation;
f32 scale;
bool is_dirty;
-} transform; \ No newline at end of file
+} transform;
+
+typedef struct vec4i {
+ i32 x, y, z, w;
+} vec4i;
+
+typedef struct vec4u {
+ u32 x, y, z, w;
+} vec4u; \ No newline at end of file
diff --git a/src/maths/primitives.h b/src/maths/primitives.h
new file mode 100644
index 0000000..ed52c8c
--- /dev/null
+++ b/src/maths/primitives.h
@@ -0,0 +1,163 @@
+#pragma once
+
+#include <assert.h>
+#include <stdlib.h>
+#include "core.h"
+#include "maths.h"
+#include "render_types.h"
+
+static const vec3 BACK_BOT_LEFT = (vec3){ 0, 0, 0 };
+static const vec3 BACK_BOT_RIGHT = (vec3){ 1, 0, 0 };
+static const vec3 BACK_TOP_LEFT = (vec3){ 0, 1, 0 };
+static const vec3 BACK_TOP_RIGHT = (vec3){ 1, 1, 0 };
+static const vec3 FRONT_BOT_LEFT = (vec3){ 0, 0, 1 };
+static const vec3 FRONT_BOT_RIGHT = (vec3){ 1, 0, 1 };
+static const vec3 FRONT_TOP_LEFT = (vec3){ 0, 1, 1 };
+static const vec3 FRONT_TOP_RIGHT = (vec3){ 1, 1, 1 };
+
+static mesh prim_cube_mesh_create() {
+ mesh cube = { 0 };
+ cube.vertices = vertex_darray_new(36);
+
+ // back faces
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 1 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } });
+
+ // front faces
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } });
+
+ // top faces
+ vertex_darray_push(cube.vertices,
+ (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } });
+ vertex_darray_push(cube.vertices,
+ (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } });
+
+ // bottom faces
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
+
+ // right faces
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } });
+
+ // left faces
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
+ vertex_darray_push(
+ cube.vertices,
+ (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
+
+ cube.indices_len = cube.vertices->len;
+ cube.indices = malloc(sizeof(u32) * cube.indices_len);
+
+ for (u32 i = 0; i < cube.indices_len; i++) {
+ cube.indices[i] = i;
+ }
+
+ cube.has_indices = true;
+
+ return cube;
+}
+
+/** @brief create a new model with the shape of a cube */
+static model_handle prim_cube_new(core* core) {
+ model model = { 0 };
+ mesh cube = prim_cube_mesh_create();
+
+ mesh_darray_push(model.meshes, cube);
+ assert(mesh_darray_len(model.meshes) == 1);
+
+ u32 index = (u32)model_darray_len(core->models);
+ model_darray_push_copy(core->models, &model);
+ return (model_handle){ .raw = index };
+} \ No newline at end of file