summaryrefslogtreecommitdiff
path: root/archive/src/maths
diff options
context:
space:
mode:
Diffstat (limited to 'archive/src/maths')
-rw-r--r--archive/src/maths/geometry.h50
-rw-r--r--archive/src/maths/maths.c35
-rw-r--r--archive/src/maths/maths.h321
-rw-r--r--archive/src/maths/maths_types.h84
-rw-r--r--archive/src/maths/primitives.c343
-rw-r--r--archive/src/maths/primitives.h29
6 files changed, 862 insertions, 0 deletions
diff --git a/archive/src/maths/geometry.h b/archive/src/maths/geometry.h
new file mode 100644
index 0000000..532651c
--- /dev/null
+++ b/archive/src/maths/geometry.h
@@ -0,0 +1,50 @@
+/**
+ * @file geometry.h
+ * @author your name (you@domain.com)
+ * @brief Shapes and intersections between them
+ * @version 0.1
+ * @date 2024-02-24
+ *
+ * @copyright Copyright (c) 2024
+ */
+#pragma once
+
+#include "maths.h"
+
+// typedef struct line_3d {
+// vec3 start, end;
+// } line_3d;
+
+// typedef struct plane {
+// vec3 normal;
+// } plane;
+
+typedef struct Cuboid {
+ Vec3 half_extents;
+} Cuboid;
+
+typedef struct Sphere {
+ f32 radius;
+} Sphere;
+
+// typedef struct cylinder {
+// f32 radius;
+// f32 half_height;
+// } cylinder;
+
+// typedef struct cone {
+// f32 radius;
+// f32 half_height;
+// } cone;
+
+// TODO:
+// capsule
+// torus
+// ray
+// frustum
+// conical frustum
+// wedge
+
+// 2d...
+// line
+// circle
diff --git a/archive/src/maths/maths.c b/archive/src/maths/maths.c
new file mode 100644
index 0000000..19052fe
--- /dev/null
+++ b/archive/src/maths/maths.c
@@ -0,0 +1,35 @@
+#include "maths.h"
+
+#define c_static_inline
+
+c_static_inline Vec3 vec3_create(f32 x, f32 y, f32 z) { return (Vec3){ x, y, z }; }
+c_static_inline Vec3 vec3_add(Vec3 a, Vec3 b) { return (Vec3){ a.x + b.x, a.y + b.y, a.z + b.z }; }
+c_static_inline Vec3 vec3_sub(Vec3 a, Vec3 b) { return (Vec3){ a.x - b.x, a.y - b.y, a.z - b.z }; }
+c_static_inline Vec3 vec3_mult(Vec3 a, f32 s) { return (Vec3){ a.x * s, a.y * s, a.z * s }; }
+c_static_inline Vec3 vec3_div(Vec3 a, f32 s) { return (Vec3){ a.x / s, a.y / s, a.z / s }; }
+
+c_static_inline f32 vec3_len_squared(Vec3 a) { return (a.x * a.x) + (a.y * a.y) + (a.z * a.z); }
+c_static_inline f32 vec3_len(Vec3 a) { return sqrtf(vec3_len_squared(a)); }
+c_static_inline Vec3 vec3_negate(Vec3 a) { return (Vec3){ -a.x, -a.y, -a.z }; }
+PUB c_static_inline Vec3 vec3_normalise(Vec3 a) {
+ f32 length = vec3_len(a);
+ return vec3_div(a, length);
+}
+
+c_static_inline f32 vec3_dot(Vec3 a, Vec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
+c_static_inline Vec3 vec3_cross(Vec3 a, Vec3 b) {
+ return (
+ Vec3){ .x = a.y * b.z - a.z * b.y, .y = a.z * b.x - a.x * b.z, .z = a.x * b.y - a.y * b.x };
+}
+
+Mat4 mat4_ident() {
+ return (Mat4){ .data = { 1.0, 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1.0 } };
+}
+
+Mat4 transform_to_mat(Transform* tf) {
+ 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));
+ return mat4_mult(mat4_mult(scale, rotation), translation);
+} \ No newline at end of file
diff --git a/archive/src/maths/maths.h b/archive/src/maths/maths.h
new file mode 100644
index 0000000..e77b81a
--- /dev/null
+++ b/archive/src/maths/maths.h
@@ -0,0 +1,321 @@
+/**
+ * @file maths.h
+ * @author your name (you@domain.com)
+ * @brief
+ * @version 0.1
+ * @date 2024-02-24
+ * @copyright Copyright (c) 2024
+ */
+#pragma once
+
+#include <math.h>
+#include <stdio.h>
+#include "defines.h"
+#include "maths_types.h"
+
+// #undef c_static_inline
+// #define c_static_inline static
+
+// --- 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
+PUB c_static_inline Vec3 vec3_create(f32 x, f32 y, f32 z);
+#define vec3(x, y, z) ((Vec3){ x, y, z })
+PUB c_static_inline Vec3 vec3_add(Vec3 a, Vec3 b);
+PUB c_static_inline Vec3 vec3_sub(Vec3 a, Vec3 b);
+PUB c_static_inline Vec3 vec3_mult(Vec3 a, f32 s);
+PUB c_static_inline Vec3 vec3_div(Vec3 a, f32 s);
+
+PUB c_static_inline f32 vec3_len_squared(Vec3 a);
+PUB c_static_inline f32 vec3_len(Vec3 a);
+PUB c_static_inline Vec3 vec3_negate(Vec3 a);
+PUB c_static_inline Vec3 vec3_normalise(Vec3 a);
+
+PUB c_static_inline f32 vec3_dot(Vec3 a, Vec3 b);
+PUB c_static_inline Vec3 vec3_cross(Vec3 a, Vec3 b);
+
+static const Vec3 VEC3_X = vec3(1.0, 0.0, 0.0);
+static const Vec3 VEC3_NEG_X = vec3(-1.0, 0.0, 0.0);
+static const Vec3 VEC3_Y = vec3(0.0, 1.0, 0.0);
+static const Vec3 VEC3_NEG_Y = vec3(0.0, -1.0, 0.0);
+static const Vec3 VEC3_Z = vec3(0.0, 0.0, 1.0);
+static const Vec3 VEC3_NEG_Z = vec3(0.0, 0.0, -1.0);
+static const Vec3 VEC3_ZERO = vec3(0.0, 0.0, 0.0);
+static const Vec3 VEC3_ONES = vec3(1.0, 1.0, 1.0);
+
+static void print_vec3(Vec3 v) {
+ printf("{ x: %f, y: %f, z: %f )\n", (f64)v.x, (f64)v.y, (f64)v.z);
+}
+
+// TODO: Dimension 2
+static Vec2 vec2_create(f32 x, f32 y) { return (Vec2){ x, y }; }
+#define vec2(x, y) ((Vec2){ x, y })
+static Vec2 vec2_div(Vec2 a, f32 s) { return (Vec2){ a.x / s, a.y / s }; }
+
+// TODO: Dimension 4
+static 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 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 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 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 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);
+ }
+
+ // TODO: Are there math functions that take floats instead of doubles?
+
+ // Since dot is in range [0, DOT_THRESHOLD], acos is safe
+ f64 theta_0 = cos((f64)dot); // theta_0 = angle between input vectors
+ f64 theta = theta_0 * (f64)percentage; // theta = angle between v0 and result
+ f64 sin_theta = sin((f64)theta); // compute this value only once
+ f64 sin_theta_0 = sin((f64)theta_0); // compute this value only once
+
+ f32 s0 =
+ cos(theta) - (f64)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
+
+Mat4 mat4_ident();
+
+static Mat4 mat4_translation(Vec3 position) {
+ Mat4 out_matrix = mat4_ident();
+ out_matrix.data[12] = position.x;
+ out_matrix.data[13] = position.y;
+ out_matrix.data[14] = position.z;
+ return out_matrix;
+}
+
+static Mat4 mat4_scale(Vec3 scale) {
+ Mat4 out_matrix = mat4_ident();
+ out_matrix.data[0] = scale.x;
+ out_matrix.data[5] = scale.y;
+ out_matrix.data[10] = scale.z;
+ return out_matrix;
+}
+
+// TODO: double check this
+static 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 Mat4 mat4_mult(Mat4 lhs, Mat4 rhs) {
+ Mat4 out_matrix = mat4_ident();
+
+ const f32* m1_ptr = lhs.data;
+ const f32* m2_ptr = rhs.data;
+ f32* dst_ptr = out_matrix.data;
+
+ for (i32 i = 0; i < 4; ++i) {
+ for (i32 j = 0; j < 4; ++j) {
+ *dst_ptr = m1_ptr[0] * m2_ptr[0 + j] + m1_ptr[1] * m2_ptr[4 + j] + m1_ptr[2] * m2_ptr[8 + j] +
+ m1_ptr[3] * m2_ptr[12 + j];
+ dst_ptr++;
+ }
+ m1_ptr += 4;
+ }
+
+ 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 */
+c_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) {
+ 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;
+ 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;
+}
+#endif
+
+/** @brief Creates an orthographic projection matrix */
+static inline Mat4 mat4_orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 near_clip,
+ f32 far_clip) {
+ // source: kohi game engine.
+ Mat4 out_matrix = mat4_ident();
+
+ f32 lr = 1.0f / (left - right);
+ f32 bt = 1.0f / (bottom - top);
+ f32 nf = 1.0f / (near_clip - far_clip);
+
+ out_matrix.data[0] = -2.0f * lr;
+ out_matrix.data[5] = -2.0f * bt;
+ out_matrix.data[10] = 2.0f * nf;
+
+ out_matrix.data[12] = (left + right) * lr;
+ out_matrix.data[13] = (top + bottom) * bt;
+ out_matrix.data[14] = (far_clip + near_clip) * nf;
+
+ return out_matrix;
+}
+
+static inline Mat4 mat4_look_at(Vec3 position, Vec3 target, Vec3 up) {
+ Mat4 out_matrix;
+ Vec3 z_axis;
+ z_axis.x = target.x - position.x;
+ z_axis.y = target.y - position.y;
+ z_axis.z = target.z - position.z;
+
+ z_axis = vec3_normalise(z_axis);
+ Vec3 x_axis = vec3_normalise(vec3_cross(z_axis, up));
+ Vec3 y_axis = vec3_cross(x_axis, z_axis);
+
+ out_matrix.data[0] = x_axis.x;
+ out_matrix.data[1] = y_axis.x;
+ out_matrix.data[2] = -z_axis.x;
+ out_matrix.data[3] = 0;
+ out_matrix.data[4] = x_axis.y;
+ out_matrix.data[5] = y_axis.y;
+ out_matrix.data[6] = -z_axis.y;
+ out_matrix.data[7] = 0;
+ out_matrix.data[8] = x_axis.z;
+ out_matrix.data[9] = y_axis.z;
+ out_matrix.data[10] = -z_axis.z;
+ out_matrix.data[11] = 0;
+ out_matrix.data[12] = -vec3_dot(x_axis, position);
+ out_matrix.data[13] = -vec3_dot(y_axis, position);
+ out_matrix.data[14] = vec3_dot(z_axis, position);
+ out_matrix.data[15] = 1.0f;
+
+ return out_matrix;
+}
+
+// ...
+
+// --- Transform Implementations
+
+#define TRANSFORM_DEFAULT \
+ ((Transform){ .position = VEC3_ZERO, \
+ .rotation = (Quat){ .x = 0., .y = 0., .z = 0., .w = 1. }, \
+ .scale = 1.0, \
+ .is_dirty = false })
+
+static Transform transform_create(Vec3 pos, Quat rot, Vec3 scale) {
+ return (Transform){ .position = pos, .rotation = rot, .scale = scale, .is_dirty = true };
+}
+
+Mat4 transform_to_mat(Transform* tf);
+
+// --- Sizing asserts
+
+_Static_assert(alignof(Vec3) == 4, "Vec3 is 4 byte aligned");
+_Static_assert(sizeof(Vec3) == 12, "Vec3 is 12 bytes so has no padding");
+
+_Static_assert(alignof(Vec4) == 4, "Vec4 is 4 byte aligned");
diff --git a/archive/src/maths/maths_types.h b/archive/src/maths/maths_types.h
new file mode 100644
index 0000000..66d260d
--- /dev/null
+++ b/archive/src/maths/maths_types.h
@@ -0,0 +1,84 @@
+/**
+ * @file maths_types.h
+ * @author Omniscient
+ * @brief Maths types
+ * @date 2024-02-24
+ * @copyright Copyright (c) 2024
+ */
+#pragma once
+
+#include "defines.h"
+
+// --- Constants
+#define PI 3.14159265358979323846
+#define HALF_PI 1.57079632679489661923
+#define TAU (2.0 * PI)
+
+// --- Types
+
+/** @brief 2D Vector */
+typedef struct Vec2 {
+ f32 x, y;
+} Vec2;
+
+/** @brief 4x4 Matrix */
+typedef struct Mat4 {
+ // TODO: use this format for more readable code: vec4 x_axis, y_axis, z_axis, w_axis;
+ f32 data[16];
+} Mat4;
+
+/** @brief Three dimensional bounding box */
+typedef struct Bbox_3D {
+ Vec3 min; // minimum point of the box
+ Vec3 max; // maximum point of the box
+} Bbox_3D;
+
+/** @brief 3D Axis-aligned bounding box */
+typedef Bbox_3D Aabb_3D;
+
+/** @brief 3D affine transformation */
+typedef struct Transform {
+ Vec3 position;
+ Quat rotation;
+ Vec3 scale;
+ bool is_dirty;
+} Transform;
+
+typedef struct Vec4i {
+ i32 x, y, z, w;
+} Vec4i;
+
+typedef struct Vec4u {
+ u32 x, y, z, w;
+} Vec4u;
+
+// --- Some other types
+typedef struct u32x3 {
+ union {
+ struct {
+ u32 x;
+ u32 y;
+ u32 z;
+ };
+ struct {
+ u32 r;
+ u32 g;
+ u32 b;
+ };
+ };
+} u32x3;
+#define u32x3(x, y, z) ((u32x3){ x, y, z })
+
+typedef struct u32x2 {
+ u32 x;
+ u32 y;
+} u32x2;
+#define u32x2(x, y) ((u32x2){ x, y })
+
+// Type aliass
+
+typedef struct Vec2 f32x2;
+#define f32x2(x, y) ((f32x2){ x, y })
+
+typedef struct Vec3 f32x3;
+#define f32x3(x, y, z) ((f32x3){ x, y, z })
diff --git a/archive/src/maths/primitives.c b/archive/src/maths/primitives.c
new file mode 100644
index 0000000..c24d1e2
--- /dev/null
+++ b/archive/src/maths/primitives.c
@@ -0,0 +1,343 @@
+#include "primitives.h"
+#include "colours.h"
+#include "log.h"
+#include "maths.h"
+#include "maths_types.h"
+#include "ral_types.h"
+#include "render_types.h"
+
+// --- Helpers
+
+void push_triangle(u32_darray* arr, u32 i0, u32 i1, u32 i2) {
+ u32_darray_push(arr, i0);
+ u32_darray_push(arr, i1);
+ u32_darray_push(arr, i2);
+}
+
+Vec3 plane_vertex_positions[] = {
+ (Vec3){ -0.5, 0, -0.5 },
+ (Vec3){ 0.5, 0, -0.5 },
+ (Vec3){ -0.5, 0, 0.5 },
+ (Vec3){ 0.5, 0, 0.5 },
+};
+
+Geometry Geo_CreatePlane(f32x2 extents, u32 tiling_u, u32 tiling_v) {
+ CASSERT(tiling_u >= 1 && tiling_v >= 1);
+ Vertex_darray* vertices = Vertex_darray_new(4);
+ u32_darray* indices = u32_darray_new(vertices->len);
+
+ Vec3 vert_pos[4];
+ memcpy(&vert_pos, plane_vertex_positions, sizeof(plane_vertex_positions));
+ for (int i = 0; i < 4; i++) {
+ vert_pos[i].x *= extents.x;
+ vert_pos[i].z *= extents.y;
+ }
+ VERT_3D(vertices, vert_pos[0], VEC3_Y, vec2(0, 0)); // back left
+ VERT_3D(vertices, vert_pos[1], VEC3_Y, vec2(1 * tiling_u, 0 * tiling_v)); // back right
+ VERT_3D(vertices, vert_pos[2], VEC3_Y, vec2(0, 1 * tiling_v)); // front left
+ VERT_3D(vertices, vert_pos[3], VEC3_Y, vec2(1 * tiling_u, 1 * tiling_v)); // front right
+
+ // push_triangle(indices, 0, 1, 2);
+ // push_triangle(indices, 2, 1, 3);
+ push_triangle(indices, 2, 1, 0);
+ push_triangle(indices, 1, 2, 3);
+
+ for (int i = 0; i < 4; i++) {
+ printf("Vertex %d: (%f, %f, %f)\n", i, vert_pos[i].x, vert_pos[i].y, vert_pos[i].z);
+ }
+
+ Geometry geo = { .format = VERTEX_STATIC_3D,
+ .vertices = vertices,
+ .has_indices = true,
+ .index_count = indices->len,
+ .indices = indices };
+
+ return geo;
+}
+
+Geometry Geo_CreateCuboid(f32x3 extents) {
+ Vertex_darray* vertices = Vertex_darray_new(36);
+
+ // back faces
+ VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_NEG_Z, vec2(1, 0));
+ VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Z, vec2(0, 1));
+ VERT_3D(vertices, BACK_TOP_LEFT, VEC3_NEG_Z, vec2(0, 0));
+ VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_NEG_Z, vec2(1, 0));
+ VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_NEG_Z, vec2(1, 1));
+ VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Z, vec2(0, 1));
+
+ // front faces
+ VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_Z, vec2(0, 1));
+ VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_Z, vec2(1, 0));
+ VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_Z, vec2(0, 0));
+ VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_Z, vec2(0, 1));
+ VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_Z, vec2(1, 1));
+ VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_Z, vec2(1, 0));
+
+ // top faces
+ VERT_3D(vertices, BACK_TOP_LEFT, VEC3_Y, vec2(0, 0));
+ VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_Y, vec2(0, 1));
+ VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_Y, vec2(1, 1));
+ VERT_3D(vertices, BACK_TOP_LEFT, VEC3_Y, vec2(0, 0));
+ VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_Y, vec2(1, 1));
+ VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_Y, vec2(1, 0));
+
+ // bottom faces
+ VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Y, vec2(0, 1));
+ VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_NEG_Y, vec2(1, 1));
+ VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_NEG_Y, vec2(0, 1));
+ VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Y, vec2(0, 1));
+ VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_NEG_Y, vec2(1, 1));
+ VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_NEG_Y, vec2(0, 1));
+
+ // right faces
+ VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_X, vec2(0, 0));
+ VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_X, vec2(1, 1));
+ VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_X, vec2(1, 0));
+ VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_X, vec2(1, 1));
+ VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_X, vec2(0, 0));
+ VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_X, vec2(0, 1));
+
+ // left faces
+ VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_NEG_X, vec2(0, 0));
+ VERT_3D(vertices, BACK_TOP_LEFT, VEC3_NEG_X, vec2(0, 0));
+ VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_X, vec2(0, 0));
+ VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_X, vec2(0, 0));
+ VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_NEG_X, vec2(0, 0));
+ VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_NEG_X, vec2(0, 0));
+
+ u32_darray* indices = u32_darray_new(vertices->len);
+
+ for (u32 i = 0; i < vertices->len; i++) {
+ u32_darray_push(indices, i);
+ vertices->data[i].static_3d.position =
+ vec3_sub(vertices->data[i].static_3d.position,
+ vec3(0.5, 0.5, 0.5)); // make center of the cube is the origin of mesh space
+ }
+
+ Geometry geo = {
+ .format = VERTEX_STATIC_3D,
+ .vertices = vertices,
+ .has_indices = true,
+ .index_count = indices->len,
+ .indices = indices, // FIXME: make darray methods that return stack allocated struct
+ };
+
+ return geo;
+}
+
+// --- Spheres
+
+Vec3 spherical_to_cartesian_coords(f32 rho, f32 theta, f32 phi) {
+ f32 x = rho * sin(phi) * cos(theta);
+ f32 y = rho * cos(phi);
+ f32 z = rho * sin(phi) * sin(theta);
+ return vec3(x, y, z);
+}
+
+Geometry Geo_CreateUVsphere(f32 radius, u32 north_south_lines, u32 east_west_lines) {
+ assert(east_west_lines >= 3); // sphere will be degenerate and look gacked without at least 3
+ assert(north_south_lines >= 3);
+
+ Vertex_darray* vertices = Vertex_darray_new(2 + (east_west_lines - 1) * north_south_lines);
+
+ // Create a UV sphere with spherical coordinates
+ // a point P on the unit sphere can be represented P(r, theta, phi)
+ // for each vertex we must convert that to a cartesian R3 coordinate
+
+ // Top point
+ Vertex top = { .static_3d = { .position = vec3(0, radius, 0),
+ .normal = vec3_normalise(vec3(0, radius, 0)),
+ .tex_coords = vec2(0, 0) } };
+ Vertex_darray_push(vertices, top);
+
+ // parallels
+ for (u32 i = 0; i < (east_west_lines - 1); i++) {
+ // phi should range from 0 to pi
+ f32 phi = PI * (((f32)i + 1) / (f32)east_west_lines);
+
+ // meridians
+ for (u32 j = 0; j < east_west_lines; j++) {
+ // theta should range from 0 to 2PI
+ f32 theta = TAU * ((f32)j / (f32)north_south_lines);
+ Vec3 position = spherical_to_cartesian_coords(radius, theta, phi);
+ // f32 d = vec3_len(position);
+ // print_vec3(position);
+ // printf("Phi %f Theta %f d %d\n", phi, theta, d);
+ // assert(d == radius); // all points on the sphere should be 'radius' away from the origin
+ Vertex v = { .static_3d = {
+ .position = position,
+ .normal =
+ vec3_normalise(position), // normal vector on sphere is same as position
+ .tex_coords = vec2(0, 0) // TODO
+ } };
+ Vertex_darray_push(vertices, v);
+ }
+ }
+
+ // Bottom point
+ Vertex bot = { .static_3d = { .position = vec3(0, -radius, 0),
+ .normal = vec3_normalise(vec3(0, -radius, 0)),
+ .tex_coords = vec2(0, 0) } };
+ Vertex_darray_push(vertices, bot);
+
+ u32_darray* indices = u32_darray_new(1);
+
+ // top bottom rings
+ for (u32 i = 0; i < north_south_lines; i++) {
+ u32 i1 = i + 1;
+ u32 i2 = (i + 1) % north_south_lines + 1;
+ push_triangle(indices, 0, i2, i1);
+ /* TRACE("Push triangle (%.2f %.2f %.2f)->(%.2f %.2f %.2f)->(%.2f %.2f %.2f)\n", */
+ /* vertices->data[0].static_3d.position.x, vertices->data[0].static_3d.position.y, */
+ /* vertices->data[0].static_3d.position.z, vertices->data[i1].static_3d.position.x, */
+ /* vertices->data[i1].static_3d.position.y, vertices->data[i1].static_3d.position.z, */
+ /* vertices->data[i2].static_3d.position.x, vertices->data[i2].static_3d.position.y, */
+ /* vertices->data[i2].static_3d.position.z); */
+ u32 bot = vertices->len - 1;
+ u32 i3 = i + north_south_lines * (east_west_lines - 2) + 1;
+ u32 i4 = (i + 1) % north_south_lines + north_south_lines * (east_west_lines - 2) + 1;
+ push_triangle(indices, bot, i3, i4);
+ }
+
+ // quads
+ for (u32 i = 0; i < east_west_lines - 2; i++) {
+ u32 ring_start = i * north_south_lines + 1;
+ u32 next_ring_start = (i + 1) * north_south_lines + 1;
+ /* printf("ring start %d next ring start %d\n", ring_start, next_ring_start); */
+ /* print_vec3(vertices->data[ring_start].static_3d.position); */
+ /* print_vec3(vertices->data[next_ring_start].static_3d.position); */
+ for (u32 j = 0; j < north_south_lines; j++) {
+ u32 i0 = ring_start + j;
+ u32 i1 = next_ring_start + j;
+ u32 i2 = ring_start + (j + 1) % north_south_lines;
+ u32 i3 = next_ring_start + (j + 1) % north_south_lines;
+ push_triangle(indices, i0, i2, i1);
+ /* TRACE("Push triangle (%.2f %.2f %.2f)->(%.2f %.2f %.2f)->(%.2f %.2f %.2f)\n", */
+ /* vertices->data[i0].static_3d.position.x, vertices->data[i0].static_3d.position.y, */
+ /* vertices->data[i0].static_3d.position.z, vertices->data[i1].static_3d.position.x, */
+ /* vertices->data[i1].static_3d.position.y, vertices->data[i1].static_3d.position.z, */
+ /* vertices->data[i2].static_3d.position.x, vertices->data[i2].static_3d.position.y, */
+ /* vertices->data[i2].static_3d.position.z); */
+ push_triangle(indices, i1, i2, i3);
+ }
+ }
+
+ Geometry geo = {
+ .format = VERTEX_STATIC_3D,
+ .vertices = vertices,
+ .has_indices = true,
+ .index_count = indices->len,
+ .indices = indices,
+ };
+
+ return geo;
+}
+
+Geometry Geo_CreateCone(f32 radius, f32 height, u32 resolution) {
+ Vertex_darray* vertices = Vertex_darray_new((resolution + 1) * 2);
+ u32_darray* indices = u32_darray_new(resolution * 2 * 3);
+
+ // TODO: decide how UVs are unwrapped
+
+ // tip
+ VERT_3D(vertices, vec3(0.0, height, 0.0), VEC3_Y, vec2(0, 0));
+
+ // sides
+ f32 step = TAU / resolution;
+
+ for (u32 i = 0; i < resolution; i++) {
+ f32 x = cos(step * i) * radius;
+ f32 z = sin(step * i) * radius;
+ Vec3 pos = vec3(x, 0.0, z);
+ Vec3 tip_to_vertex = vec3_sub(pos, vertices->data[0].static_3d.position);
+ Vec3 center_to_vertex = pos;
+ Vec3 tangent = vec3_cross(VEC3_Y, center_to_vertex);
+ Vec3 normal_dir = vec3_cross(tangent, tip_to_vertex);
+ Vec3 normal = vec3_normalise(normal_dir);
+ VERT_3D(vertices, pos, normal, vec2(0, 0));
+ }
+ for (u32 i = 1; i < resolution; i++) {
+ push_triangle(indices, 0, i + 1, i);
+ }
+ push_triangle(indices, 0, 1, resolution);
+
+ // base center
+ u32 center_idx = vertices->len;
+ VERT_3D(vertices, VEC3_ZERO, VEC3_NEG_Y, vec2(0, 0));
+
+ // base circle
+ for (u32 i = 0; i < resolution; i++) {
+ f32 x = cos(step * i) * radius;
+ f32 z = sin(step * i) * radius;
+ VERT_3D(vertices, vec3(x, 0.0, z), VEC3_NEG_Z, vec2(0, 0));
+ }
+ for (u32 i = 1; i < resolution; i++) {
+ push_triangle(indices, center_idx, center_idx + i, center_idx + i + 1);
+ }
+ push_triangle(indices, center_idx, center_idx + resolution, center_idx + 1);
+
+ Geometry geo = {
+ .format = VERTEX_STATIC_3D,
+ .vertices = vertices,
+ .has_indices = true,
+ .index_count = indices->len,
+ .indices = indices,
+ };
+ return geo;
+}
+
+Geometry Geo_CreateCylinder(f32 radius, f32 height, u32 resolution) {
+ Vertex_darray* vertices = Vertex_darray_new(1);
+ u32_darray* indices = u32_darray_new(1);
+
+ f32 step = TAU / resolution;
+
+ // bot cap
+ VERT_3D(vertices, VEC3_ZERO, VEC3_NEG_Y, vec2(0, 0));
+ for (u32 i = 0; i < resolution; i++) {
+ VERT_3D(vertices, vec3(cos(step * i) * radius, 0.0, sin(step * i) * radius), VEC3_NEG_Y,
+ vec2(0, 0));
+ }
+ for (u32 i = 1; i < resolution; i++) {
+ push_triangle(indices, 0, i, i + 1);
+ }
+ push_triangle(indices, 0, resolution, 1);
+
+ // top cap
+ u32 center_idx = vertices->len;
+ VERT_3D(vertices, vec3(0.0, height, 0.0), VEC3_Y, vec2(0, 0));
+ for (u32 i = 0; i < resolution; i++) {
+ VERT_3D(vertices, vec3(cos(step * i) * radius, height, sin(step * i) * radius), VEC3_Y,
+ vec2(0, 0));
+ }
+ for (u32 i = 1; i < resolution; i++) {
+ push_triangle(indices, center_idx, center_idx + i + 1, center_idx + i);
+ }
+ push_triangle(indices, center_idx, center_idx + 1, center_idx + resolution);
+
+ // sides
+ u32 sides_start = vertices->len;
+ for (u32 i = 0; i < resolution; i++) {
+ f32 x = cos(step * i) * radius;
+ f32 z = sin(step * i) * radius;
+ // top then bottom
+ VERT_3D(vertices, vec3(x, height, z), vec3_normalise(vec3(x, 0.0, z)), vec2(0, 0));
+ VERT_3D(vertices, vec3(x, 0.0, z), vec3_normalise(vec3(x, 0.0, z)), vec2(0, 0));
+ }
+ for (u32 i = 0; i < resolution; i++) {
+ u32 current = sides_start + i * 2;
+ u32 next = sides_start + ((i + 1) % resolution) * 2;
+ push_triangle(indices, current, next, current + 1);
+ push_triangle(indices, current + 1, next, next + 1);
+ }
+
+ Geometry geo = {
+ .format = VERTEX_STATIC_3D,
+ .vertices = vertices,
+ .has_indices = true,
+ .index_count = indices->len,
+ .indices = indices,
+ };
+ return geo;
+}
diff --git a/archive/src/maths/primitives.h b/archive/src/maths/primitives.h
new file mode 100644
index 0000000..4965545
--- /dev/null
+++ b/archive/src/maths/primitives.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <assert.h>
+#include <stdlib.h>
+#include "core.h"
+#include "maths_types.h"
+#include "render_types.h"
+
+Geometry Geo_CreatePlane(f32x2 extents, u32 tiling_u, u32 tiling_v);
+Geometry Geo_CreateCuboid(f32x3 extents);
+Geometry Geo_CreateCylinder(f32 radius, f32 height, u32 resolution);
+Geometry Geo_CreateCone(f32 radius, f32 height, u32 resolution);
+Geometry Geo_CreateUVsphere(f32 radius, u32 north_south_lines, u32 east_west_lines);
+Geometry Geo_CreateIcosphere(f32 radius, f32 n_subdivisions);
+
+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 };
+
+#define VERT_3D(arr, pos, norm, uv) \
+ { \
+ Vertex v = { .static_3d = { .position = pos, .normal = norm, .tex_coords = uv } }; \
+ Vertex_darray_push(arr, v); \
+ } \ No newline at end of file