#pragma once
#include <math.h>
typedef struct Vec2f {
union {
struct {
float x, y;
};
struct {
float u, v;
};
};
Vec2f() : x(0.0f), y(0.0f) {};
Vec2f(float x_, float y_) {
x = x_;
y = y_;
}
Vec2f operator+(const Vec2f &other) const {
return Vec2f(x + other.x, y + other.y);
}
Vec2f operator-(const Vec2f &other) const {
return Vec2f(x - other.x, y - other.y);
}
Vec2f operator*(float s) const {
return Vec2f(x * s, y * s);
}
Vec2f operator/(float s) const {
if (s != 0.0f) {
return Vec2f(x / s, y / s);
}
return Vec2f();
}
Vec2f normalized() const {
float len = length();
return (len > 0) ? (*this * (1.0f / len)) : Vec2f();
}
float dot(const Vec2f &other) const {
return x * other.x + y * other.y;
}
float length() const {
return sqrtf(x * x + y * y);
}
} vec2f;
typedef struct Vec3f {
union {
struct {
float x, y, z;
};
struct {
float r, g, b;
};
};
Vec3f() : x(0.0f), y(0.0f), z(0.0f) {};
Vec3f(float x_, float y_, float z_) {
x = x_;
y = y_;
z = z_;
}
Vec3f operator+(const Vec3f &o) const {
return Vec3f(x + o.x, y + o.y, z + o.z);
}
Vec3f operator-(const Vec3f &o) const {
return Vec3f(x - o.x, y - o.y, z - o.z);
}
Vec3f operator*(float s) const {
return Vec3f(x * s, y * s, z * s);
}
Vec3f operator/(float s) const {
if (s != 0.0f) {
return Vec3f(x / s, y / s, z / s);
}
return Vec3f();
}
Vec3f normalized() const {
float len = length();
if (len > 0.0f) {
return *this * (1.0f / len);
}
return Vec3f();
}
float length() const {
return sqrtf(x * x + y * y + z * z);
}
Vec3f cross(const Vec3f &o) const {
return Vec3f(y * o.z - z * o.y, z * o.x - x * o.z, x * o.y - y * o.x);
}
float dot(const Vec3f &o) const {
return x * o.x + y * o.y + z * o.z;
}
} vec3f;
inline vec3f operator*(float s, const vec3f &v) {
return {v.x * s, v.y * s, v.z * s};
}
typedef struct Vec4f {
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
float w = 0.0f;
Vec4f() = default;
Vec4f(float x_, float y_, float z_, float w_) {
x = x_;
y = y_;
z = z_;
w = w_;
}
// probably shouldn't be implicit? I like it though
Vec4f(const vec3f &v, float w_ = 1.0f) {
x = v.x;
y = v.y;
z = v.z;
w = w_;
}
Vec4f operator+(const Vec4f &o) const {
return Vec4f(x + o.x, y + o.y, z + o.z, w + o.w);
}
Vec4f operator*(float s) const {
return Vec4f(x * s, y * s, z * s, w * s);
}
Vec4f operator/(float s) const {
return Vec4f(x / s, y / s, z / s, w / s);
}
Vec4f operator-(const Vec4f &o) const {
return Vec4f(x - o.x, y - o.y, z - o.z, w - o.w);
}
inline Vec3f to_vec3() const {
return vec3f(x, y, z);
}
} vec4f;
typedef struct Mat4 {
// Row Major : m[row][col]
//
// Col0 Col1 Col2 Col3
// |-----------|-----------|-----------|-----------|
// Row0 | Xx | Xy | Xz | Xw |
// Row1 | Yx | Yy | Yz | Yw |
// Row2 | Zx | Zy | Zz | Zw |
// Row3 | Wx | Wy | Wy | Ww |
//
// Flat memory order (16 floats):
// Xx, Xy, Xz, Xw, Yx, Yy, Yz, Yw, Zx, Zy, Zz, Zw, Wx, Wy, Wz, Ww
float m[4][4];
static Mat4 zeroed() {
// 0 0 0 0
// 0 0 0 0
// 0 0 0 0
// 0 0 0 0
Mat4 result;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
result.m[i][j] = 0.0f;
}
}
return result;
}
// 1 0 0 0
// 0 1 0 0
// 0 0 1 0
// 0 0 0 1
static Mat4 identity() {
Mat4 result = Mat4::zeroed();
for (int i = 0; i < 4; ++i) {
result.m[i][i] = 1.0f;
}
return result;
}
Mat4 operator*(const Mat4 &o) const {
Mat4 r;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
float s = 0.0f;
for (int k = 0; k < 4; ++k) {
s += m[i][k] * o.m[k][j];
}
r.m[i][j] = s;
}
}
return r;
}
static Mat4 scale(float sx, float sy, float sz) {
Mat4 r = Mat4::identity();
// sx 0 0 0
// 0 sy 0 0
// 0 0 sz 0
// 0 0 0 1
r.m[0][0] = sx;
r.m[1][1] = sy;
r.m[2][2] = sz;
return r;
}
static Mat4 translate(float tx, float ty, float tz) {
Mat4 r = Mat4::identity();
// 1 0 0 0
// 0 1 0 0
// 0 0 1 0
// tx ty tz 1
r.m[3][0] = tx;
r.m[3][1] = ty;
r.m[3][2] = tz;
return r;
}
static Mat4 rotation_x(float a) {
Mat4 r = Mat4::identity();
// 0 0 0 0 // x axis
// 0 cosf(a) -sinf(a) 0 // y axis
// 0 cosf(a) cosf(a) 0 // z axis
// 0 0 0 1
r.m[1][1] = cosf(a);
r.m[1][2] = sinf(a);
r.m[2][1] = -sinf(a);
r.m[2][2] = cosf(a);
return r;
}
static Mat4 rotation_y(float a) {
Mat4 r = Mat4::identity();
// cosf(a) 0 -sinf(a) 0 // x axis
// 0 0 0 0 // y axis
// sinf(a) 0 cosf(a) 0 // z axis
// 0 0 0 1
r.m[0][0] = cosf(a);
r.m[0][2] = -sinf(a);
r.m[2][0] = sinf(a);
r.m[2][2] = cosf(a);
return r;
}
static Mat4 rotation_z(float a) {
// cosf(a) sinf(a) 0 0 // x axis
// -sinf(a) cosf(a) 0 0 // y axis
// 0 0 1 0 // z axis (lock)
// 0 0 0 1
Mat4 r = Mat4::identity();
r.m[0][0] = cosf(a);
r.m[0][1] = sinf(a);
r.m[1][0] = -sinf(a);
r.m[1][1] = cosf(a);
return r;
}
// Build a 4x4 rotation matrix around an arbitrary axis
static Mat4 rotation_axis(const vec3f &axis, float angle_rad) {
vec3f k = axis.normalized();
float c = cosf(angle_rad);
float s = sinf(angle_rad);
float t = 1.0f - c;
float kx = k.x, ky = k.y, kz = k.z;
Mat4 R;
R.m[0][0] = t * kx * kx + c;
R.m[0][1] = t * kx * ky - s * kz;
R.m[0][2] = t * kx * kz + s * ky;
R.m[0][3] = 0.0f;
// row 1
R.m[1][0] = t * kx * ky + s * kz;
R.m[1][1] = t * ky * ky + c;
R.m[1][2] = t * ky * kz - s * kx;
R.m[1][3] = 0.0f;
// row 2
R.m[2][0] = t * kx * kz - s * ky;
R.m[2][1] = t * ky * kz + s * kx;
R.m[2][2] = t * kz * kz + c;
R.m[2][3] = 0.0f;
// row 3
R.m[3][0] = 0.0f;
R.m[3][1] = 0.0f;
R.m[3][2] = 0.0f;
R.m[3][3] = 1.0f;
return R;
}
void transpose() {
for (int i = 0; i < 4; ++i)
for (int j = i + 1; j < 4; ++j) {
float tmp = m[i][j];
m[i][j] = m[j][i];
m[j][i] = tmp;
}
}
} mat4;
static inline vec4f operator*(const vec4f &v, const mat4 &m) {
return vec4f(
v.x * m.m[0][0] + v.y * m.m[1][0] + v.z * m.m[2][0] + v.w * m.m[3][0],
v.x * m.m[0][1] + v.y * m.m[1][1] + v.z * m.m[2][1] + v.w * m.m[3][1],
v.x * m.m[0][2] + v.y * m.m[1][2] + v.z * m.m[2][2] + v.w * m.m[3][2],
v.x * m.m[0][3] + v.y * m.m[1][3] + v.z * m.m[2][3] + v.w * m.m[3][3]
);
}
static inline vec2f vec2f_lerp(const vec2f &a, const vec2f &b, float t) {
return a * (1.0f - t) + b * t;
}
static inline vec3f vec3f_lerp(const vec3f &a, const vec3f &b, float t) {
return a * (1.0f - t) + b * t;
}
static inline vec4f vec4f_lerp(const vec4f &a, const vec4f &b, float t) {
return vec4f(
a.x + (b.x - a.x) * t,
a.y + (b.y - a.y) * t,
a.z + (b.z - a.z) * t,
a.w + (b.w - a.w) * t
);
}