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