summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2024-12-27 12:04:51 +1100
committerquou <quou@disroot.org>2024-12-27 12:04:51 +1100
commite8c93463b2ae5114f0c88e768e5625abac9d5a50 (patch)
tree3fc7b774eb9bf172fbcb95bb3a410093a5b5b856
parent0d2179f6beb7e11632b76dac0615e593cafaaf00 (diff)
3D maths
-rw-r--r--Makefile5
-rw-r--r--intermediate/ui.glsl13
-rw-r--r--maths.cpp296
-rw-r--r--maths.hpp505
-rw-r--r--sc/sc.cpp6
-rw-r--r--todo.txt2
-rw-r--r--ui.cpp36
-rw-r--r--ui.hpp8
8 files changed, 857 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index fbc4cf4..68b6b62 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ shaders = $(data_dir)/triangle.csh $(data_dir)/ui.csh
textures = $(data_dir)/22.tex $(data_dir)/kita.tex
packed_files = $(shaders) $(textures)
tools = qstd cfg sc
-objects = app.o c2.o video.o pipeline.o asset.o ui.o
+objects = app.o c2.o video.o pipeline.o asset.o ui.o maths.o
includes = -Iqstd
defines = -Dplat_x86 -Dplat_posix -Dplat_x11 -Dallocation_default_alignment=8
cflags = -MMD -MF $(basename $@).d $(includes) $(defines) $(DEBUG_COMPILE_FLAG)
@@ -61,6 +61,9 @@ asset.o:
ui.o:
$(CXX) -c $(cflags) ui.cpp -o ui.o
+maths.o:
+ $(CXX) -c $(cflags) maths.cpp -o maths.o
+
c2.o:
$(CXX) -c $(cflags) c2.cpp -o c2.o
diff --git a/intermediate/ui.glsl b/intermediate/ui.glsl
index e40d3d5..095d4df 100644
--- a/intermediate/ui.glsl
+++ b/intermediate/ui.glsl
@@ -24,6 +24,17 @@ type: vec4
name: uv
type: vec2
+[struct]
+name: Config
+[variable]
+name: projection
+type: mat4
+
+[cbuffer]
+name: config_buffer
+type: Config
+stage: vertex
+
[texture]
name: atlas
stage: fragment
@@ -40,7 +51,7 @@ type: vec4
void main() {
interpolator.colour = colour;
interpolator.uv = uv;
- gl_Position = vec4(position, 0.0, 1.0);
+ gl_Position = config_buffer.projection * vec4(position, 0.0, 1.0);
}
#endif
diff --git a/maths.cpp b/maths.cpp
new file mode 100644
index 0000000..ed8948f
--- /dev/null
+++ b/maths.cpp
@@ -0,0 +1,296 @@
+#include "maths.hpp"
+
+m4f::m4f() {}
+
+m4f::m4f(float d) {
+ for (int y = 0; y < 4; y++) {
+ for (int x = 0; x < 4; x++) {
+ m[x][y] = 0.0f;
+ }
+ }
+
+ m[0][0] = d;
+ m[1][1] = d;
+ m[2][2] = d;
+ m[3][3] = d;
+}
+
+m4f m4f::identity() {
+ return m4f(1.0f);
+}
+
+m4f m4f::screenspace(float hw, float hh) {
+ m4f r(1.0f);
+
+ r.m[0][0] = hw;
+ r.m[0][3] = hw;
+ r.m[1][1] = -hh;
+ r.m[1][3] = hh;
+
+ return r;
+}
+
+m4f m4f::operator*(const m4f& other) const {
+ m4f r(1.0f);
+
+ r.m[0][0] = m[0][0] * other.m[0][0] + m[1][0] * other.m[0][1] + m[2][0] * other.m[0][2] + m[3][0] * other.m[0][3];
+ r.m[1][0] = m[0][0] * other.m[1][0] + m[1][0] * other.m[1][1] + m[2][0] * other.m[1][2] + m[3][0] * other.m[1][3];
+ r.m[2][0] = m[0][0] * other.m[2][0] + m[1][0] * other.m[2][1] + m[2][0] * other.m[2][2] + m[3][0] * other.m[2][3];
+ r.m[3][0] = m[0][0] * other.m[3][0] + m[1][0] * other.m[3][1] + m[2][0] * other.m[3][2] + m[3][0] * other.m[3][3];
+ r.m[0][1] = m[0][1] * other.m[0][0] + m[1][1] * other.m[0][1] + m[2][1] * other.m[0][2] + m[3][1] * other.m[0][3];
+ r.m[1][1] = m[0][1] * other.m[1][0] + m[1][1] * other.m[1][1] + m[2][1] * other.m[1][2] + m[3][1] * other.m[1][3];
+ r.m[2][1] = m[0][1] * other.m[2][0] + m[1][1] * other.m[2][1] + m[2][1] * other.m[2][2] + m[3][1] * other.m[2][3];
+ r.m[3][1] = m[0][1] * other.m[3][0] + m[1][1] * other.m[3][1] + m[2][1] * other.m[3][2] + m[3][1] * other.m[3][3];
+ r.m[0][2] = m[0][2] * other.m[0][0] + m[1][2] * other.m[0][1] + m[2][2] * other.m[0][2] + m[3][2] * other.m[0][3];
+ r.m[1][2] = m[0][2] * other.m[1][0] + m[1][2] * other.m[1][1] + m[2][2] * other.m[1][2] + m[3][2] * other.m[1][3];
+ r.m[2][2] = m[0][2] * other.m[2][0] + m[1][2] * other.m[2][1] + m[2][2] * other.m[2][2] + m[3][2] * other.m[2][3];
+ r.m[3][2] = m[0][2] * other.m[3][0] + m[1][2] * other.m[3][1] + m[2][2] * other.m[3][2] + m[3][2] * other.m[3][3];
+ r.m[0][3] = m[0][3] * other.m[0][0] + m[1][3] * other.m[0][1] + m[2][3] * other.m[0][2] + m[3][3] * other.m[0][3];
+ r.m[1][3] = m[0][3] * other.m[1][0] + m[1][3] * other.m[1][1] + m[2][3] * other.m[1][2] + m[3][3] * other.m[1][3];
+ r.m[2][3] = m[0][3] * other.m[2][0] + m[1][3] * other.m[2][1] + m[2][3] * other.m[2][2] + m[3][3] * other.m[2][3];
+ r.m[3][3] = m[0][3] * other.m[3][0] + m[1][3] * other.m[3][1] + m[2][3] * other.m[3][2] + m[3][3] * other.m[3][3];
+
+ return r;
+}
+
+v4f m4f::operator*(const v4f& other) const {
+ return v4f(
+ m[0][0] * other.x + m[1][0] * other.y + m[2][0] * other.z + m[3][0] + other.w,
+ m[0][1] * other.x + m[1][1] * other.y + m[2][1] * other.z + m[3][1] + other.w,
+ m[0][2] * other.x + m[1][2] * other.y + m[2][2] * other.z + m[3][2] + other.w,
+ m[0][3] * other.x + m[1][3] * other.y + m[2][3] * other.z + m[3][3] + other.w);
+}
+
+m4f m4f::translate(m4f m, v3f v) {
+ m4f r(1.0f);
+
+ r.m[3][0] += v.x;
+ r.m[3][1] += v.y;
+ r.m[3][2] += v.z;
+
+ return m * r;
+}
+
+m4f m4f::rotate(m4f m, float a, v3f v) {
+ m4f r(1.0f);
+
+ const float c = cosf(a);
+ const float s = sinf(a);
+
+ const float omc = (float)1 - c;
+
+ const float x = v.x;
+ const float y = v.y;
+ const float z = v.z;
+
+ r.m[0][0] = x * x * omc + c;
+ r.m[0][1] = y * x * omc + z * s;
+ r.m[0][2] = x * z * omc - y * s;
+ r.m[1][0] = x * y * omc - z * s;
+ r.m[1][1] = y * y * omc + c;
+ r.m[1][2] = y * z * omc + x * s;
+ r.m[2][0] = x * z * omc + y * s;
+ r.m[2][1] = y * z * omc - x * s;
+ r.m[2][2] = z * z * omc + c;
+
+ return m * r;
+}
+
+m4f m4f::scale(m4f m, v3f v) {
+ m4f r(1.0f);
+
+ r.m[0][0] = v.x;
+ r.m[1][1] = v.y;
+ r.m[2][2] = v.z;
+
+ return m * r;
+}
+
+
+v3f m4f::get_translation() {
+ return v3f(m[3][0], m[3][1], m[3][2]);
+}
+
+m4f m4f::lookat(v3f c, v3f o, v3f u) {
+ m4f r(1.0f);
+
+ const v3f f = v3f::normalised(o - c);
+ u = v3f::normalised(u);
+ const v3f s = v3f::normalised(v3f::cross(f, u));
+ u = v3f::cross(s, f);
+
+ r.m[0][0] = s.x;
+ r.m[1][0] = s.y;
+ r.m[2][0] = s.z;
+ r.m[0][1] = u.x;
+ r.m[1][1] = u.y;
+ r.m[2][1] = u.z;
+ r.m[0][2] = -f.x;
+ r.m[1][2] = -f.y;
+ r.m[2][2] = -f.z;
+ r.m[3][0] = -v3f::dot(s, c);
+ r.m[3][1] = -v3f::dot(u, c);
+ r.m[3][2] = v3f::dot(f, c);
+
+ return r;
+}
+
+m4f m4f::pers(float fov, float asp, float n, float f) {
+ m4f r(0.0f);
+
+ float fov_rad = to_rad(fov);
+ float focal_length = 1.0f / tanf(fov_rad / 2.0f);
+
+ float x = focal_length / asp;
+ float y = -focal_length;
+ float a = f / (n - f);
+ float b = n * a;
+
+ r.m[0][0] = x;
+ r.m[1][1] = y;
+ r.m[2][2] = a;
+ r.m[3][2] = b;
+ r.m[2][3] = -1.0f;
+
+ return r;
+}
+
+m4f m4f::orth(float l, float r, float b, float t, float n, float f) {
+ m4f res(1.0f);
+
+ float* data = (float*)res.m;
+
+ float lr = 1.0f / (l - r);
+ float bt = 1.0f / (b - t);
+ float nf = 1.0f / (n - f);
+
+ data[0] = -2.0f * lr;
+ data[5] = -2.0f * bt;
+ data[10] = 2.0f * nf;
+
+ data[12] = (l + r) * lr;
+ data[13] = (t + b) * bt;
+ data[14] = (f + n) * nf;
+
+ return res;
+}
+
+m4f m4f::inverse() {
+ const float* mm = (float*)m;
+
+ float t0 = mm[10] * mm[15];
+ float t1 = mm[14] * mm[11];
+ float t2 = mm[6] * mm[15];
+ float t3 = mm[14] * mm[7];
+ float t4 = mm[6] * mm[11];
+ float t5 = mm[10] * mm[7];
+ float t6 = mm[2] * mm[15];
+ float t7 = mm[14] * mm[3];
+ float t8 = mm[2] * mm[11];
+ float t9 = mm[10] * mm[3];
+ float t10 = mm[2] * mm[7];
+ float t11 = mm[6] * mm[3];
+ float t12 = mm[8] * mm[13];
+ float t13 = mm[12] * mm[9];
+ float t14 = mm[4] * mm[13];
+ float t15 = mm[12] * mm[5];
+ float t16 = mm[4] * mm[9];
+ float t17 = mm[8] * mm[5];
+ float t18 = mm[0] * mm[13];
+ float t19 = mm[12] * mm[1];
+ float t20 = mm[0] * mm[9];
+ float t21 = mm[8] * mm[1];
+ float t22 = mm[0] * mm[5];
+ float t23 = mm[4] * mm[1];
+
+ m4f r(1.0f);
+ float* o = (float*)r.m;
+
+ o[0] = (t0 * mm[5] + t3 * mm[9] + t4 * mm[13]) - (t1 * mm[5] + t2 * mm[9] + t5 * mm[13]);
+ o[1] = (t1 * mm[1] + t6 * mm[9] + t9 * mm[13]) - (t0 * mm[1] + t7 * mm[9] + t8 * mm[13]);
+ o[2] = (t2 * mm[1] + t7 * mm[5] + t10 * mm[13]) - (t3 * mm[1] + t6 * mm[5] + t11 * mm[13]);
+ o[3] = (t5 * mm[1] + t8 * mm[5] + t11 * mm[9]) - (t4 * mm[1] + t9 * mm[5] + t10 * mm[9]);
+
+ float d = 1.0f / (mm[0] * o[0] + mm[4] * o[1] + mm[8] * o[2] + mm[12] * o[3]);
+
+ o[0] = d * o[0];
+ o[1] = d * o[1];
+ o[2] = d * o[2];
+ o[3] = d * o[3];
+ o[4] = d * ((t1 * mm[4] + t2 * mm[8] + t5 * mm[12]) - (t0 * mm[4] + t3 * mm[8] + t4 * mm[12]));
+ o[5] = d * ((t0 * mm[0] + t7 * mm[8] + t8 * mm[12]) - (t1 * mm[0] + t6 * mm[8] + t9 * mm[12]));
+ o[6] = d * ((t3 * mm[0] + t6 * mm[4] + t11 * mm[12]) - (t2 * mm[0] + t7 * mm[4] + t10 * mm[12]));
+ o[7] = d * ((t4 * mm[0] + t9 * mm[4] + t10 * mm[8]) - (t5 * mm[0] + t8 * mm[4] + t11 * mm[8]));
+ o[8] = d * ((t12 * mm[7] + t15 * mm[11] + t16 * mm[15]) - (t13 * mm[7] + t14 * mm[11] + t17 * mm[15]));
+ o[9] = d * ((t13 * mm[3] + t18 * mm[11] + t21 * mm[15]) - (t12 * mm[3] + t19 * mm[11] + t20 * mm[15]));
+ o[10] = d * ((t14 * mm[3] + t19 * mm[7] + t22 * mm[15]) - (t15 * mm[3] + t18 * mm[7] + t23 * mm[15]));
+ o[11] = d * ((t17 * mm[3] + t20 * mm[7] + t23 * mm[11]) - (t16 * mm[3] + t21 * mm[7] + t22 * mm[11]));
+ o[12] = d * ((t14 * mm[10] + t17 * mm[14] + t13 * mm[6]) - (t16 * mm[14] + t12 * mm[6] + t15 * mm[10]));
+ o[13] = d * ((t20 * mm[14] + t12 * mm[2] + t19 * mm[10]) - (t18 * mm[10] + t21 * mm[14] + t13 * mm[2]));
+ o[14] = d * ((t18 * mm[6] + t23 * mm[14] + t15 * mm[2]) - (t22 * mm[14] + t14 * mm[2] + t19 * mm[6]));
+ o[15] = d * ((t22 * mm[10] + t16 * mm[2] + t21 * mm[6]) - (t20 * mm[6] + t23 * mm[10] + t17 * mm[2]));
+
+ return r;
+}
+
+m4f m4f::transposed() {
+ m4f r(1.0f);
+
+ r.m[0][0] = m[0][0];
+ r.m[1][0] = m[0][1];
+ r.m[2][0] = m[0][2];
+ r.m[3][0] = m[0][3];
+ r.m[0][1] = m[1][0];
+ r.m[1][1] = m[1][1];
+ r.m[2][1] = m[1][2];
+ r.m[3][1] = m[1][3];
+ r.m[0][2] = m[2][0];
+ r.m[1][2] = m[2][1];
+ r.m[2][2] = m[2][2];
+ r.m[3][2] = m[2][3];
+ r.m[0][3] = m[3][0];
+ r.m[1][3] = m[3][1];
+ r.m[2][3] = m[3][2];
+ r.m[3][3] = m[3][3];
+
+ return r;
+}
+
+v4f m4f::transform(m4f m, v4f v) {
+ return v4f(
+ m.m[0][0] * v.x + m.m[1][0] * v.y + m.m[2][0] * v.z + m.m[3][0] + v.w,
+ m.m[0][1] * v.x + m.m[1][1] * v.y + m.m[2][1] * v.z + m.m[3][1] + v.w,
+ m.m[0][2] * v.x + m.m[1][2] * v.y + m.m[2][2] * v.z + m.m[3][2] + v.w,
+ m.m[0][3] * v.x + m.m[1][3] * v.y + m.m[2][3] * v.z + m.m[3][3] + v.w);
+}
+
+AABB m4f::transform(m4f m, AABB aabb) {
+ v3f corners[] = {
+ aabb.min,
+ v3f(aabb.min.x, aabb.max.y, aabb.min.z),
+ v3f(aabb.min.x, aabb.max.y, aabb.max.z),
+ v3f(aabb.min.x, aabb.min.y, aabb.max.z),
+ v3f(aabb.max.x, aabb.min.y, aabb.min.z),
+ v3f(aabb.max.x, aabb.max.y, aabb.min.z),
+ aabb.max,
+ v3f(aabb.max.x, aabb.min.y, aabb.max.z)
+ };
+
+ AABB result = {
+ .min = { INFINITY, INFINITY, INFINITY },
+ .max = { -INFINITY, -INFINITY, -INFINITY }
+ };
+
+ for (int i = 0; i < 8; i++) {
+ v4f point = m4f::transform(m, v4f(corners[i].x, corners[i].y, corners[i].z, 0.0f));
+
+ result.min.x = std::min(result.min.x, point.x);
+ result.min.y = std::min(result.min.y, point.y);
+ result.min.z = std::min(result.min.z, point.z);
+ result.max.x = std::max(result.max.x, point.x);
+ result.max.y = std::max(result.max.y, point.y);
+ result.max.z = std::max(result.max.z, point.z);
+ }
+
+ return result;
+}
diff --git a/maths.hpp b/maths.hpp
new file mode 100644
index 0000000..26e6652
--- /dev/null
+++ b/maths.hpp
@@ -0,0 +1,505 @@
+#ifndef maths_hpp
+#define maths_hpp
+
+#include <math.h>
+#include <stdint.h>
+
+template <typename T>
+T to_rad(T deg) {
+ return deg * (((T)3.14159265358979323846) / 180.0f);
+}
+
+template <typename T>
+T to_deg(T rad) {
+ return rad * (180.0f / ((T)3.14159265358979323846));
+}
+
+template <typename T>
+struct v2 {
+ T x, y;
+
+ v2() : x(0), y(0) {}
+ v2(T xy) : x(xy), y(xy) {}
+ v2(T x, T y) : x(x), y(y) {}
+
+ bool operator>(const v2<T>& other) const {
+ return x > other.x && y > other.y;
+ }
+
+ bool operator<(const v2<T>& other) const {
+ return x < other.x && y < other.y;
+ }
+
+ v2<T> operator+(const v2<T>& other) const {
+ return v2<T>(x + other.x, y + other.y);
+ }
+
+ v2<T> operator-(const v2<T>& other) const {
+ return v2<T>(x - other.x, y - other.y);
+ }
+
+ v2<T> operator*(const v2<T>& other) const {
+ return v2<T>(x * other.x, y * other.y);
+ }
+
+ v2<T> operator/(const v2<T>& other) const {
+ return v2<T>(x / other.x, y / other.y);
+ }
+
+ v2<T> operator+(T other) const {
+ return v2<T>(x + other, y + other);
+ }
+
+ v2<T> operator-(T other) const {
+ return v2<T>(x - other, y - other);
+ }
+
+ v2<T> operator*(T other) const {
+ return v2<T>(x * other, y * other);
+ }
+
+ v2<T> operator/(T other) const {
+ return v2<T>(x / other, y / other);
+ }
+
+ v2<T> operator+=(const v2<T>& other) {
+ *this = *this + other;
+ return *this;
+ }
+
+ v2<T> operator-=(const v2<T>& other) {
+ *this = *this - other;
+ return *this;
+ }
+
+ v2<T> operator*=(const v2<T>& other) {
+ *this = *this * other;
+ return *this;
+ }
+
+ v2<T> operator/=(const v2<T>& other) {
+ *this = *this / other;
+ return *this;
+ }
+
+ v2<T> operator+=(T other) {
+ *this = *this + other;
+ return *this;
+ }
+
+ v2<T> operator-=(T other) {
+ *this = *this - other;
+ return *this;
+ }
+
+ v2<T> operator*=(T other) {
+ *this = *this * other;
+ return *this;
+ }
+
+ v2<T> operator/=(T other) {
+ *this = *this / other;
+ return *this;
+ }
+
+ bool operator==(const v2<T>& other) const {
+ return x == other.x && y == other.y;
+ }
+
+ bool operator!=(const v2<T>& other) const {
+ return !(*this == other);
+ }
+
+ static T dot(const v2<T>& a, const v2<T>& b) {
+ return a.x * b.x + a.y * b.y;
+ }
+
+ static T mag_sqrd(const v2<T>& v) {
+ return v2<T>::dot(v, v);
+ }
+
+ static T mag(const v2<T>& v) {
+ return (T)sqrtf((float)v2<T>::mag_sqrd(v));
+ }
+
+ static v2<T> normalised(const v2<T>& v) {
+ const T l = v2<T>::mag(v);
+ return v2<T>(v.x / l, v.y / l);
+ }
+};
+
+template <typename T>
+v2<T> operator+(T lhs, v2<T> rhs) {
+ return v2<T>(lhs + rhs.x, lhs + rhs.y);
+}
+
+template <typename T>
+v2<T> operator-(T lhs, v2<T> rhs) {
+ return v2<T>(lhs - rhs.x, lhs - rhs.y);
+}
+
+template <typename T>
+v2<T> operator*(T lhs, v2<T> rhs) {
+ return v2<T>(lhs * rhs.x, lhs * rhs.y);
+}
+
+template <typename T>
+v2<T> operator/(T lhs, v2<T> rhs) {
+ return v2<T>(lhs / rhs.x, lhs / rhs.y);
+}
+
+template <typename T>
+v2<T> operator-(const v2<T>& v) {
+ return v2<T>(-v.x, -v.y);
+}
+
+template <typename T>
+struct v3 {
+ T x, y, z;
+
+ v3() : x(0), y(0), z(0) {}
+ v3(T xyz) : x(xyz), y(xyz), z(xyz) {}
+ v3(v2<T> xy, T z) : x(xy.x), y(xy.y), z(z) {}
+ v3(T x, v2<T> yz) : x(x), y(yz.x), z(yz.y) {}
+ v3(T x, T y, T z) : x(x), y(y), z(z) {}
+
+ bool operator>(const v3<T>& other) const {
+ return x > other.x && y > other.y && z > other.z;
+ }
+
+ bool operator<(const v3<T>& other) const {
+ return x < other.x && y < other.y && z < other.z;
+ }
+
+ v3<T> operator+(const v3<T>& other) const {
+ return v3<T>(x + other.x, y + other.y, z + other.z);
+ }
+
+ v3<T> operator-(const v3<T>& other) const {
+ return v3<T>(x - other.x, y - other.y, z - other.z);
+ }
+
+ v3<T> operator*(const v3<T>& other) const {
+ return v3<T>(x * other.x, y * other.y, z * other.z);
+ }
+
+ v3<T> operator/(const v3<T>& other) const {
+ return v3<T>(x / other.x, y / other.y, z / other.z);
+ }
+
+ v3<T> operator+(T other) const {
+ return v3<T>(x + other, y + other, z + other);
+ }
+
+ v3<T> operator-(T other) const {
+ return v3<T>(x - other, y - other, z - other);
+ }
+
+ v3<T> operator*(T other) const {
+ return v3<T>(x * other, y * other, z * other);
+ }
+
+ v3<T> operator/(T other) const {
+ return v3<T>(x / other, y / other, z / other);
+ }
+
+ v3<T> operator+=(const v3<T>& other) {
+ *this = *this + other;
+ return *this;
+ }
+
+ v3<T> operator-=(const v3<T>& other) {
+ *this = *this - other;
+ return *this;
+ }
+
+ v3<T> operator*=(const v3<T>& other) {
+ *this = *this * other;
+ return *this;
+ }
+
+ v3<T> operator/=(const v3<T>& other) {
+ *this = *this / other;
+ return *this;
+ }
+
+ v3<T> operator+=(T other) {
+ *this = *this + other;
+ return *this;
+ }
+
+ v3<T> operator-=(T other) {
+ *this = *this - other;
+ return *this;
+ }
+
+ v3<T> operator*=(T other) {
+ *this = *this * other;
+ return *this;
+ }
+
+ v3<T> operator/=(T other) {
+ *this = *this / other;
+ return *this;
+ }
+
+ bool operator==(const v3<T>& other) const {
+ return x == other.x && y == other.y && z == other.z;
+ }
+
+ bool operator!=(const v3<T>& other) const {
+ return !(*this == other);
+ }
+
+ static T dot(const v3<T>& a, const v3<T>& b) {
+ return a.x * b.x + a.y * b.y + a.z * b.z;
+ }
+
+ static v3<T> cross(const v3<T>& a, const v3<T>& b) {
+ return v3<T>(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
+ }
+
+ static T mag_sqrd(const v3<T>& v) {
+ return v3<T>::dot(v, v);
+ }
+
+ static T mag(const v3<T>& v) {
+ return (T)sqrtf((float)v3<T>::mag_sqrd(v));
+ }
+
+ static v3<T> normalised(const v3<T>& v) {
+ const T l = v3<T>::mag(v);
+ return v3<T>(v.x / l, v.y / l, v.z / l);
+ }
+};
+
+template <typename T>
+v3<T> operator+(T lhs, v3<T> rhs) {
+ return v3<T>(lhs + rhs.x, lhs + rhs.y, lhs + rhs.z);
+}
+
+template <typename T>
+v3<T> operator-(T lhs, v3<T> rhs) {
+ return v3<T>(lhs - rhs.x, lhs - rhs.y, lhs - rhs.z);
+}
+
+template <typename T>
+v3<T> operator*(T lhs, v3<T> rhs) {
+ return v3<T>(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z);
+}
+
+template <typename T>
+v3<T> operator/(T lhs, v3<T> rhs) {
+ return v3<T>(lhs / rhs.x, lhs / rhs.y, lhs / rhs.z);
+}
+
+template <typename T>
+v3<T> operator-(const v3<T>& v) {
+ return v3<T>(-v.x, -v.y, -v.z);
+}
+
+template <typename T>
+struct v4 {
+ T x, y, z, w;
+
+ v4() : x(0), y(0), z(0), w(0) {}
+ v4(T xyzw) : x(xyzw), y(xyzw), z(xyzw), w(xyzw) {}
+ v4(v2<T> xy, T z, T w) : x(xy.x), y(xy.y), z(z), w(w) {}
+ v4(v3<T> xyz, T w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
+ v4(T x, v3<T> yzw) : x(x), y(yzw.x), z(yzw.y), w(yzw.z) {}
+ v4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {}
+
+ bool operator>(const v4<T>& other) const {
+ return x > other.x && y > other.y && z > other.z && w > other.w;
+ }
+
+ bool operator<(const v4<T>& other) const {
+ return x < other.x && y < other.y && z < other.z && w < other.w;
+ }
+
+ v4<T> operator+(const v4<T>& other) const {
+ return v4<T>(x + other.x, y + other.y, z + other.z, w + other.w);
+ }
+
+ v4<T> operator-(const v4<T>& other) const {
+ return v4<T>(x - other.x, y - other.y, z - other.z, w - other.w);
+ }
+
+ v4<T> operator*(const v4<T>& other) const {
+ return v4<T>(x * other.x, y * other.y, z * other.z, w * other.w);
+ }
+
+ v4<T> operator/(const v4<T>& other) const {
+ return v4<T>(x / other.x, y / other.y, z / other.z, w / other.w);
+ }
+
+ v4<T> operator+(T other) const {
+ return v4<T>(x + other, y + other, z + other, w + other);
+ }
+
+ v4<T> operator-(T other) const {
+ return v4<T>(x - other, y - other, z - other, w - other);
+ }
+
+ v4<T> operator*(T other) const {
+ return v4<T>(x * other, y * other, z * other, w * other);
+ }
+
+ v4<T> operator/(T other) const {
+ return v4<T>(x / other, y / other, z / other, w / other);
+ }
+
+ v4<T> operator+=(const v4<T>& other) {
+ *this = *this + other;
+ return *this;
+ }
+
+ v4<T> operator-=(const v4<T>& other) {
+ *this = *this - other;
+ return *this;
+ }
+
+ v4<T> operator*=(const v4<T>& other) {
+ *this = *this * other;
+ return *this;
+ }
+
+ v4<T> operator/=(const v4<T>& other) {
+ *this = *this / other;
+ return *this;
+ }
+
+ v4<T> operator+=(T other) {
+ *this = *this + other;
+ return *this;
+ }
+
+ v4<T> operator-=(T other) {
+ *this = *this - other;
+ return *this;
+ }
+
+ v4<T> operator*=(T other) {
+ *this = *this * other;
+ return *this;
+ }
+
+ v4<T> operator/=(T other) {
+ *this = *this / other;
+ return *this;
+ }
+
+ bool operator==(const v4<T>& other) const {
+ return x == other.x && y == other.y && z == other.z && w == other.w;
+ }
+
+ bool operator!=(const v4<T>& other) const {
+ return !(*this == other);
+ }
+
+ static T dot(const v4<T>& a, const v4<T>& b) {
+ return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
+ }
+
+ static T mag_sqrd(const v4<T>& v) {
+ return v4<T>::dot(v, v);
+ }
+
+ static T mag(const v4<T>& v) {
+ return (T)sqrtf((float)v4<T>::mag_sqrd(v));
+ }
+
+ static v4<T> normalised(const v4<T>& v) {
+ const T l = v4<T>::mag(v);
+ return v4<T>(v.x / l, v.y / l, v.z / l, v.w / l);
+ }
+};
+
+template <typename T>
+v4<T> operator+(T lhs, v4<T> rhs) {
+ return v4<T>(lhs + rhs.x, lhs + rhs.y, lhs + rhs.z, lhs + rhs.w);
+}
+
+template <typename T>
+v4<T> operator-(T lhs, v4<T> rhs) {
+ return v4<T>(lhs - rhs.x, lhs - rhs.y, lhs - rhs.z, lhs - rhs.w);
+}
+
+template <typename T>
+v4<T> operator*(T lhs, v4<T> rhs) {
+ return v4<T>(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs - rhs.w);
+}
+
+template <typename T>
+v4<T> operator/(T lhs, v4<T> rhs) {
+ return v4<T>(lhs / rhs.x, lhs / rhs.y, lhs / rhs.z, lhs - rhs.w);
+}
+
+template <typename T>
+v4<T> operator-(const v4<T>& v) {
+ return v4<T>(-v.x, -v.y, -v.z, -v.w);
+}
+
+typedef v2<int> v2i;
+typedef v2<float> v2f;
+typedef v2<double> v2d;
+typedef v3<int> v3i;
+typedef v3<float> v3f;
+typedef v3<double> v3d;
+typedef v4<int> v4i;
+typedef v4<float> v4f;
+typedef v4<double> v4d;
+
+template struct v2<int>;
+template struct v2<float>;
+template struct v2<double>;
+template struct v3<int>;
+template struct v3<float>;
+template struct v3<double>;
+template struct v4<int>;
+template struct v4<float>;
+template struct v4<double>;
+
+struct AABB {
+ v3f min, max;
+};
+
+struct m4f {
+ float m[4][4];
+
+ m4f();
+ m4f(float d);
+
+ static m4f identity();
+ static m4f screenspace(float hw, float hh);
+
+ m4f operator*(const m4f& other) const;
+ v4f operator*(const v4f& other) const;
+
+ static m4f translate(m4f m, v3f v);
+ static m4f rotate(m4f m, float a, v3f v);
+ static m4f scale(m4f m, v3f v);
+
+ v3f get_translation();
+
+ static m4f lookat(v3f c, v3f o, v3f u);
+ static m4f pers(float fov, float asp, float n, float f);
+ static m4f orth(float l, float r, float b, float t, float n, float f);
+
+ static v4f transform(m4f m, v4f v);
+ static AABB transform(m4f m, AABB aabb);
+
+ m4f inverse();
+ m4f transposed();
+};
+
+inline static v4f make_color(uint32_t rgb, uint8_t a) {
+ return v4f(
+ (float)((rgb >> 16) & 0xff) / 255.0f,
+ (float)((rgb >> 8) & 0xff) / 255.0f,
+ (float)((rgb) & 0xff) / 255.0f,
+ (float)a / 255.0f);
+}
+
+
+#endif
diff --git a/sc/sc.cpp b/sc/sc.cpp
index e806dd4..0f61fdf 100644
--- a/sc/sc.cpp
+++ b/sc/sc.cpp
@@ -167,6 +167,12 @@ struct Desc {
return { 12, 16 };
case svariable_type_vec4:
return { 16, 16 };
+ case svariable_type_mat2:
+ return { 16, 16 };
+ case svariable_type_mat3:
+ return { 36, 16 };
+ case svariable_type_mat4:
+ return { 64, 16 };
}
assert(0);
return { 0, 0 };
diff --git a/todo.txt b/todo.txt
index 0c1b97a..8f2662c 100644
--- a/todo.txt
+++ b/todo.txt
@@ -7,7 +7,7 @@ todo list
- [x] texture the triangle
- [x] refactor pipelines and vertex formats to be more flexible
- [x] simple text rendering
- - [ ] 3D maths library
+ - [x] 3D maths library
- [ ] model conversion
- [ ] render a model
- [ ] VRAM allocator
diff --git a/ui.cpp b/ui.cpp
index 3f773f5..dcd6a6a 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -147,16 +147,23 @@ void UI::init(Device* dev, Arena* a, Texture_Id at, Shader_Id sh) {
Buffer_Flags::vertex_buffer |
Buffer_Flags::cpu_readwrite
);
+ config_buf = device->create_buffer(
+ sizeof(UI_CBuffer),
+ Buffer_Flags::constant_buffer |
+ Buffer_Flags::cpu_readwrite
+ );
sp = &dev->get_shader(sh);
vertex_format = sp->vf;
shader_info.vert_binding = sp->binding_index("verts");
shader_info.atlas_binding = sp->descriptor_binding("atlas");
+ shader_info.config_binding = sp->descriptor_binding("config_buffer");
sampler = create_clamped_point(device);
}
void UI::destroy() {
device->destroy_texture(atlas);
device->destroy_buffer(mesh);
+ device->destroy_buffer(config_buf);
device->destroy_sampler(sampler);
}
@@ -200,7 +207,7 @@ int UI::render_label(const Label* l, int off) {
int x = l->x;
int y = l->y;
const char* c;
- float o = 10.0f * ndc[0];
+ float o = 10.0f;
Vertex* verts = (Vertex*)device->map_buffer(
mesh,
off * sizeof(Vertex),
@@ -213,22 +220,22 @@ int UI::render_label(const Label* l, int off) {
uo, uo + w
};
verts[i] = Vertex {
- (float)x * ndc[0], (float)y * ndc[1], uv[0], 0.0f, 1.0f, 1.0f, 1.0f, 1.0f
+ (float)x, (float)y, uv[0], 0.0f, 1.0f, 1.0f, 1.0f, 1.0f
};
verts[i + 1] = Vertex {
- (float)x * ndc[0], (float)y * ndc[1] + o, uv[0], 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
+ (float)x, (float)y + o, uv[0], 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
};
verts[i + 2] = Vertex {
- (float)x * ndc[0] + o, (float)y * ndc[1] + o, uv[1], 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
+ (float)x + o, (float)y + o, uv[1], 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
};
verts[i + 3] = Vertex {
- (float)x * ndc[0], (float)y * ndc[1], uv[0], 0.0f, 1.0f, 1.0f, 1.0f, 1.0f
+ (float)x, (float)y, uv[0], 0.0f, 1.0f, 1.0f, 1.0f, 1.0f
};
verts[i + 4] = Vertex {
- (float)x * ndc[0] + o, (float)y * ndc[1], uv[1], 0.0f, 1.0f, 1.0f, 1.0f, 1.0f
+ (float)x + o, (float)y, uv[1], 0.0f, 1.0f, 1.0f, 1.0f, 1.0f
};
verts[i + 5] = Vertex {
- (float)x * ndc[0] + o, (float)y * ndc[1] + o, uv[1], 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
+ (float)x + o, (float)y + o, uv[1], 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
};
x += 10;
}
@@ -240,8 +247,18 @@ void UI::render(Arena* s, Texture_Id target) {
Element* e = tree;
int vc = 0;
Texture& t = device->get_texture(target);
- ndc[0] = 4.0f / (float)t.w;
- ndc[1] = 4.0f / (float)t.h;
+ UI_CBuffer* config = (UI_CBuffer*)device->map_buffer(
+ config_buf,
+ 0,
+ sizeof(UI_CBuffer)
+ );
+ config->projection = m4f::orth(
+ 0.0f, (float)t.w,
+ 0.0f, (float)t.h,
+ -1.0f,
+ 1.0f
+ );
+ device->unmap_buffer(config_buf);
for (; e; e = e->next) {
switch (e->type) {
case Element::Type::label:
@@ -258,6 +275,7 @@ void UI::render(Arena* s, Texture_Id target) {
pb.begin(device);
pb.shader(shader);
pb.vertex_format(vertex_format);
+ pb.cbuffer(shader_info.config_binding, config_buf);
pb.texture(shader_info.atlas_binding, atlas, sampler);
Pipeline& pip = pb.build();
diff --git a/ui.hpp b/ui.hpp
index a181afe..c002fc9 100644
--- a/ui.hpp
+++ b/ui.hpp
@@ -1,6 +1,7 @@
#ifndef ui_hpp
#define ui_hpp
+#include "maths.hpp"
#include "video.hpp"
struct Arena;
@@ -33,13 +34,16 @@ struct UI {
Texture_Id atlas;
Shader_Id shader;
Vertex_Format_Id vertex_format;
- Buffer_Id mesh;
+ Buffer_Id mesh, config_buf;
Sampler_Id sampler;
+ struct UI_CBuffer {
+ m4f projection;
+ };
struct {
int vert_binding;
int atlas_binding;
+ int config_binding;
} shader_info;
- float ndc[2];
static int text_width(const char* t);
static int text_height(const char* t);