diff --git a/src/lol/math/transform.h b/src/lol/math/transform.h index 2d2fd32b..bf951f63 100644 --- a/src/lol/math/transform.h +++ b/src/lol/math/transform.h @@ -197,6 +197,7 @@ struct quat_t : public linear_ops::base return quat_t(w, -x, -y, -z); } + /* Transform vectors or points */ inline vec_t transform(vec_t const &v) const { quat_t p = quat_t(0, v.x, v.y, v.z); @@ -268,11 +269,21 @@ struct sqt_t : q(other.q), t(other.t), s(other.s) {} /* Various explicit constructors */ - inline constexpr sqt_t(T const &s_, - quat_t const &q_, - vec_t const &t_) - : s(s_), q(q_), t(t_) {} + explicit inline constexpr sqt_t(T const &s_, + quat_t const &q_, + vec_t const &t_) + : q(q_), t(t_), s(s_) {} + explicit inline constexpr sqt_t(T const &s_) + : q(1.f), t(0.f), s(s_) {} + + explicit inline constexpr sqt_t(quat_t const &q_) + : q(q_), t(0.f), s(1.f) {} + + explicit inline constexpr sqt_t(vec_t const &t_) + : q(1.f), t(t_), s(1.f) {} + + /* Transform vectors or points */ inline vec_t transform(vec_t const &v) const { return t + q.transform(s * v); @@ -280,7 +291,7 @@ struct sqt_t inline vec_t transform(vec_t const &v) const { - // XXX: needs serious testing + // XXX: needs serious testing for w != 1 vec_t tmp = q.transform(vec_t(s * v.xyz, v.w)); return vec_t(tmp.xyz, 0.f) + vec_t(t, 1.f) * tmp.w; } @@ -295,6 +306,14 @@ struct sqt_t return transform(v); } + /* Compose two SQTs together */ + inline sqt_t operator *(sqt_t const &other) const + { + return sqt_t(s * other.s, + q * other.q, + transform(other.t)); + } + quat_t q; vec_t t; T s; diff --git a/src/t/math/sqt.cpp b/src/t/math/sqt.cpp new file mode 100644 index 00000000..5bdff20c --- /dev/null +++ b/src/t/math/sqt.cpp @@ -0,0 +1,94 @@ +// +// Lol Engine — Unit tests for the SQT transform class +// +// Copyright © 2010—2015 Sam Hocevar +// +// Lol Engine is free software. It comes without any warranty, to +// the extent permitted by applicable law. You can redistribute it +// and/or modify it under the terms of the Do What the Fuck You Want +// to Public License, Version 2, as published by the WTFPL Task Force. +// See http://www.wtfpl.net/ for more details. +// + +#include + +#include + +namespace lol +{ + +static sqt const test_sqt_1(1.5f, + quat::rotate(radians(20.f), + normalize(vec3(1.f, 2.f, 3.f))), + vec3(1.f, -1.f, 0.5f)); + +static vec4 test_vec4s[] = +{ + vec4(1.f, 0.f, 0.f, 1.f), + vec4(0.f, 1.f, 0.f, 1.f), + vec4(0.f, 0.f, 1.f, 1.f), + vec4(1.f, 2.f, 3.f, 1.f), + vec4(-1.f, 50.f, 12.f, 1.f), + vec4(20.f, -10.f, 0.f, 1.f), + vec4(-20.f, 10.f, 8.f, 1.f), +}; + +lolunit_declare_fixture(sqt_test) +{ + lolunit_declare_test(transform_vec3_vec4) + { + /* We check that transforming a vec3 and a vec4 with w==1 + * yield the same results. */ + for (vec4 v0 : test_vec4s) + { + vec4 v1 = test_sqt_1.transform(v0); + vec3 v2 = test_sqt_1.transform(v0.xyz); + + lolunit_assert_doubles_equal(v1.x, v2.x, 1e-5f); + lolunit_assert_doubles_equal(v1.y, v2.y, 1e-5f); + lolunit_assert_doubles_equal(v1.z, v2.z, 1e-5f); + lolunit_assert_doubles_equal(v1.w, 1.0f, 1e-5f); + } + } + + lolunit_declare_test(sqt_vs_matrix_vec4) + { + /* We check that transforming a vec4 with an SQT and a + * vec4 with a product of 4×4 matrices yield the same + * results. */ + mat4 m = mat4::translate(test_sqt_1.t) + * mat4(test_sqt_1.q) + * mat4::scale(test_sqt_1.s); + + for (vec4 v0 : test_vec4s) + { + vec4 v1 = test_sqt_1 * v0; + vec4 v2 = m * v0; + + lolunit_assert_doubles_equal(v1.x, v2.x, 1e-5f); + lolunit_assert_doubles_equal(v1.y, v2.y, 1e-5f); + lolunit_assert_doubles_equal(v1.z, v2.z, 1e-5f); + lolunit_assert_doubles_equal(v1.w, v2.w, 1e-5f); + } + } + + lolunit_declare_test(sqt_composition_vec4) + { + /* We check that transforming a vec4 with an SQT and a + * second SQT yields the same result as transforming a + * vec4 with the product of the two SQTs. */ + for (vec4 v0 : test_vec4s) + { + vec4 v1 = (test_sqt_1 * test_sqt_1) * v0; + vec4 v2 = test_sqt_1 * (test_sqt_1 * v0); + + lolunit_assert_doubles_equal(v1.x, v2.x, 1e-5f); + lolunit_assert_doubles_equal(v1.y, v2.y, 1e-5f); + lolunit_assert_doubles_equal(v1.z, v2.z, 1e-5f); + lolunit_assert_doubles_equal(v1.w, v2.w, 1e-5f); + } + } +}; + +} /* namespace lol */ +