|
3 | 3 | // SIMD math library for game developers
|
4 | 4 | // https://github.com/michal-z/zig-gamedev/tree/main/libs/zmath
|
5 | 5 | //
|
6 |
| -// See util.zig for additional functionality. |
7 |
| -// |
8 | 6 | // Should work on all OSes supported by Zig. Works on x86_64 and ARM.
|
9 | 7 | // Provides ~140 optimized routines and ~70 extensive tests.
|
10 | 8 | // Can be used with any graphics API.
|
|
264 | 262 | //
|
265 | 263 | // ==============================================================================
|
266 | 264 |
|
267 |
| -pub const util = @import("util.zig"); |
268 |
| - |
269 |
| -// ensure transitive closure of test coverage |
270 |
| -comptime { |
271 |
| - _ = util; |
272 |
| -} |
273 |
| - |
274 | 265 | // Fundamental types
|
275 | 266 | pub const F32x4 = @Vector(4, f32);
|
276 | 267 | pub const F32x8 = @Vector(8, f32);
|
@@ -4539,6 +4530,147 @@ pub fn approxEqAbs(v0: anytype, v1: anytype, eps: f32) bool {
|
4539 | 4530 | return true;
|
4540 | 4531 | }
|
4541 | 4532 |
|
| 4533 | +/// ============================================================================== |
| 4534 | +/// |
| 4535 | +/// Collection of useful functions building on top of, and extending, core zmath. |
| 4536 | +/// https://github.com/michal-z/zig-gamedev/tree/main/libs/zmath |
| 4537 | +/// |
| 4538 | +/// ------------------------------------------------------------------------------ |
| 4539 | +/// 1. Matrix functions |
| 4540 | +/// ------------------------------------------------------------------------------ |
| 4541 | +/// |
| 4542 | +/// As an example, in a left handed Y-up system: |
| 4543 | +/// getAxisX is equivalent to the right vector |
| 4544 | +/// getAxisY is equivalent to the up vector |
| 4545 | +/// getAxisZ is equivalent to the forward vector |
| 4546 | +/// |
| 4547 | +/// getTranslationVec(m: Mat) Vec |
| 4548 | +/// getAxisX(m: Mat) Vec |
| 4549 | +/// getAxisY(m: Mat) Vec |
| 4550 | +/// getAxisZ(m: Mat) Vec |
| 4551 | +/// |
| 4552 | +/// ============================================================================== |
| 4553 | +pub const util = struct { |
| 4554 | + pub fn getTranslationVec(m: Mat) Vec { |
| 4555 | + var _translation = m[3]; |
| 4556 | + _translation[3] = 0; |
| 4557 | + return _translation; |
| 4558 | + } |
| 4559 | + |
| 4560 | + pub fn set_TranslationVec(m: *Mat, _translation: Vec) void { |
| 4561 | + const w = m[3][3]; |
| 4562 | + m[3] = _translation; |
| 4563 | + m[3][3] = w; |
| 4564 | + } |
| 4565 | + |
| 4566 | + pub fn getScaleVec(m: Mat) Vec { |
| 4567 | + const scale_x = length3(f32x4(m[0][0], m[1][0], m[2][0], 0))[0]; |
| 4568 | + const scale_y = length3(f32x4(m[0][1], m[1][1], m[2][1], 0))[0]; |
| 4569 | + const scale_z = length3(f32x4(m[0][2], m[1][2], m[2][2], 0))[0]; |
| 4570 | + return f32x4(scale_x, scale_y, scale_z, 0); |
| 4571 | + } |
| 4572 | + |
| 4573 | + pub fn getRotationQuat(_m: Mat) Quat { |
| 4574 | + // Ortho normalize given matrix. |
| 4575 | + const c1 = normalize3(f32x4(_m[0][0], _m[1][0], _m[2][0], 0)); |
| 4576 | + const c2 = normalize3(f32x4(_m[0][1], _m[1][1], _m[2][1], 0)); |
| 4577 | + const c3 = normalize3(f32x4(_m[0][2], _m[1][2], _m[2][2], 0)); |
| 4578 | + var m = _m; |
| 4579 | + m[0][0] = c1[0]; |
| 4580 | + m[1][0] = c1[1]; |
| 4581 | + m[2][0] = c1[2]; |
| 4582 | + m[0][1] = c2[0]; |
| 4583 | + m[1][1] = c2[1]; |
| 4584 | + m[2][1] = c2[2]; |
| 4585 | + m[0][2] = c3[0]; |
| 4586 | + m[1][2] = c3[1]; |
| 4587 | + m[2][2] = c3[2]; |
| 4588 | + |
| 4589 | + // Extract rotation |
| 4590 | + return quatFromMat(m); |
| 4591 | + } |
| 4592 | + |
| 4593 | + pub fn getAxisX(m: Mat) Vec { |
| 4594 | + return normalize3(f32x4(m[0][0], m[0][1], m[0][2], 0.0)); |
| 4595 | + } |
| 4596 | + |
| 4597 | + pub fn getAxisY(m: Mat) Vec { |
| 4598 | + return normalize3(f32x4(m[1][0], m[1][1], m[1][2], 0.0)); |
| 4599 | + } |
| 4600 | + |
| 4601 | + pub fn getAxisZ(m: Mat) Vec { |
| 4602 | + return normalize3(f32x4(m[2][0], m[2][1], m[2][2], 0.0)); |
| 4603 | + } |
| 4604 | + |
| 4605 | + test "zmath.util.mat.translation" { |
| 4606 | + // zig fmt: off |
| 4607 | + const mat_data = [18]f32{ |
| 4608 | + 1.0, |
| 4609 | + 2.0, 3.0, 4.0, 5.0, |
| 4610 | + 6.0, 7.0, 8.0, 9.0, |
| 4611 | + 10.0,11.0, 12.0,13.0, |
| 4612 | + 14.0, 15.0, 16.0, 17.0, |
| 4613 | + 18.0, |
| 4614 | + }; |
| 4615 | + // zig fmt: on |
| 4616 | + const mat = loadMat(mat_data[1..]); |
| 4617 | + try expectVecApproxEqAbs(getTranslationVec(mat), f32x4(14.0, 15.0, 16.0, 0.0), 0.0001); |
| 4618 | + } |
| 4619 | + |
| 4620 | + test "zmath.util.mat.scale" { |
| 4621 | + const mat = mul(scaling(3, 4, 5), translation(6, 7, 8)); |
| 4622 | + const scale = getScaleVec(mat); |
| 4623 | + try expectVecApproxEqAbs(scale, f32x4(3.0, 4.0, 5.0, 0.0), 0.0001); |
| 4624 | + } |
| 4625 | + |
| 4626 | + test "zmath.util.mat.rotation" { |
| 4627 | + const rotate_origin = matFromRollPitchYaw(0.1, 1.2, 2.3); |
| 4628 | + const mat = mul(mul(rotate_origin, scaling(3, 4, 5)), translation(6, 7, 8)); |
| 4629 | + const rotate_get = getRotationQuat(mat); |
| 4630 | + const v0 = mul(f32x4s(1), rotate_origin); |
| 4631 | + const v1 = mul(f32x4s(1), quatToMat(rotate_get)); |
| 4632 | + try expectVecApproxEqAbs(v0, v1, 0.0001); |
| 4633 | + } |
| 4634 | + |
| 4635 | + test "zmath.util.mat.z_vec" { |
| 4636 | + const degToRad = std.math.degreesToRadians; |
| 4637 | + var z_vec = getAxisZ(identity()); |
| 4638 | + try expectVecApproxEqAbs(z_vec, f32x4(0.0, 0.0, 1.0, 0), 0.0001); |
| 4639 | + const rot_yaw = rotationY(degToRad(90)); |
| 4640 | + identity = mul(identity(), rot_yaw); |
| 4641 | + z_vec = getAxisZ(identity()); |
| 4642 | + try expectVecApproxEqAbs(z_vec, f32x4(1.0, 0.0, 0.0, 0), 0.0001); |
| 4643 | + } |
| 4644 | + |
| 4645 | + test "zmath.util.mat.y_vec" { |
| 4646 | + const degToRad = std.math.degreesToRadians; |
| 4647 | + var y_vec = getAxisY(identity()); |
| 4648 | + try expectVecApproxEqAbs(y_vec, f32x4(0.0, 1.0, 0.0, 0), 0.01); |
| 4649 | + const rot_yaw = rotationY(degToRad(90)); |
| 4650 | + identity = mul(identity(), rot_yaw); |
| 4651 | + y_vec = getAxisY(identity()); |
| 4652 | + try expectVecApproxEqAbs(y_vec, f32x4(0.0, 1.0, 0.0, 0), 0.01); |
| 4653 | + const rot_pitch = rotationX(degToRad(90)); |
| 4654 | + identity = mul(identity(), rot_pitch); |
| 4655 | + y_vec = getAxisY(identity()); |
| 4656 | + try expectVecApproxEqAbs(y_vec, f32x4(0.0, 0.0, 1.0, 0), 0.01); |
| 4657 | + } |
| 4658 | + |
| 4659 | + test "zmath.util.mat.right" { |
| 4660 | + const degToRad = std.math.degreesToRadians; |
| 4661 | + var right = getAxisX(identity()); |
| 4662 | + try expectVecApproxEqAbs(right, f32x4(1.0, 0.0, 0.0, 0), 0.01); |
| 4663 | + const rot_yaw = rotationY(degToRad(90)); |
| 4664 | + identity = mul(identity, rot_yaw); |
| 4665 | + right = getAxisX(identity()); |
| 4666 | + try expectVecApproxEqAbs(right, f32x4(0.0, 0.0, -1.0, 0), 0.01); |
| 4667 | + const rot_pitch = rotationX(degToRad(90)); |
| 4668 | + identity = mul(identity(), rot_pitch); |
| 4669 | + right = getAxisX(identity()); |
| 4670 | + try expectVecApproxEqAbs(right, f32x4(0.0, 1.0, 0.0, 0), 0.01); |
| 4671 | + } |
| 4672 | +}; // util |
| 4673 | + |
4542 | 4674 | // ------------------------------------------------------------------------------
|
4543 | 4675 | // This software is available under 2 licenses -- choose whichever you prefer.
|
4544 | 4676 | // ------------------------------------------------------------------------------
|
|
0 commit comments