vulkan-zig/libs/zmath/src/util.zig
2024-07-22 00:27:24 +02:00

188 lines
7.7 KiB
Zig

// ==============================================================================
//
// Collection of useful functions building on top of, and extending, core zmath.
// https://github.com/michal-z/zig-gamedev/tree/main/libs/zmath
//
// ------------------------------------------------------------------------------
// 1. Matrix functions
// ------------------------------------------------------------------------------
//
// As an example, in a left handed Y-up system:
// getAxisX is equivalent to the right vector
// getAxisY is equivalent to the up vector
// getAxisZ is equivalent to the forward vector
//
// getTranslationVec(m: Mat) Vec
// getAxisX(m: Mat) Vec
// getAxisY(m: Mat) Vec
// getAxisZ(m: Mat) Vec
//
// ==============================================================================
const zm = @import("zmath.zig");
const std = @import("std");
const math = std.math;
const expect = std.testing.expect;
pub fn getTranslationVec(m: zm.Mat) zm.Vec {
var translation = m[3];
translation[3] = 0;
return translation;
}
pub fn setTranslationVec(m: *zm.Mat, translation: zm.Vec) void {
const w = m[3][3];
m[3] = translation;
m[3][3] = w;
}
pub fn getScaleVec(m: zm.Mat) zm.Vec {
const scale_x = zm.length3(zm.f32x4(m[0][0], m[1][0], m[2][0], 0))[0];
const scale_y = zm.length3(zm.f32x4(m[0][1], m[1][1], m[2][1], 0))[0];
const scale_z = zm.length3(zm.f32x4(m[0][2], m[1][2], m[2][2], 0))[0];
return zm.f32x4(scale_x, scale_y, scale_z, 0);
}
pub fn getRotationQuat(_m: zm.Mat) zm.Quat {
// Ortho normalize given matrix.
const c1 = zm.normalize3(zm.f32x4(_m[0][0], _m[1][0], _m[2][0], 0));
const c2 = zm.normalize3(zm.f32x4(_m[0][1], _m[1][1], _m[2][1], 0));
const c3 = zm.normalize3(zm.f32x4(_m[0][2], _m[1][2], _m[2][2], 0));
var m = _m;
m[0][0] = c1[0];
m[1][0] = c1[1];
m[2][0] = c1[2];
m[0][1] = c2[0];
m[1][1] = c2[1];
m[2][1] = c2[2];
m[0][2] = c3[0];
m[1][2] = c3[1];
m[2][2] = c3[2];
// Extract rotation
return zm.quatFromMat(m);
}
pub fn getAxisX(m: zm.Mat) zm.Vec {
return zm.normalize3(zm.f32x4(m[0][0], m[0][1], m[0][2], 0.0));
}
pub fn getAxisY(m: zm.Mat) zm.Vec {
return zm.normalize3(zm.f32x4(m[1][0], m[1][1], m[1][2], 0.0));
}
pub fn getAxisZ(m: zm.Mat) zm.Vec {
return zm.normalize3(zm.f32x4(m[2][0], m[2][1], m[2][2], 0.0));
}
test "zmath.util.mat.translation" {
// zig fmt: off
const mat_data = [18]f32{
1.0,
2.0, 3.0, 4.0, 5.0,
6.0, 7.0, 8.0, 9.0,
10.0,11.0, 12.0,13.0,
14.0, 15.0, 16.0, 17.0,
18.0,
};
// zig fmt: on
const mat = zm.loadMat(mat_data[1..]);
const translation = getTranslationVec(mat);
try zm.expectVecApproxEqAbs(translation, zm.f32x4(14.0, 15.0, 16.0, 0.0), 0.0001);
}
test "zmath.util.mat.scale" {
const mat = zm.mul(zm.scaling(3, 4, 5), zm.translation(6, 7, 8));
const scale = getScaleVec(mat);
try zm.expectVecApproxEqAbs(scale, zm.f32x4(3.0, 4.0, 5.0, 0.0), 0.0001);
}
test "zmath.util.mat.rotation" {
const rotate_origin = zm.matFromRollPitchYaw(0.1, 1.2, 2.3);
const mat = zm.mul(zm.mul(rotate_origin, zm.scaling(3, 4, 5)), zm.translation(6, 7, 8));
const rotate_get = getRotationQuat(mat);
const v0 = zm.mul(zm.f32x4s(1), rotate_origin);
const v1 = zm.mul(zm.f32x4s(1), zm.quatToMat(rotate_get));
try zm.expectVecApproxEqAbs(v0, v1, 0.0001);
}
test "zmath.util.mat.z_vec" {
const degToRad = std.math.degreesToRadians;
var identity = zm.identity();
var z_vec = getAxisZ(identity);
try zm.expectVecApproxEqAbs(z_vec, zm.f32x4(0.0, 0.0, 1.0, 0), 0.0001);
const rot_yaw = zm.rotationY(degToRad(90));
identity = zm.mul(identity, rot_yaw);
z_vec = getAxisZ(identity);
try zm.expectVecApproxEqAbs(z_vec, zm.f32x4(1.0, 0.0, 0.0, 0), 0.0001);
}
test "zmath.util.mat.y_vec" {
const degToRad = std.math.degreesToRadians;
var identity = zm.identity();
var y_vec = getAxisY(identity);
try zm.expectVecApproxEqAbs(y_vec, zm.f32x4(0.0, 1.0, 0.0, 0), 0.01);
const rot_yaw = zm.rotationY(degToRad(90));
identity = zm.mul(identity, rot_yaw);
y_vec = getAxisY(identity);
try zm.expectVecApproxEqAbs(y_vec, zm.f32x4(0.0, 1.0, 0.0, 0), 0.01);
const rot_pitch = zm.rotationX(degToRad(90));
identity = zm.mul(identity, rot_pitch);
y_vec = getAxisY(identity);
try zm.expectVecApproxEqAbs(y_vec, zm.f32x4(0.0, 0.0, 1.0, 0), 0.01);
}
test "zmath.util.mat.right" {
const degToRad = std.math.degreesToRadians;
var identity = zm.identity();
var right = getAxisX(identity);
try zm.expectVecApproxEqAbs(right, zm.f32x4(1.0, 0.0, 0.0, 0), 0.01);
const rot_yaw = zm.rotationY(degToRad(90));
identity = zm.mul(identity, rot_yaw);
right = getAxisX(identity);
try zm.expectVecApproxEqAbs(right, zm.f32x4(0.0, 0.0, -1.0, 0), 0.01);
const rot_pitch = zm.rotationX(degToRad(90));
identity = zm.mul(identity, rot_pitch);
right = getAxisX(identity);
try zm.expectVecApproxEqAbs(right, zm.f32x4(0.0, 1.0, 0.0, 0), 0.01);
}
// ------------------------------------------------------------------------------
// This software is available under 2 licenses -- choose whichever you prefer.
// ------------------------------------------------------------------------------
// ALTERNATIVE A - MIT License
// Copyright (c) 2022 Michal Ziulek and Contributors
// Permission is hereby granted, free of charge, to any person obtaining identity 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.
// ------------------------------------------------------------------------------
// ALTERNATIVE B - Public Domain (www.unlicense.org)
// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
// software, either in source code form or as identity compiled binary, for any purpose,
// commercial or non-commercial, and by any means.
// In jurisdictions that recognize copyright laws, the author or authors of this
// software dedicate any and all copyright interest in the software to the public
// domain. We make this dedication for the benefit of the public at large and to
// the detriment of our heirs and successors. We intend this dedication to be an
// overt act of relinquishment in perpetuity of all present and future rights to
// this software under copyright law.
// 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 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.
// ------------------------------------------------------------------------------