#ifndef _PIUMA_LIB_MATH_H_ #define _PIUMA_LIB_MATH_H_ #include "types.h" #include // Vector types union v2 { struct { f32 x, y; }; struct { f32 r, g; }; struct { f32 u, v; }; struct { f32 E[2]; }; }; union v2s { struct { s32 x, y; }; struct { s32 r, g; }; struct { s32 u, v; }; struct { s32 E[2]; }; }; union v2u { struct { u32 x, y; }; struct { u32 r, g; }; struct { u32 u, v; }; struct { u32 E[2]; }; }; union v3 { struct { f32 x, y, z; }; struct { f32 r, g, b; }; struct { f32 u, v, w_; }; struct { f32 E[3]; }; struct { v2 xy; f32 ignored0; }; struct { f32 ignored1; v2 yz; }; struct { v2 uv; f32 ignored2; }; struct { f32 ignored3; v2 vw_; }; struct { f32 pitch; f32 yaw; f32 roll; }; }; union v3s { struct { s32 x, y, z; }; struct { s32 r, g, b; }; struct { s32 u, v, w_; }; struct { s32 E[3]; }; struct { v2s xy; s32 ignored0; }; struct { s32 ignored1; v2s yz; }; struct { v2s uv; s32 ignored2; }; struct { s32 ignored3; v2s vw_; }; struct { s32 pitch; s32 yaw; s32 roll; }; }; union v3u { struct { u32 x, y, z; }; struct { u32 r, g, b; }; struct { u32 u, v, w_; }; struct { u32 E[3]; }; struct { v2u xy; u32 ignored0; }; struct { u32 ignored1; v2u yz; }; struct { v2u uv; u32 ignored2; }; struct { u32 ignored3; v2u vw_; }; struct { u32 pitch; u32 yaw; u32 roll; }; }; union v4 { struct { f32 x, y, z, w; }; struct { f32 r, g, b, a; }; struct { f32 E[4]; }; struct { v2 xy; f32 ignored0; f32 ignored1; }; struct { f32 ignored2; v2 yz; f32 ignored3; }; struct { f32 ignored4; f32 ignored5; v2 zw; }; struct { v2 uv; f32 ignored6; f32 ignored7; }; struct { v3 xyz; f32 ignored8; }; struct { v3 rgb; f32 ignored9; }; }; union v4s { struct { s32 x, y, z, w; }; struct { s32 r, g, b, a; }; struct { s32 E[4]; }; struct { v2s xy; s32 ignored0; s32 ignored1; }; struct { s32 ignored2; v2s yz; s32 ignored3; }; struct { s32 ignored4; s32 ignored5; v2s zw; }; struct { v2s uv; s32 ignored6; s32 ignored7; }; struct { v3s xyz; s32 ignored8; }; struct { v3s rgb; s32 ignored9; }; }; union v4u { struct { u32 x, y, z, w; }; struct { u32 r, g, b, a; }; struct { u32 E[4]; }; struct { v2u xy; u32 ignored0; u32 ignored1; }; struct { u32 ignored2; v2u yz; u32 ignored3; }; struct { u32 ignored4; u32 ignored5; v2u zw; }; struct { v2u uv; u32 ignored6; u32 ignored7; }; struct { v3u xyz; u32 ignored8; }; struct { v3u rgb; u32 ignored9; }; }; // Matrix types union m3x3 { struct { v3 row[3]; }; struct { f32 E[3][3]; }; }; typedef m3x3 m3; union m4x4 { struct { v4 row[4]; }; struct { f32 E[4][4]; }; }; typedef m4x4 m4; static const m3 m3_zero = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const m3 m3_identity = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; static const m4 m4_zero = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const m4 m4_identity = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; // Angles static const f32 PI = 3.141592653589793238462643383; static const f32 TAU = 6.283185307179586476925286766; #define radians(x) (x*TAU/360) #define degrees(x) (x*360/TAU) // Utilities #define square(x) ((x)*(x)) #define minimum(a, b) ((a) < (b) ? (a) : (b)) #define maximum(a, b) ((a) > (b) ? (a) : (b)) inline f32 clamp(f32 min, f32 max, f32 value) { if(value < min) return min; if(value > max) return max; return value; } inline f32 lerp(f32 start, f32 end, f32 u) { //return (1 - u) * start + u * end; return start + (end - start) * u; } inline v3 lerp(v3 start, v3 end, f32 u) { f32 x = lerp(start.x, end.x, u); f32 y = lerp(start.y, end.y, u); f32 z = lerp(start.z, end.z, u); return v3{x, y, z}; } inline v4 lerp(v4 start, v4 end, f32 u) { f32 x = lerp(start.x, end.x, u); f32 y = lerp(start.y, end.y, u); f32 z = lerp(start.z, end.z, u); f32 w = lerp(start.w, end.w, u); return v4{x, y, z, w}; } inline f32 map(f32 new_start, f32 new_end, f32 old_start, f32 old_end, f32 u) { f32 old_range = old_end - old_start; f32 new_range = new_end - new_start; return (u - old_start) / old_range * new_range + new_start; } // Conversions inline v2 V2(v2s a) { return {(f32)a.x, (f32)a.y}; } inline v2 V2(v2u a) { return {(f32)a.x, (f32)a.y}; } inline v2s V2S(v2 a) { return {(s32)a.x, (s32)a.y}; } inline v2s V2S(v2u a) { return {(s32)a.x, (s32)a.y}; } inline v2u V2U(v2 a) { return {(u32)a.x, (u32)a.y}; } inline v2u V2U(v2s a) { return {(u32)a.x, (u32)a.y}; } inline v3 V3(v2 a, f32 z) { return {a.x, a.y, z}; } inline v3 V3(v3s a) { return {(f32)a.x, (f32)a.y, (f32)a.z}; } inline v3 V3(v3u a) { return {(f32)a.x, (f32)a.y, (f32)a.z}; } inline v3 V3(f32 e[3]) { return v3{e[0], e[1], e[2]}; } inline v3 V3(v4 v) { return v3{v.x / v.w, v.y / v.w, v.z / v.w}; } inline v3s V3S(v2s a, s32 z) { return {a.x, a.y, z}; } inline v3s V3S(v3 a) { return {(s32)a.x, (s32)a.y, (s32)a.z}; } inline v3s V3S(v3u a) { return {(s32)a.x, (s32)a.y, (s32)a.z}; } inline v3u V3U(v2u a, u32 z) { return {a.x, a.y, z}; } inline v3u V3U(v3 a) { return {(u32)a.x, (u32)a.y, (u32)a.z}; } inline v3u V3U(v3s a) { return {(u32)a.x, (u32)a.y, (u32)a.z}; } inline v4 V4(v2 a, f32 z, f32 w) { v4 result; result.xy = a; result.z = z; result.w = w; return result; } inline v4 V4(v3 a, f32 w) { v4 result; result.xyz = a; result.w = w; return result; } inline v4 V4(f32 e[4]) { return v4{e[0], e[1], e[2], e[3]}; } inline m3 M3(m4 m) { return m3{ m.row[0].xyz, m.row[1].xyz, m.row[2].xyz }; } inline m4 M4(m3 m) { return m4{ V4(m.row[0], 0), V4(m.row[1], 0), V4(m.row[2], 0), v4{0,0,0,1} }; } // Operators inline v2 operator+(v2 a) { return a; } inline v2 operator-(v2 a) { v2 result = { -a.x, -a.y }; return result; } inline bool operator==(v2 a, v2 b) { return a.x == b.x && a.y == b.y; } inline bool operator!=(v2 a, v2 b) { return !(a == b); } inline v2 operator+(v2 a, v2 b) { v2 result; result.x = a.x + b.x; result.y = a.y + b.y; return result; } inline v2 operator-(v2 a, v2 b) { v2 result; result.x = a.x - b.x; result.y = a.y - b.y; return result; } inline v2 operator*(v2 a, v2 b) { v2 result; result.x = a.x * b.x; result.y = a.y * b.y; return result; } inline v2 operator/(v2 a, v2 b) { v2 result; result.x = a.x / b.x; result.y = a.y / b.y; return result; } inline v2 operator*(v2 a, f32 b) { v2 result; result.x = a.x * b; result.y = a.y * b; return result; } inline v2 operator/(v2 a, f32 b) { v2 result; result.x = a.x / b; result.y = a.y / b; return result; } inline v2 operator*(f32 a, v2 b) { v2 result; result.x = a * b.x; result.y = a * b.y; return result; } inline v2 & operator+=(v2 &a, v2 b) { a = a + b; return a; } inline v2 & operator-=(v2 &a, v2 b) { a = a - b; return a; } inline v2 & operator*=(v2 &a, v2 b) { a = a * b; return a; } inline v2 & operator/=(v2 &a, v2 b) { a = a / b; return a; } inline v2 & operator*=(v2 &a, f32 b) { a = a * b; return a; } inline v2 & operator/=(v2 &a, f32 b) { a = a / b; return a; } inline v2s operator+(v2s a) { return a; } inline v2s operator-(v2s a) { v2s result = { -a.x, -a.y }; return result; } inline bool operator==(v2s a, v2s b) { return a.x == b.x && a.y == b.y; } inline bool operator!=(v2s a, v2s b) { return !(a == b); } inline v2s operator+(v2s a, v2s b) { v2s result; result.x = a.x + b.x; result.y = a.y + b.y; return result; } inline v2s operator-(v2s a, v2s b) { v2s result; result.x = a.x - b.x; result.y = a.y - b.y; return result; } inline v2s operator*(v2s a, v2s b) { v2s result; result.x = a.x * b.x; result.y = a.y * b.y; return result; } inline v2s operator/(v2s a, v2s b) { v2s result; result.x = a.x / b.x; result.y = a.y / b.y; return result; } inline v2s operator*(v2s a, f32 b) { v2s result; result.x = a.x * b; result.y = a.y * b; return result; } inline v2s operator/(v2s a, f32 b) { v2s result; result.x = a.x / b; result.y = a.y / b; return result; } inline v2s operator*(f32 a, v2s b) { v2s result; result.x = a * b.x; result.y = a * b.y; return result; } inline v2s & operator+=(v2s &a, v2s b) { a = a + b; return a; } inline v2s & operator-=(v2s &a, v2s b) { a = a - b; return a; } inline v2s & operator*=(v2s &a, v2s b) { a = a * b; return a; } inline v2s & operator/=(v2s &a, v2s b) { a = a / b; return a; } inline v2s & operator*=(v2s &a, f32 b) { a = a * b; return a; } inline v2s & operator/=(v2s &a, f32 b) { a = a / b; return a; } inline v2u operator+(v2u a) { return a; } inline v2u operator-(v2u a) { v2u result = { -a.x, -a.y }; return result; } inline bool operator==(v2u a, v2u b) { return a.x == b.x && a.y == b.y; } inline bool operator!=(v2u a, v2u b) { return !(a == b); } inline v2u operator+(v2u a, v2u b) { v2u result; result.x = a.x + b.x; result.y = a.y + b.y; return result; } inline v2u operator-(v2u a, v2u b) { v2u result; result.x = a.x - b.x; result.y = a.y - b.y; return result; } inline v2u operator*(v2u a, v2u b) { v2u result; result.x = a.x * b.x; result.y = a.y * b.y; return result; } inline v2u operator/(v2u a, v2u b) { v2u result; result.x = a.x / b.x; result.y = a.y / b.y; return result; } inline v2u operator*(v2u a, f32 b) { v2u result; result.x = a.x * b; result.y = a.y * b; return result; } inline v2u operator/(v2u a, f32 b) { v2u result; result.x = a.x / b; result.y = a.y / b; return result; } inline v2u operator*(f32 a, v2u b) { v2u result; result.x = a * b.x; result.y = a * b.y; return result; } inline v2u & operator+=(v2u &a, v2u b) { a = a + b; return a; } inline v2u & operator-=(v2u &a, v2u b) { a = a - b; return a; } inline v2u & operator*=(v2u &a, v2u b) { a = a * b; return a; } inline v2u & operator/=(v2u &a, v2u b) { a = a / b; return a; } inline v2u & operator*=(v2u &a, f32 b) { a = a * b; return a; } inline v2u & operator/=(v2u &a, f32 b) { a = a / b; return a; } inline v3 operator+(v3 a) { return a; } inline v3 operator-(v3 a) { v3 result = { -a.x, -a.y, -a.z }; return result; } inline bool operator==(v3 a, v3 b) { return a.x == b.x && a.y == b.y && a.z == b.z; } inline bool operator!=(v3 a, v3 b) { return !(a == b); } inline v3 operator+(v3 a, v3 b) { v3 result; result.x = a.x + b.x; result.y = a.y + b.y; result.z = a.z + b.z; return result; } inline v3 operator-(v3 a, v3 b) { v3 result; result.x = a.x - b.x; result.y = a.y - b.y; result.z = a.z - b.z; return result; } inline v3 operator*(v3 a, v3 b) { v3 result; result.x = a.x * b.x; result.y = a.y * b.y; result.z = a.z * b.z; return result; } inline v3 operator/(v3 a, v3 b) { v3 result; result.x = a.x / b.x; result.y = a.y / b.y; result.z = a.z / b.z; return result; } inline v3 operator*(v3 a, f32 b) { v3 result; result.x = a.x * b; result.y = a.y * b; result.z = a.z * b; return result; } inline v3 operator/(v3 a, f32 b) { v3 result; result.x = a.x / b; result.y = a.y / b; result.z = a.z / b; return result; } inline v3 operator*(f32 a, v3 b) { v3 result; result.x = a * b.x; result.y = a * b.y; result.z = a * b.z; return result; } inline v3 & operator+=(v3 &a, v3 b) { a = a + b; return a; } inline v3 & operator-=(v3 &a, v3 b) { a = a - b; return a; } inline v3 & operator*=(v3 &a, v3 b) { a = a * b; return a; } inline v3 & operator/=(v3 &a, v3 b) { a = a / b; return a; } inline v3 & operator*=(v3 &a, f32 b) { a = a * b; return a; } inline v3 & operator/=(v3 &a, f32 b) { a = a / b; return a; } inline v4 operator+(v4 a) { return a; } inline v4 operator-(v4 a) { v4 result = { -a.x, -a.y, -a.z, -a.w }; return result; } inline bool operator==(v4 a, v4 b) { return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; } inline bool operator!=(v4 a, v4 b) { return !(a == b); } inline v4 operator+(v4 a, v4 b) { v4 result; result.x = a.x + b.x; result.y = a.y + b.y; result.z = a.z + b.z; result.w = a.w + b.w; return result; } inline v4 operator-(v4 a, v4 b) { v4 result; result.x = a.x - b.x; result.y = a.y - b.y; result.z = a.z - b.z; result.w = a.w - b.w; return result; } inline v4 operator*(v4 a, v4 b) { v4 result; result.x = a.x * b.x; result.y = a.y * b.y; result.z = a.z * b.z; result.w = a.w * b.w; return result; } inline v4 operator/(v4 a, v4 b) { v4 result; result.x = a.x / b.x; result.y = a.y / b.y; result.z = a.z / b.z; result.w = a.w / b.w; return result; } inline v4 operator*(v4 a, f32 b) { v4 result; result.x = a.x * b; result.y = a.y * b; result.z = a.z * b; result.w = a.w * b; return result; } inline v4 operator/(v4 a, f32 b) { v4 result; result.x = a.x / b; result.y = a.y / b; result.z = a.z / b; result.w = a.w / b; return result; } inline v4 operator*(f32 a, v4 b) { v4 result; result.x = a * b.x; result.y = a * b.y; result.z = a * b.z; result.w = a * b.w; return result; } inline v4 & operator+=(v4 &a, v4 b) { a = a + b; return a; } inline v4 & operator-=(v4 &a, v4 b) { a = a - b; return a; } inline v4 & operator*=(v4 &a, v4 b) { a = a * b; return a; } inline v4 & operator/=(v4 &a, v4 b) { a = a / b; return a; } inline v4 & operator*=(v4 &a, f32 b) { a = a * b; return a; } inline v4 & operator/=(v4 &a, f32 b) { a = a / b; return a; } // Vector functions inline f32 dot(v2 a, v2 b) { return a.x*b.x + a.y*b.y; } inline f32 dot(v3 a, v3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; } inline f32 dot(v4 a, v4 b) { return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; } inline v3 cross(v3 a, v3 b) { v3 result; result.x = a.y*b.z - a.z*b.y; result.y = a.z*b.x - a.x*b.z; result.z = a.x*b.y - a.y*b.x; return result; } inline f32 length(v2 a) { return sqrt(dot(a,a)); } inline f32 length(v3 a) { return sqrt(dot(a,a)); } inline f32 length(v4 a) { return sqrt(dot(a,a)); } inline f32 length2(v2 a) { return dot(a,a); } inline f32 length2(v3 a) { return dot(a,a); } inline f32 length2(v4 a) { return dot(a,a); } inline f32 distance(v2 a, v2 b) { return length(a - b); } inline f32 distance(v3 a, v3 b) { return length(a - b); } inline f32 distance(v4 a, v4 b) { return length(a - b); } inline f32 distance2(v2 a, v2 b) { return length2(a - b); } inline f32 distance2(v3 a, v3 b) { return length2(a - b); } inline f32 distance2(v4 a, v4 b) { return length2(a - b); } inline v2 normalize(v2 a) { return a / length(a); } inline v3 normalize(v3 a) { return a / length(a); } inline v4 normalize(v4 a) { return a / length(a); } // Matrix operators inline v3 extract_column(m3 m, u8 column_index) { v3 result; result.x = m.E[0][column_index]; result.y = m.E[1][column_index]; result.z = m.E[2][column_index]; return result; } inline v4 extract_column(m4 m, u8 column_index) { v4 result; result.x = m.E[0][column_index]; result.y = m.E[1][column_index]; result.z = m.E[2][column_index]; result.w = m.E[3][column_index]; return result; } inline v3 operator*(m3 m, v3 v) { v3 result; result.x = dot(m.row[0], v); result.y = dot(m.row[1], v); result.z = dot(m.row[2], v); return result; } inline m3 operator*(m3 a, m3 b) { m3 result; v3 c0 = extract_column(b, 0); v3 c1 = extract_column(b, 1); v3 c2 = extract_column(b, 2); result.E[0][0] = dot(a.row[0], c0); result.E[0][1] = dot(a.row[0], c1); result.E[0][2] = dot(a.row[0], c2); result.E[1][0] = dot(a.row[1], c0); result.E[1][1] = dot(a.row[1], c1); result.E[1][2] = dot(a.row[1], c2); result.E[2][0] = dot(a.row[2], c0); result.E[2][1] = dot(a.row[2], c1); result.E[2][2] = dot(a.row[2], c2); return result; } inline v4 operator*(m4 m, v4 v) { v4 result; result.x = dot(m.row[0], v); result.y = dot(m.row[1], v); result.z = dot(m.row[2], v); result.w = dot(m.row[3], v); return result; } inline m4 operator*(m4 a, m4 b) { m4 result; v4 c0 = extract_column(b, 0); v4 c1 = extract_column(b, 1); v4 c2 = extract_column(b, 2); v4 c3 = extract_column(b, 3); result.E[0][0] = dot(a.row[0], c0); result.E[0][1] = dot(a.row[0], c1); result.E[0][2] = dot(a.row[0], c2); result.E[0][3] = dot(a.row[0], c3); result.E[1][0] = dot(a.row[1], c0); result.E[1][1] = dot(a.row[1], c1); result.E[1][2] = dot(a.row[1], c2); result.E[1][3] = dot(a.row[1], c3); result.E[2][0] = dot(a.row[2], c0); result.E[2][1] = dot(a.row[2], c1); result.E[2][2] = dot(a.row[2], c2); result.E[2][3] = dot(a.row[2], c3); result.E[3][0] = dot(a.row[3], c0); result.E[3][1] = dot(a.row[3], c1); result.E[3][2] = dot(a.row[3], c2); result.E[3][3] = dot(a.row[3], c3); return result; } // Matrix functions inline m3 m3_make_diagonal_matrix(f32 value) { m3 result = m3_zero; result.E[0][0] = value; result.E[1][1] = value; result.E[2][2] = value; return result; } inline m4 m4_make_diagonal_matrix(f32 value) { m4 result = m4_zero; result.E[0][0] = value; result.E[1][1] = value; result.E[2][2] = value; result.E[3][3] = value; return result; } inline f32 determinant_of_minor(m3 m, int skip_r, int skip_c) { f32 minor[2][2]; for(int r = 0, source_r = 0; r < 2; r++, source_r++) { if(source_r == skip_r) source_r++; for(int c = 0, source_c = 0; c < 2; c++, source_c++) { if(source_c == skip_c) source_c++; minor[r][c] = m.E[source_r][source_c]; } } return minor[0][0] * minor[1][1] - minor[0][1] * minor[1][0]; } inline f32 determinant(m3 m) { return + m.E[0][0] * m.E[1][1] * m.E[2][2] + m.E[0][1] * m.E[1][2] * m.E[2][0] + m.E[0][2] * m.E[1][0] * m.E[2][1] - m.E[0][2] * m.E[1][1] * m.E[2][0] - m.E[0][1] * m.E[1][0] * m.E[2][2] - m.E[0][0] * m.E[1][2] * m.E[2][1]; } inline m3 transpose(m3 m) { m3 result; result.E[0][0] = m.E[0][0]; result.E[0][1] = m.E[1][0]; result.E[0][2] = m.E[2][0]; result.E[1][0] = m.E[0][1]; result.E[1][1] = m.E[1][1]; result.E[1][2] = m.E[2][1]; result.E[2][0] = m.E[0][2]; result.E[2][1] = m.E[1][2]; result.E[2][2] = m.E[2][2]; result.E[3][0] = m.E[0][3]; result.E[3][1] = m.E[1][3]; result.E[3][2] = m.E[2][3]; return result; } inline m3 inverse(m3 m) { m3 result; f32 one_over_det = 1.0 / determinant(m); f32 sign = 1; for(int r = 0; r < 3; r++) { for(int c = 0; c < 3; c++) { result.E[c][r] = sign * determinant_of_minor(m, r, c) * one_over_det; sign = -sign; } } return result; } inline f32 determinant_of_minor(m4 m, int skip_r, int skip_c) { m3 minor; for(int r = 0, source_r = 0; r < 3; r++, source_r++) { if(source_r == skip_r) source_r++; for(int c = 0, source_c = 0; c < 3; c++, source_c++) { if(source_c == skip_c) source_c++; minor.E[r][c] = m.E[source_r][source_c]; } } return determinant(minor); } inline f32 determinant(m4 m) { f32 result = 0; f32 sign = 1; int r = 0; // Laplace theorem for(int c = 0; c < 4; c++) { result += m.E[r][c] * sign * determinant_of_minor(m, r, c); sign = -sign; } return result; } inline m4 transpose(m4 m) { m4 result; result.E[0][0] = m.E[0][0]; result.E[0][1] = m.E[1][0]; result.E[0][2] = m.E[2][0]; result.E[0][3] = m.E[3][0]; result.E[1][0] = m.E[0][1]; result.E[1][1] = m.E[1][1]; result.E[1][2] = m.E[2][1]; result.E[1][3] = m.E[3][1]; result.E[2][0] = m.E[0][2]; result.E[2][1] = m.E[1][2]; result.E[2][2] = m.E[2][2]; result.E[2][3] = m.E[3][2]; result.E[3][0] = m.E[0][3]; result.E[3][1] = m.E[1][3]; result.E[3][2] = m.E[2][3]; result.E[3][3] = m.E[3][3]; return result; } inline m4 inverse(m4 m) { m4 result; f32 one_over_det = 1.0 / determinant(m); f32 sign_a = 1; for(int r = 0; r < 4; r++) { f32 sign_b = sign_a; for(int c = 0; c < 4; c++) { result.E[c][r] = sign_b * determinant_of_minor(m, r, c) * one_over_det; sign_b = -sign_b; } sign_a = -sign_a; } return result; } #endif