From 516d6f9f3e7402be440e1d832361e31b99da438c Mon Sep 17 00:00:00 2001 From: matthew Date: Mon, 28 Jul 2025 08:03:09 +1000 Subject: [PATCH] implemented a (working) camera --- src/gears/game.d | 28 ++-- src/gears/main.d | 20 --- src/gears/renderer.d | 2 + src/shared/math.d | 372 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 371 insertions(+), 51 deletions(-) diff --git a/src/gears/game.d b/src/gears/game.d index b97a89c..5b9e7c3 100644 --- a/src/gears/game.d +++ b/src/gears/game.d @@ -123,39 +123,37 @@ void Update(Game* g, Camera* cam) { Mat4 rotation = RotationMatrix(cam); - //cam.pos += (rotation * Vec4(cam.velocity * 0.5, 0.0)).xyz * g.delta; + cam.pos += (rotation * Vec4(cam.velocity * 0.5, 0.0)).xyz * g.delta; Extent ext = GetExtent(&g.rd); g.globals.view_matrix = ViewMatrix(cam); - g.globals.projection_matrix = Mat4Identity(); - //g.globals.projection_matrix.perspective(Radians(70.0), cast(f32)(ext.x) / cast(f32)(ext.y), 10000.0, 0.1); - //g.globals.projection_matrix.rows[1][1] *= -1.0; + Mat4Identity(&g.globals.projection_matrix); + Perspective(&g.globals.projection_matrix, Radians(70.0), cast(f32)(ext.x), cast(f32)(ext.y), 10000.0, 0.1); + g.globals.projection_matrix[1, 1] *= -1.0; - //g.globals.view_projection = g.globals.projection_matrix * g.globals.view_matrix; + g.globals.view_projection = g.globals.projection_matrix * g.globals.view_matrix; g.globals.res.x = cast(f32)ext.x; g.globals.res.y = cast(f32)ext.y; - - //g.globals.projection_matrix = g.globals.projection_matrix.transposed(); - //g.globals.view_matrix = g.globals.view_matrix.transposed(); - //g.globals.view_projection = g.globals.view_projection.transposed(); } pragma(inline): Mat4 RotationMatrix(Camera* cam) { - //Quat pitch_rotation = Quat.fromAxis(Vec3(1.0, 0.0, 0.0), cam.pitch); - //Quat yaw_rotation = Quat.fromAxis(Vec3(0.0, -1.0, 0.0), cam.yaw); - return Mat4Identity(); //cast(Mat4)(yaw_rotation) * cast(Mat4)(pitch_rotation); + Quat pitch_rotation, yaw_rotation; + QuatFromAxis(&pitch_rotation, cam.pitch, Vec3(1.0, 0.0, 0.0)); + QuatFromAxis(&yaw_rotation, cam.yaw, Vec3(0.0, -1.0, 0.0)); + return Inverse(cast(Mat4)(yaw_rotation) * cast(Mat4)(pitch_rotation)); } pragma(inline): Mat4 ViewMatrix(Camera* cam) { - //Mat4 translation = Mat4.translation(cam.pos); - //Mat4 rotation = RotationMatrix(cam); - return Mat4Identity(); //(translation * rotation).inverse(); + Mat4 translation; + Translate(&translation, cam.pos); + Mat4 rotation = RotationMatrix(cam); + return translation * rotation; } void diff --git a/src/gears/main.d b/src/gears/main.d index 23e706a..adb1f79 100644 --- a/src/gears/main.d +++ b/src/gears/main.d @@ -14,26 +14,6 @@ import math; void main() { - Mat4 mat1 = Mat4Identity(); - Mat4 mat2 = Mat4Identity(); - mat1.v[0] = 2.0; - mat1.v[4] = 3.0; - mat1.v[7] = 25.0; - mat1.v[11] = 55.0; - - mat2.v[2] = 13.0; - mat2.v[5] = 2.0; - mat2.v[9] = 23.0; - mat2.v[10] = 15.0; - mat2.v[11] = 34.0; - - mat2 = mat1 * mat2; - - Logf("%s", mat2.vec[0].v); - Logf("%s", mat2.vec[1].v); - Logf("%s", mat2.vec[2].v); - Logf("%s", mat2.vec[3].v); - PlatformWindow window = CreateWindow("Video Game", 1920, 1080); Game g = InitGame(&window); diff --git a/src/gears/renderer.d b/src/gears/renderer.d index f4b03d6..41b3349 100644 --- a/src/gears/renderer.d +++ b/src/gears/renderer.d @@ -496,6 +496,8 @@ LoadModel(Renderer* rd, string name) indices[vi+2] = vi+2; } + assert(vertices.length > 0 && indices.length > 0, "Error loading model"); + CreateBuffer(&rd.vk, &model.vertex_buffer, BT.Vertex, vertices.length * Vertex.sizeof, false); CreateBuffer(&rd.vk, &model.index_buffer, BT.Index, indices.length * u32.sizeof, false); diff --git a/src/shared/math.d b/src/shared/math.d index 9fe25da..9765496 100644 --- a/src/shared/math.d +++ b/src/shared/math.d @@ -1,6 +1,7 @@ import aliases; import util; import std.math; +import core.stdc.math : tanf, cosf, sinf, sqrtf; import std.traits; import inteli; import std.meta; @@ -17,6 +18,8 @@ f32 Radians(f32 deg) return deg * (PI / 180.0); } +// TODO: Clean this mess up + enum IsVector(T) = is(T : Vector!U, U...); struct Vector(T, int N) @@ -56,6 +59,14 @@ struct Vector(T, int N) nothrow @nogc pure: + this(Vec3, f32)(Vec3 v3, f32 f) + { + x = v3.x; + y = v3.y; + z = v3.z; + w = f; + } + this(Args...)(Args args) { static if (args.length == 1) @@ -186,33 +197,88 @@ struct Vector(T, int N) } } - Vector opBinary(string op, U)(U operand) if (is(U: Vector) || (IsConvertible!(U))) + static if (N == 4) { - Vector result; + Vector opBinary(string op, U)(U operand) if ((is(U: Vector!(f32, 4)) && is(T: f32)) && (op == "*" || op == "+" || op == "-" || op == "/")) + { + Vector result; + f32* l = &x; + f32* r = &operand.x; + f32* res = &result.x; + + asm pure @nogc nothrow + { + mov R8, l; + mov R9, r; + mov R10, res; + movups XMM0, x.offsetof[R8]; + movups XMM1, operand.x.offsetof[R9]; + } + static if (op == "*") asm pure @nogc nothrow { mulps XMM0, XMM1; } + else static if (op == "-") asm pure @nogc nothrow { subps XMM0, XMM1; } + else static if (op == "+") asm pure @nogc nothrow { addps XMM0, XMM1; } + else static if (op == "/") asm pure @nogc nothrow { divps XMM0, XMM1; } + asm pure @nogc nothrow + { + movups result.x.offsetof[R10], XMM0; + } - static if (is(U: T)) - { - mixin(GenerateLoop!("result.v[@] = cast(T)(v[@] " ~ op ~ " operand);", N)()); + return result; } - else + + Vector opBinary(string op, U)(U operand) if (IsConvertible!(U) && (op == "*" || op == "+" || op == "-" || op == "/")) { + Vector result; Vector other = operand; - mixin(GenerateLoop!("result.v[@] = cast(T)(v[@] " ~ op ~ " other.v[@]);", N)()); + f32* l = &x; + f32* r = &other.x; + f32* res = &result.x; + + asm pure @nogc nothrow + { + mov R8, l; + mov R9, r; + mov R10, res; + movups XMM0, x.offsetof[R8]; + movups XMM1, other.x.offsetof[R9]; + } + static if (op == "*") asm pure @nogc nothrow { mulps XMM0, XMM1; } + else static if (op == "-") asm pure @nogc nothrow { subps XMM0, XMM1; } + else static if (op == "+") asm pure @nogc nothrow { addps XMM0, XMM1; } + else static if (op == "/") asm pure @nogc nothrow { divps XMM0, XMM1; } + asm pure @nogc nothrow + { + movups result.x.offsetof[R8], XMM0; + } + + return result; + } + } + else + { + Vector opBinary(string op, U)(U operand) if (is(U: Vector) && U._N == N && (op == "*" || op == "+" || op == "-" || op == "/")) + { + Vector res; + mixin(GenerateLoop!("res.v[@] = v[@] " ~ op ~ " operand.v[@];", N)()); + return res; } - return result; + Vector opBinary(string op, U)(U operand) if (IsConvertible!(U) && (op == "*" || op == "+" || op == "-" || op == "/")) + { + Vector res; + Vector other = operand; + mixin(GenerateLoop!("res.v[@] = v[@] " ~ op ~ " other.v[@];", N)()); + return res; + } } + + ref T opIndex(size_t i) { return v[i]; } - ref const(T) opIndex(size_t i) const - { - return v[i]; - } - T opIndexAssign(U : T)(U x, size_t i) { return v[i] = x; @@ -325,6 +391,7 @@ struct Matrix(T, int D) alias T _T; enum N = D*D; + enum _D = D; union { @@ -393,6 +460,16 @@ struct Matrix(T, int D) return this; } + ref T opIndex(size_t i, size_t j) + { + return v[(i * D) + j]; + } + + T opIndexAssign(U: T)(U x, size_t i, size_t j) + { + return v[(i * D) + j] = x; + } + Matrix opBinary(string op)(T scalar) if (op == "*") { Matrix result; @@ -414,7 +491,50 @@ struct Matrix(T, int D) static if (D == 4) { - Matrix opBinary(string op, U)(U x) if (is(U: Matrix!(T, D)) && is(T: f32)) + Vec4 opBinary(string op, U)(U x) if (is(U: Vec4) && is(T: f32) && (op == "*")) + { + Vec4 result; + + auto res = &result; + auto m = &this; + auto v = &x; + + asm pure @trusted @nogc nothrow + { + mov R8, m; + mov R9, v; + mov R10, res; + + movups XMM0, vec.offsetof[R8]+00; + movups XMM1, vec.offsetof[R8]+16; + movups XMM2, vec.offsetof[R8]+32; + movups XMM3, vec.offsetof[R8]+48; + + movups XMM4, x.x.offsetof[R9]; + movups XMM5, XMM4; + shufps XMM5, XMM5, 0; + movups XMM6, XMM4; + shufps XMM6, XMM6, 85; + movups XMM7, XMM4; + shufps XMM7, XMM7, 170; + movups XMM8, XMM4; + shufps XMM8, XMM8, 255; + + mulps XMM3, XMM8; + mulps XMM2, XMM7; + addps XMM3, XMM2; + mulps XMM1, XMM6; + addps XMM3, XMM1; + mulps XMM0, XMM5; + addps XMM3, XMM0; + + movups result.x.offsetof[R10], XMM3; + } + + return result; + } + + Matrix opBinary(string op, U)(U x) if (is(U: Matrix!(T, D)) && is(T: f32) && (op == "*")) { Matrix result; @@ -555,6 +675,69 @@ struct Matrix(T, int D) } } +struct Quat +{ + union + { + f32[4] v; + Vec4 vec; + struct + { + f32 x; + f32 y; + f32 z; + f32 w; + }; + }; + + this(f32 w, f32 x, f32 y, f32 z) + { + vec.x = x; + vec.y = y; + vec.z = z; + vec.w = w; + } + + U opCast(U)() if (is(U: Mat4)) + { + f32 norm = Normalize(&vec); + f32 s = norm > 0.0 ? 2.0 / norm : 0.0; + + f32 _x = x; + f32 _y = y; + f32 _z = z; + f32 _w = w; + + f32 xx = s * x * x; f32 xy = s * x * y; f32 wx = s * w * x; + f32 yy = s * y * y; f32 yz = s * y * z; f32 wy = s * w * y; + f32 zz = s * z * z; f32 xz = s * x * z; f32 wz = s * w * z; + + U mat; + + mat[0, 0] = 1.0 - yy - zz; + mat[1, 1] = 1.0 - xx - zz; + mat[2, 2] = 1.0 - xx - yy; + + mat[0, 1] = xy + wz; + mat[1, 2] = yz + wx; + mat[2, 0] = xz + wy; + + mat[1, 0] = xy - wz; + mat[2, 1] = yz - wx; + mat[0, 2] = xz - wy; + + mat[0, 3] = 0.0; + mat[1, 3] = 0.0; + mat[2, 3] = 0.0; + mat[3, 0] = 0.0; + mat[3, 1] = 0.0; + mat[3, 2] = 0.0; + mat[3, 3] = 1.0; + + return mat; + } +} + nothrow @nogc pragma(inline): Mat4 Mat4Identity() { @@ -566,6 +749,17 @@ Mat4Identity() ); } +pragma(inline): void +Mat4Identity(Mat4* mat) +{ + MatZero(mat); + + (*mat)[0, 0] = 1.0; + (*mat)[1, 1] = 1.0; + (*mat)[2, 2] = 1.0; + (*mat)[3, 3] = 1.0; +} + nothrow @nogc pragma(inline): Mat3 Mat3Identity() { @@ -585,14 +779,160 @@ Mat2Identity() ); } -T SquaredMagnitude(T)(T v) if (IsVector!(T)) +pragma(inline): void +QuatFromAxis(Quat* q, f32 angle, Vec3 axis) +{ + Vec3 k; + + f32 a = angle * 0.5f; + f32 c = cosf(a); + f32 s = sinf(a); + + NormalizeTo(&axis, &k); + + q.x = s * k.x; + q.y = s * k.y; + q.z = s * k.z; + q.w = c; +} + +pragma(inline): f32 +Dot(Vec2* l, Vec2* r) +{ + return l.x * r.x + l.y * r.y; +} + +pragma(inline): f32 +Dot(Vec3* l, Vec3* r) +{ + return l.x * r.x + l.y * r.y + l.z * r.z; +} + +pragma(inline): f32 +Dot(Vec4* l, Vec4* r) +{ + // TODO: SIMD this + return l.x * r.x + l.y * r.y + l.z * r.z + l.w * r.w; +} + +pragma(inline): f32 +Normalize(Vec3* v) +{ + return sqrtf(Dot(v, v)); +} + +pragma(inline): f32 +Normalize(Vec4* v) +{ + // TODO: SIMD this + return sqrtf(Dot(v, v)); +} + +pragma(inline): void +NormalizeTo(Vec3* v, Vec3* dst) +{ + f32 norm = Normalize(v); + + if (norm < f32.epsilon) + { + dst.x = dst.y = dst.z = 0.0; + } + else + { + *dst = (*v) * (1.0 / norm); + } +} + +pragma(inline): void +Perspective(Mat4* mat, f32 fov, f32 width, f32 height, f32 near, f32 far) +{ + MatZero(mat); + + f32 f = 1.0 / tanf(fov * 0.5); + f32 fn = 1.0 / (near - far); + + (*mat)[0, 0] = f / (width / height); + (*mat)[1, 1] = f; + (*mat)[2, 2] = far * fn; + (*mat)[2, 3] = -1.0; + (*mat)[3, 2] = near * far * fn; +} + +pragma(inline): void +MatZero(Mat4* mat) +{ + auto v = &mat.vec; + asm @nogc nothrow + { + mov R8, v; + xorps XMM0, XMM0; + movups mat.vec.offsetof[R8]+00, XMM0; + movups mat.vec.offsetof[R8]+16, XMM0; + movups mat.vec.offsetof[R8]+32, XMM0; + movups mat.vec.offsetof[R8]+48, XMM0; + } +} + +pragma(inline): void +Translate(Mat4* mat, Vec3 vec) +{ + Mat4Identity(mat); + (*mat)[3, 0] = vec[0]; + (*mat)[3, 1] = vec[1]; + (*mat)[3, 2] = vec[2]; +} + +pragma(inline): Mat4 +Inverse(Mat4 mat) +{ + // TODO: SIMD this + f32 a = mat[0, 0], b = mat[0, 1], c = mat[0, 2], d = mat[0, 3], + e = mat[1, 0], f = mat[1, 1], g = mat[1, 2], h = mat[1, 3], + i = mat[2, 0], j = mat[2, 1], k = mat[2, 2], l = mat[2, 3], + m = mat[3, 0], n = mat[3, 1], o = mat[3, 2], p = mat[3, 3]; + + f32 c1 = k * p - l * o, c2 = c * h - d * g, c3 = i * p - l * m, + c4 = a * h - d * e, c5 = j * p - l * n, c6 = b * h - d * f, + c7 = i * n - j * m, c8 = a * f - b * e, c9 = j * o - k * n, + c10 = b * g - c * f, c11 = i * o - k * m, c12 = a * g - c * e; + + f32 idt = 1.0/(c8*c1+c4*c9+c10*c3+c2*c7-c12*c5-c6*c11), ndt = -idt; + + Mat4 res; + + res[0, 0] = (f * c1 - g * c5 + h * c9) * idt; + res[0, 1] = (b * c1 - c * c5 + d * c9) * ndt; + res[0, 2] = (n * c2 - o * c6 + p * c10) * idt; + res[0, 3] = (j * c2 - k * c6 + l * c10) * ndt; + + res[1, 0] = (e * c1 - g * c3 + h * c11) * ndt; + res[1, 1] = (a * c1 - c * c3 + d * c11) * idt; + res[1, 2] = (m * c2 - o * c4 + p * c12) * ndt; + res[1, 3] = (i * c2 - k * c4 + l * c12) * idt; + + res[2, 0] = (e * c5 - f * c3 + h * c7) * idt; + res[2, 1] = (a * c5 - b * c3 + d * c7) * ndt; + res[2, 2] = (m * c6 - n * c4 + p * c8) * idt; + res[2, 3] = (i * c6 - j * c4 + l * c8) * ndt; + + res[3, 0] = (e * c9 - f * c11 + g * c7) * ndt; + res[3, 1] = (a * c9 - b * c11 + c * c7) * idt; + res[3, 2] = (m * c10 - n * c12 + o * c8) * ndt; + res[3, 3] = (i * c10 - j * c12 + k * c8) * idt; + + return res; +} + +pragma(inline): T +SquaredMagnitude(T)(T v) if (IsVector!(T)) { T sum_squares = 0; mixin(GenerateLoop!("sum_squares += v.v[@] * v.v[@];", v._N)()); return sum_squares; } -T SquaredDistTo(T)(T l, T r) if (IsVector!(T)) +pragma(inline): T +SquaredDistTo(T)(T l, T r) if (IsVector!(T)) { return SquaredMagnitude(r - l); }