diff options
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | intermediate/ui.glsl | 13 | ||||
-rw-r--r-- | maths.cpp | 296 | ||||
-rw-r--r-- | maths.hpp | 505 | ||||
-rw-r--r-- | sc/sc.cpp | 6 | ||||
-rw-r--r-- | todo.txt | 2 | ||||
-rw-r--r-- | ui.cpp | 36 | ||||
-rw-r--r-- | ui.hpp | 8 |
8 files changed, 857 insertions, 14 deletions
@@ -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 @@ -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 }; @@ -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 @@ -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(); @@ -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); |