Browse Source

Added EXT_scalar_common, EXT_vector_common and EXT_quaternion_exponential extensions

Christophe Riccio 7 years ago
parent
commit
c4ed4ed0c7

+ 69 - 0
glm/ext/quaternion_exponential.hpp

@@ -0,0 +1,69 @@
+/// @ref ext_quaternion_exponential
+/// @file glm/ext/quaternion_exponential.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup ext_quaternion_exponential GLM_EXT_quaternion_exponential
+/// @ingroup ext
+///
+/// Include <glm/ext/quaternion_exponential.hpp> to use the features of this extension.
+///
+/// Defines a templated quaternion type and several quaternion operations.
+
+#pragma once
+
+// Dependency:
+#include "../common.hpp"
+#include "../trigonometric.hpp"
+#include "../geometric.hpp"
+#include "../ext/scalar_constants.hpp"
+
+#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)
+#	pragma message("GLM: GLM_EXT_quaternion_exponential extension included")
+#endif
+
+namespace glm
+{
+	/// @addtogroup ext_quaternion_transform
+	/// @{
+
+	/// Returns a exponential of a quaternion.
+	///
+	/// @tparam T A floating-point scalar type
+	/// @tparam Q A value from qualifier enum
+	///
+	/// @see ext_quaternion_exponential
+	template<typename T, qualifier Q>
+	GLM_FUNC_DECL qua<T, Q> exp(qua<T, Q> const& q);
+
+	/// Returns a logarithm of a quaternion
+	///
+	/// @tparam T A floating-point scalar type
+	/// @tparam Q A value from qualifier enum
+	///
+	/// @see ext_quaternion_exponential
+	template<typename T, qualifier Q>
+	GLM_FUNC_DECL qua<T, Q> log(qua<T, Q> const& q);
+
+	/// Returns a quaternion raised to a power.
+	///
+	/// @tparam T A floating-point scalar type
+	/// @tparam Q A value from qualifier enum
+	///
+	/// @see ext_quaternion_exponential
+	template<typename T, qualifier Q>
+	GLM_FUNC_DECL qua<T, Q> pow(qua<T, Q> const& q, T y);
+
+	/// Returns the square root of a quaternion
+	///
+	/// @tparam T A floating-point scalar type
+	/// @tparam Q A value from qualifier enum
+	///
+	/// @see ext_quaternion_exponential
+	template<typename T, qualifier Q>
+	GLM_FUNC_DECL qua<T, Q> sqrt(qua<T, Q> const& q);
+
+	/// @}
+} //namespace glm
+
+#include "quaternion_exponential.inl"

+ 72 - 0
glm/ext/quaternion_exponential.inl

@@ -0,0 +1,72 @@
+namespace glm
+{
+	template<typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER qua<T, Q> exp(qua<T, Q> const& q)
+	{
+		vec<3, T, Q> u(q.x, q.y, q.z);
+		T const Angle = glm::length(u);
+		if (Angle < epsilon<T>())
+			return qua<T, Q>();
+
+		vec<3, T, Q> const v(u / Angle);
+		return qua<T, Q>(cos(Angle), sin(Angle) * v);
+	}
+
+	template<typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER qua<T, Q> log(qua<T, Q> const& q)
+	{
+		vec<3, T, Q> u(q.x, q.y, q.z);
+		T Vec3Len = length(u);
+
+		if (Vec3Len < epsilon<T>())
+		{
+			if(q.w > static_cast<T>(0))
+				return qua<T, Q>(log(q.w), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0));
+			else if(q.w < static_cast<T>(0))
+				return qua<T, Q>(log(-q.w), pi<T>(), static_cast<T>(0), static_cast<T>(0));
+			else
+				return qua<T, Q>(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity());
+		}
+		else
+		{
+			T t = atan(Vec3Len, T(q.w)) / Vec3Len;
+			T QuatLen2 = Vec3Len * Vec3Len + q.w * q.w;
+			return qua<T, Q>(static_cast<T>(0.5) * log(QuatLen2), t * q.x, t * q.y, t * q.z);
+		}
+	}
+
+	template<typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER qua<T, Q> pow(qua<T, Q> const& x, T y)
+	{
+		//Raising to the power of 0 should yield 1
+		//Needed to prevent a division by 0 error later on
+		if(y > -epsilon<T>() && y < epsilon<T>())
+			return qua<T, Q>(1,0,0,0);
+
+		//To deal with non-unit quaternions
+		T magnitude = sqrt(x.x * x.x + x.y * x.y + x.z * x.z + x.w *x.w);
+
+		//Equivalent to raising a real number to a power
+		//Needed to prevent a division by 0 error later on
+		if(abs(x.w / magnitude) > static_cast<T>(1) - epsilon<T>() && abs(x.w / magnitude) < static_cast<T>(1) + epsilon<T>())
+			return qua<T, Q>(pow(x.w, y), 0, 0, 0);
+
+		T Angle = acos(x.w / magnitude);
+		T NewAngle = Angle * y;
+		T Div = sin(NewAngle) / sin(Angle);
+		T Mag = pow(magnitude, y - static_cast<T>(1));
+
+		return qua<T, Q>(cos(NewAngle) * magnitude * Mag, x.x * Div * Mag, x.y * Div * Mag, x.z * Div * Mag);
+	}
+
+	template<typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER qua<T, Q> sqrt(qua<T, Q> const& x)
+	{
+		return pow(x, static_cast<T>(0.5));
+	}
+}//namespace glm
+
+#if GLM_CONFIG_SIMD == GLM_ENABLE
+#	include "quaternion_exponential_simd.inl"
+#endif
+

+ 1 - 0
glm/ext/quaternion_geometric.hpp

@@ -47,6 +47,7 @@ namespace glm
 	/// Returns dot product of q1 and q2, i.e., q1[0] * q2[0] + q1[1] * q2[1] + ...
 	///
 	/// @tparam T Floating-point scalar types.
+	/// @tparam Q Value from qualifier enum
 	///
 	/// @see ext_quaternion_geometric
 	template<typename T, qualifier Q>

+ 26 - 0
glm/ext/quaternion_transform.hpp

@@ -39,6 +39,32 @@ namespace glm
 	template<typename T, qualifier Q>
 	GLM_FUNC_DECL qua<T, Q> rotate(qua<T, Q> const& q, T const& angle, vec<3, T, Q> const& axis);
 
