diff options
Diffstat (limited to 'src/maths')
-rw-r--r-- | src/maths/maths.h | 118 | ||||
-rw-r--r-- | src/maths/maths_types.h | 42 | ||||
-rw-r--r-- | src/maths/primitives.c | 138 | ||||
-rw-r--r-- | src/maths/primitives.h | 13 |
4 files changed, 288 insertions, 23 deletions
diff --git a/src/maths/maths.h b/src/maths/maths.h index 3301634..217f2e0 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -9,6 +9,7 @@ #pragma once #include <math.h> +#include <stdio.h> #include "maths_types.h" // --- Helpers @@ -20,7 +21,7 @@ // 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)) +#define vec3(x, y, z) ((vec3){ 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 }; } @@ -48,10 +49,16 @@ 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 }; } +#define vec2(x, y) ((vec2){ x, y }) +static inline vec2 vec2_div(vec2 a, f32 s) { return (vec2){ a.x / s, a.y / s }; } // 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 @@ -78,6 +85,52 @@ static quat quat_from_axis_angle(vec3 axis, f32 angle, bool normalize) { 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() { @@ -139,6 +192,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) { @@ -151,6 +241,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, @@ -210,7 +301,7 @@ static inline mat4 mat4_look_at(vec3 position, vec3 target, vec3 up) { #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 }) @@ -219,10 +310,10 @@ static transform transform_create(vec3 pos, quat rot, f32 scale) { } static inline mat4 transform_to_mat(transform *tf) { - mat4 trans = mat4_translation(tf->position); - mat4 rot = mat4_rotation(tf->rotation); mat4 scale = mat4_scale(tf->scale); - return mat4_mult(trans, mat4_mult(rot, scale)); + mat4 rotation = mat4_rotation(tf->rotation); + mat4 translation = mat4_translation(tf->position); + return mat4_mult(translation, mat4_mult(rotation, scale)); } // --- Sizing asserts @@ -231,20 +322,3 @@ _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"); - -// --- 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 }) diff --git a/src/maths/maths_types.h b/src/maths/maths_types.h index ba741b9..5ef09db 100644 --- a/src/maths/maths_types.h +++ b/src/maths/maths_types.h @@ -60,4 +60,44 @@ typedef struct transform { quat rotation; f32 scale; bool is_dirty; -} transform;
\ No newline at end of file +} transform; +typedef transform transform3d; + +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) ((u32x3){ 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/src/maths/primitives.c b/src/maths/primitives.c new file mode 100644 index 0000000..b9ec868 --- /dev/null +++ b/src/maths/primitives.c @@ -0,0 +1,138 @@ +#include "primitives.h" +#include "colours.h" +#include "maths.h" +#include "ral_types.h" +#include "render_types.h" + +// TODO: move to another file +void geo_free_data(geometry_data* geo) { + vertex_darray_free(geo->vertices); + geo->vertices = NULL; + // TODO: do indices as well + /* if (geo->has_indices) { */ + /* u32_darray_free(&geo->indices); */ + /* } */ +} + +// vertices +f32 plane_vertex_positions[] = { + // triangle 1 + -0.5, 0, -0.5, -0.5, 0, 0.5, 0.5, 0, -0.5, + // triangle 2 + 0.5, 0, -0.5, -0.5, 0, 0.5, 0.5, 0, 0.5 +}; + +geometry_data geo_create_plane(f32x2 extents) { + f32x2 half_extents = vec2_div(extents, 2.0); + vertex_format format = VERTEX_STATIC_3D; + vertex_darray* vertices = vertex_darray_new(4); + + // vertex_darray_push(vertices, (vertex){ .static_3d = { .position = } }); + + // return (geometry_data) { .format = format, .vertices =.has_indices = true, } +} + +// OLD + +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); \ + } + +geometry_data geo_create_cuboid(f32x3 extents) { + /* static mesh prim_cube_mesh_create() { */ + 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); + } + + geometry_data geo = { + .format = VERTEX_STATIC_3D, + .vertices = vertices, + .has_indices = true, + .indices = *indices, // FIXME: make darray methods that return stack allocated struct + .colour = vec3(0, 0, 0), + }; + + return geo; +} + +/* /\** @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 }; */ +/* } */ + +// --- Spheres + +geometry_data geo_create_uvsphere(f32 radius, f32 north_south_lines, f32 east_west_lines) { + // TODO +} diff --git a/src/maths/primitives.h b/src/maths/primitives.h new file mode 100644 index 0000000..3e0cc5f --- /dev/null +++ b/src/maths/primitives.h @@ -0,0 +1,13 @@ +#pragma once + +#include <assert.h> +#include <stdlib.h> +#include "core.h" +#include "maths_types.h" +#include "render_types.h" + +geometry_data geo_create_plane(f32x2 extents); +geometry_data geo_create_cuboid(f32x3 extents); +geometry_data geo_create_cylinder(f32 radius, f32 height, u32 resolution); +geometry_data geo_create_uvsphere(f32 radius, f32 north_south_lines, f32 east_west_lines); +geometry_data geo_create_icosphere(f32 radius, f32 n_subdivisions);
\ No newline at end of file |