Crafter.Math/project.cpp
Jorijn van der Graaf 087c8b32c3
feat: quaternion operations, and transforms that mean the same in 4x4 and 4x3
- A 4-vector doubles as a unit quaternion in (x, y, z, w) order:
  QuanternionMultiply, QuanternionConjugate, QuanternionFromAxisAngle,
  QuanternionFromUnitVectors (shortest arc), QuanternionNlerp and
  QuanternionSlerp, next to the existing QuanternionFromBasis.
- MatrixRowMajor gains Rotation (from a quaternion), TRS, InverseAffine,
  Transpose and Decompose. The 4x4 transforms row vectors and the 4x3
  column vectors (the VkTransformMatrixKHR layout); each of these means the
  same transform in both. The 4x3 Rotation copied the 4x4's rows, which
  rotated by the inverse.
- The static Normalize no longer assumes three components.
- Tests: Quaternion, and Matrix extended.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 19:07:06 +02:00

68 lines
2.6 KiB
C++

//SPDX-License-Identifier: LGPL-3.0-only
//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
import std;
import Crafter.Build;
namespace fs = std::filesystem;
using namespace Crafter;
extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> args) {
std::array<fs::path, 8> mathInterfaces = {
"interfaces/Crafter.Math-Basic",
"interfaces/Crafter.Math",
"interfaces/Crafter.Math-Common",
"interfaces/Crafter.Math-Vector",
"interfaces/Crafter.Math-Intersection",
"interfaces/Crafter.Math-MatrixRowMajor",
"interfaces/Crafter.Math-VectorF16",
"interfaces/Crafter.Math-VectorF32",
};
Configuration cfg;
cfg.path = "./";
cfg.name = "Crafter.Math";
cfg.outputName = "Crafter.Math";
cfg.type = ConfigurationType::LibraryStatic;
ApplyStandardArgs(cfg, args);
{
std::array<fs::path, 0> impls = {};
cfg.GetInterfacesAndImplementations(mathInterfaces, impls);
}
// SIMD tier matrix: each tier rebuilds the math interfaces with its own
// -march so codegen actually varies. Per-arch gating is just an `if`
// around the AddMarchVariants call.
std::array<MarchTier, 3> x86Tiers = {{
{"sapphirerapids", "native"},
{"x86-64-v4", "generic"},
{"x86-64-v3", "generic"},
}};
// RISC-V tiers mirror the x86 selector: register width is picked from
// the guaranteed VLEN encoded in the march's Zvl* suffix. rv64gcv →
// ZVL128B (matches the RVA23 baseline).
std::array<MarchTier, 3> riscvTiers = {{
{"rv64gcv_zvl512b", "generic"},
{"rv64gcv_zvl256b", "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 bool isX86 = target.starts_with("x86_64") || target.starts_with("i686");
const bool isRiscv = target.starts_with("riscv");
const bool isArm = target.starts_with("aarch64");
for (std::string_view name : { "Vector", "Intersection", "Matrix", "Quaternion" }) {
if (isX86) cfg.AddMarchVariants(name, mathInterfaces, x86Tiers);
if (isRiscv) cfg.AddMarchVariants(name, mathInterfaces, riscvTiers);
if (isArm) cfg.AddMarchVariants(name, mathInterfaces, armTiers);
}
return cfg;
}