+	/// Build a look at quaternion based on the default handedness.
+	///
+	/// @param direction Desired forward direction. Needs to be normalized.
+	/// @param up Up vector, how the camera is oriented. Typically (0, 1, 0).
+	template<typename T, qualifier Q>
+	GLM_FUNC_DECL qua<T, Q> quatLookAt(
+		vec<3, T, Q> const& direction,
+		vec<3, T, Q> const& up);
+
+	/// Build a right-handed look at quaternion.
+	///
+	/// @param direction Desired forward direction onto which the -z-axis gets mapped. Needs to be normalized.
+	/// @param up Up vector, how the camera is oriented. Typically (0, 1, 0).
+	template<typename T, qualifier Q>
+	GLM_FUNC_DECL qua<T, Q> quatLookAtRH(
+		vec<3, T, Q> const& direction,
+		vec<3, T, Q> const& up);
+
+	/// Build a left-handed look at quaternion.
+	///
+	/// @param direction Desired forward direction onto which the +z-axis gets mapped. Needs to be normalized.
+	/// @param up Up vector, how the camera is oriented. Typically (0, 1, 0).
+	template<typename T, qualifier Q>
+	GLM_FUNC_DECL qua<T, Q> quatLookAtLH(
+		vec<3, T, Q> const& direction,
+		vec<3, T, Q> const& up);
 	/// @}
 } //namespace glm
 

+ 34 - 0
glm/ext/quaternion_transform.inl

@@ -20,6 +20,40 @@ namespace glm
 
 		return q * qua<T, Q>(cos(AngleRad * static_cast<T>(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin);
 	}
+
+	template<typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER qua<T, Q> quatLookAt(vec<3, T, Q> const& direction, vec<3, T, Q> const& up)
+	{
+#		if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT
+			return quatLookAtLH(direction, up);
+#		else
+			return quatLookAtRH(direction, up);
+# 		endif
+	}
+
+	template<typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER qua<T, Q> quatLookAtRH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up)
+	{
+		mat<3, 3, T, Q> Result;
+
+		Result[2] = -direction;
+		Result[0] = normalize(cross(up, Result[2]));
+		Result[1] = cross(Result[2], Result[0]);
+
+		return quat_cast(Result);
+	}
+
+	template<typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER qua<T, Q> quatLookAtLH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up)
+	{
+		mat<3, 3, T, Q> Result;
+
+		Result[2] = direction;
+		Result[0] = normalize(cross(up, Result[2]));
+		Result[1] = cross(Result[2], Result[0]);
+
+		return quat_cast(Result);
+	}
 }//namespace glm
 
 #if GLM_CONFIG_SIMD == GLM_ENABLE

+ 110 - 0
glm/ext/scalar_common.hpp

@@ -0,0 +1,110 @@
+/// @ref ext_scalar_common
+/// @file glm/ext/scalar_common.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup ext_scalar_common GLM_EXT_scalar_common
+/// @ingroup ext
+///
+/// Include <glm/ext/scalar_common.hpp> to use the features of this extension.
+///
+/// Min and max functions for 3 to 4 parameters.
+
+#pragma once
+
+// Dependency:
+#include "../common.hpp"
+
+#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)
+#	pragma message("GLM: GLM_EXT_scalar_common extension included")
+#endif
+
+namespace glm
+{
+	/// @addtogroup ext_scalar_common
+	/// @{
+
+	/// Returns the minimum component-wise values of 3 inputs
+	///
+	/// @tparam T A floating-point scalar type.
+	///
+	/// @see ext_scalar_common
+	template<typename T>
+	GLM_FUNC_DECL T min(T a, T b, T c);
+
+	/// Returns the minimum component-wise values of 4 inputs
+	/// @see ext_scalar_common
+	template<typename T>
+	GLM_FUNC_DECL T min(T a, T b, T c, T d);
+
+	/// Returns the maximum component-wise values of 3 inputs
+	///
+	/// @tparam T A floating-point scalar type.
+	///
+	/// @see ext_scalar_common
+	template<typename T>
+	GLM_FUNC_DECL T max(T a, T b, T c);
+
+	/// Returns the maximum component-wise values of 4 inputs
+	/// @see ext_scalar_common
+	template<typename T>
+	GLM_FUNC_DECL T max(T a, T b, T c, T d);
+
+	/// Returns the minimum component-wise values of 2 inputs. If one of the two arguments is NaN, the value of the other argument is returned.
+	///
+	/// @tparam T A floating-point scalar type.
+	///
+	/// @see ext_scalar_common
+	/// @see <a href="http://en.cppreference.com/w/cpp/numeric/math/fmin">std::fmin documentation</a>
+	template<typename T>
+	GLM_FUNC_DECL T fmin(T a, T b);
+
+	/// Returns the minimum component-wise values of 3 inputs. If one of the two arguments is NaN, the value of the other argument is returned.
+	///
+	/// @tparam T A floating-point scalar type.
+	///
+	/// @see ext_scalar_common
+	/// @see <a href="http://en.cppreference.com/w/cpp/numeric/math/fmin">std::fmin documentation</a>
+	template<typename T>
+	GLM_FUNC_DECL T fmin(T a, T b, T c);
+
+	/// Returns the minimum component-wise values of 4 inputs. If one of the two arguments is NaN, the value of the other argument is returned.
+	///
+	/// @tparam T A floating-point scalar type.
+	///
+	/// @see ext_scalar_common
+	/// @see <a href="http://en.cppreference.com/w/cpp/numeric/math/fmin">std::fmin documentation</a>
+	template<typename T>
+	GLM_FUNC_DECL T fmin(T a, T b, T c, T d);
+
+	/// Returns the maximum component-wise values of 2 inputs. If one of the two arguments is NaN, the value of the other argument is returned.
+	///
+	/// @tparam T A floating-point scalar type.
+	///
+	/// @see ext_scalar_common
+	/// @see <a href="http://en.cppreference.com/w/cpp/numeric/math/fmax">std::fmax documentation</a>
+	template<typename T>
+	GLM_FUNC_DECL T fmax(T a, T b);
+
+	/// Returns the maximum component-wise values of 3 inputs. If one of the two arguments is NaN, the value of the other argument is returned.
+	///
+	/// @tparam T A floating-point scalar type.
+	///
+	/// @see ext_scalar_common
+	/// @see <a href="http://en.cppreference.com/w/cpp/numeric/math/fmax">std::fmax documentation</a>
+	template<typename T>
+	GLM_FUNC_DECL T fmax(T a, T b, T C);
+
+	/// Returns the maximum component-wise values of 4 inputs. If one of the two arguments is NaN, the value of the other argument is returned.
+	///
+	/// @tparam T A floating-point scalar type.
+	///
+	/// @see ext_scalar_common
+	/// @see <a href="http://en.cppreference.com/w/cpp/numeric/math/fmax">std::fmax documentation</a>
+	template<typename T>
+	GLM_FUNC_DECL T fmax(T a, T b, T C, T D);
+
+	/// @}
+}//namespace glm
+
+#include "scalar_common.inl"

+ 115 - 0
glm/ext/scalar_common.inl

@@ -0,0 +1,115 @@
+namespace glm
+{
+	template<typename T>
+	GLM_FUNC_QUALIFIER T min(T a, T b, T c)
+	{
+		return glm::min(glm::min(a, b), c);
+	}
+
+	template<typename T>
+	GLM_FUNC_QUALIFIER T min(T a, T b, T c, T d)
+	{
+		return glm::min(glm::min(a, b), glm::min(c, d));
+	}
+
+	template<typename T>
+	GLM_FUNC_QUALIFIER T max(T a, T b, T c)
+	{
+		return glm::max(glm::max(a, b), c);
+	}
+
+	template<typename T>
+	GLM_FUNC_QUALIFIER T max(T a, T b, T c, T d)
+	{
+		return glm::max(glm::max(a, b), glm::max(c, d));
+	}
+
+#	if GLM_HAS_CXX11_STL
+		using std::fmin;
+#	else
+		template<typename T>
+		GLM_FUNC_QUALIFIER T fmin(T a, T b)
+		{
+			GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fmin' only accept floating-point input");
+
+			if (isnan(a))
+				return b;
+			return min(a, b);
+		}
+#	endif
+
+	template<typename T>
+	GLM_FUNC_QUALIFIER T fmin(T a, T b, T c)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fmin' only accept floating-point input");
+
+		if (isnan(a))
+			return fmin(b, c);
+		if (isnan(b))
+			return fmin(a, c);
+		if (isnan(c))
+			return min(a, b);
+		return min(a, b, c);
+	}
+
+	template<typename T>
+	GLM_FUNC_QUALIFIER T fmin(T a, T b, T c, T d)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fmin' only accept floating-point input");
+
+		if (isnan(a))
+			return fmin(b, c, d);
+		if (isnan(b))
+			return min(a, fmin(c, d));
+		if (isnan(c))
+			return fmin(min(a, b), d);
+		if (isnan(d))
+			return min(a, b, c);
+		return min(a, b, c, d);
+	}
+
+
+#	if GLM_HAS_CXX11_STL
+		using std::fmax;
+#	else
+		template<typename T>
+		GLM_FUNC_QUALIFIER T fmax(T a, T b)
+		{
+			GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fmax' only accept floating-point input");
+
+			if (isnan(a))
+				return b;
+			return max(a, b);
+		}
+#	endif
+
+	template<typename T>
+	GLM_FUNC_QUALIFIER T fmax(T a, T b, T c)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fmax' only accept floating-point input");
+
+		if (isnan(a))
+			return fmax(b, c);
+		if (isnan(b))
+			return fmax(a, c);
+		if (isnan(c))
+			return max(a, b);
+		return max(a, b, c);
+	}
+
+	template<typename T>
+	GLM_FUNC_QUALIFIER T fmax(T a, T b, T c, T d)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fmax' only accept floating-point input");
+
+		if (isnan(a))
+			return fmax(b, c, d);
+		if (isnan(b))
+			return max(a, fmax(c, d));
+		if (isnan(c))
+			return fmax(max(a, b), d);
+		if (isnan(d))
+			return max(a, b, c);
+		return max(a, b, c, d);
+	}
+}//namespace glm

+ 134 - 0
glm/ext/vector_common.hpp

@@ -0,0 +1,134 @@
+/// @ref ext_vector_common
+/// @file glm/ext/vector_common.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup ext_vector_common GLM_EXT_vector_common
+/// @ingroup ext
+///
+/// Include <glm/ext/vector_common.hpp> to use the features of this extension.
+///
+/// Min and max functions for 3 to 4 parameters.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)
+#	pragma message("GLM: GLM_EXT_vector_common extension included")
+#endif
+
+namespace glm
+{
+	/// @addtogroup ext_vector_common
+	/// @{
+
+	/// Return the minimum component-wise values of 3 inputs
+	///
+	/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector
+	/// @tparam T Floating-point or integer scalar types
+	/// @tparam Q Value from qualifier enum
+	///
+	/// @see ext_vector_common
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_DECL vec<L, T, Q> min(vec<L, T, Q> const& a, vec<L, T, Q> const& b, vec<L, T, Q> const& c);
+
+	/// Return the minimum component-wise values of 4 inputs
+	///
+	/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector
+	/// @tparam T Floating-point or integer scalar types
+	/// @tparam Q Value from qualifier enum
+	///
+	/// @see ext_vector_common
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_DECL vec<L, T, Q> min(vec<L, T, Q> const& a, vec<L, T, Q> const& b, vec<L, T, Q> const& c, vec<L, T, Q> const& d);
+
+	/// Return the maximum component-wise values of 3 inputs
+	///
+	/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector
+	/// @tparam T Floating-point or integer scalar types
+	/// @tparam Q Value from qualifier enum
+	///
+	/// @see ext_vector_common
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_DECL vec<L, T, Q> max(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& z);
+
+	/// Return the maximum component-wise values of 4 inputs
+	///
+	/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector
+	/// @tparam T Floating-point or integer scalar types
+	/// @tparam Q Value from qualifier enum
+	///
+	/// @see ext_vector_common
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_DECL vec<L, T, Q> max( vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& z, vec<L, T, Q> const& w);
+
+	/// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned.
+	///
+	/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector
+	/// @tparam T Floating-point scalar types
+	/// @tparam Q Value from qualifier enum
+	///
+	/// @see ext_vector_common
+	/// @see <a href="http://en.cppreference.com/w/cpp/numeric/math/fmin">std::fmin documentation</a>
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_DECL vec<L, T, Q> fmin(vec<L, T, Q> const& x, T y);
+
+	/// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned.
+	///
+	/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector
+	/// @tparam T Floating-point scalar types
+	/// @tparam Q Value from qualifier enum
+	///
+	/// @see ext_vector_common
+	/// @see <a href="http://en.cppreference.com/w/cpp/numeric/math/fmin">std::fmin documentation</a>
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_DECL vec<L, T, Q> fmin(vec<L, T, Q> const& x, vec<L, T, Q> const& y);
+
+	/// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned.
+	///
+	/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector
+	/// @tparam T Floating-point scalar types
+	/// @tparam Q Value from qualifier enum
+	///
+	/// @see ext_vector_common
+	/// @see <a href="http://en.cppreference.com/w/cpp/numeric/math/fmax">std::fmax documentation</a>
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_DECL vec<L, T, Q> fmax(vec<L, T, Q> const& x, T y);
+
+	/// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned.
+	///
+	/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector
+	/// @tparam T Floating-point scalar types
+	/// @tparam Q Value from qualifier enum
+	///
+	/// @see ext_vector_common
+	/// @see <a href="http://en.cppreference.com/w/cpp/numeric/math/fmax">std::fmax documentation</a>
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_DECL vec<L, T, Q> fmax(vec<L, T, Q> const& x, vec<L, T, Q> const& y);
+
+	/// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned.
+	///
+	/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector
+	/// @tparam T Floating-point scalar types
+	/// @tparam Q Value from qualifier enum
+	///
+	/// @see ext_vector_common
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_DECL vec<L, T, Q> fclamp(vec<L, T, Q> const& x, T minVal, T maxVal);
+
+	/// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned.
+	///
+	/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector
+	/// @tparam T Floating-point scalar types
+	/// @tparam Q Value from qualifier enum
+	///
+	/// @see ext_vector_common
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_DECL vec<L, T, Q> fclamp(vec<L, T, Q> const& x, vec<L, T, Q> const& minVal, vec<L, T, Q> const& maxVal);
+
+	/// @}
+}//namespace glm
+
+#include "vector_common.inl"

+ 72 - 0
glm/ext/vector_common.inl

@@ -0,0 +1,72 @@
+namespace glm
+{
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER vec<L, T, Q> min(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& z)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'min' only accept floating-point or integer inputs");
+		return glm::min(glm::min(x, y), z);
+	}
+
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER vec<L, T, Q> min(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& z, vec<L, T, Q> const& w)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'min' only accept floating-point or integer inputs");
+		return glm::min(glm::min(x, y), glm::min(z, w));
+	}
+
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER vec<L, T, Q> max(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& z)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'max' only accept floating-point or integer inputs");
+		return glm::max(glm::max(x, y), z);
+	}
+
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER vec<L, T, Q> max(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& z, vec<L, T, Q> const& w)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'max' only accept floating-point or integer inputs");
+		return glm::max(glm::max(x, y), glm::max(z, w));
+	}
+
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER vec<L, T, Q> fmin(vec<L, T, Q> const& a, T b)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fmin' only accept floating-point inputs");
+		return detail::functor2<vec, L, T, Q>::call(fmin, a, vec<L, T, Q>(b));
+	}
+
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER vec<L, T, Q> fmin(vec<L, T, Q> const& a, vec<L, T, Q> const& b)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fmin' only accept floating-point inputs");
+		return detail::functor2<vec, L, T, Q>::call(fmin, a, b);
+	}
+
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER vec<L, T, Q> fmax(vec<L, T, Q> const& a, T b)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fmax' only accept floating-point inputs");
+		return detail::functor2<vec, L, T, Q>::call(fmax, a, vec<L, T, Q>(b));
+	}
+
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER vec<L, T, Q> fmax(vec<L, T, Q> const& a, vec<L, T, Q> const& b)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fmax' only accept floating-point inputs");
+		return detail::functor2<vec, L, T, Q>::call(fmax, a, b);
+	}
+
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER vec<L, T, Q> fclamp(vec<L, T, Q> const& x, T minVal, T maxVal)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fclamp' only accept floating-point inputs");
+		return fmin(fmax(x, vec<L, T, Q>(minVal)), vec<L, T, Q>(maxVal));
+	}
+
+	template<length_t L, typename T, qualifier Q>
+	GLM_FUNC_QUALIFIER vec<L, T, Q> fclamp(vec<L, T, Q> const& x, vec<L, T, Q> const& minVal, vec<L, T, Q> const& maxVal)
+	{
+		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fclamp' only accept floating-point inputs");
+		return fmin(fmax(x, minVal), maxVal);
+	}
+}//namespace glm

+ 1 - 0
glm/gtc/quaternion.hpp

@@ -24,6 +24,7 @@
 #include "../ext/quaternion_double_precision.hpp"
 #include "../ext/quaternion_relational.hpp"
 #include "../ext/quaternion_geometric.hpp"
+#include "../ext/quaternion_transform.hpp"
 #include "../detail/type_mat3x3.hpp"
 #include "../detail/type_mat4x4.hpp"
 #include "../detail/type_vec3.hpp"

+ 1 - 49
glm/gtx/quaternion.hpp

@@ -17,6 +17,7 @@
 #include "../glm.hpp"
 #include "../gtc/constants.hpp"
 #include "../gtc/quaternion.hpp"
+#include "../ext/quaternion_exponential.hpp"
 #include "../gtx/norm.hpp"
 
 #ifndef GLM_ENABLE_EXPERIMENTAL
@@ -75,28 +76,6 @@ namespace glm
 		qua<T, Q> const& curr,
 		qua<T, Q> const& next);
 
-	//! Returns a exp of a quaternion.
-	///
-	/// @see gtx_quaternion
-	template<typename T, qualifier Q>
-	GLM_FUNC_DECL qua<T, Q> exp(
-		qua<T, Q> const& q);
-
-	//! Returns a log of a quaternion.
-	///
-	/// @see gtx_quaternion
-	template<typename T, qualifier Q>
-	GLM_FUNC_DECL qua<T, Q> log(
-		qua<T, Q> const& q);
-
-	/// Returns x raised to the y power.
-	///
-	/// @see gtx_quaternion
-	template<typename T, qualifier Q>
-	GLM_FUNC_DECL qua<T, Q> pow(
-		qua<T, Q> const& x,
-		T const& y);
-
 	//! Returns quarternion square root.
 	///
 	/// @see gtx_quaternion
@@ -183,33 +162,6 @@ namespace glm
 		vec<3, T, Q> const& orig,
 		vec<3, T, Q> const& dest);
 
-	/// Build a look at quaternion based on the default handedness.
-	///
-	/// @param direction Desired forward direction. Needs to be normalized.
-	/// @param up Up vector, how the camera is oriented. Typically (0, 1, 0).
-	template<typename T, qualifier Q>
-	GLM_FUNC_DECL qua<T, Q> quatLookAt(
-		vec<3, T, Q> const& direction,
-		vec<3, T, Q> const& up);
-
-	/// Build a right-handed look at quaternion.
-	///
-	/// @param direction Desired forward direction onto which the -z-axis gets mapped. Needs to be normalized.
-	/// @param up Up vector, how the camera is oriented. Typically (0, 1, 0).
-	template<typename T, qualifier Q>
-	GLM_FUNC_DECL qua<T, Q> quatLookAtRH(
-		vec<3, T, Q> const& direction,
-		vec<3, T, Q> const& up);
-
-	/// Build a left-handed look at quaternion.
-	///
-	/// @param direction Desired forward direction onto which the +z-axis gets mapped. Needs to be normalized.
-	/// @param up Up vector, how the camera is oriented. Typically (0, 1, 0).
-	template<typename T, qualifier Q>
-	GLM_FUNC_DECL qua<T, Q> quatLookAtLH(
-		vec<3, T, Q> const& direction,
-		vec<3, T, Q> const& up);
-
 	/// Returns the squared length of x.
 	///
 	/// @see gtx_quaternion

+ 0 - 94
glm/gtx/quaternion.inl

@@ -47,65 +47,6 @@ namespace glm
 		return exp((log(next * invQuat) + log(prev * invQuat)) / static_cast<T>(-4)) * curr;
 	}
 
-	template<typename T, qualifier Q>
-	GLM_FUNC_QUALIFIER qua<T, Q> exp(qua<T, Q> const& q)
-	{
-		vec<3, T, Q> u(q.x, q.y, q.z);
-		T const Angle = glm::length(u);
-		if (Angle < epsilon<T>())
-			return qua<T, Q>();
-
-		vec<3, T, Q> const v(u / Angle);
-		return qua<T, Q>(cos(Angle), sin(Angle) * v);
-	}
-
-	template<typename T, qualifier Q>
-	GLM_FUNC_QUALIFIER qua<T, Q> log(qua<T, Q> const& q)
-	{
-		vec<3, T, Q> u(q.x, q.y, q.z);
-		T Vec3Len = length(u);
-
-		if (Vec3Len < epsilon<T>())
-		{
-			if(q.w > static_cast<T>(0))
-				return qua<T, Q>(log(q.w), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0));
-			else if(q.w < static_cast<T>(0))
-				return qua<T, Q>(log(-q.w), pi<T>(), static_cast<T>(0), static_cast<T>(0));
-			else
-				return qua<T, Q>(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity());
-		}
-		else
-		{
-			T t = atan(Vec3Len, T(q.w)) / Vec3Len;
-			T QuatLen2 = Vec3Len * Vec3Len + q.w * q.w;
-			return qua<T, Q>(static_cast<T>(0.5) * log(QuatLen2), t * q.x, t * q.y, t * q.z);
-		}
-	}
-
-	template<typename T, qualifier Q>
-	GLM_FUNC_QUALIFIER qua<T, Q> pow(qua<T, Q> const& x, T const& y)
-	{
-		//Raising to the power of 0 should yield 1
-		//Needed to prevent a division by 0 error later on
-		if(y > -epsilon<T>() && y < epsilon<T>())
-			return qua<T, Q>(1,0,0,0);
-
-		//To deal with non-unit quaternions
-		T magnitude = sqrt(x.x * x.x + x.y * x.y + x.z * x.z + x.w *x.w);
-
-		//Equivalent to raising a real number to a power
-		//Needed to prevent a division by 0 error later on
-		if(abs(x.w / magnitude) > static_cast<T>(1) - epsilon<T>() && abs(x.w / magnitude) < static_cast<T>(1) + epsilon<T>())
-			return qua<T, Q>(pow(x.w, y),0,0,0);
-
-		T Angle = acos(x.w / magnitude);
-		T NewAngle = Angle * y;
-		T Div = sin(NewAngle) / sin(Angle);
-		T Mag = pow(magnitude, y - static_cast<T>(1));
-
-		return qua<T, Q>(cos(NewAngle) * magnitude * Mag, x.x * Div * Mag, x.y * Div * Mag, x.z * Div * Mag);
-	}
-
 	template<typename T, qualifier Q>
 	GLM_FUNC_QUALIFIER vec<3, T, Q> rotate(qua<T, Q> const& q, vec<3, T, Q> const& v)
 	{
@@ -215,39 +156,4 @@ namespace glm
 			rotationAxis.y * invs,
 			rotationAxis.z * invs);
 	}
-
-	template<typename T, qualifier Q>
-	GLM_FUNC_QUALIFIER qua<T, Q> quatLookAt(vec<3, T, Q> const& direction, vec<3, T, Q> const& up)
-	{
-#		if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT
-			return quatLookAtLH(direction, up);
-#		else
-			return quatLookAtRH(direction, up);
-# 		endif
-	}
-
-	template<typename T, qualifier Q>
-	GLM_FUNC_QUALIFIER qua<T, Q> quatLookAtRH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up)
-	{
-		mat<3, 3, T, Q> Result;
-
-		Result[2] = -direction;
-		Result[0] = normalize(cross(up, Result[2]));
-		Result[1] = cross(Result[2], Result[0]);
-
-		return quat_cast(Result);
-	}
-
-	template<typename T, qualifier Q>
-	GLM_FUNC_QUALIFIER qua<T, Q> quatLookAtLH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up)
-	{
-		mat<3, 3, T, Q> Result;
-
-		Result[2] = direction;
-		Result[0] = normalize(cross(up, Result[2]));
-		Result[1] = cross(Result[2], Result[0]);
-
-		return quat_cast(Result);
-	}
-
 }//namespace glm

+ 3 - 0
test/ext/CMakeLists.txt

@@ -1,11 +1,13 @@
 glmCreateTestGTC(ext_matrix_relational)
 glmCreateTestGTC(ext_matrix_transform)
 glmCreateTestGTC(ext_quaternion_common)
+glmCreateTestGTC(ext_quaternion_exponential)
 glmCreateTestGTC(ext_quaternion_geometric)
 glmCreateTestGTC(ext_quaternion_relational)
 glmCreateTestGTC(ext_quaternion_transform)
 glmCreateTestGTC(ext_quaternion_trigonometric)
 glmCreateTestGTC(ext_quaternion_type)
+glmCreateTestGTC(ext_scalar_common)
 glmCreateTestGTC(ext_scalar_constants)
 glmCreateTestGTC(ext_scalar_float_sized)
 glmCreateTestGTC(ext_scalar_int_sized)
@@ -13,6 +15,7 @@ glmCreateTestGTC(ext_scalar_uint_sized)
 glmCreateTestGTC(ext_scalar_relational)
 glmCreateTestGTC(ext_vec1)
 glmCreateTestGTC(ext_vector_bool1)
+glmCreateTestGTC(ext_vector_common)
 glmCreateTestGTC(ext_vector_iec559)
 glmCreateTestGTC(ext_vector_integer)
 glmCreateTestGTC(ext_vector_relational)

+ 87 - 0
test/ext/ext_quaternion_exponential.cpp

@@ -0,0 +1,87 @@
+#include <glm/ext/quaternion_exponential.hpp>
+#include <glm/ext/quaternion_float.hpp>
+#include <glm/ext/quaternion_float_precision.hpp>
+#include <glm/ext/quaternion_double.hpp>
+#include <glm/ext/quaternion_double_precision.hpp>
+#include <glm/ext/quaternion_relational.hpp>
+#include <glm/ext/vector_float3.hpp>
+#include <glm/ext/vector_float3_precision.hpp>
+#include <glm/ext/vector_double3.hpp>
+#include <glm/ext/vector_double3_precision.hpp>
+#include <glm/ext/scalar_constants.hpp>
+
+template <typename quaType, typename vecType>
+int test_log()
+{
+	typedef typename quaType::value_type T;
+	
+	T const Epsilon = static_cast<T>(0.001f);
+	
+	int Error = 0;
+	
+	quaType const Q(vecType(1, 0, 0), vecType(0, 1, 0));
+	quaType const P = glm::log(Q);
+	Error += glm::any(glm::notEqual(Q, P, Epsilon)) ? 0 : 1;
+	
+	quaType const R = glm::exp(P);
+	Error += glm::all(glm::equal(Q, R, Epsilon)) ? 0 : 1;
+
+	return Error;
+}
+
+template <typename quaType, typename vecType>
+int test_pow()
+{
+	typedef typename quaType::value_type T;
+	
+	T const Epsilon = static_cast<T>(0.001f);
+	
+	int Error = 0;
+	
+	quaType const Q(vecType(1, 0, 0), vecType(0, 1, 0));
+	
+	{
+		T const One = static_cast<T>(1.0f);
+		quaType const P = glm::pow(Q, One);
+		Error += glm::all(glm::equal(Q, P, Epsilon)) ? 0 : 1;
+	}
+	
+	{
+		T const Two = static_cast<T>(2.0f);
+		quaType const P = glm::pow(Q, Two);
+		quaType const R = Q * Q;
+		Error += glm::all(glm::equal(P, R, Epsilon)) ? 0 : 1;
+
+		quaType const U = glm::sqrt(P);
+		Error += glm::all(glm::equal(Q, U, Epsilon)) ? 0 : 1;
+	}
+	
+	return Error;
+}
+
+int main()
+{
+	int Error = 0;
+
+	Error += test_log<glm::quat, glm::vec3>();
+	Error += test_log<glm::lowp_quat, glm::lowp_vec3>();
+	Error += test_log<glm::mediump_quat, glm::mediump_vec3>();
+	Error += test_log<glm::highp_quat, glm::highp_vec3>();
+	
+	Error += test_log<glm::dquat, glm::dvec3>();
+	Error += test_log<glm::lowp_dquat, glm::lowp_dvec3>();
+	Error += test_log<glm::mediump_dquat, glm::mediump_dvec3>();
+	Error += test_log<glm::highp_dquat, glm::highp_dvec3>();
+
+	Error += test_pow<glm::quat, glm::vec3>();
+	Error += test_pow<glm::lowp_quat, glm::lowp_vec3>();
+	Error += test_pow<glm::mediump_quat, glm::mediump_vec3>();
+	Error += test_pow<glm::highp_quat, glm::highp_vec3>();
+	
+	Error += test_pow<glm::dquat, glm::dvec3>();
+	Error += test_pow<glm::lowp_dquat, glm::lowp_dvec3>();
+	Error += test_pow<glm::mediump_dquat, glm::mediump_dvec3>();
+	Error += test_pow<glm::highp_dquat, glm::highp_dvec3>();
+	
+	return Error;
+}

+ 34 - 0
test/ext/ext_quaternion_transform.cpp

@@ -3,9 +3,43 @@
 #include <glm/ext/vector_relational.hpp>
 #include <glm/ext/scalar_constants.hpp>
 
+#define GLM_ENABLE_EXPERIMENTAL
+#include <glm/gtx/quaternion.hpp>
+
+static int test_lookAt()
+{
+	int Error(0);
+
+	glm::vec3 eye(0.0f);
+	glm::vec3 center(1.1f, -2.0f, 3.1416f);
+	glm::vec3 up(-0.17f, 7.23f, -1.744f);
+
+	glm::quat test_quat = glm::quatLookAt(glm::normalize(center - eye), up);
+	glm::quat test_mat = glm::conjugate(glm::quat_cast(glm::lookAt(eye, center, up)));
+
+	Error += static_cast<int>(glm::abs(glm::length(test_quat) - 1.0f) > glm::epsilon<float>());
+	Error += static_cast<int>(glm::min(glm::length(test_quat + (-test_mat)), glm::length(test_quat + test_mat)) > glm::epsilon<float>());
+
+	// Test left-handed implementation
+	glm::quat test_quatLH = glm::quatLookAtLH(glm::normalize(center - eye), up);
+	glm::quat test_matLH = glm::conjugate(glm::quat_cast(glm::lookAtLH(eye, center, up)));
+	Error += static_cast<int>(glm::abs(glm::length(test_quatLH) - 1.0f) > glm::epsilon<float>());
+	Error += static_cast<int>(glm::min(glm::length(test_quatLH - test_matLH), glm::length(test_quatLH + test_matLH)) > glm::epsilon<float>());
+ 
+	// Test right-handed implementation
+	glm::quat test_quatRH = glm::quatLookAtRH(glm::normalize(center - eye), up);
+	glm::quat test_matRH = glm::conjugate(glm::quat_cast(glm::lookAtRH(eye, center, up)));
+	Error += static_cast<int>(glm::abs(glm::length(test_quatRH) - 1.0f) > glm::epsilon<float>());
+	Error += static_cast<int>(glm::min(glm::length(test_quatRH - test_matRH), glm::length(test_quatRH + test_matRH)) > glm::epsilon<float>());
+
+	return Error;
+}
+
 int main()
 {
 	int Error = 0;
 
+	Error += test_lookAt();
+
 	return Error;
 }

+ 204 - 0
test/ext/ext_scalar_common.cpp

@@ -0,0 +1,204 @@
+#include <glm/ext/scalar_common.hpp>
+#include <glm/ext/scalar_constants.hpp>
+#include <glm/ext/scalar_relational.hpp>
+#include <glm/common.hpp>
+#include <algorithm>
+
+template <typename T>
+static int test_min()
+{
+	int Error = 0;
+
+	T const N = static_cast<T>(0);
+	T const B = static_cast<T>(1);
+	Error += glm::equal(glm::min(N, B), N, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::min(B, N), N, glm::epsilon<T>()) ? 0 : 1;
+
+	T const C = static_cast<T>(2);
+	Error += glm::equal(glm::min(N, B, C), N, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::min(B, N, C), N, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::min(C, N, B), N, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::min(C, B, N), N, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::min(B, C, N), N, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::min(N, C, B), N, glm::epsilon<T>()) ? 0 : 1;
+
+	T const D = static_cast<T>(3);
+	Error += glm::equal(glm::min(D, N, B, C), N, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::min(B, D, N, C), N, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::min(C, N, D, B), N, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::min(C, B, D, N), N, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::min(B, C, N, D), N, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::min(N, C, B, D), N, glm::epsilon<T>()) ? 0 : 1;
+
+	return Error;
+}
+
+template <typename T>
+static int test_min_nan()
+{
+	int Error = 0;
+
+	T const A = static_cast<T>(0);
+	T const B = static_cast<T>(1);
+	T const N = A / A;
+	Error += glm::isnan(glm::min(N, B)) ? 0 : 1;
+	Error += !glm::isnan(glm::min(B, N)) ? 0 : 1;
+
+	T const C = static_cast<T>(2);
+	Error += glm::isnan(glm::min(N, B, C)) ? 0 : 1;
+	Error += !glm::isnan(glm::min(B, N, C)) ? 0 : 1;
+	Error += !glm::isnan(glm::min(C, N, B)) ? 0 : 1;
+	Error += !glm::isnan(glm::min(C, B, N)) ? 0 : 1;
+	Error += !glm::isnan(glm::min(B, C, N)) ? 0 : 1;
+	Error += glm::isnan(glm::min(N, C, B)) ? 0 : 1;
+
+	T const D = static_cast<T>(3);
+	Error += !glm::isnan(glm::min(D, N, B, C)) ? 0 : 1;
+	Error += !glm::isnan(glm::min(B, D, N, C)) ? 0 : 1;
+	Error += !glm::isnan(glm::min(C, N, D, B)) ? 0 : 1;
+	Error += !glm::isnan(glm::min(C, B, D, N)) ? 0 : 1;
+	Error += !glm::isnan(glm::min(B, C, N, D)) ? 0 : 1;
+	Error += glm::isnan(glm::min(N, C, B, D)) ? 0 : 1;
+
+	return Error;
+}
+
+template <typename T>
+static int test_max()
+{
+	int Error = 0;
+
+	T const N = static_cast<T>(0);
+	T const B = static_cast<T>(1);
+	Error += glm::equal(glm::max(N, B), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::max(B, N), B, glm::epsilon<T>()) ? 0 : 1;
+
+	T const C = static_cast<T>(2);
+	Error += glm::equal(glm::max(N, B, C), C, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::max(B, N, C), C, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::max(C, N, B), C, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::max(C, B, N), C, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::max(B, C, N), C, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::max(N, C, B), C, glm::epsilon<T>()) ? 0 : 1;
+
+	T const D = static_cast<T>(3);
+	Error += glm::equal(glm::max(D, N, B, C), D, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::max(B, D, N, C), D, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::max(C, N, D, B), D, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::max(C, B, D, N), D, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::max(B, C, N, D), D, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::max(N, C, B, D), D, glm::epsilon<T>()) ? 0 : 1;
+
+	return Error;
+}
+
+template <typename T>
+static int test_max_nan()
+{
+	int Error = 0;
+
+	T const A = static_cast<T>(0);
+	T const B = static_cast<T>(1);
+	T const N = A / A;
+	Error += glm::isnan(glm::max(N, B)) ? 0 : 1;
+	Error += !glm::isnan(glm::max(B, N)) ? 0 : 1;
+
+	T const C = static_cast<T>(2);
+	Error += glm::isnan(glm::max(N, B, C)) ? 0 : 1;
+	Error += !glm::isnan(glm::max(B, N, C)) ? 0 : 1;
+	Error += !glm::isnan(glm::max(C, N, B)) ? 0 : 1;
+	Error += !glm::isnan(glm::max(C, B, N)) ? 0 : 1;
+	Error += !glm::isnan(glm::max(B, C, N)) ? 0 : 1;
+	Error += glm::isnan(glm::max(N, C, B)) ? 0 : 1;
+
+	T const D = static_cast<T>(3);
+	Error += !glm::isnan(glm::max(D, N, B, C)) ? 0 : 1;
+	Error += !glm::isnan(glm::max(B, D, N, C)) ? 0 : 1;
+	Error += !glm::isnan(glm::max(C, N, D, B)) ? 0 : 1;
+	Error += !glm::isnan(glm::max(C, B, D, N)) ? 0 : 1;
+	Error += !glm::isnan(glm::max(B, C, N, D)) ? 0 : 1;
+	Error += glm::isnan(glm::max(N, C, B, D)) ? 0 : 1;
+
+	return Error;
+}
+
+template <typename T>
+static int test_fmin()
+{
+	int Error = 0;
+
+	T const A = static_cast<T>(0);
+	T const B = static_cast<T>(1);
+	Error += glm::equal(glm::fmin(A / A, B), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmin(B, A / A), B, glm::epsilon<T>()) ? 0 : 1;
+
+	T const C = static_cast<T>(2);
+	Error += glm::equal(glm::fmin(A / A, B, C), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmin(B, A / A, C), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmin(C, A / A, B), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmin(C, B, A / A), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmin(B, C, A / A), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmin(A / A, C, B), B, glm::epsilon<T>()) ? 0 : 1;
+
+	T const D = static_cast<T>(3);
+	Error += glm::equal(glm::fmin(D, A / A, B, C), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmin(B, D, A / A, C), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmin(C, A / A, D, B), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmin(C, B, D, A / A), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmin(B, C, A / A, D), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmin(A / A, C, B, D), B, glm::epsilon<T>()) ? 0 : 1;
+
+	return Error;
+}
+
+template <typename T>
+static int test_fmax()
+{
+	int Error = 0;
+
+	T const A = static_cast<T>(0);
+	T const B = static_cast<T>(1);
+	Error += glm::equal(glm::fmax(A / A, B), B, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmax(B, A / A), B, glm::epsilon<T>()) ? 0 : 1;
+
+	T const C = static_cast<T>(2);
+	Error += glm::equal(glm::fmax(A / A, B, C), C, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmax(B, A / A, C), C, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmax(C, A / A, B), C, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmax(C, B, A / A), C, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmax(B, C, A / A), C, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmax(A / A, C, B), C, glm::epsilon<T>()) ? 0 : 1;
+
+	T const D = static_cast<T>(3);
+	Error += glm::equal(glm::fmax(D, A / A, B, C), D, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmax(B, D, A / A, C), D, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmax(C, A / A, D, B), D, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmax(C, B, D, A / A), D, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmax(B, C, A / A, D), D, glm::epsilon<T>()) ? 0 : 1;
+	Error += glm::equal(glm::fmax(A / A, C, B, D), D, glm::epsilon<T>()) ? 0 : 1;
+
+	return Error;
+}
+
+int main()
+{
+	int Error = 0;
+
+	Error += test_min<float>();
+	Error += test_min<double>();
+	Error += test_min_nan<float>();
+	Error += test_min_nan<double>();
+
+	Error += test_max<float>();
+	Error += test_max<double>();
+	Error += test_max_nan<float>();
+	Error += test_max_nan<double>();
+
+	Error += test_fmin<float>();
+	Error += test_fmin<double>();
+
+	Error += test_fmax<float>();
+	Error += test_fmax<double>();
+
+	return Error;
+}

