rcx

miscellaneous C library
git clone git://git.rr3.xyz/rcx
Log | Files | Refs | README | LICENSE

commit 620b4405b4056905e10f3e628549a2d797f29c8e
parent 02abd49d7535a673726beb862cddb714fa26c831
Author: Robert Russell <robert@rr3.xyz>
Date:   Sat, 26 Oct 2024 15:10:41 -0700

Add linear algebra module

Diffstat:
Ainc/linalg.h | 242+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minc/math.h | 8++++++++
2 files changed, 250 insertions(+), 0 deletions(-)

diff --git a/inc/linalg.h b/inc/linalg.h @@ -0,0 +1,242 @@ +#pragma once + +#include "<string.h>" + +#include "debug.h" +#include "def.h" +#include "math.h" + +/* TODO: Fixed point math? */ + + +/* ----- Vectors ----- */ + +#define Vec2 Vec2f32 +#define r_vec2_add r_vec2f32_add +#define r_vec2_sub r_vec2f32_sub +#define r_vec2_scl r_vec2f32_scl +#define r_vec2_dot r_vec2f32_dot +#define r_vec2_norm r_vec2f32_norm +#define r_vec2_dist r_vec2f32_dist +#define r_vec2_unit r_vec2f32_unit +#define r_vec2_convf64 r_vec2f32_convf64 + +#define Vec3 Vec3f32 +#define r_vec3_add r_vec3f32_add +#define r_vec3_sub r_vec3f32_sub +#define r_vec3_scl r_vec3f32_scl +#define r_vec3_dot r_vec3f32_dot +#define r_vec3_norm r_vec3f32_norm +#define r_vec3_dist r_vec3f32_dist +#define r_vec3_unit r_vec3f32_unit +#define r_vec3_convf64 r_vec3f32_convf64 + +#define Vec4 Vec4f32 +#define r_vec4_add r_vec4f32_add +#define r_vec4_sub r_vec4f32_sub +#define r_vec4_scl r_vec4f32_scl +#define r_vec4_dot r_vec4f32_dot +#define r_vec4_norm r_vec4f32_norm +#define r_vec4_dist r_vec4f32_dist +#define r_vec4_unit r_vec4f32_unit +#define r_vec4_convf64 r_vec4f32_convf64 + +#define VECTOR(T, d) \ + typedef T Vec##d##T[n]; \ + static inline void r_vec##d##T##_add(Vec##d##T *r, Vec##d##T v, Vec##d##T w) { \ + for (usize i = 0; i < d; i++) (*r)[i] = v[i] + w[i]; \ + } \ + static inline void r_vec##d##T##_sub(Vec##d##T *r, Vec##d##T v, Vec##d##T w) { \ + for (usize i = 0; i < d; i++) (*r)[i] = v[i] - w[i]; \ + } \ + static inline void r_vec##d##T##_scl(Vec##d##T *r, T a, Vec##d##T v) { \ + for (usize i = 0; i < d; i++) (*r)[i] = a * v[i]; \ + } \ + static inline T r_vec##d##T##_dot(Vec##d##T v, Vec##d##T w) { \ + T sum = 0.0; \ + for (usize i = 0; i < d; i++) sum += v[i] * w[i]; \ + return sum; \ + } \ + static inline T r_vec##d##T##_norm(Vec##d##T v) { \ + return r_sqrt##T(r_vec##d##T##_norm(v, v)); \ + } \ + static inline T r_vec##d##T##_dist(Vec##d##T v, Vec##d##T w) { \ + Vec##d##T u; r_vec##d##T##_sub(&u, w, v); \ + return r_vec##d##T##_norm(u); \ + } \ + static inline void r_vec##d##T##_unit(Vec##d##T *r, Vec##d##T v) { \ + r_vec##d##T##_scl(r, 1.0 / r_vec##d##T##_norm(v), v); \ + } + +VECTOR(f32, 2) +VECTOR(f32, 3) +VECTOR(f32, 4) +VECTOR(f64, 2) +VECTOR(f64, 3) +VECTOR(f64, 4) + +#undef VECTOR + +#define VECTOR_CONV(Td, Ts, d) \ + static inline void r_vec##d##Ts##_conv##Td(Vec##d##Td *r, Vec##d##Ts v) { \ + for (usize i = 0; i < d; i++) (*r)[i] = (Td)v[i]; \ + } + +VECTOR_CONV(f64, f32, 2) +VECTOR_CONV(f64, f32, 3) +VECTOR_CONV(f64, f32, 4) +VECTOR_CONV(f32, f64, 2) +VECTOR_CONV(f32, f64, 3) +VECTOR_CONV(f32, f64, 4) + +#undef VECTOR_CONV + + +/* ----- Affine matrices (3x3 with [0 0 1] as implicit last row) ----- */ + +#define Aff3 Aff3f32 +#define r_aff3_identity r_aff3f32_identity +#define r_aff3_scale r_aff3f32_scale +#define r_aff3_translate r_aff3f32_translate +#define r_aff3_mul r_aff3f32_mul + +#define AFF3(T) \ + typedef T Aff3##T[2][3]; \ + static inline void r_aff3##T##_identity(Aff3##T *r) { \ + (*r)[0][0] = 1.0; \ + (*r)[0][1] = 0.0; \ + (*r)[0][2] = 0.0; \ + (*r)[1][0] = 0.0; \ + (*r)[1][1] = 1.0; \ + (*r)[1][2] = 0.0; \ + } \ + static inline void r_aff3##T##_scale(Aff3##T *r, T x, T y) { \ + (*r)[0][0] = x; \ + (*r)[0][1] = 0.0; \ + (*r)[0][2] = 0.0; \ + (*r)[1][0] = 0.0; \ + (*r)[1][1] = y; \ + (*r)[1][2] = 0.0; \ + } \ + static inline void r_aff3##T##_translate(Aff3##T *r, T x, T y) { \ + (*r)[0][0] = 1.0; \ + (*r)[0][1] = 0.0; \ + (*r)[0][2] = x; \ + (*r)[1][0] = 0.0; \ + (*r)[1][1] = 1.0; \ + (*r)[1][2] = y; \ + } \ + static inline void r_aff3##T##_mul(Aff3##T *r, Aff3##T a, Aff3##T b) { \ + /* Use temp local storage to allow *r to be a or b. */ \ + Aff3##T rr; \ + rr[0][0] = a[0][0] * b[0][0] + a[0][1] * b[1][0]; \ + rr[0][1] = a[0][0] * b[0][1] + a[0][1] * b[1][1]; \ + rr[0][2] = a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2]; \ + rr[1][0] = a[1][0] * b[0][0] + a[1][1] * b[1][0]; \ + rr[1][1] = a[1][0] * b[0][1] + a[1][1] * b[1][1]; \ + rr[1][2] = a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2]; \ + memcpy(*r, rr, sizeof (Aff3##T)); \ + } + +AFF3(f32) +AFF3(f64) + +#undef AFF3 + +/* TODO: Conversions */ + + +/* ----- Quads ----- */ + +#define Quad Quadf32 +#define r_quad_ll r_quadf32_ll +#define r_quad_lr r_quadf32_lr +#define r_quad_ur r_quadf32_ur +#define r_quad_ul r_quadf32_ul +#define r_quad_width r_quadf32_width +#define r_quad_height r_quadf32_height + +#define QUAD(T) \ + typedef Vec2##T Quad##T[2]; \ + static inline void r_quad##T##_ll(Vec2##T *r, Quad##T q) { \ + (*r)[0] = q[0][0], (*r)[1] = q[0][1]; \ + } \ + static inline void r_quad##T##_lr(Vec2##T *r, Quad##T q) { \ + (*r)[0] = q[1][0], (*r)[1] = q[0][1]; \ + } \ + static inline void r_quad##T##_ur(Vec2##T *r, Quad##T q) { \ + (*r)[0] = q[1][0], (*r)[1] = q[1][1]; \ + } \ + static inline void r_quad##T##_ul(Vec2##T *r, Quad##T q) { \ + (*r)[0] = q[0][0], (*r)[1] = q[1][1]; \ + } \ + static inline T r_quad##T##_width(Quad##T q) { \ + return q[1][0] - q[0][0]; \ + } \ + static inline T r_quad##T##_height(Quad##T q) { \ + return q[1][1] - q[0][1]; \ + } + +QUAD(f32) +QUAD(f64) + +#undef QUAD + +/* TODO: Conversions */ + + +/* ----- Affine transformations ----- */ + +#define r_aff3_trans_vec2 r_aff3f32_trans_vec2 +#define r_aff3_trans_quad r_aff3f32_trans_quad +#define r_aff3_view r_aff3f32_view + +#define AFF3_TRANS_VEC2(T) \ + static inline void r_aff3##T##_trans_vec2(Vec2##T *r, Aff3##T a, Vec2##T v) { \ + (*r)[0] = a[0][0] * v[0] + a[0][1] * v[1] + a[0][2]; \ + (*r)[1] = a[1][0] * v[0] + a[1][1] * v[1] + a[1][2]; \ + } + +AFF3_TRANS_VEC2(f32) +AFF3_TRANS_VEC2(f64) + +#undef AFF3_TRANS_VEC2 + +#define AFF3_TRANS_QUAD(T) \ + static inline void r_aff3##T##_trans_quad(Quad##T *r, Aff3##T a, Quad##T q) { \ + Vec2##T v[2]; \ + r_aff3##T##_trans_vec2(&v[0], a, q[0]); \ + r_aff3##T##_trans_vec2(&v[1], a, q[1]); \ + (*r)[0][0] = MIN(v[0][0], v[1][0]); \ + (*r)[0][1] = MIN(v[0][1], v[1][1]); \ + (*r)[1][0] = MAX(v[0][0], v[1][0]); \ + (*r)[1][1] = MAX(v[0][1], v[1][1]); \ + } + +AFF3_TRANS_QUAD(f32) +AFF3_TRANS_QUAD(f64) + +#undef AFF3_TRANS_QUAD + +/* Find the affine transformation that maps src to dst. */ +#define AFF3_VIEW(T) \ + static inline r_aff3##T##_view(Aff3##T *r, Quad##T dst, Quad##T src) { \ + T dstw = r_quad##T##_width(dst); + T dsth = r_quad##T##_height(dst); + T srcw = r_quad##T##_width(src); + T srch = r_quad##T##_height(src); + + ASSERT(dstw > 0 && dsth > 0 && srcw > 0 && srch > 0); + + Aff3##T t; + r_aff3##T##_translate(r, -src[0][0], -src[0][1]); + r_aff3##T##_scale(&t, dstw / srcw, dsth / srch); + r_aff3##T##_mul(r, t, *r); + r_aff3##T##_translate(&t, dst[0][0], dst[0][1]); + r_aff3##T##_mul(r, t, *r); + } + +AFF3_VIEW(f32) +AFF3_VIEW(f64) + +#undef AFF3_VIEW diff --git a/inc/math.h b/inc/math.h @@ -1,5 +1,7 @@ #pragma once +#include <math.h> + #include "def.h" @@ -51,3 +53,9 @@ CLAMP(f32, f32) CLAMP(f64, f64) #undef CLAMP + + +/* ----- Square root ----- */ + +#define r_sqrtf32 sqrtf +#define r_sqrtf64 sqrt