feat(host): vendor PyroWave + minimal Granite subset as crates/pyrowave-sys

Phase 0 of design/pyrowave-codec-plan.md — the opt-in wired-LAN ultra-low-
latency codec. Vendored at upstream 509e4f88 (API 0.4.0, Granite 44362775,
volk + vulkan-headers pins in PUNKTFUNK-VENDOR.txt), pruned to the 6.6 MB
the standalone no-renderer build needs; scripts/vendor-pyrowave.sh
reproduces the tree (a pin bump is protocol-affecting, plan §4.2).

build.rs drives the wrapper CMakeLists (static archives incl. a static
C-API lib upstream only ships shared) + bindgen over pyrowave.h; Linux and
Windows only, empty stub elsewhere (Apple gets a native Metal port, §4.7).
Offline-safe by construction: no network, no system lib, vendored Vulkan
headers — same model as the opus dep (flatpak builder has no network).

Phase-0 validation on .21 (RTX 5070 Ti, driver 610.43.03):
- upstream pyrowave-c-test + interop test (incl. dmabuf/DRM-modifier
  Vulkan<->Vulkan) pass, from the pristine AND the pruned tree
- GPU kernel times at ~1.6 bpp noise: encode/decode 0.090/0.042 ms @800p,
  0.146/0.067 @1080p, 0.226/0.103 @1440p, 0.477/0.201 @4K — order of
  magnitude under NVENC's 1-2 ms retrieve, CBR lands within ~100 B of
  target
