Compare commits
8 changed files with 4029 additions and 4838 deletions
1
.gitattributes
vendored
1
.gitattributes
vendored
|
|
@ -1 +0,0 @@
|
||||||
* text=auto eol=lf
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
A C++23 math library for the Crafter engine, distributed as a set of C++ modules. Provides generic vector and matrix types alongside SIMD-specialized fixed-size vectors for `float` and `_Float16`, plus a small set of ray intersection routines.
|
A C++23 math library for the Crafter engine, distributed as a set of C++ modules. Provides generic vector and matrix types alongside SIMD-specialized fixed-size vectors for `float` and `_Float16`, plus a small set of ray intersection routines.
|
||||||
|
|
||||||
The library is hardware-aware: it picks the widest SIMD path the target supports (SSE / AVX / AVX-512 on x86_64, NEON on AArch64, RVV on RISC-V, SIMD128 on WebAssembly) and falls back to scalar code elsewhere.
|
The library is hardware-aware: it picks the widest SIMD path the target supports (SSE / AVX / AVX-512 on x86_64, RVV on RISC-V, SIMD128 on WebAssembly) and falls back to scalar code elsewhere.
|
||||||
|
|
||||||
## Modules
|
## Modules
|
||||||
|
|
||||||
|
|
@ -10,13 +10,13 @@ The library is hardware-aware: it picks the widest SIMD path the target supports
|
||||||
|
|
||||||
| Partition | Contents |
|
| Partition | Contents |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `:Basic` | `ToRadian`, plus the `VectorF16 → VectorF32` alias on x86_64 without AVX512-FP16 and on AArch64 without ARMv8.2-FP16. |
|
| `:Basic` | `ToRadian`, plus the `VectorF16 → VectorF32` alias on x86_64 without AVX512-FP16. |
|
||||||
| `:Vector` | Generic `Vector<T, Len, Alignment>` with `.x/.y/.z/.w` and `.r/.g/.b/.a` accessors, arithmetic, comparison, and conversion operators. |
|
| `:Vector` | Generic `Vector<T, Len, Alignment>` with `.x/.y/.z/.w` and `.r/.g/.b/.a` accessors, arithmetic, comparison, and conversion operators. |
|
||||||
| `:MatrixRowMajor` | `MatrixRowMajor<T, ColumnSize, RowSize, Repeats>` — row-major matrices with packed-batch support via `Repeats`. |
|
| `:MatrixRowMajor` | `MatrixRowMajor<T, ColumnSize, RowSize, Repeats>` — row-major matrices with packed-batch support via `Repeats`. |
|
||||||
| `:VectorF32` | `VectorF32<Len, Packing>` — SIMD-specialized 32-bit float vector with `Load`/`Store`, FMA, `Cross`, `Dot`, `Length`, `Normalize`, `Sin`/`Cos`, `Shuffle`, etc. |
|
| `:VectorF32` | `VectorF32<Len, Packing>` — SIMD-specialized 32-bit float vector with `Load`/`Store`, FMA, `Cross`, `Dot`, `Length`, `Normalize`, `Sin`/`Cos`, `Shuffle`, etc. |
|
||||||
| `:VectorF16` | `VectorF16<Len, Packing>` — same surface as `VectorF32` for `_Float16` when the target supports it. |
|
| `:VectorF16` | `VectorF16<Len, Packing>` — same surface as `VectorF32` for `_Float16` when the target supports it. |
|
||||||
| `:Intersection` | `IntersectionTestRayTriangle`, `IntersectionTestRaySphere`, `IntersectionTestRayOrientedBox`. |
|
| `:Intersection` | `IntersectionTestRayTriangle`, `IntersectionTestRaySphere`, `IntersectionTestRayOrientedBox`. |
|
||||||
| `:Common` | Internal SIMD type selection (`__m128/256/512`, `__m128h/256h/512h`, `float32x4_t`, `float16x8_t`, `v128_t`, or scalar array) used by the F16/F32 vectors. |
|
| `:Common` | Internal SIMD type selection (`__m128/256/512`, `__m128h/256h/512h`, `v128_t`, or scalar array) used by the F16/F32 vectors. |
|
||||||
|
|
||||||
`Len` is the logical vector width (1–4 for most graphics use) and `Packing` is the number of vectors packed into one SIMD register — e.g. `VectorF32<3, 4>` holds four 3-vectors in a single 512-bit register, which is what the batched `Dot`, `Length`, and `Normalize` overloads operate on.
|
`Len` is the logical vector width (1–4 for most graphics use) and `Packing` is the number of vectors packed into one SIMD register — e.g. `VectorF32<3, 4>` holds four 3-vectors in a single 512-bit register, which is what the batched `Dot`, `Length`, and `Normalize` overloads operate on.
|
||||||
|
|
||||||
|
|
@ -52,8 +52,6 @@ This project uses [Crafter.Build](https://forgejo.catcrafts.net/Catcrafts/Crafte
|
||||||
- `Vector-rv64gcv_zvl512b` — RVV with VLEN≥512 (uses the 64-byte tier)
|
- `Vector-rv64gcv_zvl512b` — RVV with VLEN≥512 (uses the 64-byte tier)
|
||||||
- `Vector-rv64gcv_zvl256b` — RVV with VLEN≥256 (32-byte tier)
|
- `Vector-rv64gcv_zvl256b` — RVV with VLEN≥256 (32-byte tier)
|
||||||
- `Vector-rv64gcv` — RVA23 baseline ZVL128B (16-byte tier)
|
- `Vector-rv64gcv` — RVA23 baseline ZVL128B (16-byte tier)
|
||||||
- `Vector-armv8.2-a+fp16` — AArch64 NEON with ARMv8.2-FP16 (native `VectorF16`)
|
|
||||||
- `Vector-armv8-a` — AArch64 baseline NEON
|
|
||||||
|
|
||||||
Build and run tests via your usual Crafter.Build entry point; `build/` and `bin/` are git-ignored.
|
Build and run tests via your usual Crafter.Build entry point; `build/` and `bin/` are git-ignored.
|
||||||
|
|
||||||
|
|
@ -61,7 +59,6 @@ Build and run tests via your usual Crafter.Build entry point; `build/` and `bin/
|
||||||
|
|
||||||
- **x86_64**: SSE / AVX / AVX-512F selected per target; AVX512-FP16 is required for native `VectorF16` (otherwise it aliases `VectorF32`). F16C is used for fp16 ↔ fp32 conversion when available.
|
- **x86_64**: SSE / AVX / AVX-512F selected per target; AVX512-FP16 is required for native `VectorF16` (otherwise it aliases `VectorF32`). F16C is used for fp16 ↔ fp32 conversion when available.
|
||||||
- **RISC-V**: RVV 1.0 (the `V` extension, ratified Nov 2021, mandatory in the RVA23 profile). Storage is a 16/32/64-byte GNU vector picked at compile time from the guaranteed VLEN (`__riscv_v_fixed_vlen` from Clang's `-mrvv-vector-bits=`, else `__riscv_v_min_vlen` from the march's `Zvl*` suffix, else the ZVL128B baseline). `VectorF16` aliases `VectorF32` until a `Zvfh` path lands.
|
- **RISC-V**: RVV 1.0 (the `V` extension, ratified Nov 2021, mandatory in the RVA23 profile). Storage is a 16/32/64-byte GNU vector picked at compile time from the guaranteed VLEN (`__riscv_v_fixed_vlen` from Clang's `-mrvv-vector-bits=`, else `__riscv_v_min_vlen` from the march's `Zvl*` suffix, else the ZVL128B baseline). `VectorF16` aliases `VectorF32` until a `Zvfh` path lands.
|
||||||
- **AArch64**: NEON (`arm_neon.h`) 128-bit path; SIMD width is capped at 16 bytes, so a vector holds at most 4 floats or 8 halves. `VectorF32` only needs the ARMv8-A baseline. ARMv8.2-FP16 (`-march=armv8.2-a+fp16`, or any `-march`/`-mcpu` that implies it) is required for native `VectorF16`; otherwise it aliases `VectorF32`, which converts fp16 ↔ fp32 on `Load`/`Store`. 32-bit ARM takes the scalar fallback.
|
|
||||||
- **WebAssembly**: `wasm_simd128.h` 128-bit path; SIMD width is capped at 16 bytes.
|
- **WebAssembly**: `wasm_simd128.h` 128-bit path; SIMD width is capped at 16 bytes.
|
||||||
- **Other targets**: scalar fallback via `std::array<T, N>`.
|
- **Other targets**: scalar fallback via `std::array<T, N>`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
//SPDX-License-Identifier: LGPL-3.0-only
|
//SPDX-License-Identifier: LGPL-3.0-only
|
||||||
//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
||||||
|
|
||||||
export module Crafter.Math:Basic;
|
export module Crafter.Math:Basic;
|
||||||
import std;
|
import std;
|
||||||
import :VectorF32;
|
import :VectorF32;
|
||||||
|
|
||||||
namespace Crafter {
|
namespace Crafter {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr T ToRadian(T degrees) {
|
constexpr T ToRadian(T degrees) {
|
||||||
return degrees * (std::numbers::pi / 180);
|
return degrees * (std::numbers::pi / 180);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (defined(__x86_64) && !defined(__AVX512FP16__)) || defined(__riscv_vector) || (defined(__aarch64__) && defined(__ARM_NEON) && !defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC)) || !defined(__FLT16_MAX__)
|
#if (defined(__x86_64) && !defined(__AVX512FP16__)) || defined(__riscv_vector) || !defined(__FLT16_MAX__)
|
||||||
export template <std::uint32_t Len, std::uint32_t Packing>
|
export template <std::uint32_t Len, std::uint32_t Packing>
|
||||||
using VectorF16 = VectorF32<Len, Packing>;
|
using VectorF16 = VectorF32<Len, Packing>;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
@ -8,9 +8,6 @@ module;
|
||||||
#ifdef __wasm_simd128__
|
#ifdef __wasm_simd128__
|
||||||
#include <wasm_simd128.h>
|
#include <wasm_simd128.h>
|
||||||
#endif
|
#endif
|
||||||
#if defined(__aarch64__) && defined(__ARM_NEON)
|
|
||||||
#include <arm_neon.h>
|
|
||||||
#endif
|
|
||||||
#ifdef __riscv_vector
|
#ifdef __riscv_vector
|
||||||
#include <riscv_vector.h>
|
#include <riscv_vector.h>
|
||||||
// Compile-time VLEN selection. RVV is VLA at the ISA level, but storage in
|
// Compile-time VLEN selection. RVV is VLA at the ISA level, but storage in
|
||||||
|
|
@ -40,11 +37,9 @@ import std;
|
||||||
// VectorF16 exists as a real struct when _Float16 is available AND we are not
|
// VectorF16 exists as a real struct when _Float16 is available AND we are not
|
||||||
// on x86_64 without AVX512FP16 (that path aliases VectorF16 to VectorF32 in
|
// on x86_64 without AVX512FP16 (that path aliases VectorF16 to VectorF32 in
|
||||||
// Crafter.Math:Basic for performance). The same alias kicks in on RISC-V until
|
// Crafter.Math:Basic for performance). The same alias kicks in on RISC-V until
|
||||||
// a Zvfh path lands, and on AArch64 NEON without ARMv8.2-FP16 arithmetic,
|
// a Zvfh path lands. Each translation unit that needs this distinction
|
||||||
// where VectorF32 converts fp16 <-> fp32 on Load/Store. Each translation unit
|
// redefines the same condition since macros do not cross module boundaries.
|
||||||
// that needs this distinction redefines the same condition since macros do not
|
#if defined(__FLT16_MAX__) && (!defined(__x86_64) || defined(__AVX512FP16__)) && !defined(__riscv_vector)
|
||||||
// cross module boundaries.
|
|
||||||
#if defined(__FLT16_MAX__) && (!defined(__x86_64) || defined(__AVX512FP16__)) && !defined(__riscv_vector) && !(defined(__aarch64__) && defined(__ARM_NEON) && !defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC))
|
|
||||||
namespace Crafter {
|
namespace Crafter {
|
||||||
export template <std::uint8_t Len, std::uint8_t Packing>
|
export template <std::uint8_t Len, std::uint8_t Packing>
|
||||||
struct VectorF16;
|
struct VectorF16;
|
||||||
|
|
@ -57,7 +52,7 @@ namespace Crafter {
|
||||||
|
|
||||||
template <std::uint8_t Len, std::uint8_t Packing, typename T>
|
template <std::uint8_t Len, std::uint8_t Packing, typename T>
|
||||||
struct VectorBase {
|
struct VectorBase {
|
||||||
#if defined(__FLT16_MAX__) && (!defined(__x86_64) || defined(__AVX512FP16__)) && !defined(__riscv_vector) && !(defined(__aarch64__) && defined(__ARM_NEON) && !defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC))
|
#if defined(__FLT16_MAX__) && (!defined(__x86_64) || defined(__AVX512FP16__)) && !defined(__riscv_vector)
|
||||||
template <std::uint8_t L, std::uint8_t P>
|
template <std::uint8_t L, std::uint8_t P>
|
||||||
friend struct VectorF16;
|
friend struct VectorF16;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -94,11 +89,6 @@ namespace Crafter {
|
||||||
>;
|
>;
|
||||||
#elif defined(__wasm_simd128__)
|
#elif defined(__wasm_simd128__)
|
||||||
using VectorType = v128_t;
|
using VectorType = v128_t;
|
||||||
#elif defined(__aarch64__) && defined(__ARM_NEON)
|
|
||||||
// NEON registers are 128 bits wide, so every instantiation is one
|
|
||||||
// register: four floats, or eight halves for the native VectorF16
|
|
||||||
// that exists when the target has ARMv8.2-FP16 arithmetic.
|
|
||||||
using VectorType = std::conditional_t<std::is_same_v<T, float>, float32x4_t, float16x8_t>;
|
|
||||||
#elif defined(__riscv_vector)
|
#elif defined(__riscv_vector)
|
||||||
// RVV tier mirrors the x86 selector: pick the widest register the
|
// RVV tier mirrors the x86 selector: pick the widest register the
|
||||||
// toolchain guarantees, then size each instantiation down to the
|
// toolchain guarantees, then size each instantiation down to the
|
||||||
|
|
@ -128,10 +118,6 @@ namespace Crafter {
|
||||||
// WASM SIMD only has 128-bit vectors; cap at 16 bytes so the entire
|
// WASM SIMD only has 128-bit vectors; cap at 16 bytes so the entire
|
||||||
// VectorType always fits in a single v128_t.
|
// VectorType always fits in a single v128_t.
|
||||||
static constexpr std::uint8_t Max = 16;
|
static constexpr std::uint8_t Max = 16;
|
||||||
#elif defined(__aarch64__) && defined(__ARM_NEON)
|
|
||||||
// NEON only has 128-bit vectors; cap at 16 bytes so the entire
|
|
||||||
// VectorType always fits in a single register.
|
|
||||||
static constexpr std::uint8_t Max = 16;
|
|
||||||
#elif defined(__riscv_vector)
|
#elif defined(__riscv_vector)
|
||||||
// RVV tier selected at compile time from the guaranteed VLEN. ZVL128B
|
// RVV tier selected at compile time from the guaranteed VLEN. ZVL128B
|
||||||
// is the RVA23 baseline; ZVL256B / ZVL512B unlock wider registers
|
// is the RVA23 baseline; ZVL256B / ZVL512B unlock wider registers
|
||||||
|
|
@ -712,77 +698,5 @@ namespace Crafter {
|
||||||
out_sin = _mm512_xor_ps(out_sin, x_sign);
|
out_sin = _mm512_xor_ps(out_sin, x_sign);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__aarch64__) && defined(__ARM_NEON)
|
|
||||||
// --- 128-bit (NEON) helpers, same algorithm as the SSE ones above ---
|
|
||||||
// Reduce |x| into [-pi/4, pi/4], return reduced value and quadrant
|
|
||||||
static constexpr void range_reduce_f32x4(float32x4_t ax, float32x4_t& r, float32x4_t& r2, int32x4_t& q) {
|
|
||||||
float32x4_t fq = vrndnq_f32(vmulq_f32(ax, vdupq_n_f32(two_over_pi)));
|
|
||||||
q = vcvtq_s32_f32(fq);
|
|
||||||
// ax - fq * pi/2 as an fmla with the constant negated, not as
|
|
||||||
// vfmsq_f32: that one is a wrapper function in clang's arm_neon.h,
|
|
||||||
// and calling it from two module units (here and :VectorF32) fails
|
|
||||||
// some importers with "definition with same mangled name as
|
|
||||||
// another definition".
|
|
||||||
r = vfmaq_f32(ax, fq, vdupq_n_f32(-pi_over_2_hi));
|
|
||||||
r = vfmaq_f32(r, fq, vdupq_n_f32(-pi_over_2_lo));
|
|
||||||
r2 = vmulq_f32(r, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
// vfmaq_f32(a, b, c) is a + b*c, so each Horner step reads
|
|
||||||
// "next coefficient + accumulator * r2".
|
|
||||||
static constexpr void sincos_poly_f32x4(float32x4_t r, float32x4_t r2, float32x4_t& cos_r, float32x4_t& sin_r) {
|
|
||||||
cos_r = vfmaq_f32(vdupq_n_f32(c8), vdupq_n_f32(c10), r2);
|
|
||||||
cos_r = vfmaq_f32(vdupq_n_f32(c6), cos_r, r2);
|
|
||||||
cos_r = vfmaq_f32(vdupq_n_f32(c4), cos_r, r2);
|
|
||||||
cos_r = vfmaq_f32(vdupq_n_f32(c2), cos_r, r2);
|
|
||||||
cos_r = vfmaq_f32(vdupq_n_f32(c0), cos_r, r2);
|
|
||||||
|
|
||||||
sin_r = vfmaq_f32(vdupq_n_f32(s7), vdupq_n_f32(s9), r2);
|
|
||||||
sin_r = vfmaq_f32(vdupq_n_f32(s5), sin_r, r2);
|
|
||||||
sin_r = vfmaq_f32(vdupq_n_f32(s3), sin_r, r2);
|
|
||||||
sin_r = vfmaq_f32(vdupq_n_f32(s1), sin_r, r2);
|
|
||||||
sin_r = vfmaq_f32(vdupq_n_f32(1.0f), sin_r, r2);
|
|
||||||
sin_r = vmulq_f32(sin_r, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr void sincos_f32x4(float32x4_t x, float32x4_t& out_sin, float32x4_t& out_cos) {
|
|
||||||
uint32x4_t x_sign = vandq_u32(vreinterpretq_u32_f32(x), vdupq_n_u32(0x80000000u));
|
|
||||||
float32x4_t ax = vabsq_f32(x);
|
|
||||||
|
|
||||||
float32x4_t r, r2; int32x4_t q;
|
|
||||||
range_reduce_f32x4(ax, r, r2, q);
|
|
||||||
|
|
||||||
float32x4_t cos_r, sin_r;
|
|
||||||
sincos_poly_f32x4(r, r2, cos_r, sin_r);
|
|
||||||
|
|
||||||
uint32x4_t is_odd = vtstq_s32(q, vdupq_n_s32(1));
|
|
||||||
|
|
||||||
// cos: swap on odd, negate if (q+1)&2
|
|
||||||
out_cos = vbslq_f32(is_odd, sin_r, cos_r);
|
|
||||||
int32x4_t cos_neg = vandq_s32(vaddq_s32(q, vdupq_n_s32(1)), vdupq_n_s32(2));
|
|
||||||
out_cos = vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(out_cos), vshlq_n_s32(cos_neg, 30)));
|
|
||||||
|
|
||||||
// sin: swap on odd, negate if q&2, apply input sign
|
|
||||||
out_sin = vbslq_f32(is_odd, cos_r, sin_r);
|
|
||||||
int32x4_t sin_neg = vandq_s32(q, vdupq_n_s32(2));
|
|
||||||
out_sin = vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(out_sin), vshlq_n_s32(sin_neg, 30)));
|
|
||||||
out_sin = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(out_sin), x_sign));
|
|
||||||
}
|
|
||||||
|
|
||||||
// The single-result variants share sincos_f32x4; the half that is not
|
|
||||||
// returned is dead code the compiler drops after inlining.
|
|
||||||
static constexpr float32x4_t cos_f32x4(float32x4_t x) {
|
|
||||||
float32x4_t s, c;
|
|
||||||
sincos_f32x4(x, s, c);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr float32x4_t sin_f32x4(float32x4_t x) {
|
|
||||||
float32x4_t s, c;
|
|
||||||
sincos_f32x4(x, s, c);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -1,469 +1,469 @@
|
||||||
//SPDX-License-Identifier: LGPL-3.0-only
|
//SPDX-License-Identifier: LGPL-3.0-only
|
||||||
//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
||||||
|
|
||||||
export module Crafter.Math:Vector;
|
export module Crafter.Math:Vector;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
namespace Crafter {
|
namespace Crafter {
|
||||||
template <typename T, std::uint32_t Len, std::uint32_t Aligment>
|
template <typename T, std::uint32_t Len, std::uint32_t Aligment>
|
||||||
struct __attribute__((packed)) VectorBase {
|
struct __attribute__((packed)) VectorBase {
|
||||||
T v[Aligment];
|
T v[Aligment];
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, std::uint32_t Aligment>
|
template <typename T, std::uint32_t Aligment>
|
||||||
struct __attribute__((packed)) VectorBase<T, 1, Aligment> {
|
struct __attribute__((packed)) VectorBase<T, 1, Aligment> {
|
||||||
union {
|
union {
|
||||||
T v[Aligment];
|
T v[Aligment];
|
||||||
T x, r;
|
T x, r;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, std::uint32_t Aligment>
|
template <typename T, std::uint32_t Aligment>
|
||||||
struct __attribute__((packed)) VectorBase<T, 2, Aligment> {
|
struct __attribute__((packed)) VectorBase<T, 2, Aligment> {
|
||||||
union {
|
union {
|
||||||
T v[Aligment];
|
T v[Aligment];
|
||||||
struct __attribute__((packed)) {
|
struct __attribute__((packed)) {
|
||||||
T x, y;
|
T x, y;
|
||||||
};
|
};
|
||||||
struct __attribute__((packed)) {
|
struct __attribute__((packed)) {
|
||||||
T r, g;
|
T r, g;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
constexpr VectorBase<T, 2, Aligment>(T x, T y): x(x), y(y) {
|
constexpr VectorBase<T, 2, Aligment>(T x, T y): x(x), y(y) {
|
||||||
|
|
||||||
}
|
}
|
||||||
constexpr VectorBase<T, 2, Aligment>() = default;
|
constexpr VectorBase<T, 2, Aligment>() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, std::uint32_t Aligment>
|
template <typename T, std::uint32_t Aligment>
|
||||||
struct __attribute__((packed)) VectorBase<T, 3, Aligment> {
|
struct __attribute__((packed)) VectorBase<T, 3, Aligment> {
|
||||||
union {
|
union {
|
||||||
T v[Aligment];
|
T v[Aligment];
|
||||||
struct __attribute__((packed)) {
|
struct __attribute__((packed)) {
|
||||||
T x, y, z;
|
T x, y, z;
|
||||||
};
|
};
|
||||||
struct __attribute__((packed)) {
|
struct __attribute__((packed)) {
|
||||||
T r, g, b;
|
T r, g, b;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
constexpr VectorBase<T, 3, Aligment>(T x, T y, T z): x(x), y(y), z(z) {
|
constexpr VectorBase<T, 3, Aligment>(T x, T y, T z): x(x), y(y), z(z) {
|
||||||
|
|
||||||
}
|
}
|
||||||
constexpr VectorBase<T, 3, Aligment>() = default;
|
constexpr VectorBase<T, 3, Aligment>() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, std::uint32_t Aligment>
|
template <typename T, std::uint32_t Aligment>
|
||||||
struct __attribute__((packed)) VectorBase<T, 4, Aligment> {
|
struct __attribute__((packed)) VectorBase<T, 4, Aligment> {
|
||||||
union {
|
union {
|
||||||
T v[Aligment];
|
T v[Aligment];
|
||||||
struct __attribute__((packed)) {
|
struct __attribute__((packed)) {
|
||||||
T x, y, z, w;
|
T x, y, z, w;
|
||||||
};
|
};
|
||||||
struct __attribute__((packed)) {
|
struct __attribute__((packed)) {
|
||||||
T r, g, b, a;
|
T r, g, b, a;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
constexpr VectorBase<T, 4, Aligment>(T x, T y, T z, T w): x(x), y(y), z(z), w(w) {
|
constexpr VectorBase<T, 4, Aligment>(T x, T y, T z, T w): x(x), y(y), z(z), w(w) {
|
||||||
|
|
||||||
}
|
}
|
||||||
constexpr VectorBase<T, 4, Aligment>() = default;
|
constexpr VectorBase<T, 4, Aligment>() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, std::uint32_t Len>
|
template <typename T, std::uint32_t Len>
|
||||||
struct VectorBase<T, Len, 0> {
|
struct VectorBase<T, Len, 0> {
|
||||||
T v[Len];
|
T v[Len];
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct VectorBase<T, 1, 0> {
|
struct VectorBase<T, 1, 0> {
|
||||||
union {
|
union {
|
||||||
T v[1];
|
T v[1];
|
||||||
T x, r;
|
T x, r;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct VectorBase<T, 2, 0> {
|
struct VectorBase<T, 2, 0> {
|
||||||
union {
|
union {
|
||||||
T v[2];
|
T v[2];
|
||||||
struct {
|
struct {
|
||||||
T x, y;
|
T x, y;
|
||||||
};
|
};
|
||||||
struct {
|
struct {
|
||||||
T r, g;
|
T r, g;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
constexpr VectorBase<T, 2, 0>(T x, T y): x(x), y(y) {
|
constexpr VectorBase<T, 2, 0>(T x, T y): x(x), y(y) {
|
||||||
|
|
||||||
}
|
}
|
||||||
constexpr VectorBase<T, 2, 0>() = default;
|
constexpr VectorBase<T, 2, 0>() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct VectorBase<T, 3, 0> {
|
struct VectorBase<T, 3, 0> {
|
||||||
union {
|
union {
|
||||||
T v[3];
|
T v[3];
|
||||||
struct {
|
struct {
|
||||||
T x, y, z;
|
T x, y, z;
|
||||||
};
|
};
|
||||||
struct {
|
struct {
|
||||||
T r, g, b;
|
T r, g, b;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
constexpr VectorBase<T, 3, 0>(T x, T y, T z): x(x), y(y), z(z) {
|
constexpr VectorBase<T, 3, 0>(T x, T y, T z): x(x), y(y), z(z) {
|
||||||
|
|
||||||
}
|
}
|
||||||
constexpr VectorBase<T, 3, 0>() = default;
|
constexpr VectorBase<T, 3, 0>() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct VectorBase<T, 4, 0> {
|
struct VectorBase<T, 4, 0> {
|
||||||
union {
|
union {
|
||||||
T v[4];
|
T v[4];
|
||||||
struct {
|
struct {
|
||||||
T x, y, z, w;
|
T x, y, z, w;
|
||||||
};
|
};
|
||||||
struct {
|
struct {
|
||||||
T r, g, b, a;
|
T r, g, b, a;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
constexpr VectorBase<T, 4, 0>(T x, T y, T z, T w): x(x), y(y), z(z), w(w) {
|
constexpr VectorBase<T, 4, 0>(T x, T y, T z, T w): x(x), y(y), z(z), w(w) {
|
||||||
|
|
||||||
}
|
}
|
||||||
constexpr VectorBase<T, 4, 0>() = default;
|
constexpr VectorBase<T, 4, 0>() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename T, std::uint32_t Len, std::uint32_t Aligment = 0>
|
export template <typename T, std::uint32_t Len, std::uint32_t Aligment = 0>
|
||||||
class Vector : public VectorBase<T, Len, Aligment> {
|
class Vector : public VectorBase<T, Len, Aligment> {
|
||||||
public:
|
public:
|
||||||
constexpr Vector(T x, T y, T z, T w ) requires(std::same_as<T, T> && Len == 4) : VectorBase<T, Len, Aligment>(x, y, z, w) {
|
constexpr Vector(T x, T y, T z, T w ) requires(std::same_as<T, T> && Len == 4) : VectorBase<T, Len, Aligment>(x, y, z, w) {
|
||||||
|
|
||||||
}
|
}
|
||||||
constexpr Vector(T x, T y, T z) requires(std::same_as<T, T> && Len == 3) : VectorBase<T, Len, Aligment>(x, y, z) {
|
constexpr Vector(T x, T y, T z) requires(std::same_as<T, T> && Len == 3) : VectorBase<T, Len, Aligment>(x, y, z) {
|
||||||
|
|
||||||
}
|
}
|
||||||
constexpr Vector(T x, T y) requires(std::same_as<T, T> && Len == 2) : VectorBase<T, Len, Aligment>(x, y) {
|
constexpr Vector(T x, T y) requires(std::same_as<T, T> && Len == 2) : VectorBase<T, Len, Aligment>(x, y) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Vector() = default;
|
constexpr Vector() = default;
|
||||||
|
|
||||||
template <std::uint32_t BAlignment>
|
template <std::uint32_t BAlignment>
|
||||||
constexpr operator Vector<T, Len, BAlignment>() const {
|
constexpr operator Vector<T, Len, BAlignment>() const {
|
||||||
Vector<T, Len, BAlignment> returnVector;
|
Vector<T, Len, BAlignment> returnVector;
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
returnVector.v[i] = this->v[i];
|
returnVector.v[i] = this->v[i];
|
||||||
}
|
}
|
||||||
return returnVector;
|
return returnVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
||||||
constexpr Vector<T, Len, Aligment> operator+(Vector<T, Blen, BAlignment> b) const {
|
constexpr Vector<T, Len, Aligment> operator+(Vector<T, Blen, BAlignment> b) const {
|
||||||
Vector<T, Len, Aligment> resultVector;
|
Vector<T, Len, Aligment> resultVector;
|
||||||
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
||||||
resultVector.v[i] = this->v[i]+b.v[i];
|
resultVector.v[i] = this->v[i]+b.v[i];
|
||||||
}
|
}
|
||||||
return resultVector;
|
return resultVector;
|
||||||
}
|
}
|
||||||
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
||||||
constexpr Vector<T, Len, Aligment> operator-(Vector<T, Blen, BAlignment> b) const {
|
constexpr Vector<T, Len, Aligment> operator-(Vector<T, Blen, BAlignment> b) const {
|
||||||
Vector<T, Len, Aligment> resultVector;
|
Vector<T, Len, Aligment> resultVector;
|
||||||
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
||||||
resultVector.v[i] = this->v[i]-b.v[i];
|
resultVector.v[i] = this->v[i]-b.v[i];
|
||||||
}
|
}
|
||||||
return resultVector;
|
return resultVector;
|
||||||
}
|
}
|
||||||
constexpr Vector<T, Len, Aligment> operator-(){
|
constexpr Vector<T, Len, Aligment> operator-(){
|
||||||
Vector<T, Len, Aligment> resultVector;
|
Vector<T, Len, Aligment> resultVector;
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
resultVector.v[i] = -this->v[i];
|
resultVector.v[i] = -this->v[i];
|
||||||
}
|
}
|
||||||
return resultVector;
|
return resultVector;
|
||||||
}
|
}
|
||||||
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
||||||
constexpr Vector<T, Len, Aligment> operator*(Vector<T, Blen, BAlignment> b) const {
|
constexpr Vector<T, Len, Aligment> operator*(Vector<T, Blen, BAlignment> b) const {
|
||||||
Vector<T, Len, Aligment> resultVector;
|
Vector<T, Len, Aligment> resultVector;
|
||||||
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
||||||
resultVector.v[i] = this->v[i]*b.v[i];
|
resultVector.v[i] = this->v[i]*b.v[i];
|
||||||
}
|
}
|
||||||
return resultVector;
|
return resultVector;
|
||||||
}
|
}
|
||||||
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
||||||
constexpr Vector<T, Len, Aligment> operator/(Vector<T, Blen, BAlignment> b) const {
|
constexpr Vector<T, Len, Aligment> operator/(Vector<T, Blen, BAlignment> b) const {
|
||||||
Vector<T, Len, Aligment> resultVector;
|
Vector<T, Len, Aligment> resultVector;
|
||||||
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
||||||
resultVector.v[i] = this->v[i]/b.v[i];
|
resultVector.v[i] = this->v[i]/b.v[i];
|
||||||
}
|
}
|
||||||
return resultVector;
|
return resultVector;
|
||||||
}
|
}
|
||||||
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
||||||
constexpr void operator+=(Vector<T, Blen, BAlignment> b){
|
constexpr void operator+=(Vector<T, Blen, BAlignment> b){
|
||||||
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
||||||
this->v[i]+=b.v[i];
|
this->v[i]+=b.v[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
||||||
constexpr void operator-=(Vector<T, Blen, BAlignment> b){
|
constexpr void operator-=(Vector<T, Blen, BAlignment> b){
|
||||||
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
||||||
this->v[i]-=b.v[i];
|
this->v[i]-=b.v[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
||||||
constexpr void operator*=(Vector<T, Blen, BAlignment> b){
|
constexpr void operator*=(Vector<T, Blen, BAlignment> b){
|
||||||
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
||||||
this->v[i]*=b.v[i];
|
this->v[i]*=b.v[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
||||||
constexpr void operator/=(Vector<T, Blen, BAlignment> b){
|
constexpr void operator/=(Vector<T, Blen, BAlignment> b){
|
||||||
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
||||||
this->v[i]/=b.v[i];
|
this->v[i]/=b.v[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BT>
|
template <typename BT>
|
||||||
constexpr Vector<T, Len, Aligment> operator+(BT b) const requires std::is_arithmetic_v<BT> {
|
constexpr Vector<T, Len, Aligment> operator+(BT b) const requires std::is_arithmetic_v<BT> {
|
||||||
Vector<T, Len, Aligment> resultVector;
|
Vector<T, Len, Aligment> resultVector;
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
resultVector.v[i] = this->v[i] + b;
|
resultVector.v[i] = this->v[i] + b;
|
||||||
}
|
}
|
||||||
return resultVector;
|
return resultVector;
|
||||||
}
|
}
|
||||||
template <typename BT>
|
template <typename BT>
|
||||||
constexpr Vector<T, Len, Aligment> operator-(BT b) const requires std::is_arithmetic_v<BT> {
|
constexpr Vector<T, Len, Aligment> operator-(BT b) const requires std::is_arithmetic_v<BT> {
|
||||||
Vector<T, Len, Aligment> resultVector;
|
Vector<T, Len, Aligment> resultVector;
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
resultVector.v[i] = this->v[i] - b;
|
resultVector.v[i] = this->v[i] - b;
|
||||||
}
|
}
|
||||||
return resultVector;
|
return resultVector;
|
||||||
}
|
}
|
||||||
template <typename BT>
|
template <typename BT>
|
||||||
constexpr Vector<T, Len, Aligment> operator*(BT b) const requires std::is_arithmetic_v<BT> {
|
constexpr Vector<T, Len, Aligment> operator*(BT b) const requires std::is_arithmetic_v<BT> {
|
||||||
Vector<T, Len, Aligment> resultVector;
|
Vector<T, Len, Aligment> resultVector;
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
resultVector.v[i] = this->v[i] * b;
|
resultVector.v[i] = this->v[i] * b;
|
||||||
}
|
}
|
||||||
return resultVector;
|
return resultVector;
|
||||||
}
|
}
|
||||||
template <typename BT>
|
template <typename BT>
|
||||||
constexpr Vector<T, Len, Aligment> operator/(BT b) const requires std::is_arithmetic_v<BT> {
|
constexpr Vector<T, Len, Aligment> operator/(BT b) const requires std::is_arithmetic_v<BT> {
|
||||||
Vector<T, Len, Aligment> resultVector;
|
Vector<T, Len, Aligment> resultVector;
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
resultVector.v[i] = this->v[i] / b;
|
resultVector.v[i] = this->v[i] / b;
|
||||||
}
|
}
|
||||||
return resultVector;
|
return resultVector;
|
||||||
}
|
}
|
||||||
template <typename BT>
|
template <typename BT>
|
||||||
constexpr void operator+=(BT b) requires std::is_arithmetic_v<BT>{
|
constexpr void operator+=(BT b) requires std::is_arithmetic_v<BT>{
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
this->v[i] += b;
|
this->v[i] += b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template <typename BT>
|
template <typename BT>
|
||||||
constexpr void operator-=(BT b) requires std::is_arithmetic_v<BT>{
|
constexpr void operator-=(BT b) requires std::is_arithmetic_v<BT>{
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
this->v[i] -= b;
|
this->v[i] -= b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template <typename BT>
|
template <typename BT>
|
||||||
constexpr void operator*=(BT b) requires std::is_arithmetic_v<BT>{
|
constexpr void operator*=(BT b) requires std::is_arithmetic_v<BT>{
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
this->v[i] *= b;
|
this->v[i] *= b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template <typename BT>
|
template <typename BT>
|
||||||
constexpr void operator/=(BT b) requires std::is_arithmetic_v<BT>{
|
constexpr void operator/=(BT b) requires std::is_arithmetic_v<BT>{
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
this->v[i] /= b;
|
this->v[i] /= b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BT, std::uint32_t Blen, std::uint32_t BAlignment>
|
template <typename BT, std::uint32_t Blen, std::uint32_t BAlignment>
|
||||||
constexpr bool operator==(Vector<BT, Blen, BAlignment> b) const {
|
constexpr bool operator==(Vector<BT, Blen, BAlignment> b) const {
|
||||||
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
||||||
if(this->v[i] != b.v[i]) {
|
if(this->v[i] != b.v[i]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BT, std::uint32_t Blen, std::uint32_t BAlignment>
|
template <typename BT, std::uint32_t Blen, std::uint32_t BAlignment>
|
||||||
constexpr bool operator!=(Vector<BT, Blen, BAlignment> b) const {
|
constexpr bool operator!=(Vector<BT, Blen, BAlignment> b) const {
|
||||||
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
||||||
if(this->v[i] != b.v[i]) {
|
if(this->v[i] != b.v[i]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void Normalize() {
|
constexpr void Normalize() {
|
||||||
T fLength = Length();
|
T fLength = Length();
|
||||||
|
|
||||||
fLength = 1.0f / fLength;
|
fLength = 1.0f / fLength;
|
||||||
|
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
this->v[i] *= fLength;
|
this->v[i] *= fLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void Invert() {
|
constexpr void Invert() {
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
this->v[i] = -this->v[i];
|
this->v[i] = -this->v[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr T Length() const {
|
constexpr T Length() const {
|
||||||
T Result = LengthSq();
|
T Result = LengthSq();
|
||||||
return std::sqrtf(Result);
|
return std::sqrtf(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr T LengthSq() const {
|
constexpr T LengthSq() const {
|
||||||
return Dot(*this, *this);
|
return Dot(*this, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename AT, std::uint32_t Alen, std::uint32_t AAlignment, typename BT, std::uint32_t Blen, std::uint32_t BAlignment>
|
template <typename AT, std::uint32_t Alen, std::uint32_t AAlignment, typename BT, std::uint32_t Blen, std::uint32_t BAlignment>
|
||||||
constexpr static Vector<T, Len, Aligment> Cross(Vector<AT, Alen, AAlignment> a, Vector<BT, Blen, BAlignment> b) requires(Len == 3 && Alen >= 3 && Blen >= 3) {
|
constexpr static Vector<T, Len, Aligment> Cross(Vector<AT, Alen, AAlignment> a, Vector<BT, Blen, BAlignment> b) requires(Len == 3 && Alen >= 3 && Blen >= 3) {
|
||||||
return Vector<T, Len, Aligment>(
|
return Vector<T, Len, Aligment>(
|
||||||
(a.v[1] * b.v[2]) - (a.v[2] * b.v[1]),
|
(a.v[1] * b.v[2]) - (a.v[2] * b.v[1]),
|
||||||
(a.v[2] * b.v[0]) - (a.v[0] * b.v[2]),
|
(a.v[2] * b.v[0]) - (a.v[0] * b.v[2]),
|
||||||
(a.v[0] * b.v[1]) - (a.v[1] * b.v[0])
|
(a.v[0] * b.v[1]) - (a.v[1] * b.v[0])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename AT, std::uint32_t Alen, std::uint32_t AAlignment>
|
template <typename AT, std::uint32_t Alen, std::uint32_t AAlignment>
|
||||||
constexpr static Vector<T, Len, Aligment> Normalize(Vector<AT, Alen, AAlignment> a) requires(Len == Alen) {
|
constexpr static Vector<T, Len, Aligment> Normalize(Vector<AT, Alen, AAlignment> a) requires(Len == Alen) {
|
||||||
Vector<T, 3, 0> returned;
|
Vector<T, 3, 0> returned;
|
||||||
T fLength = a.Length();
|
T fLength = a.Length();
|
||||||
|
|
||||||
if (fLength > 0) {
|
if (fLength > 0) {
|
||||||
fLength = 1.0f / fLength;
|
fLength = 1.0f / fLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(std::uint32_t i = 0; i < Len; i++) {
|
for(std::uint32_t i = 0; i < Len; i++) {
|
||||||
returned.v[i] = a.v[i] * fLength;
|
returned.v[i] = a.v[i] * fLength;
|
||||||
}
|
}
|
||||||
return returned;
|
return returned;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename AT, std::uint32_t Alen, std::uint32_t AAlignment, typename BT, std::uint32_t Blen, std::uint32_t BAlignment>
|
template <typename AT, std::uint32_t Alen, std::uint32_t AAlignment, typename BT, std::uint32_t Blen, std::uint32_t BAlignment>
|
||||||
constexpr static T Dot(Vector<AT, Alen, AAlignment> a, Vector<BT, Blen, BAlignment> b) requires(Alen >= Len && Blen >= Len) {
|
constexpr static T Dot(Vector<AT, Alen, AAlignment> a, Vector<BT, Blen, BAlignment> b) requires(Alen >= Len && Blen >= Len) {
|
||||||
T accumulate = a.v[0] * b.v[0];
|
T accumulate = a.v[0] * b.v[0];
|
||||||
for(std::uint32_t i = 1; i < Len; i++) {
|
for(std::uint32_t i = 1; i < Len; i++) {
|
||||||
accumulate += a.v[i] * b.v[i];
|
accumulate += a.v[i] * b.v[i];
|
||||||
}
|
}
|
||||||
return accumulate;
|
return accumulate;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename AT, std::uint32_t AAlignment, typename BT, std::uint32_t BAlignment>
|
template <typename AT, std::uint32_t AAlignment, typename BT, std::uint32_t BAlignment>
|
||||||
constexpr static Vector<T, 3, Aligment> Rotate(Vector<AT, 3, AAlignment> v, Vector<BT, 4, BAlignment> q) requires(Len == 3) {
|
constexpr static Vector<T, 3, Aligment> Rotate(Vector<AT, 3, AAlignment> v, Vector<BT, 4, BAlignment> q) requires(Len == 3) {
|
||||||
Vector<T, 3, 0> qv(q.x, q.y, q.z);
|
Vector<T, 3, 0> qv(q.x, q.y, q.z);
|
||||||
Vector<T, 3, 0> t = Vector<T, 3, Aligment>::Cross(qv, v) * T(2);
|
Vector<T, 3, 0> t = Vector<T, 3, Aligment>::Cross(qv, v) * T(2);
|
||||||
return v + t * q.w + Vector<T, 3, Aligment>::Cross(qv, t);
|
return v + t * q.w + Vector<T, 3, Aligment>::Cross(qv, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename AT, std::uint32_t AAlignment, typename BT, std::uint32_t BAlignment, typename PT, std::uint32_t PAlignment>
|
template <typename AT, std::uint32_t AAlignment, typename BT, std::uint32_t BAlignment, typename PT, std::uint32_t PAlignment>
|
||||||
constexpr static Vector<T, 3, Aligment> RotatePivot(Vector<AT, 3, AAlignment> v, Vector<BT, 4, BAlignment> q, Vector<PT, 3, PAlignment> pivot) requires(Len == 3) {
|
constexpr static Vector<T, 3, Aligment> RotatePivot(Vector<AT, 3, AAlignment> v, Vector<BT, 4, BAlignment> q, Vector<PT, 3, PAlignment> pivot) requires(Len == 3) {
|
||||||
Vector<T, 3, 0> translated = v - pivot;
|
Vector<T, 3, 0> translated = v - pivot;
|
||||||
Vector<T, 3, 0> qv(q.x, q.y, q.z);
|
Vector<T, 3, 0> qv(q.x, q.y, q.z);
|
||||||
Vector<T, 3, 0> t = Cross(qv, translated) * T(2);
|
Vector<T, 3, 0> t = Cross(qv, translated) * T(2);
|
||||||
Vector<T, 3, 0> rotated = translated + t * q.w +Cross(qv, t);
|
Vector<T, 3, 0> rotated = translated + t * q.w +Cross(qv, t);
|
||||||
return rotated + pivot;
|
return rotated + pivot;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename AT, std::uint32_t AAlignment, typename BT, std::uint32_t BAlignment, typename CT, std::uint32_t CAlignment>
|
template <typename AT, std::uint32_t AAlignment, typename BT, std::uint32_t BAlignment, typename CT, std::uint32_t CAlignment>
|
||||||
constexpr static Vector<T, 4, Aligment> QuanternionFromBasis(Vector<AT, 3, AAlignment> right, Vector<BT, 3, BAlignment> up, Vector<CT, 3, CAlignment> forward) requires(Len == 4) {
|
constexpr static Vector<T, 4, Aligment> QuanternionFromBasis(Vector<AT, 3, AAlignment> right, Vector<BT, 3, BAlignment> up, Vector<CT, 3, CAlignment> forward) requires(Len == 4) {
|
||||||
T m00 = right.x;
|
T m00 = right.x;
|
||||||
T m01 = up.x;
|
T m01 = up.x;
|
||||||
T m02 = forward.x;
|
T m02 = forward.x;
|
||||||
|
|
||||||
T m10 = right.y;
|
T m10 = right.y;
|
||||||
T m11 = up.y;
|
T m11 = up.y;
|
||||||
T m12 = forward.y;
|
T m12 = forward.y;
|
||||||
|
|
||||||
T m20 = right.z;
|
T m20 = right.z;
|
||||||
T m21 = up.z;
|
T m21 = up.z;
|
||||||
T m22 = forward.z;
|
T m22 = forward.z;
|
||||||
|
|
||||||
T trace = m00 + m11 + m22;
|
T trace = m00 + m11 + m22;
|
||||||
|
|
||||||
Vector<T, 4, Aligment> q;
|
Vector<T, 4, Aligment> q;
|
||||||
|
|
||||||
if (trace > std::numeric_limits<T>::epsilon()) {
|
if (trace > std::numeric_limits<T>::epsilon()) {
|
||||||
T s = std::sqrt(trace + T(1)) * T(2);
|
T s = std::sqrt(trace + T(1)) * T(2);
|
||||||
q.w = T(0.25) * s;
|
q.w = T(0.25) * s;
|
||||||
q.x = (m21 - m12) / s;
|
q.x = (m21 - m12) / s;
|
||||||
q.y = (m02 - m20) / s;
|
q.y = (m02 - m20) / s;
|
||||||
q.z = (m10 - m01) / s;
|
q.z = (m10 - m01) / s;
|
||||||
}
|
}
|
||||||
else if ((m00 > m11) && (m00 > m22)) {
|
else if ((m00 > m11) && (m00 > m22)) {
|
||||||
T s = std::sqrt(T(1) + m00 - m11 - m22) * T(2);
|
T s = std::sqrt(T(1) + m00 - m11 - m22) * T(2);
|
||||||
q.w = (m21 - m12) / s;
|
q.w = (m21 - m12) / s;
|
||||||
q.x = T(0.25) * s;
|
q.x = T(0.25) * s;
|
||||||
q.y = (m01 + m10) / s;
|
q.y = (m01 + m10) / s;
|
||||||
q.z = (m02 + m20) / s;
|
q.z = (m02 + m20) / s;
|
||||||
}
|
}
|
||||||
else if (m11 > m22) {
|
else if (m11 > m22) {
|
||||||
T s = std::sqrt(T(1) + m11 - m00 - m22) * T(2);
|
T s = std::sqrt(T(1) + m11 - m00 - m22) * T(2);
|
||||||
q.w = (m02 - m20) / s;
|
q.w = (m02 - m20) / s;
|
||||||
q.x = (m01 + m10) / s;
|
q.x = (m01 + m10) / s;
|
||||||
q.y = T(0.25) * s;
|
q.y = T(0.25) * s;
|
||||||
q.z = (m12 + m21) / s;
|
q.z = (m12 + m21) / s;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
T s = std::sqrt(T(1) + m22 - m00 - m11) * T(2);
|
T s = std::sqrt(T(1) + m22 - m00 - m11) * T(2);
|
||||||
q.w = (m10 - m01) / s;
|
q.w = (m10 - m01) / s;
|
||||||
q.x = (m02 + m20) / s;
|
q.x = (m02 + m20) / s;
|
||||||
q.y = (m12 + m21) / s;
|
q.y = (m12 + m21) / s;
|
||||||
q.z = T(0.25) * s;
|
q.z = T(0.25) * s;
|
||||||
}
|
}
|
||||||
|
|
||||||
q.Normalize();
|
q.Normalize();
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static Vector<T, 4, Aligment> QuanternionFromEuler(T rollHalf, T pitchHalf, T yawHalf) {
|
constexpr static Vector<T, 4, Aligment> QuanternionFromEuler(T rollHalf, T pitchHalf, T yawHalf) {
|
||||||
T cr = std::cos(rollHalf);
|
T cr = std::cos(rollHalf);
|
||||||
T sr = std::sin(rollHalf);
|
T sr = std::sin(rollHalf);
|
||||||
T cp = std::cos(pitchHalf);
|
T cp = std::cos(pitchHalf);
|
||||||
T sp = std::sin(pitchHalf);
|
T sp = std::sin(pitchHalf);
|
||||||
T cy = std::cos(yawHalf);
|
T cy = std::cos(yawHalf);
|
||||||
T sy = std::sin(yawHalf);
|
T sy = std::sin(yawHalf);
|
||||||
|
|
||||||
return Vector<T, 4, Aligment>(
|
return Vector<T, 4, Aligment>(
|
||||||
sr * cp * cy - cr * sp * sy,
|
sr * cp * cy - cr * sp * sy,
|
||||||
cr * sp * cy + sr * cp * sy,
|
cr * sp * cy + sr * cp * sy,
|
||||||
cr * cp * sy - sr * sp * cy,
|
cr * cp * sy - sr * sp * cy,
|
||||||
cr * cp * cy + sr * sp * sy
|
cr * cp * cy + sr * sp * sy
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T, std::uint32_t Len, std::uint32_t Aligment>
|
template <typename T, std::uint32_t Len, std::uint32_t Aligment>
|
||||||
struct std::formatter<Crafter::Vector<T, Len, Aligment>> : std::formatter<std::string> {
|
struct std::formatter<Crafter::Vector<T, Len, Aligment>> : std::formatter<std::string> {
|
||||||
auto format(const Crafter::Vector<T, Len, Aligment>& vec, format_context& ctx) const {
|
auto format(const Crafter::Vector<T, Len, Aligment>& vec, format_context& ctx) const {
|
||||||
std::string out = "{";
|
std::string out = "{";
|
||||||
for(std::uint32_t i2 = 0; i2 < Len; i2++) {
|
for(std::uint32_t i2 = 0; i2 < Len; i2++) {
|
||||||
#ifdef __x86_64
|
#ifdef __x86_64
|
||||||
if constexpr(std::same_as<T, _Float16>) {
|
if constexpr(std::same_as<T, _Float16>) {
|
||||||
out += std::format("{}", static_cast<float>(vec.v[i2]));
|
out += std::format("{}", static_cast<float>(vec.v[i2]));
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
out += std::format("{}", vec.v[i2]);
|
out += std::format("{}", vec.v[i2]);
|
||||||
}
|
}
|
||||||
if (i2 + 1 < Len) out += ",";
|
if (i2 + 1 < Len) out += ",";
|
||||||
}
|
}
|
||||||
out += "}";
|
out += "}";
|
||||||
return std::formatter<std::string>::format(out, ctx);
|
return std::formatter<std::string>::format(out, ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, std::uint32_t Len, std::uint32_t Aligment, typename BT>
|
template <typename T, std::uint32_t Len, std::uint32_t Aligment, typename BT>
|
||||||
constexpr Crafter::Vector<T, Len, Aligment> operator*(BT b, const Crafter::Vector<T, Len, Aligment>& v) requires std::is_arithmetic_v<BT> {
|
constexpr Crafter::Vector<T, Len, Aligment> operator*(BT b, const Crafter::Vector<T, Len, Aligment>& v) requires std::is_arithmetic_v<BT> {
|
||||||
return v * b;
|
return v * b;
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
10
project.cpp
10
project.cpp
|
|
@ -46,22 +46,12 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
|
||||||
{"rv64gcv", "generic"},
|
{"rv64gcv", "generic"},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// AArch64 has a single NEON register width (128-bit), so the tiers
|
|
||||||
// differ in VectorF16 only: ARMv8.2-FP16 gives it a native half-precision
|
|
||||||
// path, the baseline aliases it to VectorF32.
|
|
||||||
std::array<MarchTier, 2> armTiers = {{
|
|
||||||
{"armv8.2-a+fp16", "generic"},
|
|
||||||
{"armv8-a", "generic"},
|
|
||||||
}};
|
|
||||||
|
|
||||||
const std::string_view target = cfg.target;
|
const std::string_view target = cfg.target;
|
||||||
const bool isX86 = target.starts_with("x86_64") || target.starts_with("i686");
|
const bool isX86 = target.starts_with("x86_64") || target.starts_with("i686");
|
||||||
const bool isRiscv = target.starts_with("riscv");
|
const bool isRiscv = target.starts_with("riscv");
|
||||||
const bool isArm = target.starts_with("aarch64");
|
|
||||||
for (std::string_view name : { "Vector", "Intersection", "Matrix" }) {
|
for (std::string_view name : { "Vector", "Intersection", "Matrix" }) {
|
||||||
if (isX86) cfg.AddMarchVariants(name, mathInterfaces, x86Tiers);
|
if (isX86) cfg.AddMarchVariants(name, mathInterfaces, x86Tiers);
|
||||||
if (isRiscv) cfg.AddMarchVariants(name, mathInterfaces, riscvTiers);
|
if (isRiscv) cfg.AddMarchVariants(name, mathInterfaces, riscvTiers);
|
||||||
if (isArm) cfg.AddMarchVariants(name, mathInterfaces, armTiers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cfg;
|
return cfg;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue