189 lines
7.7 KiB
Zig
189 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.
|
||
|
// ------------------------------------------------------------------------------
|