- cargo test -p pyrowave-sys green (static link + API-version pin check)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 00:35:10 +02:00
parent 1b73361372
commit 4c3b11445c
396 changed files with 140058 additions and 0 deletions
@@ -0,0 +1,52 @@
/* Copyright (c) 2017-2026 Hans-Kristian Arntzen
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "muglm.hpp"
#include <limits>
namespace muglm
{
mat4 mat4_cast(const quat &q);
mat_affine mat_affine_cast(const quat &q);
mat3 mat3_cast(const quat &q);
mat4 translate(const vec3 &v);
mat4 scale(const vec3 &v);
mat_affine translate_affine(const vec3 &v);
mat_affine scale_affine(const vec3 &v);
mat2 inverse(const mat2 &m);
mat3 inverse(const mat3 &m);
mat4 inverse(const mat4 &m);
float determinant(const mat2 &m);
float determinant(const mat3 &m);
constexpr float InfiniteFarPlane = std::numeric_limits<float>::max();
mat4 perspective(float fovy, float aspect, float near, float far);
mat4 frustum(float left, float right, float bottom, float top, float near, float far);
// Orthogonal projection cannot have infinite far-plane.
mat4 ortho(float left, float right, float bottom, float top, float near, float far);
void decompose(const mat4 &m, vec3 &scale, quat &rot, vec3 &trans);
}
@@ -0,0 +1,460 @@
/* Copyright (c) 2017-2026 Hans-Kristian Arntzen
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "matrix_helper.hpp"
#include "muglm_impl.hpp"
#include "simd_headers.hpp"
namespace muglm
{
mat3 mat3_cast(const quat &q_)
{
auto &q = q_.as_vec4();
mat3 res(1.0f);
float qxx = q.x * q.x;
float qyy = q.y * q.y;
float qzz = q.z * q.z;
float qxz = q.x * q.z;
float qxy = q.x * q.y;
float qyz = q.y * q.z;
float qwx = q.w * q.x;
float qwy = q.w * q.y;
float qwz = q.w * q.z;
res[0][0] = 1.0f - 2.0f * (qyy + qzz);
res[0][1] = 2.0f * (qxy + qwz);
res[0][2] = 2.0f * (qxz - qwy);
res[1][0] = 2.0f * (qxy - qwz);
res[1][1] = 1.0f - 2.0f * (qxx + qzz);
res[1][2] = 2.0f * (qyz + qwx);
res[2][0] = 2.0f * (qxz + qwy);
res[2][1] = 2.0f * (qyz - qwx);
res[2][2] = 1.0f - 2.0f * (qxx + qyy);
return res;
}
mat4 mat4_cast(const quat &q)
{
return mat4(mat3_cast(q));
}
mat_affine mat_affine_cast(const quat &q)
{
return mat_affine(mat3_cast(q));
}
mat4 translate(const vec3 &v)
{
return mat4(
vec4(1.0f, 0.0f, 0.0f, 0.0f),
vec4(0.0f, 1.0f, 0.0f, 0.0f),
vec4(0.0f, 0.0f, 1.0f, 0.0f),
vec4(v, 1.0f));
}
mat4 scale(const vec3 &v)
{
return mat4(
vec4(v.x, 0.0f, 0.0f, 0.0f),
vec4(0.0f, v.y, 0.0f, 0.0f),
vec4(0.0f, 0.0f, v.z, 0.0f),
vec4(0.0f, 0.0f, 0.0f, 1.0f));
}
mat_affine translate_affine(const vec3 &v)
{
return mat_affine(
vec4(1.0f, 0.0f, 0.0f, v.x),
vec4(0.0f, 1.0f, 0.0f, v.y),
vec4(0.0f, 0.0f, 1.0f, v.z));
}
mat_affine scale_affine(const vec3 &v)
{
return mat_affine(
vec4(v.x, 0.0f, 0.0f, 0.0f),
vec4(0.0f, v.y, 0.0f, 0.0f),
vec4(0.0f, 0.0f, v.z, 0.0f));
}
float determinant(const mat2 &m)
{
return m[0][0] * m[1][1] - m[1][0] * m[0][1];
}
mat2 inverse(const mat2 &m)
{
float OneOverDeterminant = 1.0f / determinant(m);
mat2 Inverse(
vec2(m[1][1] * OneOverDeterminant,
-m[0][1] * OneOverDeterminant),
vec2(-m[1][0] * OneOverDeterminant,
m[0][0] * OneOverDeterminant));
return Inverse;
}
float determinant(const mat3 &m)
{
return m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])
- m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])
+ m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]);
}
mat3 inverse(const mat3 &m)
{
float OneOverDeterminant = 1.0f / determinant(m);
mat3 Inverse;
Inverse[0][0] = +(m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDeterminant;
Inverse[1][0] = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDeterminant;
Inverse[2][0] = +(m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDeterminant;
Inverse[0][1] = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDeterminant;
Inverse[1][1] = +(m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDeterminant;
Inverse[2][1] = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDeterminant;
Inverse[0][2] = +(m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDeterminant;
Inverse[1][2] = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDeterminant;
Inverse[2][2] = +(m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDeterminant;
return Inverse;
}
mat4 inverse(const mat4 &m)
{
float Coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
float Coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
float Coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
float Coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
float Coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
float Coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
float Coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
float Coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
float Coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
float Coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
float Coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
float Coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
float Coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
float Coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
float Coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
float Coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
float Coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
float Coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
vec4 Fac0(Coef00, Coef00, Coef02, Coef03);
vec4 Fac1(Coef04, Coef04, Coef06, Coef07);
vec4 Fac2(Coef08, Coef08, Coef10, Coef11);
vec4 Fac3(Coef12, Coef12, Coef14, Coef15);
vec4 Fac4(Coef16, Coef16, Coef18, Coef19);
vec4 Fac5(Coef20, Coef20, Coef22, Coef23);
vec4 Vec0(m[1][0], m[0][0], m[0][0], m[0][0]);
vec4 Vec1(m[1][1], m[0][1], m[0][1], m[0][1]);
vec4 Vec2(m[1][2], m[0][2], m[0][2], m[0][2]);
vec4 Vec3(m[1][3], m[0][3], m[0][3], m[0][3]);
vec4 Inv0(Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2);
vec4 Inv1(Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4);
vec4 Inv2(Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5);
vec4 Inv3(Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5);
vec4 SignA(+1, -1, +1, -1);
vec4 SignB(-1, +1, -1, +1);
mat4 Inverse(Inv0 * SignA, Inv1 * SignB, Inv2 * SignA, Inv3 * SignB);
vec4 Row0(Inverse[0][0], Inverse[1][0], Inverse[2][0], Inverse[3][0]);
vec4 Dot0(m[0] * Row0);
float Dot1 = (Dot0.x + Dot0.y) + (Dot0.z + Dot0.w);
float OneOverDeterminant = 1.0f / Dot1;
return Inverse * OneOverDeterminant;
}
void decompose(const mat4 &m, vec3 &scale, quat &rotation, vec3 &trans)
{
vec4 rot;
// Make a lot of assumptions.
// We don't need skew, nor perspective.
// Isolate translation.
trans = m[3].xyz();
vec3 cols[3];
cols[0] = m[0].xyz();
cols[1] = m[1].xyz();
cols[2] = m[2].xyz();
scale.x = length(cols[0]);
scale.y = length(cols[1]);
scale.z = length(cols[2]);
// Isolate scale.
cols[0] /= scale.x;
cols[1] /= scale.y;
cols[2] /= scale.z;
vec3 pdum3 = cross(cols[1], cols[2]);
if (dot(cols[0], pdum3) < 0.0f)
{
scale = -scale;
cols[0] = -cols[0];
cols[1] = -cols[1];
cols[2] = -cols[2];
}
int i, j, k = 0;
float root, trace = cols[0].x + cols[1].y + cols[2].z;
if (trace > 0.0f)
{
root = sqrt(trace + 1.0f);
rot.w = 0.5f * root;
root = 0.5f / root;
rot.x = root * (cols[1].z - cols[2].y);
rot.y = root * (cols[2].x - cols[0].z);
rot.z = root * (cols[0].y - cols[1].x);
}
else
{
static const int Next[3] = {1, 2, 0};
i = 0;
if (cols[1].y > cols[0].x) i = 1;
if (cols[2].z > cols[i][i]) i = 2;
j = Next[i];
k = Next[j];
root = sqrt(cols[i][i] - cols[j][j] - cols[k][k] + 1.0f);
rot[i] = 0.5f * root;
root = 0.5f / root;
rot[j] = root * (cols[i][j] + cols[j][i]);
rot[k] = root * (cols[i][k] + cols[k][i]);
rot.w = root * (cols[j][k] - cols[k][j]);
}
rotation = quat(rot);
}
mat4 ortho(float left, float right, float bottom, float top, float near, float far)
{
mat4 result(1.0f);
result[0][0] = 2.0f / (right - left);
result[1][1] = 2.0f / (top - bottom);
result[3][0] = -(right + left) / (right - left);
result[3][1] = -(top + bottom) / (top - bottom);
result[2][2] = 1.0f / (far - near);
result[3][2] = 1.0f + near / (far - near);
result[0].y *= -1.0f;
result[1].y *= -1.0f;
result[2].y *= -1.0f;
result[3].y *= -1.0f;
return result;
}
mat4 frustum(float left, float right, float bottom, float top, float near, float far)
{
mat4 result(0.0f);
result[0][0] = (2.0f * near) / (right - left);
result[1][1] = (2.0f * near) / (top - bottom);
result[2][0] = (right + left) / (right - left);
result[2][1] = (top + bottom) / (top - bottom);
// Inverse Z
if (far == InfiniteFarPlane)
{
result[3][2] = -near;
}
else
{
result[2][2] = -1.0f - far / (near - far);
result[3][2] = -(far * near) / (near - far);
}
result[2][3] = -1.0f;
// Y-flip so we don't have to bother with negative viewport heights.
result[0].y *= -1.0f;
result[1].y *= -1.0f;
result[2].y *= -1.0f;
result[3].y *= -1.0f;
return result;
}
mat4 perspective(float fovy, float aspect, float near, float far)
{
float tanHalfFovy = tan(fovy / 2.0f);
mat4 result(0.0f);
result[0][0] = 1.0f / (aspect * tanHalfFovy);
result[1][1] = 1.0f / (tanHalfFovy);
// Inverse Z
if (far == InfiniteFarPlane)
{
result[3][2] = near;
}
else
{
result[2][2] = -1.0f - far / (near - far);
result[3][2] = -(far * near) / (near - far);
}
result[2][3] = -1.0f;
// Y-flip so we don't have to bother with negative viewport heights.
result[0].y *= -1.0f;
result[1].y *= -1.0f;
result[2].y *= -1.0f;
result[3].y *= -1.0f;
return result;
}
void transpose(mat4 &dst, const mat4 &src)
{
#if __SSE__
__m128 r0 = _mm_loadu_ps(src[0].data);
__m128 r1 = _mm_loadu_ps(src[1].data);
__m128 r2 = _mm_loadu_ps(src[2].data);
__m128 r3 = _mm_loadu_ps(src[3].data);
_MM_TRANSPOSE4_PS(r0, r1, r2, r3);
_mm_storeu_ps(dst[0].data, r0);
_mm_storeu_ps(dst[1].data, r1);
_mm_storeu_ps(dst[2].data, r2);
_mm_storeu_ps(dst[3].data, r3);
#elif defined(__ARM_NEON)
float32x4x4_t a = vld4q_f32(src[0].data);
vst1q_f32(dst[0].data, a.val[0]);
vst1q_f32(dst[1].data, a.val[1]);
vst1q_f32(dst[2].data, a.val[2]);
vst1q_f32(dst[3].data, a.val[3]);
#else
dst = transpose(src);
#endif
}
void transpose_to_affine(vec4 dst[3], const mat4 &src)
{
#if __SSE__
__m128 r0 = _mm_loadu_ps(src[0].data);
__m128 r1 = _mm_loadu_ps(src[1].data);
__m128 r2 = _mm_loadu_ps(src[2].data);
__m128 r3 = _mm_loadu_ps(src[3].data);
_MM_TRANSPOSE4_PS(r0, r1, r2, r3);
_mm_storeu_ps(dst[0].data, r0);
_mm_storeu_ps(dst[1].data, r1);
_mm_storeu_ps(dst[2].data, r2);
#elif defined(__ARM_NEON)
float32x4x4_t a = vld4q_f32(src[0].data);
vst1q_f32(dst[0].data, a.val[0]);
vst1q_f32(dst[1].data, a.val[1]);
vst1q_f32(dst[2].data, a.val[2]);
#else
mat4 m = transpose(src);
for (int i = 0; i < 3; i++)
dst[i] = m[i];
#endif
}
void transpose_from_affine(mat4 &dst, const vec4 src[3])
{
#if __SSE__
__m128 r0 = _mm_loadu_ps(src[0].data);
__m128 r1 = _mm_loadu_ps(src[1].data);
__m128 r2 = _mm_loadu_ps(src[2].data);
__m128 r3 = _mm_set_ps(1, 0, 0, 0);
_MM_TRANSPOSE4_PS(r0, r1, r2, r3);
_mm_storeu_ps(dst[0].data, r0);
_mm_storeu_ps(dst[1].data, r1);
_mm_storeu_ps(dst[2].data, r2);
_mm_storeu_ps(dst[3].data, r3);
#elif defined(__ARM_NEON)
alignas(16) static const float r3_data[] = { 0, 0, 0, 1 };
float32x4_t r0 = vld1q_f32(src[0].data);
float32x4_t r1 = vld1q_f32(src[1].data);
float32x4_t r2 = vld1q_f32(src[2].data);
float32x4_t r3 = vld1q_f32(r3_data);
float32x4x4_t r = { r0, r1, r2, r3 };
vst4q_f32(dst[0].data, r);
#else
mat4 m = transpose(src);
for (int i = 0; i < 3; i++)
dst[i] = m[i];
#endif
}
void mat_affine::to_mat4(muglm::mat4 &m) const
{
transpose_from_affine(m, vec);
}
mat4 mat_affine::to_mat4() const
{
mat4 m;
to_mat4(m);
return m;
}
float mat_affine::get_uniform_scale() const
{
return length(vec[0].xyz());
}
vec3 mat_affine::get_translation() const
{
// this * vec4(0, 0, 0, 1)
return { vec[0].w, vec[1].w, vec[2].w };
}
vec3 mat_affine::get_forward() const
{
// this * vec4(0, 0, -1, 0).
return { -vec[0].z, -vec[1].z, -vec[2].z };
}
vec3 mat_affine::get_right() const
{
return { vec[0].x, vec[1].x, vec[2].x };
}
vec3 mat_affine::get_up() const
{
return { vec[0].y, vec[1].y, vec[2].y };
}
}
@@ -0,0 +1,993 @@
/* Copyright (c) 2017-2026 Hans-Kristian Arntzen
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
namespace muglm
{
template <typename T> struct tvec2;
template <typename T> struct tvec3;
template <typename T> struct tvec4;
template <typename T> struct tmat2;
template <typename T> struct tmat3;
template <typename T> struct tmat4;
template <typename T>
struct tvec2
{
tvec2() = default;
tvec2(const tvec2 &) = default;
tvec2 &operator=(const tvec2 &) = default;
explicit inline tvec2(T v) noexcept
{
x = v;
y = v;
}
template <typename U>
explicit inline tvec2(const tvec2<U> &u) noexcept
{
x = T(u.x);
y = T(u.y);
}
inline tvec2(T x_, T y_) noexcept
{
x = x_;
y = y_;
}
union
{
T data[2];
struct
{
T x, y;
};
};
inline T &operator[](size_t index)
{
return data[index];
}
inline const T &operator[](size_t index) const
{
return data[index];
}
inline tvec2 xx() const;
inline tvec2 xy() const;
inline tvec2 yx() const;
inline tvec2 yy() const;
inline tvec3<T> xxx() const;
inline tvec3<T> xxy() const;
inline tvec3<T> xyx() const;
inline tvec3<T> xyy() const;
inline tvec3<T> yxx() const;
inline tvec3<T> yxy() const;
inline tvec3<T> yyx() const;
inline tvec3<T> yyy() const;
inline tvec4<T> xxxx() const;
inline tvec4<T> xxxy() const;
inline tvec4<T> xxyx() const;
inline tvec4<T> xxyy() const;
inline tvec4<T> xyxx() const;
inline tvec4<T> xyxy() const;
inline tvec4<T> xyyx() const;
inline tvec4<T> xyyy() const;
inline tvec4<T> yxxx() const;
inline tvec4<T> yxxy() const;
inline tvec4<T> yxyx() const;
inline tvec4<T> yxyy() const;
inline tvec4<T> yyxx() const;
inline tvec4<T> yyxy() const;
inline tvec4<T> yyyx() const;
inline tvec4<T> yyyy() const;
};
template <typename T>
struct tvec3
{
tvec3() = default;
tvec3(const tvec3 &) = default;
tvec3 &operator=(const tvec3 &) = default;
template <typename U>
explicit inline tvec3(const tvec3<U> &u) noexcept
{
x = T(u.x);
y = T(u.y);
z = T(u.z);
}
inline tvec3(const tvec2<T> &a, T b) noexcept
{
x = a.x;
y = a.y;
z = b;
}
inline tvec3(T a, const tvec2<T> &b) noexcept
{
x = a;
y = b.x;
z = b.y;
}
explicit inline tvec3(T v) noexcept
{
x = v;
y = v;
z = v;
}
inline tvec3(T x_, T y_, T z_) noexcept
{
x = x_;
y = y_;
z = z_;
}
union
{
T data[3];
struct
{
T x, y, z;
};
};
inline T &operator[](size_t index)
{
return data[index];
}
inline const T &operator[](size_t index) const
{
return data[index];
}
inline tvec2<T> xx() const;
inline tvec2<T> xy() const;
inline tvec2<T> xz() const;
inline tvec2<T> yx() const;
inline tvec2<T> yy() const;
inline tvec2<T> yz() const;
inline tvec2<T> zx() const;
inline tvec2<T> zy() const;
inline tvec2<T> zz() const;
inline tvec3<T> xxx() const;
inline tvec3<T> xxy() const;
inline tvec3<T> xxz() const;
inline tvec3<T> xyx() const;
inline tvec3<T> xyy() const;
inline tvec3<T> xyz() const;
inline tvec3<T> xzx() const;
inline tvec3<T> xzy() const;
inline tvec3<T> xzz() const;
inline tvec3<T> yxx() const;
inline tvec3<T> yxy() const;
inline tvec3<T> yxz() const;
inline tvec3<T> yyx() const;
inline tvec3<T> yyy() const;
inline tvec3<T> yyz() const;
inline tvec3<T> yzx() const;
inline tvec3<T> yzy() const;
inline tvec3<T> yzz() const;
inline tvec3<T> zxx() const;
inline tvec3<T> zxy() const;
inline tvec3<T> zxz() const;
inline tvec3<T> zyx() const;
inline tvec3<T> zyy() const;
inline tvec3<T> zyz() const;
inline tvec3<T> zzx() const;
inline tvec3<T> zzy() const;
inline tvec3<T> zzz() const;
inline tvec4<T> xxxx() const;
inline tvec4<T> xxxy() const;
inline tvec4<T> xxxz() const;
inline tvec4<T> xxyx() const;
inline tvec4<T> xxyy() const;
inline tvec4<T> xxyz() const;
inline tvec4<T> xxzx() const;
inline tvec4<T> xxzy() const;
inline tvec4<T> xxzz() const;
inline tvec4<T> xyxx() const;
inline tvec4<T> xyxy() const;
inline tvec4<T> xyxz() const;
inline tvec4<T> xyyx() const;
inline tvec4<T> xyyy() const;
inline tvec4<T> xyyz() const;
inline tvec4<T> xyzx() const;
inline tvec4<T> xyzy() const;
inline tvec4<T> xyzz() const;
inline tvec4<T> xzxx() const;
inline tvec4<T> xzxy() const;
inline tvec4<T> xzxz() const;
inline tvec4<T> xzyx() const;
inline tvec4<T> xzyy() const;
inline tvec4<T> xzyz() const;
inline tvec4<T> xzzx() const;
inline tvec4<T> xzzy() const;
inline tvec4<T> xzzz() const;
inline tvec4<T> yxxx() const;
inline tvec4<T> yxxy() const;
inline tvec4<T> yxxz() const;
inline tvec4<T> yxyx() const;
inline tvec4<T> yxyy() const;
inline tvec4<T> yxyz() const;
inline tvec4<T> yxzx() const;
inline tvec4<T> yxzy() const;
inline tvec4<T> yxzz() const;
inline tvec4<T> yyxx() const;
inline tvec4<T> yyxy() const;
inline tvec4<T> yyxz() const;
inline tvec4<T> yyyx() const;
inline tvec4<T> yyyy() const;
inline tvec4<T> yyyz() const;
inline tvec4<T> yyzx() const;
inline tvec4<T> yyzy() const;
inline tvec4<T> yyzz() const;
inline tvec4<T> yzxx() const;
inline tvec4<T> yzxy() const;
inline tvec4<T> yzxz() const;
inline tvec4<T> yzyx() const;
inline tvec4<T> yzyy() const;
inline tvec4<T> yzyz() const;
inline tvec4<T> yzzx() const;
inline tvec4<T> yzzy() const;
inline tvec4<T> yzzz() const;
inline tvec4<T> zxxx() const;
inline tvec4<T> zxxy() const;
inline tvec4<T> zxxz() const;
inline tvec4<T> zxyx() const;
inline tvec4<T> zxyy() const;
inline tvec4<T> zxyz() const;
inline tvec4<T> zxzx() const;
inline tvec4<T> zxzy() const;
inline tvec4<T> zxzz() const;
inline tvec4<T> zyxx() const;
inline tvec4<T> zyxy() const;
inline tvec4<T> zyxz() const;
inline tvec4<T> zyyx() const;
inline tvec4<T> zyyy() const;
inline tvec4<T> zyyz() const;
inline tvec4<T> zyzx() const;
inline tvec4<T> zyzy() const;
inline tvec4<T> zyzz() const;
inline tvec4<T> zzxx() const;
inline tvec4<T> zzxy() const;
inline tvec4<T> zzxz() const;
inline tvec4<T> zzyx() const;
inline tvec4<T> zzyy() const;
inline tvec4<T> zzyz() const;
inline tvec4<T> zzzx() const;
inline tvec4<T> zzzy() const;
inline tvec4<T> zzzz() const;
};
template <typename T>
struct tvec4
{
tvec4() = default;
tvec4(const tvec4 &) = default;
tvec4 &operator=(const tvec4 &) = default;
template <typename U>
explicit inline tvec4(const tvec4<U> &u) noexcept
{
x = T(u.x);
y = T(u.y);
z = T(u.z);
w = T(u.w);
}
inline tvec4(const tvec2<T> &a, const tvec2<T> &b) noexcept
{
x = a.x;
y = a.y;
z = b.x;
w = b.y;
}
inline tvec4(const tvec3<T> &a, T b) noexcept
{
x = a.x;
y = a.y;
z = a.z;
w = b;
}
inline tvec4(T a, const tvec3<T> &b) noexcept
{
x = a;
y = b.x;
z = b.y;
w = b.z;
}
inline tvec4(const tvec2<T> &a, T b, T c) noexcept
{
x = a.x;
y = a.y;
z = b;
w = c;
}
inline tvec4(T a, const tvec2<T> &b, T c) noexcept
{
x = a;
y = b.x;
z = b.y;
w = c;
}
inline tvec4(T a, T b, const tvec2<T> &c) noexcept
{
x = a;
y = b;
z = c.x;
w = c.y;
}
explicit inline tvec4(T v) noexcept
{
x = v;
y = v;
z = v;
w = v;
}
inline tvec4(T x_, T y_, T z_, T w_) noexcept
{
x = x_;
y = y_;
z = z_;
w = w_;
}
inline T &operator[](size_t index)
{
return data[index];
}
inline const T &operator[](size_t index) const
{
return data[index];
}
union
{
T data[4];
struct
{
T x, y, z, w;
};
};
inline tvec2<T> xx() const;
inline tvec2<T> xy() const;
inline tvec2<T> xz() const;
inline tvec2<T> xw() const;
inline tvec2<T> yx() const;
inline tvec2<T> yy() const;
inline tvec2<T> yz() const;
inline tvec2<T> yw() const;
inline tvec2<T> zx() const;
inline tvec2<T> zy() const;
inline tvec2<T> zz() const;
inline tvec2<T> zw() const;
inline tvec2<T> wx() const;
inline tvec2<T> wy() const;
inline tvec2<T> wz() const;
inline tvec2<T> ww() const;
inline tvec3<T> xxx() const;
inline tvec3<T> xxy() const;
inline tvec3<T> xxz() const;
inline tvec3<T> xxw() const;
inline tvec3<T> xyx() const;
inline tvec3<T> xyy() const;
inline tvec3<T> xyz() const;
inline tvec3<T> xyw() const;
inline tvec3<T> xzx() const;
inline tvec3<T> xzy() const;
inline tvec3<T> xzz() const;
inline tvec3<T> xzw() const;
inline tvec3<T> xwx() const;
inline tvec3<T> xwy() const;
inline tvec3<T> xwz() const;
inline tvec3<T> xww() const;
inline tvec3<T> yxx() const;
inline tvec3<T> yxy() const;
inline tvec3<T> yxz() const;
inline tvec3<T> yxw() const;
inline tvec3<T> yyx() const;
inline tvec3<T> yyy() const;
inline tvec3<T> yyz() const;
inline tvec3<T> yyw() const;
inline tvec3<T> yzx() const;
inline tvec3<T> yzy() const;
inline tvec3<T> yzz() const;
inline tvec3<T> yzw() const;
inline tvec3<T> ywx() const;
inline tvec3<T> ywy() const;
inline tvec3<T> ywz() const;
inline tvec3<T> yww() const;
inline tvec3<T> zxx() const;
inline tvec3<T> zxy() const;
inline tvec3<T> zxz() const;
inline tvec3<T> zxw() const;
inline tvec3<T> zyx() const;
inline tvec3<T> zyy() const;
inline tvec3<T> zyz() const;
inline tvec3<T> zyw() const;
inline tvec3<T> zzx() const;
inline tvec3<T> zzy() const;
inline tvec3<T> zzz() const;
inline tvec3<T> zzw() const;
inline tvec3<T> zwx() const;
inline tvec3<T> zwy() const;
inline tvec3<T> zwz() const;
inline tvec3<T> zww() const;
inline tvec3<T> wxx() const;
inline tvec3<T> wxy() const;
inline tvec3<T> wxz() const;
inline tvec3<T> wxw() const;
inline tvec3<T> wyx() const;
inline tvec3<T> wyy() const;
inline tvec3<T> wyz() const;
inline tvec3<T> wyw() const;
inline tvec3<T> wzx() const;
inline tvec3<T> wzy() const;
inline tvec3<T> wzz() const;
inline tvec3<T> wzw() const;
inline tvec3<T> wwx() const;
inline tvec3<T> wwy() const;
inline tvec3<T> wwz() const;
inline tvec3<T> www() const;
inline tvec4 xxxx() const;
inline tvec4 xxxy() const;
inline tvec4 xxxz() const;
inline tvec4 xxxw() const;
inline tvec4 xxyx() const;
inline tvec4 xxyy() const;
inline tvec4 xxyz() const;
inline tvec4 xxyw() const;
inline tvec4 xxzx() const;
inline tvec4 xxzy() const;
inline tvec4 xxzz() const;
inline tvec4 xxzw() const;
inline tvec4 xxwx() const;
inline tvec4 xxwy() const;
inline tvec4 xxwz() const;
inline tvec4 xxww() const;
inline tvec4 xyxx() const;
inline tvec4 xyxy() const;
inline tvec4 xyxz() const;
inline tvec4 xyxw() const;
inline tvec4 xyyx() const;
inline tvec4 xyyy() const;
inline tvec4 xyyz() const;
inline tvec4 xyyw() const;
inline tvec4 xyzx() const;
inline tvec4 xyzy() const;
inline tvec4 xyzz() const;
inline tvec4 xyzw() const;
inline tvec4 xywx() const;
inline tvec4 xywy() const;
inline tvec4 xywz() const;
inline tvec4 xyww() const;
inline tvec4 xzxx() const;
inline tvec4 xzxy() const;
inline tvec4 xzxz() const;
inline tvec4 xzxw() const;
inline tvec4 xzyx() const;
inline tvec4 xzyy() const;
inline tvec4 xzyz() const;
inline tvec4 xzyw() const;
inline tvec4 xzzx() const;
inline tvec4 xzzy() const;
inline tvec4 xzzz() const;
inline tvec4 xzzw() const;
inline tvec4 xzwx() const;
inline tvec4 xzwy() const;
inline tvec4 xzwz() const;
inline tvec4 xzww() const;
inline tvec4 xwxx() const;
inline tvec4 xwxy() const;
inline tvec4 xwxz() const;
inline tvec4 xwxw() const;
inline tvec4 xwyx() const;
inline tvec4 xwyy() const;
inline tvec4 xwyz() const;
inline tvec4 xwyw() const;
inline tvec4 xwzx() const;
inline tvec4 xwzy() const;
inline tvec4 xwzz() const;
inline tvec4 xwzw() const;
inline tvec4 xwwx() const;
inline tvec4 xwwy() const;
inline tvec4 xwwz() const;
inline tvec4 xwww() const;
inline tvec4 yxxx() const;
inline tvec4 yxxy() const;
inline tvec4 yxxz() const;
inline tvec4 yxxw() const;
inline tvec4 yxyx() const;
inline tvec4 yxyy() const;
inline tvec4 yxyz() const;
inline tvec4 yxyw() const;
inline tvec4 yxzx() const;
inline tvec4 yxzy() const;
inline tvec4 yxzz() const;
inline tvec4 yxzw() const;
inline tvec4 yxwx() const;
inline tvec4 yxwy() const;
inline tvec4 yxwz() const;
inline tvec4 yxww() const;
inline tvec4 yyxx() const;
inline tvec4 yyxy() const;
inline tvec4 yyxz() const;
inline tvec4 yyxw() const;
inline tvec4 yyyx() const;
inline tvec4 yyyy() const;
inline tvec4 yyyz() const;
inline tvec4 yyyw() const;
inline tvec4 yyzx() const;
inline tvec4 yyzy() const;
inline tvec4 yyzz() const;
inline tvec4 yyzw() const;
inline tvec4 yywx() const;
inline tvec4 yywy() const;
inline tvec4 yywz() const;
inline tvec4 yyww() const;
inline tvec4 yzxx() const;
inline tvec4 yzxy() const;
inline tvec4 yzxz() const;
inline tvec4 yzxw() const;
inline tvec4 yzyx() const;
inline tvec4 yzyy() const;
inline tvec4 yzyz() const;
inline tvec4 yzyw() const;
inline tvec4 yzzx() const;
inline tvec4 yzzy() const;
inline tvec4 yzzz() const;
inline tvec4 yzzw() const;
inline tvec4 yzwx() const;
inline tvec4 yzwy() const;
inline tvec4 yzwz() const;
inline tvec4 yzww() const;
inline tvec4 ywxx() const;
inline tvec4 ywxy() const;
inline tvec4 ywxz() const;
inline tvec4 ywxw() const;
inline tvec4 ywyx() const;
inline tvec4 ywyy() const;
inline tvec4 ywyz() const;
inline tvec4 ywyw() const;
inline tvec4 ywzx() const;
inline tvec4 ywzy() const;
inline tvec4 ywzz() const;
inline tvec4 ywzw() const;
inline tvec4 ywwx() const;
inline tvec4 ywwy() const;
inline tvec4 ywwz() const;
inline tvec4 ywww() const;
inline tvec4 zxxx() const;
inline tvec4 zxxy() const;
inline tvec4 zxxz() const;
inline tvec4 zxxw() const;
inline tvec4 zxyx() const;
inline tvec4 zxyy() const;
inline tvec4 zxyz() const;
inline tvec4 zxyw() const;
inline tvec4 zxzx() const;
inline tvec4 zxzy() const;
inline tvec4 zxzz() const;
inline tvec4 zxzw() const;
inline tvec4 zxwx() const;
inline tvec4 zxwy() const;
inline tvec4 zxwz() const;
inline tvec4 zxww() const;
inline tvec4 zyxx() const;
inline tvec4 zyxy() const;
inline tvec4 zyxz() const;
inline tvec4 zyxw() const;
inline tvec4 zyyx() const;
inline tvec4 zyyy() const;
inline tvec4 zyyz() const;
inline tvec4 zyyw() const;
inline tvec4 zyzx() const;
inline tvec4 zyzy() const;
inline tvec4 zyzz() const;
inline tvec4 zyzw() const;
inline tvec4 zywx() const;
inline tvec4 zywy() const;
inline tvec4 zywz() const;
inline tvec4 zyww() const;
inline tvec4 zzxx() const;
inline tvec4 zzxy() const;
inline tvec4 zzxz() const;
inline tvec4 zzxw() const;
inline tvec4 zzyx() const;
inline tvec4 zzyy() const;
inline tvec4 zzyz() const;
inline tvec4 zzyw() const;
inline tvec4 zzzx() const;
inline tvec4 zzzy() const;
inline tvec4 zzzz() const;
inline tvec4 zzzw() const;
inline tvec4 zzwx() const;
inline tvec4 zzwy() const;
inline tvec4 zzwz() const;
inline tvec4 zzww() const;
inline tvec4 zwxx() const;
inline tvec4 zwxy() const;
inline tvec4 zwxz() const;
inline tvec4 zwxw() const;
inline tvec4 zwyx() const;
inline tvec4 zwyy() const;
inline tvec4 zwyz() const;
inline tvec4 zwyw() const;
inline tvec4 zwzx() const;
inline tvec4 zwzy() const;
inline tvec4 zwzz() const;
inline tvec4 zwzw() const;
inline tvec4 zwwx() const;
inline tvec4 zwwy() const;
inline tvec4 zwwz() const;
inline tvec4 zwww() const;
inline tvec4 wxxx() const;
inline tvec4 wxxy() const;
inline tvec4 wxxz() const;
inline tvec4 wxxw() const;
inline tvec4 wxyx() const;
inline tvec4 wxyy() const;
inline tvec4 wxyz() const;
inline tvec4 wxyw() const;
inline tvec4 wxzx() const;
inline tvec4 wxzy() const;
inline tvec4 wxzz() const;
inline tvec4 wxzw() const;
inline tvec4 wxwx() const;
inline tvec4 wxwy() const;
inline tvec4 wxwz() const;
inline tvec4 wxww() const;
inline tvec4 wyxx() const;
inline tvec4 wyxy() const;
inline tvec4 wyxz() const;
inline tvec4 wyxw() const;
inline tvec4 wyyx() const;
inline tvec4 wyyy() const;
inline tvec4 wyyz() const;
inline tvec4 wyyw() const;
inline tvec4 wyzx() const;
inline tvec4 wyzy() const;
inline tvec4 wyzz() const;
inline tvec4 wyzw() const;
inline tvec4 wywx() const;
inline tvec4 wywy() const;
inline tvec4 wywz() const;
inline tvec4 wyww() const;
inline tvec4 wzxx() const;
inline tvec4 wzxy() const;
inline tvec4 wzxz() const;
inline tvec4 wzxw() const;
inline tvec4 wzyx() const;
inline tvec4 wzyy() const;
inline tvec4 wzyz() const;
inline tvec4 wzyw() const;
inline tvec4 wzzx() const;
inline tvec4 wzzy() const;
inline tvec4 wzzz() const;
inline tvec4 wzzw() const;
inline tvec4 wzwx() const;
inline tvec4 wzwy() const;
inline tvec4 wzwz() const;
inline tvec4 wzww() const;
inline tvec4 wwxx() const;
inline tvec4 wwxy() const;
inline tvec4 wwxz() const;
inline tvec4 wwxw() const;
inline tvec4 wwyx() const;
inline tvec4 wwyy() const;
inline tvec4 wwyz() const;
inline tvec4 wwyw() const;
inline tvec4 wwzx() const;
inline tvec4 wwzy() const;
inline tvec4 wwzz() const;
inline tvec4 wwzw() const;
inline tvec4 wwwx() const;
inline tvec4 wwwy() const;
inline tvec4 wwwz() const;
inline tvec4 wwww() const;
};
template <typename T>
struct tmat2
{
tmat2() = default;
tmat2(const tmat2 &) = default;
tmat2 &operator=(const tmat2 &) = default;
explicit inline tmat2(T v) noexcept
{
vec[0] = tvec2<T>(v, T(0));
vec[1] = tvec2<T>(T(0), v);
}
inline tmat2(const tvec2<T> &a, const tvec2<T> &b) noexcept
{
vec[0] = a;
vec[1] = b;
}
inline tvec2<T> &operator[](size_t index)
{
return vec[index];
}
inline const tvec2<T> &operator[](size_t index) const
{
return vec[index];
}
private:
tvec2<T> vec[2];
};
template <typename T>
struct tmat3
{
tmat3() = default;
tmat3(const tmat3 &) = default;
tmat3 &operator=(const tmat3 &) = default;
explicit inline tmat3(T v) noexcept
{
vec[0] = tvec3<T>(v, T(0), T(0));
vec[1] = tvec3<T>(T(0), v, T(0));
vec[2] = tvec3<T>(T(0), T(0), v);
}
inline tmat3(const tvec3<T> &a, const tvec3<T> &b, const tvec3<T> &c) noexcept
{
vec[0] = a;
vec[1] = b;
vec[2] = c;
}
explicit inline tmat3(const tmat4<T> &m) noexcept
{
for (int col = 0; col < 3; col++)
for (int row = 0; row < 3; row++)
vec[col][row] = m[col][row];
}
inline tvec3<T> &operator[](size_t index)
{
return vec[index];
}
inline const tvec3<T> &operator[](size_t index) const
{
return vec[index];
}
private:
tvec3<T> vec[3];
};
template <typename T>
struct tmat4
{
tmat4() = default;
tmat4(const tmat4 &) = default;
tmat4 &operator=(const tmat4 &) = default;
explicit inline tmat4(T v) noexcept
{
vec[0] = tvec4<T>(v, T(0), T(0), T(0));
vec[1] = tvec4<T>(T(0), v, T(0), T(0));
vec[2] = tvec4<T>(T(0), T(0), v, T(0));
vec[3] = tvec4<T>(T(0), T(0), T(0), v);
}
explicit inline tmat4(const tmat3<T> &m) noexcept
{
vec[0] = tvec4<T>(m[0], T(0));
vec[1] = tvec4<T>(m[1], T(0));
vec[2] = tvec4<T>(m[2], T(0));
vec[3] = tvec4<T>(T(0), T(0), T(0), T(1));
}
inline tmat4(const tvec4<T> &a, const tvec4<T> &b, const tvec4<T> &c, const tvec4<T> &d) noexcept
{
vec[0] = a;
vec[1] = b;
vec[2] = c;
vec[3] = d;
}
inline tvec4<T> &operator[](size_t index)
{
return vec[index];
}
inline const tvec4<T> &operator[](size_t index) const
{
return vec[index];
}
private:
tvec4<T> vec[4];
};
using uint = uint32_t;
using vec2 = tvec2<float>;
using vec3 = tvec3<float>;
using vec4 = tvec4<float>;
using mat2 = tmat2<float>;
using mat3 = tmat3<float>;
using mat4 = tmat4<float>;
using dvec2 = tvec2<double>;
using dvec3 = tvec3<double>;
using dvec4 = tvec4<double>;
using dmat2 = tmat2<double>;
using dmat3 = tmat3<double>;
using dmat4 = tmat4<double>;
using ivec2 = tvec2<int32_t>;
using ivec3 = tvec3<int32_t>;
using ivec4 = tvec4<int32_t>;
using uvec2 = tvec2<uint32_t>;
using uvec3 = tvec3<uint32_t>;
using uvec4 = tvec4<uint32_t>;
using u16vec2 = tvec2<uint16_t>;
using u16vec3 = tvec3<uint16_t>;
using u16vec4 = tvec4<uint16_t>;
using i16vec2 = tvec2<int16_t>;
using i16vec3 = tvec3<int16_t>;
using i16vec4 = tvec4<int16_t>;
using u8vec2 = tvec2<uint8_t>;
using u8vec3 = tvec3<uint8_t>;
using u8vec4 = tvec4<uint8_t>;
using i8vec2 = tvec2<int8_t>;
using i8vec3 = tvec3<int8_t>;
using i8vec4 = tvec4<int8_t>;
using bvec2 = tvec2<bool>;
using bvec3 = tvec3<bool>;
using bvec4 = tvec4<bool>;
void transpose(mat4 &dst, const mat4 &src);
void transpose_to_affine(vec4 dst[3], const mat4 &src);
struct mat_affine
{
mat_affine() = default;
mat_affine(const mat_affine &) = default;
mat_affine &operator=(const mat_affine &) = default;
explicit inline mat_affine(const mat4 &m)
{
transpose_to_affine(vec, m);
}
explicit inline mat_affine(const mat3 &m)
: vec{{m[0][0], m[1][0], m[2][0], 0.0f},
{m[0][1], m[1][1], m[2][1], 0.0f},
{m[0][2], m[1][2], m[2][2], 0.0f}}
{
}
explicit inline mat_affine(float v)
: vec{{v, 0, 0, 0}, {0, v, 0, 0}, {0, 0, v, 0}}
{
}
inline mat_affine(const vec4 &r0, const vec4 &r1, const vec4 &r2)
: vec{r0, r1, r2}
{
}
inline vec4 &operator[](size_t index)
{
return vec[index];
}
inline const vec4 &operator[](size_t index) const
{
return vec[index];
}
float get_uniform_scale() const;
vec3 get_translation() const;
// Based on identity view pointing to -Z axis, Y up.
vec3 get_forward() const;
vec3 get_right() const;
vec3 get_up() const;
mat4 to_mat4() const;
void to_mat4(mat4 &m) const;
inline mat3 to_mat3() const
{
return {
vec3(vec[0][0], vec[1][0], vec[2][0]),
vec3(vec[0][1], vec[1][1], vec[2][1]),
vec3(vec[0][2], vec[1][2], vec[2][2]),
};
}
private:
vec4 vec[3];
};
struct quat : private vec4
{
quat() = default;
quat(const quat &) = default;
quat(float w_, float x_, float y_, float z_)
: vec4(x_, y_, z_, w_)
{}
explicit inline quat(const vec4 &v)
: vec4(v)
{}
inline quat(float w_, const vec3 &v_)
: vec4(v_, w_)
{}
inline const vec4 &as_vec4() const
{
return *static_cast<const vec4 *>(this);
}
quat &operator=(const quat &) = default;
using vec4::x;
using vec4::y;
using vec4::z;
using vec4::w;
};
template <typename T> constexpr inline T pi() { return T(3.1415926535897932384626433832795028841971); }
template <typename T> constexpr inline T half_pi() { return T(0.5) * pi<T>(); }
template <typename T> constexpr inline T one_over_root_two() { return T(0.7071067811865476); }
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,251 @@
/* Copyright (c) 2017-2026 Hans-Kristian Arntzen
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "muglm_impl.hpp"
#include "matrix_helper.hpp"
#include "simd.hpp"
#include <assert.h>
#include <stdlib.h>
#include "aabb.hpp"
using namespace muglm;
#define MATH_ASSERT(x) do { \
if (!bool(x)) \
abort(); \
} while(0)
template <typename T>
static void assert_equal_epsilon(const T &a, const T &b, float epsilon = 0.0001f)
{
MATH_ASSERT(all(lessThanEqual(abs(a - b), T(epsilon))));
}
template <typename T>
static void assert_equal(const T &a, const T &b)
{
MATH_ASSERT(all(equal(a, b)));
}
static void assert_equal_epsilon(const mat2 &a, const mat2 &b, float epsilon = 0.0001f)
{
assert_equal_epsilon(a[0], b[0], epsilon);
assert_equal_epsilon(a[1], b[1], epsilon);
}
static void assert_equal_epsilon(const mat3 &a, const mat3 &b, float epsilon = 0.0001f)
{
assert_equal_epsilon(a[0], b[0], epsilon);
assert_equal_epsilon(a[1], b[1], epsilon);
assert_equal_epsilon(a[2], b[2], epsilon);
}
static void assert_equal_epsilon(const mat4 &a, const mat4 &b, float epsilon = 0.0001f)
{
assert_equal_epsilon(a[0], b[0], epsilon);
assert_equal_epsilon(a[1], b[1], epsilon);
assert_equal_epsilon(a[2], b[2], epsilon);
assert_equal_epsilon(a[3], b[3], epsilon);
}
static void assert_equal_epsilon(const mat_affine &a, const mat_affine &b, float epsilon = 0.0001f)
{
assert_equal_epsilon(a[0], b[0], epsilon);
assert_equal_epsilon(a[1], b[1], epsilon);
assert_equal_epsilon(a[2], b[2], epsilon);
}
static void assert_equal(const mat2 &a, const mat2 &b)
{
assert_equal_epsilon(a, b, 0.0f);
}
static void assert_equal(const mat3 &a, const mat3 &b)
{
assert_equal_epsilon(a, b, 0.0f);
}
static void assert_equal(const mat4 &a, const mat4 &b)
{
assert_equal_epsilon(a, b, 0.0f);
}
static void test_mat2()
{
mat2 m(vec2(2.0f, 0.5f), vec2(8.0f, 4.0f));
mat2 inv_m = inverse(m);
mat2 mul0 = m * inv_m;
mat2 mul1 = inv_m * m;
assert_equal_epsilon(mul0, mat2(1.0f));
assert_equal_epsilon(mul1, mat2(1.0f));
assert_equal(transpose(transpose(m)), m);
}
static void test_mat3()
{
mat3 m(vec3(2.0f, 0.5f, -3.0f), vec3(8.0f, 4.0f, 0.25f), vec3(-20.0f, 5.0f, 1.0f));
mat3 inv_m = inverse(m);
mat3 mul0 = m * inv_m;
mat3 mul1 = inv_m * m;
assert_equal_epsilon(mul0, mat3(1.0f));
assert_equal_epsilon(mul1, mat3(1.0f));
assert_equal(transpose(transpose(m)), m);
}
static void test_mat4()
{
mat4 m(vec4(2.0f, 0.5f, -3.0f, 1.0f), vec4(8.0f, 4.0f, 0.25f, 8.0f), vec4(8.0f, -20.0f, 5.0f, 1.0f), vec4(0.0f, 1.0f, 2.0f, 3.0f));
mat4 inv_m = inverse(m);
mat4 mul0 = m * inv_m;
mat4 mul1 = inv_m * m;
assert_equal_epsilon(mul0, mat4(1.0f));
assert_equal_epsilon(mul1, mat4(1.0f));
assert_equal(transpose(transpose(m)), m);
}
static void test_quat()
{
// X
{
quat q = angleAxis(half_pi<float>(), vec3(0.0f, 0.0f, 1.0f));
vec3 y = q * vec3(1.0f, 0.0f, 0.0f);
assert_equal_epsilon(y, vec3(0.0f, 1.0f, 0.0f));
quat half_q = angleAxis(0.5f * half_pi<float>(), vec3(0.0f, 0.0f, 1.0f));
q = half_q * half_q;
y = q * vec3(1.0f, 0.0f, 0.0f);
assert_equal_epsilon(y, vec3(0.0f, 1.0f, 0.0f));
}
// Y
{
quat q = angleAxis(half_pi<float>(), vec3(0.0f, 1.0f, 0.0f));
vec3 y = q * vec3(1.0f, 0.0f, 0.0f);
assert_equal_epsilon(y, vec3(0.0f, 0.0f, -1.0f));
quat half_q = angleAxis(0.5f * half_pi<float>(), vec3(0.0f, 1.0f, 0.0f));
q = half_q * half_q;
y = q * vec3(1.0f, 0.0f, 0.0f);
assert_equal_epsilon(y, vec3(0.0f, 0.0f, -1.0f));
}
assert_equal_epsilon(mat3_cast(quat(1.0f, 0.0f, 0.0f, 0.0f)), mat3(1.0f));
assert_equal_epsilon(mat4_cast(quat(1.0f, 0.0f, 0.0f, 0.0f)), mat4(1.0f));
}
static void test_decompose()
{
vec3 scaling(4.0f, -3.0f, 2.0f);
quat rotate = angleAxis(0.543f, vec3(0.1f, 0.2f, -0.9f));
vec3 trans(5.0f, 4.0f, 2.0f);
mat4 original = translate(trans) * mat4_cast(rotate) * scale(scaling);
vec3 s, t;
quat r;
decompose(original, s, r, t);
mat4 reconstructed = translate(t) * mat4_cast(r) * scale(s);
assert_equal_epsilon(original, reconstructed);
}
static void test_transpose()
{
mat4 original(vec4(1, 2, 3, 4), vec4(5, 6, 7, 8), vec4(9, 10, 11, 12), vec4(13, 14, 15, 16));
mat4 transposed = transpose(original);
mat_affine aff{original};
const mat4 expected_transposed(
vec4(1, 5, 9, 13),
vec4(2, 6, 10, 14),
vec4(3, 7, 11, 15),
vec4(4, 8, 12, 16));
mat_affine expected_aff;
for (int i = 0; i < 3; i++)
expected_aff[i] = expected_transposed[i];
assert_equal_epsilon(expected_transposed, transposed, 0.0f);
assert_equal_epsilon(expected_aff, aff, 0.0f);
}
static void test_affine()
{
mat4 a(vec4(1, 2, 3, 0), vec4(5, 6, 7, 0),
vec4(9, 10, 11, 0), vec4(13, 14, 15, 1));
mat4 b(vec4(17, 18, 19, 0), vec4(21, 22, 23, 0),
vec4(25, 26, 27, 0), vec4(29, 30, 31, 1));
mat4 c = a * b;
mat_affine aff_c(c);
mat_affine aff_a(a);
mat_affine aff_b(b);
mat_affine res;
Granite::SIMD::mul(res, aff_a, aff_b);
assert_equal_epsilon(res, aff_c, 0.0f);
}
static void test_affine_mul()
{
mat4 a(vec4(1, 2, 3, 0), vec4(5, 6, 7, 0),
vec4(9, 10, 11, 0), vec4(13, 14, 15, 1));
vec4 b(1, 2, 3, 1);
mat_affine aff_a(a);
vec4 ref = a * b;
vec4 res4, res_affine;
Granite::SIMD::mul(res4, a, b);
Granite::SIMD::mul(res_affine, aff_a, b);
assert_equal_epsilon(ref, res4, 0.0f);
assert_equal_epsilon(ref, res_affine, 0.0f);
}
static void test_aabb_transform()
{
mat4 m(vec4(1, 2, 3, 0), vec4(5, 6, 7, 0),
vec4(9, 10, 11, 0), vec4(13, 14, 15, 1));
Granite::AABB aabb{vec3(-1, -2, -4), vec3(3, 7, 4)};
Granite::AABB reference_aabb, affine_aabb;
Granite::SIMD::transform_aabb(reference_aabb, aabb, m);
Granite::SIMD::transform_aabb(affine_aabb, aabb, mat_affine(m));
assert_equal_epsilon(reference_aabb.get_maximum4(), affine_aabb.get_maximum4(), 0.0f);
assert_equal_epsilon(reference_aabb.get_minimum4(), affine_aabb.get_minimum4(), 0.0f);
}
int main()
{
test_mat2();
test_mat3();
test_mat4();
test_quat();
test_decompose();
test_transpose();
test_affine();
test_affine_mul();
test_aabb_transform();
}