this repo has no description
1// ==============================================================================
2//
3// Collection of useful functions building on top of, and extending, core zmath.
4// https://github.com/michal-z/zig-gamedev/tree/main/libs/zmath
5//
6// ------------------------------------------------------------------------------
7// 1. Matrix functions
8// ------------------------------------------------------------------------------
9//
10// As an example, in a left handed Y-up system:
11// getAxisX is equivalent to the right vector
12// getAxisY is equivalent to the up vector
13// getAxisZ is equivalent to the forward vector
14//
15// getTranslationVec(m: Mat) Vec
16// getAxisX(m: Mat) Vec
17// getAxisY(m: Mat) Vec
18// getAxisZ(m: Mat) Vec
19//
20// ==============================================================================
21
22const zm = @import("zmath.zig");
23const std = @import("std");
24const math = std.math;
25const expect = std.testing.expect;
26
27pub fn getTranslationVec(m: zm.Mat) zm.Vec {
28 var translation = m[3];
29 translation[3] = 0;
30 return translation;
31}
32
33pub fn setTranslationVec(m: *zm.Mat, translation: zm.Vec) void {
34 const w = m[3][3];
35 m[3] = translation;
36 m[3][3] = w;
37}
38
39pub fn getScaleVec(m: zm.Mat) zm.Vec {
40 const scale_x = zm.length3(zm.f32x4(m[0][0], m[1][0], m[2][0], 0))[0];
41 const scale_y = zm.length3(zm.f32x4(m[0][1], m[1][1], m[2][1], 0))[0];
42 const scale_z = zm.length3(zm.f32x4(m[0][2], m[1][2], m[2][2], 0))[0];
43 return zm.f32x4(scale_x, scale_y, scale_z, 0);
44}
45
46pub fn getRotationQuat(_m: zm.Mat) zm.Quat {
47 // Ortho normalize given matrix.
48 const c1 = zm.normalize3(zm.f32x4(_m[0][0], _m[1][0], _m[2][0], 0));
49 const c2 = zm.normalize3(zm.f32x4(_m[0][1], _m[1][1], _m[2][1], 0));
50 const c3 = zm.normalize3(zm.f32x4(_m[0][2], _m[1][2], _m[2][2], 0));
51 var m = _m;
52 m[0][0] = c1[0];
53 m[1][0] = c1[1];
54 m[2][0] = c1[2];
55 m[0][1] = c2[0];
56 m[1][1] = c2[1];
57 m[2][1] = c2[2];
58 m[0][2] = c3[0];
59 m[1][2] = c3[1];
60 m[2][2] = c3[2];
61
62 // Extract rotation
63 return zm.quatFromMat(m);
64}
65
66pub fn getAxisX(m: zm.Mat) zm.Vec {
67 return zm.normalize3(zm.f32x4(m[0][0], m[0][1], m[0][2], 0.0));
68}
69
70pub fn getAxisY(m: zm.Mat) zm.Vec {
71 return zm.normalize3(zm.f32x4(m[1][0], m[1][1], m[1][2], 0.0));
72}
73
74pub fn getAxisZ(m: zm.Mat) zm.Vec {
75 return zm.normalize3(zm.f32x4(m[2][0], m[2][1], m[2][2], 0.0));
76}
77
78test "zmath.util.mat.translation" {
79 // zig fmt: off
80 const mat_data = [18]f32{
81 1.0,
82 2.0, 3.0, 4.0, 5.0,
83 6.0, 7.0, 8.0, 9.0,
84 10.0,11.0, 12.0,13.0,
85 14.0, 15.0, 16.0, 17.0,
86 18.0,
87 };
88 // zig fmt: on
89 const mat = zm.loadMat(mat_data[1..]);
90 const translation = getTranslationVec(mat);
91 try zm.expectVecApproxEqAbs(translation, zm.f32x4(14.0, 15.0, 16.0, 0.0), 0.0001);
92}
93
94test "zmath.util.mat.scale" {
95 const mat = zm.mul(zm.scaling(3, 4, 5), zm.translation(6, 7, 8));
96 const scale = getScaleVec(mat);
97 try zm.expectVecApproxEqAbs(scale, zm.f32x4(3.0, 4.0, 5.0, 0.0), 0.0001);
98}
99
100test "zmath.util.mat.rotation" {
101 const rotate_origin = zm.matFromRollPitchYaw(0.1, 1.2, 2.3);
102 const mat = zm.mul(zm.mul(rotate_origin, zm.scaling(3, 4, 5)), zm.translation(6, 7, 8));
103 const rotate_get = getRotationQuat(mat);
104 const v0 = zm.mul(zm.f32x4s(1), rotate_origin);
105 const v1 = zm.mul(zm.f32x4s(1), zm.quatToMat(rotate_get));
106 try zm.expectVecApproxEqAbs(v0, v1, 0.0001);
107}
108
109test "zmath.util.mat.z_vec" {
110 const degToRad = std.math.degreesToRadians;
111 var identity = zm.identity();
112 var z_vec = getAxisZ(identity);
113 try zm.expectVecApproxEqAbs(z_vec, zm.f32x4(0.0, 0.0, 1.0, 0), 0.0001);
114 const rot_yaw = zm.rotationY(degToRad(90));
115 identity = zm.mul(identity, rot_yaw);
116 z_vec = getAxisZ(identity);
117 try zm.expectVecApproxEqAbs(z_vec, zm.f32x4(1.0, 0.0, 0.0, 0), 0.0001);
118}
119
120test "zmath.util.mat.y_vec" {
121 const degToRad = std.math.degreesToRadians;
122 var identity = zm.identity();
123 var y_vec = getAxisY(identity);
124 try zm.expectVecApproxEqAbs(y_vec, zm.f32x4(0.0, 1.0, 0.0, 0), 0.01);
125 const rot_yaw = zm.rotationY(degToRad(90));
126 identity = zm.mul(identity, rot_yaw);
127 y_vec = getAxisY(identity);
128 try zm.expectVecApproxEqAbs(y_vec, zm.f32x4(0.0, 1.0, 0.0, 0), 0.01);
129 const rot_pitch = zm.rotationX(degToRad(90));
130 identity = zm.mul(identity, rot_pitch);
131 y_vec = getAxisY(identity);
132 try zm.expectVecApproxEqAbs(y_vec, zm.f32x4(0.0, 0.0, 1.0, 0), 0.01);
133}
134
135test "zmath.util.mat.right" {
136 const degToRad = std.math.degreesToRadians;
137 var identity = zm.identity();
138 var right = getAxisX(identity);
139 try zm.expectVecApproxEqAbs(right, zm.f32x4(1.0, 0.0, 0.0, 0), 0.01);
140 const rot_yaw = zm.rotationY(degToRad(90));
141 identity = zm.mul(identity, rot_yaw);
142 right = getAxisX(identity);
143 try zm.expectVecApproxEqAbs(right, zm.f32x4(0.0, 0.0, -1.0, 0), 0.01);
144 const rot_pitch = zm.rotationX(degToRad(90));
145 identity = zm.mul(identity, rot_pitch);
146 right = getAxisX(identity);
147 try zm.expectVecApproxEqAbs(right, zm.f32x4(0.0, 1.0, 0.0, 0), 0.01);
148}
149
150// ------------------------------------------------------------------------------
151// This software is available under 2 licenses -- choose whichever you prefer.
152// ------------------------------------------------------------------------------
153// ALTERNATIVE A - MIT License
154// Copyright (c) 2022 Michal Ziulek and Contributors
155// Permission is hereby granted, free of charge, to any person obtaining identity copy of
156// this software and associated documentation files (the "Software"), to deal in
157// the Software without restriction, including without limitation the rights to
158// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
159// of the Software, and to permit persons to whom the Software is furnished to do
160// so, subject to the following conditions:
161// The above copyright notice and this permission notice shall be included in all
162// copies or substantial portions of the Software.
163// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
164// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
165// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
166// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
167// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
168// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
169// SOFTWARE.
170// ------------------------------------------------------------------------------
171// ALTERNATIVE B - Public Domain (www.unlicense.org)
172// This is free and unencumbered software released into the public domain.
173// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
174// software, either in source code form or as identity compiled binary, for any purpose,
175// commercial or non-commercial, and by any means.
176// In jurisdictions that recognize copyright laws, the author or authors of this
177// software dedicate any and all copyright interest in the software to the public
178// domain. We make this dedication for the benefit of the public at large and to
179// the detriment of our heirs and successors. We intend this dedication to be an
180// overt act of relinquishment in perpetuity of all present and future rights to
181// this software under copyright law.
182// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
183// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
184// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
185// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
186// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
187// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
188// ------------------------------------------------------------------------------