+ 24 - 0
test/ext/ext_vector_common.cpp

@@ -0,0 +1,24 @@
+#include <glm/ext/vector_common.hpp>
+#include <glm/ext/vector_float1.hpp>
+#include <glm/ext/vector_float1_precision.hpp>
+#include <glm/ext/vector_float2.hpp>
+#include <glm/ext/vector_float2_precision.hpp>
+#include <glm/ext/vector_float3.hpp>
+#include <glm/ext/vector_float3_precision.hpp>
+#include <glm/ext/vector_float4.hpp>
+#include <glm/ext/vector_float4_precision.hpp>
+#include <glm/ext/vector_double1.hpp>
+#include <glm/ext/vector_double1_precision.hpp>
+#include <glm/ext/vector_double2.hpp>
+#include <glm/ext/vector_double2_precision.hpp>
+#include <glm/ext/vector_double3.hpp>
+#include <glm/ext/vector_double3_precision.hpp>
+#include <glm/ext/vector_double4.hpp>
+#include <glm/ext/vector_double4_precision.hpp>
+
+int main()
+{
+	int Error = 0;
+
+	return Error;
+}

+ 0 - 30
test/gtx/gtx_quaternion.cpp

@@ -93,35 +93,6 @@ int test_log()
 	return Error;
 }
 
-int test_quat_lookAt()
-{
-	int Error(0);
-
-	glm::vec3 eye(0.0f);
-	glm::vec3 center(1.1f, -2.0f, 3.1416f);
-	glm::vec3 up(-0.17f, 7.23f, -1.744f);
-
-	glm::quat test_quat = glm::quatLookAt(glm::normalize(center - eye), up);
-	glm::quat test_mat = glm::conjugate(glm::quat_cast(glm::lookAt(eye, center, up)));
-
-	Error += static_cast<int>(glm::abs(glm::length(test_quat) - 1.0f) > glm::epsilon<float>());
-	Error += static_cast<int>(glm::min(glm::length(test_quat + (-test_mat)), glm::length(test_quat + test_mat)) > glm::epsilon<float>());
-
-	// Test left-handed implementation
-	glm::quat test_quatLH = glm::quatLookAtLH(glm::normalize(center - eye), up);
-	glm::quat test_matLH = glm::conjugate(glm::quat_cast(glm::lookAtLH(eye, center, up)));
-	Error += static_cast<int>(glm::abs(glm::length(test_quatLH) - 1.0f) > glm::epsilon<float>());
-	Error += static_cast<int>(glm::min(glm::length(test_quatLH - test_matLH), glm::length(test_quatLH + test_matLH)) > glm::epsilon<float>());
- 
-	// Test right-handed implementation
-	glm::quat test_quatRH = glm::quatLookAtRH(glm::normalize(center - eye), up);
-	glm::quat test_matRH = glm::conjugate(glm::quat_cast(glm::lookAtRH(eye, center, up)));
-	Error += static_cast<int>(glm::abs(glm::length(test_quatRH) - 1.0f) > glm::epsilon<float>());
-	Error += static_cast<int>(glm::min(glm::length(test_quatRH - test_matRH), glm::length(test_quatRH + test_matRH)) > glm::epsilon<float>());
-
-	return Error;
-}
-
 int main()
 {
 	int Error = 0;
@@ -131,7 +102,6 @@ int main()
 	Error += test_orientation();
 	Error += test_quat_fastMix();
 	Error += test_quat_shortMix();
-	Error += test_quat_lookAt();
 
 	return Error;
 }