13#define TRANSFORM_INLINE
14#elif defined(__GNUC__) || defined(__clang__)
15#define TRANSFORM_INLINE
17#define TRANSFORM_INLINE
25template<
typename T, precision Q = defaultp>
36 using col_t =
typename mat4_t::col_type;
345 void rotate(const
quat_t& q) noexcept;
353 void rotate(T
x, T
y, T
z) noexcept;
359 void rotate(const
vec3_t& v) noexcept;
381 void scale(T
x, T
y, T
z = T(1)) noexcept;
395 void translate(T
x, T
y, T
z = T(0)) noexcept;
401 void translate(const
vec3_t& v) noexcept;
578 operator const T*() const noexcept;
592 auto operator==(const
transform_t& t) const noexcept ->
bool;
599 auto operator!=(const
transform_t& t) const noexcept ->
bool;
613 auto operator*(const
vec4_t& v) const noexcept ->
vec4_t;
629 void update_components() const noexcept;
638 void update_matrix() const noexcept;
647 void make_matrix_dirty() noexcept;
648 void make_components_dirty() noexcept;
651 auto is_skew_zero() const noexcept ->
bool;
652 auto is_perspective_identity() const noexcept ->
bool;
653 auto is_scale_uniform() const noexcept ->
bool;
655 auto can_use_simplified_calculations() const noexcept ->
bool;
656 auto can_use_simplified_calculations_without_uniform_scale() const noexcept ->
bool;
712 mutable
bool matrix_needs_recompute_ = false;
721 mutable
bool components_need_recompute_ = false;
723 mutable
bool is_skew_zero_cached_ = true;
724 mutable
bool is_perspective_identity_cached_ = true;
725 mutable
bool is_scale_uniform_cached_ = true;
728template<typename T, precision Q>
731 const auto& m = t.get_matrix();
732 return glm::inverse(m);
735template<
typename T, precision Q>
738 const auto& m = t.get_matrix();
739 return glm::transpose(m);
742template<
typename T, precision Q>
745 , is_skew_zero_cached_(
false)
746 , is_perspective_identity_cached_(
false)
747 , is_scale_uniform_cached_(
false)
749 make_components_dirty();
752template<
typename T, precision Q>
759template<
typename T, precision Q>
765template<
typename T, precision Q>
771template<
typename T, precision Q>
777template<
typename T, precision Q>
783template<
typename T, precision Q>
787 position_ = position;
791template<
typename T, precision Q>
797template<
typename T, precision Q>
803template<
typename T, precision Q>
809template<
typename T, precision Q>
817template<
typename T, precision Q>
823 static auto repeat_working = [](
float t,
float length)
825 return (t - (floor(t / length) * length));
828 angles.x = repeat_working(angles.x - hint.x + T(180), T(360)) + hint.x - T(180);
829 angles.y = repeat_working(angles.y - hint.y + T(180), T(360)) + hint.y - T(180);
830 angles.z = repeat_working(angles.z - hint.z + T(180), T(360)) + hint.z - T(180);
835template<
typename T, precision Q>
841template<
typename T, precision Q>
847template<
typename T, precision Q>
853template<
typename T, precision Q>
859template<
typename T, precision Q>
866template<
typename T, precision Q>
871 is_scale_uniform_cached_ = is_scale_uniform();
876template<
typename T, precision Q>
882template<
typename T, precision Q>
888template<
typename T, precision Q>
894 is_skew_zero_cached_ = is_skew_zero();
898template<
typename T, precision Q>
904template<
typename T, precision Q>
910template<
typename T, precision Q>
914 perspective_ = perspective;
915 is_perspective_identity_cached_ = is_perspective_identity();
920template<
typename T, precision Q>
926template<
typename T, precision Q>
932template<
typename T, precision Q>
939template<
typename T, precision Q>
946template<
typename T, precision Q>
953template<
typename T, precision Q>
957 rotation_ = glm::normalize(
rotation);
961template<
typename T, precision Q>
968template<
typename T, precision Q>
974template<
typename T, precision Q>
977 if(can_use_simplified_calculations_without_uniform_scale())
986template<
typename T, precision Q>
989 if(can_use_simplified_calculations_without_uniform_scale())
998template<
typename T, precision Q>
1001 if(can_use_simplified_calculations_without_uniform_scale())
1010template<
typename T, precision Q>
1013 return normalize(
x_axis());
1016template<
typename T, precision Q>
1019 return normalize(
y_axis());
1022template<
typename T, precision Q>
1025 return normalize(
z_axis());
1028template<
typename T, precision Q>
1035template<
typename T, precision Q>
1042template<
typename T, precision Q>
1048template<
typename T, precision Q>
1052 quat_t delta_rotation(v);
1056template<
typename T, precision Q>
1062template<
typename T, precision Q>
1066 quat_t delta_rotation(v);
1070template<
typename T, precision Q>
1076template<
typename T, precision Q>
1082template<
typename T, precision Q>
1088template<
typename T, precision Q>
1094template<
typename T, precision Q>
1100template<
typename T, precision Q>
1108template<
typename T, precision Q>
1111 return compare(rhs, epsilon<T>());
1114template<
typename T, precision Q>
1153 const auto& m2 = rhs.get_matrix();
1156 for(
int i = 0; i < 4; ++i)
1158 vec4_t diff = m1[i] - m2[i];
1164 if(!glm::epsilonEqual(m1[i].w, m2[i].w, T(0.001)))
1170 if(!glm::all(glm::epsilonEqual(diff, glm::zero<vec4_t>(), tolerance)))
1179template<
typename T, precision Q>
1186template<
typename T, precision Q>
1193template<
typename T, precision Q>
1200template<
typename T, precision Q>
1207template<
typename T, precision Q>
1211 if(can_use_simplified_calculations_without_uniform_scale())
1219 return vec3_t(result) / result.w;
1222template<
typename T, precision Q>
1226 if(can_use_simplified_calculations_without_uniform_scale())
1241 result *= inv_scale;
1248 return vec3_t(result) / result.w;
1251template<
typename T, precision Q>
1256 if(can_use_simplified_calculations())
1267 mat3_t normal_matrix = glm::transpose(glm::inverse(linear_matrix));
1270 return normal_matrix * v;
1273template<
typename T, precision Q>
1277 if(can_use_simplified_calculations())
1285 mat3_t normal_matrix = glm::transpose(linear_matrix);
1288 return normal_matrix * v;
1291template<
typename T, precision Q>
1298template<
typename T, precision Q>
1304template<
typename T, precision Q>
1312template<
typename T, precision Q>
1320template<
typename T, precision Q>
1328template<
typename T, precision Q>
1334template<
typename T, precision Q>
1342template<
typename T, precision Q>
1371template<
typename T, precision Q>
1374 return compare(t, math::epsilon<T>()) == 0;
1377template<
typename T, precision Q>
1380 return compare(t, math::epsilon<T>()) != 0;
1383template<
typename T, precision Q>
1390template<
typename T, precision Q>
1393 if(components_need_recompute_)
1397 components_need_recompute_ =
false;
1399 is_perspective_identity_cached_ = is_perspective_identity();
1400 is_skew_zero_cached_ = is_skew_zero();
1401 is_scale_uniform_cached_ = is_scale_uniform();
1405template<
typename T, precision Q>
1408 if(matrix_needs_recompute_)
1410 if(can_use_simplified_calculations())
1413 const auto identity_matrix = glm::identity<mat4_t>();
1415 glm::scale(identity_matrix,
get_scale());
1430 matrix_needs_recompute_ =
false;
1434template<
typename T, precision Q>
1437 matrix_needs_recompute_ =
true;
1440template<
typename T, precision Q>
1443 components_need_recompute_ =
true;
1446template<
typename T, precision Q>
1447TRANSFORM_INLINE auto transform_t<T, Q>::is_skew_zero() const noexcept ->
bool
1449 return glm::all(glm::epsilonEqual(
get_skew(), glm::zero<vec3_t>(), glm::epsilon<T>()));
1452template<
typename T, precision Q>
1453TRANSFORM_INLINE auto transform_t<T, Q>::is_perspective_identity() const noexcept ->
bool
1458template<
typename T, precision Q>
1459TRANSFORM_INLINE auto transform_t<T, Q>::is_scale_uniform() const noexcept ->
bool
1461 const T epsilon = glm::epsilon<T>();
1466template<
typename T, precision Q>
1467TRANSFORM_INLINE auto transform_t<T, Q>::can_use_simplified_calculations() const noexcept ->
bool
1469 return can_use_simplified_calculations_without_uniform_scale() && is_scale_uniform_cached_;
1472template<
typename T, precision Q>
1474TRANSFORM_INLINE auto transform_t<T, Q>::can_use_simplified_calculations_without_uniform_scale() const noexcept ->
bool
1476 return !components_need_recompute_ && is_skew_zero_cached_ && is_perspective_identity_cached_;
1479template<
typename T, precision Q>
1485template<
typename T, precision Q>
1492template<
typename T, precision Q>
1498template<
typename T, precision Q>
1504template<
typename T, precision Q>
1517 return glm::to_string(v);
1525template<
typename T, qualifier Q>
1526struct compute_to_string<math::transform_t<T, Q>>
1530 char const* prefix_str = prefix<T>::value();
1531 return detail::format(
"%stransform((translation:%s, scale:%s, rotation:%s/rotation_euler:%s, skew:%s))",
1534 to_string(
x.get_scale()).c_str(),
1535 to_string(
x.get_rotation()).c_str(),
1536 to_string(
x.get_rotation_euler()).c_str(),
1537 to_string(
x.get_skew()).c_str());
1543inline auto look_rotation(
const glm::vec3& forward,
const glm::vec3& upwards) -> glm::quat
1545 auto view = glm::lookAt(
1546 math::zero<math::vec3>(),
1551 glm::mat4 model = glm::inverse(view);
1552 return glm::quat_cast(model);
1558 glm::vec3 f = glm::normalize(from);
1559 glm::vec3 t = glm::normalize(to);
1562 float dot_product = glm::dot(f, t);
1563 dot_product = glm::clamp(dot_product, -1.0f, 1.0f);
1564 float angle = glm::acos(dot_product);
1567 if(glm::epsilonEqual(dot_product, 1.0f, 1e-5f))
1570 return glm::identity<glm::quat>();
1574 if(glm::epsilonEqual(dot_product, -1.0f, 1e-5f))
1579 glm::vec3 orth = glm::abs(f.x) > glm::abs(f.z) ? glm::vec3(-f.y, f.x, 0.0f) : glm::vec3(0.0f, -f.z, f.y);
1580 orth = glm::normalize(orth);
1581 return glm::angleAxis(glm::pi<float>(), orth);
1585 glm::vec3 axis = glm::cross(f, t);
1588 float len_sq = glm::dot(axis, axis);
1593 return glm::identity<glm::quat>();
1596 axis = glm::normalize(axis);
1599 return glm::angleAxis(angle, axis);
1604 matrix[3] = glm::vec4(glm::vec3(matrix[3]) - camera_position, 1.0f);
auto look_rotation(const glm::vec3 &forward, const glm::vec3 &upwards) -> glm::quat
void set_position_relative(glm::mat4 &matrix, const glm::vec3 &camera_position)
auto from_to_rotation(const glm::vec3 &from, const glm::vec3 &to) -> glm::quat
GLM_FUNC_QUALIFIER T scale_fix(T &in)
auto inverse(transform_t< T, Q > const &t) noexcept -> transform_t< T, Q >
GLM_FUNC_QUALIFIER void glm_recompose(mat< 4, 4, T, Q > &model_matrix, vec< 3, T, Q > const &in_scale, qua< T, Q > const &in_orientation, vec< 3, T, Q > const &in_translation, vec< 3, T, Q > const &in_skew, vec< 4, T, Q > const &in_perspective)
TRANSFORM_INLINE auto to_string(const T &v) -> std::string
auto transpose(transform_t< T, Q > const &t) noexcept -> transform_t< T, Q >
GLM_FUNC_QUALIFIER bool glm_decompose(mat< 4, 4, T, Q > const &ModelMatrix, vec< 3, T, Q > &Scale, qua< T, Q > &Orientation, vec< 3, T, Q > &Translation, vec< 3, T, Q > &Skew, vec< 4, T, Q > &Perspective)