aboutsummaryrefslogtreecommitdiff
path: root/include/matrix4.h
diff options
context:
space:
mode:
authornumzero <numzer0@yandex.ru>2023-03-25 10:42:11 +0300
committernumzero <numzer0@yandex.ru>2023-03-25 10:42:47 +0300
commitd97d1708d68a98c039db8a06c4110bfc961d3fb1 (patch)
tree1a90cd7a34793982aa9376468feb41e67d2b7cdc /include/matrix4.h
parentba77d01c91a363ad932ecd26c3eaba82ddf7a6f0 (diff)
parent799c8b936f9a2cc4f3a8bc56237fb9a8dedf853e (diff)
downloadirrlicht-d97d1708d68a98c039db8a06c4110bfc961d3fb1.tar.xz
Resolve conflicts with master
Diffstat (limited to 'include/matrix4.h')
-rw-r--r--include/matrix4.h116
1 files changed, 66 insertions, 50 deletions
diff --git a/include/matrix4.h b/include/matrix4.h
index efd353d..1245546 100644
--- a/include/matrix4.h
+++ b/include/matrix4.h
@@ -143,7 +143,7 @@ namespace core
//! Set this matrix to the product of two matrices
/** Calculate b*a, no optimization used,
- use it if you know you never have a identity matrix */
+ use it if you know you never have an identity matrix */
CMatrix4<T>& setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
//! Multiply by another matrix.
@@ -151,7 +151,8 @@ namespace core
CMatrix4<T> operator*(const CMatrix4<T>& other) const;
//! Multiply by another matrix.
- /** Calculate and return other*this */
+ /** Like calling: (*this) = (*this) * other
+ */
CMatrix4<T>& operator*=(const CMatrix4<T>& other);
//! Multiply by scalar.
@@ -187,14 +188,25 @@ namespace core
//! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
CMatrix4<T>& setRotationDegrees( const vector3d<T>& rotation );
- //! Get the rotation, as set by setRotation() when you already know the scale.
- /** If you already know the scale then this function is faster than the other getRotationDegrees overload.
- NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.
+ //! Get the rotation, as set by setRotation() when you already know the scale used to create the matrix
+ /** NOTE: The scale needs to be the correct one used to create this matrix.
+ You can _not_ use the result of getScale(), but have to save your scale
+ variable in another place (like ISceneNode does).
+ NOTE: No scale value can be 0 or the result is undefined.
+ NOTE: It does not necessarily return the *same* Euler angles as those set by setRotationDegrees(),
+ but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.
+ NOTE: It will (usually) give wrong results when further transformations have been added in the matrix (like shear).
+ WARNING: There have been troubles with this function over the years and we may still have missed some corner cases.
+ It's generally safer to keep the rotation and scale you used to create the matrix around and work with those.
*/
core::vector3d<T> getRotationDegrees(const vector3d<T>& scale) const;
//! Returns the rotation, as set by setRotation().
/** NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.
+ NOTE: This only works correct if no other matrix operations have been done on the inner 3x3 matrix besides
+ setting rotation (so no scale/shear). Thought it (probably) works as long as scale doesn't flip handedness.
+ NOTE: It does not necessarily return the *same* Euler angles as those set by setRotationDegrees(),
+ but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.
*/
core::vector3d<T> getRotationDegrees() const;
@@ -828,11 +840,9 @@ namespace core
//! Returns the absolute values of the scales of the matrix.
/**
- Note that this returns the absolute (positive) values unless only scale is set.
- Unfortunately it does not appear to be possible to extract any original negative
- values. The best that we could do would be to arbitrarily make one scale
- negative if one or three of them were negative.
- FIXME - return the original values.
+ Note: You only get back original values if the matrix only set the scale.
+ Otherwise the result is a scale you can use to normalize the matrix axes,
+ but it's usually no longer what you did set with setScale.
*/
template <class T>
inline vector3d<T> CMatrix4<T>::getScale() const
@@ -895,33 +905,16 @@ namespace core
}
- //! Returns a rotation that is equivalent to that set by setRotationDegrees().
- /** This code was sent in by Chev. Note that it does not necessarily return
- the *same* Euler angles as those set by setRotationDegrees(), but the rotation will
- be equivalent, i.e. will have the same result when used to rotate a vector or node.
- This code was originally written by by Chev.
+ //! Returns a rotation which (mostly) works in combination with the given scale
+ /**
+ This code was originally written by by Chev (assuming no scaling back then,
+ we can be blamed for all problems added by regarding scale)
*/
template <class T>
inline core::vector3d<T> CMatrix4<T>::getRotationDegrees(const vector3d<T>& scale_) const
{
const CMatrix4<T> &mat = *this;
- core::vector3d<T> scale(scale_);
- // we need to check for negative scale on to axes, which would bring up wrong results
- if (scale.Y<0 && scale.Z<0)
- {
- scale.Y =-scale.Y;
- scale.Z =-scale.Z;
- }
- else if (scale.X<0 && scale.Z<0)
- {
- scale.X =-scale.X;
- scale.Z =-scale.Z;
- }
- else if (scale.X<0 && scale.Y<0)
- {
- scale.X =-scale.X;
- scale.Y =-scale.Y;
- }
+ const core::vector3d<f64> scale(core::iszero(scale_.X) ? FLT_MAX : scale_.X , core::iszero(scale_.Y) ? FLT_MAX : scale_.Y, core::iszero(scale_.Z) ? FLT_MAX : scale_.Z);
const core::vector3d<f64> invScale(core::reciprocal(scale.X),core::reciprocal(scale.Y),core::reciprocal(scale.Z));
f64 Y = -asin(core::clamp(mat[2]*invScale.X, -1.0, 1.0));
@@ -930,7 +923,7 @@ namespace core
f64 rotx, roty, X, Z;
- if (!core::iszero(C))
+ if (!core::iszero((T)C))
{
const f64 invC = core::reciprocal(C);
rotx = mat[10] * invC * invScale.Z;
@@ -957,14 +950,37 @@ namespace core
}
//! Returns a rotation that is equivalent to that set by setRotationDegrees().
- /** This code was sent in by Chev. Note that it does not necessarily return
- the *same* Euler angles as those set by setRotationDegrees(), but the rotation will
- be equivalent, i.e. will have the same result when used to rotate a vector or node.
- This code was originally written by by Chev. */
template <class T>
inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const
{
- return getRotationDegrees(getScale());
+ // Note: Using getScale() here make it look like it could do matrix decomposition.
+ // It can't! It works (or should work) as long as rotation doesn't flip the handedness
+ // aka scale swapping 1 or 3 axes. (I think we could catch that as well by comparing
+ // crossproduct of first 2 axes to direction of third axis, but TODO)
+ // And maybe it should also offer the solution for the simple calculation
+ // without regarding scaling as Irrlicht did before 1.7
+ core::vector3d<T> scale(getScale());
+
+ // We assume the matrix uses rotations instead of negative scaling 2 axes.
+ // Otherwise it fails even for some simple cases, like rotating around
+ // 2 axes by 180° which getScale thinks is a negative scaling.
+ if (scale.Y<0 && scale.Z<0)
+ {
+ scale.Y =-scale.Y;
+ scale.Z =-scale.Z;
+ }
+ else if (scale.X<0 && scale.Z<0)
+ {
+ scale.X =-scale.X;
+ scale.Z =-scale.Z;
+ }
+ else if (scale.X<0 && scale.Y<0)
+ {
+ scale.X =-scale.X;
+ scale.Y =-scale.Y;
+ }
+
+ return getRotationDegrees(scale);
}
@@ -1156,10 +1172,10 @@ namespace core
template <class T>
inline void CMatrix4<T>::rotateVect( vector3df& vect ) const
{
- vector3df tmp = vect;
- vect.X = tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8];
- vect.Y = tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9];
- vect.Z = tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10];
+ vector3d<T> tmp(static_cast<T>(vect.X), static_cast<T>(vect.Y), static_cast<T>(vect.Z));
+ vect.X = static_cast<f32>(tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8]);
+ vect.Y = static_cast<f32>(tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9]);
+ vect.Z = static_cast<f32>(tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10]);
}
//! An alternate transform vector method, writing into a second vector
@@ -1183,24 +1199,24 @@ namespace core
template <class T>
inline void CMatrix4<T>::inverseRotateVect( vector3df& vect ) const
{
- vector3df tmp = vect;
- vect.X = tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2];
- vect.Y = tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6];
- vect.Z = tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10];
+ vector3d<T> tmp(static_cast<T>(vect.X), static_cast<T>(vect.Y), static_cast<T>(vect.Z));
+ vect.X = static_cast<f32>(tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2]);
+ vect.Y = static_cast<f32>(tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6]);
+ vect.Z = static_cast<f32>(tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10]);
}
template <class T>
inline void CMatrix4<T>::transformVect( vector3df& vect) const
{
- f32 vector[3];
+ T vector[3];
vector[0] = vect.X*M[0] + vect.Y*M[4] + vect.Z*M[8] + M[12];
vector[1] = vect.X*M[1] + vect.Y*M[5] + vect.Z*M[9] + M[13];
vector[2] = vect.X*M[2] + vect.Y*M[6] + vect.Z*M[10] + M[14];
- vect.X = vector[0];
- vect.Y = vector[1];
- vect.Z = vector[2];
+ vect.X = static_cast<f32>(vector[0]);
+ vect.Y = static_cast<f32>(vector[1]);
+ vect.Z = static_cast<f32>(vector[2]);
}
template <class T>