diff --git a/SDK/include/NDK/Algorithm.hpp b/SDK/include/NDK/Algorithm.hpp index 61582012d..da75f4ff7 100644 --- a/SDK/include/NDK/Algorithm.hpp +++ b/SDK/include/NDK/Algorithm.hpp @@ -20,6 +20,6 @@ namespace Ndk template bool IsSystem(S& system); } -#include +#include #endif // NDK_ALGORITHM_HPP diff --git a/SDK/include/NDK/Component.inl b/SDK/include/NDK/Component.inl index b016fd8be..e39091224 100644 --- a/SDK/include/NDK/Component.inl +++ b/SDK/include/NDK/Component.inl @@ -2,7 +2,7 @@ // This file is part of the "Nazara Development Kit" // For conditions of distribution and use, see copyright notice in Prerequesites.hpp -#include +#include #include namespace Ndk diff --git a/SDK/include/NDK/Components/CameraComponent.hpp b/SDK/include/NDK/Components/CameraComponent.hpp index 4eea340e8..f96d32da4 100644 --- a/SDK/include/NDK/Components/CameraComponent.hpp +++ b/SDK/include/NDK/Components/CameraComponent.hpp @@ -33,20 +33,20 @@ namespace Ndk inline void EnsureViewMatrixUpdate() const; inline void EnsureViewportUpdate() const; - inline float GetAspectRatio() const; - inline Nz::Vector3f GetEyePosition() const; - inline Nz::Vector3f GetForward() const; + inline float GetAspectRatio() const override; + inline Nz::Vector3f GetEyePosition() const override; + inline Nz::Vector3f GetForward() const override; inline float GetFOV() const; - inline const Nz::Frustumf& GetFrustum() const; + inline const Nz::Frustumf& GetFrustum() const override; inline unsigned int GetLayer() const; - inline const Nz::Matrix4f& GetProjectionMatrix() const; + inline const Nz::Matrix4f& GetProjectionMatrix() const override; inline Nz::ProjectionType GetProjectionType() const; - inline const Nz::RenderTarget* GetTarget() const; + inline const Nz::RenderTarget* GetTarget() const override; inline const Nz::Rectf& GetTargetRegion() const; - inline const Nz::Matrix4f& GetViewMatrix() const; - inline const Nz::Recti& GetViewport() const; - inline float GetZFar() const; - inline float GetZNear() const; + inline const Nz::Matrix4f& GetViewMatrix() const override; + inline const Nz::Recti& GetViewport() const override; + inline float GetZFar() const override; + inline float GetZNear() const override; inline void SetFOV(float fov); inline void SetLayer(unsigned int layer); diff --git a/SDK/include/NDK/System.inl b/SDK/include/NDK/System.inl index c7bfdf401..9b382d924 100644 --- a/SDK/include/NDK/System.inl +++ b/SDK/include/NDK/System.inl @@ -2,7 +2,7 @@ // This file is part of the "Nazara Development Kit" // For conditions of distribution and use, see copyright notice in Prerequesites.hpp -#include +#include #include namespace Ndk diff --git a/examples/DopplerEffect/main.cpp b/examples/DopplerEffect/main.cpp index 42d838356..b6d2d034b 100644 --- a/examples/DopplerEffect/main.cpp +++ b/examples/DopplerEffect/main.cpp @@ -13,12 +13,13 @@ #include // Thread::Sleep #include #include +#include #include int main() { - // NzKeyboard ne nécessite pas l'initialisation du module Utilitaire - Nz::Initializer audio; + // NzKeyboard nécessite l'initialisation du module Utilitaire + Nz::Initializer audio; if (!audio) { std::cout << "Failed to initialize audio module" << std::endl; diff --git a/include/Nazara/Core/Hash/Whirlpool.hpp b/include/Nazara/Core/Hash/Whirlpool.hpp index 600e23b25..f7922254d 100644 --- a/include/Nazara/Core/Hash/Whirlpool.hpp +++ b/include/Nazara/Core/Hash/Whirlpool.hpp @@ -23,8 +23,8 @@ namespace Nz void Begin() override; ByteArray End() override; - std::size_t GetDigestLength() const; - const char* GetHashName() const; + std::size_t GetDigestLength() const override; + const char* GetHashName() const override; private: HashWhirlpool_state* m_state; diff --git a/include/Nazara/Graphics/DeferredRenderQueue.hpp b/include/Nazara/Graphics/DeferredRenderQueue.hpp index 76bff6926..fecd507be 100644 --- a/include/Nazara/Graphics/DeferredRenderQueue.hpp +++ b/include/Nazara/Graphics/DeferredRenderQueue.hpp @@ -42,7 +42,7 @@ namespace Nz void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override; void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) override; - void Clear(bool fully = false); + void Clear(bool fully = false) override; struct MeshDataComparator { diff --git a/include/Nazara/Graphics/ForwardRenderQueue.hpp b/include/Nazara/Graphics/ForwardRenderQueue.hpp index 3a5d3ef33..9a17f5d2f 100644 --- a/include/Nazara/Graphics/ForwardRenderQueue.hpp +++ b/include/Nazara/Graphics/ForwardRenderQueue.hpp @@ -44,7 +44,7 @@ namespace Nz void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override; void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) override; - void Clear(bool fully = false); + void Clear(bool fully = false) override; void Sort(const AbstractViewer* viewer); diff --git a/include/Nazara/Graphics/GuillotineTextureAtlas.hpp b/include/Nazara/Graphics/GuillotineTextureAtlas.hpp index b40e4f610..42449712c 100644 --- a/include/Nazara/Graphics/GuillotineTextureAtlas.hpp +++ b/include/Nazara/Graphics/GuillotineTextureAtlas.hpp @@ -19,7 +19,7 @@ namespace Nz GuillotineTextureAtlas() = default; ~GuillotineTextureAtlas() = default; - UInt32 GetStorage() const; + UInt32 GetStorage() const override; private: AbstractImage* ResizeImage(AbstractImage* oldImage, const Vector2ui& size) const override; diff --git a/include/Nazara/Graphics/ParticleSystem.hpp b/include/Nazara/Graphics/ParticleSystem.hpp index 34dcbb137..76b834f6e 100644 --- a/include/Nazara/Graphics/ParticleSystem.hpp +++ b/include/Nazara/Graphics/ParticleSystem.hpp @@ -33,7 +33,7 @@ namespace Nz void AddController(ParticleControllerRef controller); void AddEmitter(ParticleEmitter* emitter); void AddGenerator(ParticleGeneratorRef generator); - void AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix) const; + void AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix) const override; void ApplyControllers(ParticleMapper& mapper, unsigned int particleCount, float elapsedTime); diff --git a/include/Nazara/Graphics/SkeletalModel.hpp b/include/Nazara/Graphics/SkeletalModel.hpp index 059d6b835..6ae25923e 100644 --- a/include/Nazara/Graphics/SkeletalModel.hpp +++ b/include/Nazara/Graphics/SkeletalModel.hpp @@ -54,7 +54,7 @@ namespace Nz bool HasAnimation() const; - bool IsAnimated() const; + bool IsAnimated() const override; bool IsAnimationEnabled() const; bool LoadFromFile(const String& filePath, const SkeletalModelParameters& params = SkeletalModelParameters()); diff --git a/include/Nazara/Math/Algorithm.hpp b/include/Nazara/Math/Algorithm.hpp index 841c3569a..c7d4dd024 100644 --- a/include/Nazara/Math/Algorithm.hpp +++ b/include/Nazara/Math/Algorithm.hpp @@ -30,32 +30,32 @@ namespace Nz { - template T Approach(T value, T objective, T increment); + template constexpr T Approach(T value, T objective, T increment); template constexpr T Clamp(T value, T min, T max); - template T CountBits(T value); + template constexpr T CountBits(T value); template constexpr T FromDegrees(T degrees); template constexpr T FromRadians(T radians); template constexpr T DegreeToRadian(T degrees); - template T GetNearestPowerOfTwo(T number); - unsigned int GetNumberLength(signed char number); - unsigned int GetNumberLength(unsigned char number); + template constexpr T GetNearestPowerOfTwo(T number); + constexpr unsigned int GetNumberLength(signed char number); + constexpr unsigned int GetNumberLength(unsigned char number); unsigned int GetNumberLength(int number); - unsigned int GetNumberLength(unsigned int number); + constexpr unsigned int GetNumberLength(unsigned int number); unsigned int GetNumberLength(long long number); - unsigned int GetNumberLength(unsigned long long number); + constexpr unsigned int GetNumberLength(unsigned long long number); unsigned int GetNumberLength(float number, UInt8 precision = NAZARA_CORE_DECIMAL_DIGITS); unsigned int GetNumberLength(double number, UInt8 precision = NAZARA_CORE_DECIMAL_DIGITS); unsigned int GetNumberLength(long double number, UInt8 precision = NAZARA_CORE_DECIMAL_DIGITS); - template unsigned int IntegralLog2(T number); - template unsigned int IntegralLog2Pot(T pot); - unsigned int IntegralPow(unsigned int base, unsigned int exponent); - template T Lerp(T from, T to, T2 interpolation); - template T MultiplyAdd(T x, T y, T z); - template T NormalizeAngle(T angle); - template bool NumberEquals(T a, T b); - template bool NumberEquals(T a, T b, T maxDifference); + template constexpr unsigned int IntegralLog2(T number); + template constexpr unsigned int IntegralLog2Pot(T pot); + constexpr unsigned int IntegralPow(unsigned int base, unsigned int exponent); + template constexpr T Lerp(const T& from, const T& to, const T2& interpolation); + template constexpr T MultiplyAdd(T x, T y, T z); + template constexpr T NormalizeAngle(T angle); + template constexpr bool NumberEquals(T a, T b); + template constexpr bool NumberEquals(T a, T b, T maxDifference); String NumberToString(long long number, UInt8 radix = 10); - template T RadianToDegree(T radians); + template constexpr T RadianToDegree(T radians); long long StringToNumber(String str, UInt8 radix = 10, bool* ok = nullptr); template constexpr T ToDegrees(T angle); template constexpr T ToRadians(T angle); diff --git a/include/Nazara/Math/Algorithm.inl b/include/Nazara/Math/Algorithm.inl index 1a4fceded..c42a1b8b5 100644 --- a/include/Nazara/Math/Algorithm.inl +++ b/include/Nazara/Math/Algorithm.inl @@ -98,10 +98,18 @@ namespace Nz } } + /*! + * \brief Approaches the objective, beginning with value and with increment + * \return The nearest value of the objective you can get with the value and the increment for one step + * + * \param value Initial value + * \param objective Target value + * \parma increment One step value + */ + template - T Approach(T value, T objective, T increment) + constexpr T Approach(T value, T objective, T increment) { - ///TODO: Marquer comme constexpr en C++14 if (value < objective) return std::min(value + increment, objective); else if (value > objective) @@ -110,14 +118,30 @@ namespace Nz return value; } + /*! + * \brief Clamps value between min and max and returns the expected value + * \return If value is not in the interval of min..max, value obtained is the nearest limit of this interval + * + * \param value Value to clamp + * \param min Minimum of the interval + * \param max Maximum of the interval + */ + template constexpr T Clamp(T value, T min, T max) { return std::max(std::min(value, max), min); } + /*! + * \brief Gets number of bits set in the number + * \return The number of bits set to 1 + * + * \param value The value to count bits + */ + template - T CountBits(T value) + constexpr T CountBits(T value) { // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan unsigned int count = 0; @@ -130,12 +154,26 @@ namespace Nz return count; } + /*! + * \brief Converts degree to radian + * \return The representation in radian of the angle in degree (0..2*pi) + * + * \param degrees Angle in degree (this is expected between 0..360) + */ + template constexpr T DegreeToRadian(T degrees) { return degrees * T(M_PI/180.0); } + /*! + * \brief Gets the unit from degree and convert it according to NAZARA_MATH_ANGLE_RADIAN + * \return Express the degrees + * + * \param degrees Convert degree to NAZARA_MATH_ANGLE_RADIAN unit + */ + template constexpr T FromDegrees(T degrees) { @@ -146,6 +184,13 @@ namespace Nz #endif } + /*! + * \brief Gets the unit from radian and convert it according to NAZARA_MATH_ANGLE_RADIAN + * \return Express the radians + * + * \param radians Convert radian to NAZARA_MATH_ANGLE_RADIAN unit + */ + template constexpr T FromRadians(T radians) { @@ -156,22 +201,33 @@ namespace Nz #endif } + /*! + * \brief Gets the nearest power of two for the number + * \return First power of two containing the number + * + * \param number Number to get nearest power + */ + template - T GetNearestPowerOfTwo(T number) + constexpr T GetNearestPowerOfTwo(T number) { - ///TODO: Marquer comme constexpr en C++14 T x = 1; - // Tant que x est plus petit que n, on décale ses bits vers la gauche, ce qui revient à multiplier par deux while (x < number) - x <<= 1; + x <<= 1; // We multiply by 2 return x; } - inline unsigned int GetNumberLength(signed char number) + /*! + * \brief Gets the number of digits to represent the number in base 10 + * \return Number of digits + * + * \param number Number to get number of digits + */ + + constexpr unsigned int GetNumberLength(signed char number) { - ///TODO: Marquer comme constexpr en C++14 - // Le standard définit le char comme étant codé sur un octet + // Char is expected to be 1 byte static_assert(sizeof(number) == 1, "Signed char must be one byte-sized"); if (number >= 100) @@ -188,10 +244,16 @@ namespace Nz return 4; } - inline unsigned int GetNumberLength(unsigned char number) + /*! + * \brief Gets the number of digits to represent the number in base 10 + * \return Number of digits + * + * \param number Number to get number of digits + */ + + constexpr unsigned int GetNumberLength(unsigned char number) { - ///TODO: Marquer comme constexpr en C++14 - // Le standard définit le char comme étant codé sur un octet + // Char is expected to be 1 byte static_assert(sizeof(number) == 1, "Unsigned char must be one byte-sized"); if (number >= 100) @@ -202,6 +264,13 @@ namespace Nz return 1; } + /*! + * \brief Gets the number of digits to represent the number in base 10 + * \return Number of digits + * + * \param number Number to get number of digits + */ + inline unsigned int GetNumberLength(int number) { if (number == 0) @@ -210,7 +279,14 @@ namespace Nz return static_cast(std::log10(std::abs(number))) + (number < 0 ? 2 : 1); } - inline unsigned int GetNumberLength(unsigned int number) + /*! + * \brief Gets the number of digits to represent the number in base 10 + * \return Number of digits + * + * \param number Number to get number of digits + */ + + constexpr unsigned int GetNumberLength(unsigned int number) { if (number == 0) return 1; @@ -218,6 +294,13 @@ namespace Nz return static_cast(std::log10(number))+1; } + /*! + * \brief Gets the number of digits to represent the number in base 10 + * \return Number of digits + * + * \param number Number to get number of digits + */ + inline unsigned int GetNumberLength(long long number) { if (number == 0) @@ -226,7 +309,14 @@ namespace Nz return static_cast(std::log10(std::abs(number))) + (number < 0 ? 2 : 1); } - inline unsigned int GetNumberLength(unsigned long long number) + /*! + * \brief Gets the number of digits to represent the number in base 10 + * \return Number of digits + * + * \param number Number to get number of digits + */ + + constexpr unsigned int GetNumberLength(unsigned long long number) { if (number == 0) return 1; @@ -234,40 +324,90 @@ namespace Nz return static_cast(std::log10(number)) + 1; } + /*! + * \brief Gets the number of digits to represent the number in base 10 + * \return Number of digits + 1 for the dot + * + * \param number Number to get number of digits + * \param precision Number of digit after the dot + */ + inline unsigned int GetNumberLength(float number, UInt8 precision) { - // L'imprécision des flottants nécessite un cast (log10(9.99999) = 0.99999) - return GetNumberLength(static_cast(number)) + precision + 1; // Plus un pour le point + // The imprecision of floats need a cast (log10(9.99999) = 0.99999) + return GetNumberLength(static_cast(number)) + precision + 1; // Plus one for the dot } + /*! + * \brief Gets the number of digits to represent the number in base 10 + * \return Number of digits + 1 for the dot + * + * \param number Number to get number of digits + * \param precision Number of digit after the dot + */ + inline unsigned int GetNumberLength(double number, UInt8 precision) { - // L'imprécision des flottants nécessite un cast (log10(9.99999) = 0.99999) - return GetNumberLength(static_cast(number)) + precision + 1; // Plus un pour le point + // The imprecision of floats need a cast (log10(9.99999) = 0.99999) + return GetNumberLength(static_cast(number)) + precision + 1; // Plus one for the dot } + /*! + * \brief Gets the number of digits to represent the number in base 10 + * \return Number of digits + 1 for the dot + * + * \param number Number to get number of digits + * \param precision Number of digit after the dot + */ + inline unsigned int GetNumberLength(long double number, UInt8 precision) { - // L'imprécision des flottants nécessite un cast (log10(9.99999) = 0.99999) - return GetNumberLength(static_cast(number)) + precision + 1; // Plus un pour le point + // The imprecision of floats need a cast (log10(9.99999) = 0.99999) + return GetNumberLength(static_cast(number)) + precision + 1; // Plus one for the dot } + /*! + * \brief Gets the log in base 2 of integral number + * \return Log of the number (floor) + * + * \param number To get log in base 2 + * + * \remark If number is 0, 0 is returned + */ + template - unsigned int IntegralLog2(T number) + constexpr unsigned int IntegralLog2(T number) { - // Proxy nécessaire pour éviter un problème de surcharge + // Proxy needed to avoid an overload problem return Detail::IntegralLog2(number); } + /*! + * \brief Gets the log in base 2 of integral number, only works for power of two ! + * \return Log of the number + * + * \param number To get log in base 2 + * + * \remark Only works for power of two + * \remark If number is 0, 0 is returned + */ + template - unsigned int IntegralLog2Pot(T pot) + constexpr unsigned int IntegralLog2Pot(T pot) { return Detail::IntegralLog2Pot(pot); } - inline unsigned int IntegralPow(unsigned int base, unsigned int exponent) + /*! + * \brief Gets the power of integrals + * \return base^exponent for integral + * + * \param base Base of the exponentation + * \parma exponent Power for the base + */ + + constexpr unsigned int IntegralPow(unsigned int base, unsigned int exponent) { - ///TODO: Marquer comme constexpr en C++14 unsigned int r = 1; for (unsigned int i = 0; i < exponent; ++i) r *= base; @@ -275,8 +415,22 @@ namespace Nz return r; } + /*! + * \brief Interpolates the value to other one with a factor of interpolation + * \return A new value which is the interpolation of two values + * + * \param from Initial value + * \param to Target value + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * \remark With NAZARA_DEBUG, a NazaraWarning is produced + * + * \see Lerp + */ + template - T Lerp(T from, T to, T2 interpolation) + constexpr T Lerp(const T& from, const T& to, const T2& interpolation) { #ifdef NAZARA_DEBUG if (interpolation < T2(0.0) || interpolation > T2(1.0)) @@ -286,15 +440,26 @@ namespace Nz return from + interpolation * (to - from); } + /*! + * \brief Multiplies X and Y, then add Z + * \return The result of X * Y + Z + * + * \param x is X + * \param y is Y + * \param z is Z + * + * \remark This function is meant to use a special instruction in CPU + */ + template - T MultiplyAdd(T x, T y, T z) + constexpr T MultiplyAdd(T x, T y, T z) { - return x*y + z; + return x * y + z; } #ifdef FP_FAST_FMAF template<> - inline float MultiplyAdd(float x, float y, float z) + constexpr float MultiplyAdd(float x, float y, float z) { return std::fmaf(x, y, z); } @@ -302,7 +467,7 @@ namespace Nz #ifdef FP_FAST_FMA template<> - inline double MultiplyAdd(double x, double y, double z) + constexpr double MultiplyAdd(double x, double y, double z) { return std::fma(x, y, z); } @@ -310,14 +475,21 @@ namespace Nz #ifdef FP_FAST_FMAL template<> - inline long double MultiplyAdd(long double x, long double y, long double z) + constexpr long double MultiplyAdd(long double x, long double y, long double z) { return std::fmal(x, y, z); } #endif + /*! + * \brief Normalizes the angle + * \return Normalized value between 0..2*(pi if radian or 180 if degrees) + * + * \param angle Angle to normalize + */ + template - T NormalizeAngle(T angle) + constexpr T NormalizeAngle(T angle) { #if NAZARA_MATH_ANGLE_RADIAN const T limit = T(M_PI); @@ -333,14 +505,31 @@ namespace Nz return angle - limit; } + /*! + * \brief Checks whether two numbers are equal + * \return true if they are equal within a certain epsilon + * + * \param a First value + * \param b Second value + */ + template - bool NumberEquals(T a, T b) + constexpr bool NumberEquals(T a, T b) { return NumberEquals(a, b, std::numeric_limits::epsilon()); } + /*! + * \brief Checks whether two numbers are equal + * \return true if they are equal within the max difference + * + * \param a First value + * \param b Second value + * \param maxDifference Epsilon of comparison (expected to be positive) + */ + template - bool NumberEquals(T a, T b, T maxDifference) + constexpr bool NumberEquals(T a, T b, T maxDifference) { if (b > a) std::swap(a, b); @@ -349,6 +538,17 @@ namespace Nz return diff <= maxDifference; } + /*! + * \brief Converts the number to String + * \return String representation of the number + * + * \param number Number to represent + * \param radix Base of the number + * + * \remark radix is meant to be between 2 and 36, other values are potentially undefined behavior + * \remark With NAZARA_MATH_SAFE, a NazaraError is produced and String() is returned + */ + inline String NumberToString(long long number, UInt8 radix) { #if NAZARA_MATH_SAFE @@ -389,12 +589,31 @@ namespace Nz return str.Reverse(); } + /*! + * \brief Converts radian to degree + * \return The representation in degree of the angle in radian (0..360) + * + * \param radians Angle in radian (this is expected between 0..2*pi) + */ + template - T RadianToDegree(T radians) + constexpr T RadianToDegree(T radians) { return radians * T(180.0/M_PI); } + /*! + * \brief Converts the string to number + * \return Number which is represented by the string + * + * \param str String representation + * \param radix Base of the number + * \param ok Optional argument to know if convertion is correct + * + * \remark radix is meant to be between 2 and 36, other values are potentially undefined behavior + * \remark With NAZARA_MATH_SAFE, a NazaraError is produced and 0 is returned + */ + inline long long StringToNumber(String str, UInt8 radix, bool* ok) { #if NAZARA_MATH_SAFE @@ -444,6 +663,13 @@ namespace Nz return (negative) ? -static_cast(total) : total; } + /*! + * \brief Gets the degree from unit and convert it according to NAZARA_MATH_ANGLE_RADIAN + * \return Express in degrees + * + * \param angle Convert degree from NAZARA_MATH_ANGLE_RADIAN unit to degrees + */ + template constexpr T ToDegrees(T angle) { @@ -454,6 +680,13 @@ namespace Nz #endif } + /*! + * \brief Gets the radian from unit and convert it according to NAZARA_MATH_ANGLE_RADIAN + * \return Express in radians + * + * \param angle Convert degree from NAZARA_MATH_ANGLE_RADIAN unit to radians + */ + template constexpr T ToRadians(T angle) { @@ -461,8 +694,8 @@ namespace Nz return angle; #else return DegreeToRadian(angle); + #endif } - #endif } #include diff --git a/include/Nazara/Math/BoundingVolume.inl b/include/Nazara/Math/BoundingVolume.inl index 13b41a63e..4cde59731 100644 --- a/include/Nazara/Math/BoundingVolume.inl +++ b/include/Nazara/Math/BoundingVolume.inl @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Mathematics module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -13,42 +13,108 @@ namespace Nz { + + /*! + * \class Nz::BoundingVolume + * \brief Math class that represents a bounding volume, a combination of a box and an oriented box + * + * \remark You need to call Update not to have undefined behaviour + */ + + /*! + * \brief Constructs a BoundingVolume object by default + * + * \remark extend is set to Extend_Null, aabb and obb are uninitialized + */ + template BoundingVolume::BoundingVolume() : extend(Extend_Null) { } + /*! + * \brief Constructs a BoundingVolume object from Extend + * \param Extend Extend of the volume part of enumeration Extend + * + * \remark Aabb and obb are uninitialized + */ + template BoundingVolume::BoundingVolume(Extend Extend) { Set(Extend); } + /*! + * \brief Constructs a BoundingVolume object from its position and sizes + * + * \param X X component of position + * \param Y Y component of position + * \param Z Z component of position + * \param Width Width of the box (following X) + * \param Height Height of the box (following Y) + * \param Depth Depth of the box (following Z) + * + * \remark Aabb is uninitialized + */ + template BoundingVolume::BoundingVolume(T X, T Y, T Z, T Width, T Height, T Depth) { Set(X, Y, Z, Width, Height, Depth); } + /*! + * \brief Constructs a BoundingVolume object from a box + * + * \param box Box object + * + * \remark Aabb is uninitialized + */ + template BoundingVolume::BoundingVolume(const Box& box) { Set(box); } + /*! + * \brief Constructs a BoundingVolume object from an oriented box + * + * \param orientedBox OrientedBox object + * + * \remark Aabb is uninitialized + */ + template BoundingVolume::BoundingVolume(const OrientedBox& orientedBox) { Set(orientedBox); } + /*! + * \brief Constructs a BoundingVolume object from two vectors representing point of the space + * (X, Y, Z) will be the components minimum of the two vectors and the (width, height, depth) will be the components maximum - minimum + * + * \param vec1 First point + * \param vec2 Second point + * + * \remark Aabb is uninitialized + */ + template BoundingVolume::BoundingVolume(const Vector3& vec1, const Vector3& vec2) { Set(vec1, vec2); } + /*! + * \brief Constructs a BoundingVolume object from another type of BoundingVolume + * + * \param volume BoundingVolume of type U to convert to type T + */ + template template BoundingVolume::BoundingVolume(const BoundingVolume& volume) @@ -56,24 +122,46 @@ namespace Nz Set(volume); } + /*! + * \brief Checks whether the volume is finite + * \return true if extend is Extend_Finite + */ + template bool BoundingVolume::IsFinite() const { return extend == Extend_Finite; } + /*! + * \brief Checks whether the volume is infinite + * \return true if extend is Extend_Infinite + */ + template bool BoundingVolume::IsInfinite() const { return extend == Extend_Infinite; } + /*! + * \brief Checks whether the volume is null + * \return true if extend is Extend_Null + */ + template bool BoundingVolume::IsNull() const { return extend == Extend_Null; } + /*! + * \brief Makes the bounding volume infinite + * \return A reference to this bounding volume with Extend_Infinite for extend + * + * \see Infinite + */ + template BoundingVolume& BoundingVolume::MakeInfinite() { @@ -82,6 +170,13 @@ namespace Nz return *this; } + /*! + * \brief Makes the bounding volume null + * \return A reference to this bounding volume with Extend_Null for extend + * + * \see Null + */ + template BoundingVolume& BoundingVolume::MakeNull() { @@ -90,6 +185,15 @@ namespace Nz return *this; } + /*! + * \brief Sets the extend of the bounding volume from Extend + * \return A reference to this bounding volume + * + * \param Extend New extend + * + * \remark This method is meant to be called with Extend_Infinite or Extend_Null + */ + template BoundingVolume& BoundingVolume::Set(Extend Extend) { @@ -98,6 +202,18 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the bounding volume + * \return A reference to this bounding volume + * + * \param X X position + * \param Y Y position + * \param Z Z position + * \param Width Width of the oriented box (following X) + * \param Height Height of the oriented box (following Y) + * \param Depth Depth of the oriented box (following Z) + */ + template BoundingVolume& BoundingVolume::Set(T X, T Y, T Z, T Width, T Height, T Depth) { @@ -107,15 +223,29 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the bounding volume from another bounding volume + * \return A reference to this bounding volume + * + * \param volume The other bounding volume + */ + template BoundingVolume& BoundingVolume::Set(const BoundingVolume& volume) { - obb.Set(volume.obb); // Seul l'OBB est importante pour la suite + obb.Set(volume.obb); // Only OBB is important for the moment extend = volume.extend; return *this; } + /*! + * \brief Sets the components of the bounding volume from a box + * \return A reference to this bounding volume + * + * \param box Box object + */ + template BoundingVolume& BoundingVolume::Set(const Box& box) { @@ -125,6 +255,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the bounding volume from an oriented box + * \return A reference to this bounding volume + * + * \param orientedBox OrientedBox object + */ + template BoundingVolume& BoundingVolume::Set(const OrientedBox& orientedBox) { @@ -134,6 +271,14 @@ namespace Nz return *this; } + /*! + * \brief Sets a BoundingVolume object from two vectors representing point of the space + * (X, Y, Z) will be the components minimum of the two vectors and the (width, height, depth) will be the components maximum - minimum + * + * \param vec1 First point + * \param vec2 Second point + */ + template BoundingVolume& BoundingVolume::Set(const Vector3& vec1, const Vector3& vec2) { @@ -143,6 +288,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the bounding volume from another type of BoundingVolume + * \return A reference to this bounding volume + * + * \param volume BoundingVolume of type U to convert its components + */ + template template BoundingVolume& BoundingVolume::Set(const BoundingVolume& volume) @@ -153,6 +305,13 @@ namespace Nz return *this; } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "BoundingVolume(localBox="")" if finite, or "BoundingVolume(Infinite)" or "BoundingVolume(Null)" + * + * \remark If enumeration is not defined in Extend, a NazaraError is thrown and "BoundingVolume(ERROR)" is returned + */ + template String BoundingVolume::ToString() const { @@ -173,6 +332,12 @@ namespace Nz return "BoundingVolume(ERROR)"; } + /*! + * \brief Updates the obb and the aabb of the bounding volume + * + * \param transformMatrix Matrix4 which represents the transformation to apply + */ + template void BoundingVolume::Update(const Matrix4& transformMatrix) { @@ -183,6 +348,12 @@ namespace Nz aabb.ExtendTo(obb(i)); } + /*! + * \brief Updates the obb and the aabb of the bounding volume + * + * \param translation Vector3 which represents the translation to apply + */ + template void BoundingVolume::Update(const Vector3& translation) { @@ -193,6 +364,13 @@ namespace Nz aabb.ExtendTo(obb(i)); } + /*! + * \brief Multiplies the lengths of the obb with the scalar + * \return A BoundingVolume where the position is the same and width, height and depth are the product of the old width, height and depth and the scalar + * + * \param scale The scalar to multiply width, height and depth with + */ + template BoundingVolume BoundingVolume::operator*(T scalar) const { @@ -202,6 +380,13 @@ namespace Nz return volume; } + /*! + * \brief Multiplies the lengths of this bounding volume with the scalar + * \return A reference to this bounding volume where lengths are the product of these lengths and the scalar + * + * \param scalar The scalar to multiply width, height and depth with + */ + template BoundingVolume& BoundingVolume::operator*=(T scalar) { @@ -210,6 +395,13 @@ namespace Nz return *this; } + /*! + * \brief Compares the bounding volume to other one + * \return true if the two bounding volumes are the same + * + * \param volume Other bounding volume to compare with + */ + template bool BoundingVolume::operator==(const BoundingVolume& volume) const { @@ -222,12 +414,26 @@ namespace Nz return false; } + /*! + * \brief Compares the bounding volume to other one + * \return false if the two bounding volumes are the same + * + * \param volume Other bounding volume to compare with + */ + template bool BoundingVolume::operator!=(const BoundingVolume& volume) const { return !operator==(volume); } + /*! + * \brief Shorthand for the bounding volume (Extend_Infinite) + * \return A bounding volume with Extend_Infinite + * + * \see MakeInfinite + */ + template BoundingVolume BoundingVolume::Infinite() { @@ -237,6 +443,21 @@ namespace Nz return volume; } + /*! + * \brief Interpolates the bounding volume to other one with a factor of interpolation + * \return A new bounding volume box which is the interpolation of two bounding volumes + * + * \param from Initial bounding volume + * \param to Target bounding volume + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * \remark With NAZARA_DEBUG, a NazaraError is thrown and Null() is returned + * \remark If enumeration is not defined in Extend, a NazaraError is thrown and Null() is returned + * + * \see Lerp + */ + template BoundingVolume BoundingVolume::Lerp(const BoundingVolume& from, const BoundingVolume& to, T interpolation) { @@ -275,13 +496,13 @@ namespace Nz return from.obb * interpolation; } - // Si nous arrivons ici c'est que l'extend est invalide + // If we arrive here, the extend is invalid NazaraError("Invalid extend type (From) (0x" + String::Number(from.extend, 16) + ')'); return Null(); } case Extend_Infinite: - return Infinite(); // Un petit peu d'infini est infini quand même ;) + return Infinite(); // A little bit of infinity is already too much ;) case Extend_Null: { @@ -297,17 +518,24 @@ namespace Nz return Null(); } - // Si nous arrivons ici c'est que l'extend est invalide + // If we arrive here, the extend is invalid NazaraError("Invalid extend type (From) (0x" + String::Number(from.extend, 16) + ')'); return Null(); } } - // Si nous arrivons ici c'est que l'extend est invalide + // If we arrive here, the extend is invalid NazaraError("Invalid extend type (To) (0x" + String::Number(to.extend, 16) + ')'); return Null(); } + /*! + * \brief Shorthand for the bounding volume (Extend_Null) + * \return A bounding volume with Extend_Null + * + * \see MakeNull + */ + template BoundingVolume BoundingVolume::Null() { @@ -316,13 +544,21 @@ namespace Nz return volume; } - - template - std::ostream& operator<<(std::ostream& out, const BoundingVolume& volume) - { - out << volume.ToString(); - return out; } + +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param volume The bounding volume to output +*/ + +template +std::ostream& operator<<(std::ostream& out, const Nz::BoundingVolume& volume) +{ + out << volume.ToString(); + return out; } #undef F diff --git a/include/Nazara/Math/Box.hpp b/include/Nazara/Math/Box.hpp index 158d7753c..d8de5bdab 100644 --- a/include/Nazara/Math/Box.hpp +++ b/include/Nazara/Math/Box.hpp @@ -40,8 +40,8 @@ namespace Nz Box& ExtendTo(const Vector3& point); Sphere GetBoundingSphere() const; - Vector3 GetCorner(BoxCorner corner) const; Vector3 GetCenter() const; + Vector3 GetCorner(BoxCorner corner) const; Vector3 GetLengths() const; Vector3 GetMaximum() const; Vector3 GetMinimum() const; diff --git a/include/Nazara/Math/Box.inl b/include/Nazara/Math/Box.inl index a39f867da..a377b7d8f 100644 --- a/include/Nazara/Math/Box.inl +++ b/include/Nazara/Math/Box.inl @@ -12,41 +12,103 @@ namespace Nz { + /*! + * \class Nz::Box + * \brief Math class that represents a three dimensional box + */ + + /*! + * \brief Constructs a Box object from its width, height and depth + * + * \param Width Width of the box (following X) + * \param Height Height of the box (following Y) + * \param Depth Depth of the box (following Z) + * + * \remark Position will be (0, 0, 0) + */ + template Box::Box(T Width, T Height, T Depth) { Set(Width, Height, Depth); } + /*! + * \brief Constructs a Rect object from its position, width, height and depth + * + * \param X X position + * \param Y Y position + * \param Z Z position + * \param Width Width of the box (following X) + * \param Height Height of the box (following Y) + * \param Depth Depth of the box (following Z) + */ + template Box::Box(T X, T Y, T Z, T Width, T Height, T Depth) { Set(X, Y, Z, Width, Height, Depth); } + /*! + * \brief Constructs a Box object from an array of six elements + * + * \param vec[6] vec[0] is X position, vec[1] is Y position, vec[2] is Z position, vec[3] is width, vec[4] is height and vec[5] is depth + */ + + template + Box::Box(const T vec[6]) + { + Set(vec); + } + + /*! + * \brief Constructs a Box object from a Rect + * + * \param rect Rectangle which describes (X, Y) position and (width, height) lenghts + * + * \remark Z position is 0 and depth is 1 + */ + template Box::Box(const Rect& rect) { Set(rect); } + /*! + * \brief Constructs a Box object from a vector representing width, height and depth + * + * \param lengths (Width, Height, Depth) of the box + * + * \remark Positions will be (0, 0, 0) + */ + template Box::Box(const Vector3& lengths) { Set(lengths); } + /*! + * \brief Constructs a Box object from two vectors representing point of the space + * (X, Y, Z) will be the components minimum of the two vectors and the (width, height, depth) will be the components maximum - minimum + * + * \param vec1 First point + * \param vec2 Second point + */ + template Box::Box(const Vector3& vec1, const Vector3& vec2) { Set(vec1, vec2); } - template - Box::Box(const T vec[6]) - { - Set(vec); - } + /*! + * \brief Constructs a Box object from another type of Box + * + * \param box Box of type U to convert to type T + */ template template @@ -55,27 +117,67 @@ namespace Nz Set(box); } + /*! + * \brief Tests whether the box contains the provided point inclusive of the edge of the box + * \return true if inclusive + * + * \param X X position of the point + * \param Y Y position of the point + * \param Z Z position of the point + * + * \see Contains + */ + template bool Box::Contains(T X, T Y, T Z) const { - return X >= x && X <= x+width && - Y >= y && Y <= y+height && - Z >= z && Z <= z+depth; + return X >= x && X <= x + width && + Y >= y && Y <= y + height && + Z >= z && Z <= z + depth; } + /*! + * \brief Tests whether the box contains the provided box inclusive of the edge of the box + * \return true if inclusive + * + * \param box Other box to test + * + * \see Contains + */ + template bool Box::Contains(const Box& box) const { return Contains(box.x, box.y, box.z) && - Contains(box.x + box.width, box.y + box.height, box.z + box.depth); + Contains(box.x + box.width, box.y + box.height, box.z + box.depth); } + /*! + * \brief Tests whether the box contains the provided point inclusive of the edge of the box + * \return true if inclusive + * + * \param point Position of the point + * + * \see Contains + */ + template bool Box::Contains(const Vector3& point) const { return Contains(point.x, point.y, point.z); } + /*! + * \brief Extends the box to contain the point in the boundary + * \return A reference to this box extended + * + * \param X X position of the point + * \param Y Y position of the point + * \param Z Z position of the point + * + * \see ExtendTo + */ + template Box& Box::ExtendTo(T X, T Y, T Z) { @@ -94,6 +196,15 @@ namespace Nz return *this; } + /*! + * \brief Extends the box to contain the box + * \return A reference to this box extended + * + * \param box Other box to contain + * + * \see ExtendTo + */ + template Box& Box::ExtendTo(const Box& box) { @@ -112,12 +223,54 @@ namespace Nz return *this; } + /*! + * \brief Extends the box to contain the point in the boundary + * \return A reference to this box extended + * + * \param point Position of the point + * + * \see ExtendTo + */ + template Box& Box::ExtendTo(const Vector3& point) { return ExtendTo(point.x, point.y, point.z); } + /*! + * \brief Gets the bounding sphere for the box + * \return A sphere containing the box + * + * \see GetSquaredBoundingSphere + */ + + template + Sphere Box::GetBoundingSphere() const + { + return Sphere(GetCenter(), GetRadius()); + } + + /*! + * \brief Gets a Vector3 for the center + * \return The position of the center of the box + */ + + template + Vector3 Box::GetCenter() const + { + return GetPosition() + GetLengths() / F(2.0); + } + + /*! + * \brief Gets the Vector3 for the corner + * \return The position of the corner of the box according to enum BoxCorner + * + * \param corner Enumeration of type BoxCorner + * + * \remark If enumeration is not defined in BoxCorner, a NazaraError is thrown and a Vector3 uninitialised is returned + */ + template Vector3 Box::GetCorner(BoxCorner corner) const { @@ -152,17 +305,10 @@ namespace Nz return Vector3(); } - template - Sphere Box::GetBoundingSphere() const - { - return Sphere(GetCenter(), GetRadius()); - } - - template - Vector3 Box::GetCenter() const - { - return GetPosition() + GetLengths()/F(2.0); - } + /*! + * \brief Gets a Vector3 for the lengths + * \return The lengths of the box (width, height, depth) + */ template Vector3 Box::GetLengths() const @@ -170,19 +316,41 @@ namespace Nz return Vector3(width, height, depth); } + /*! + * \brief Gets a Vector3 for the maximum point + * \return The BoxCorner_NearRightTop of the box + * + * \see GetCorner + */ + template Vector3 Box::GetMaximum() const { return GetPosition() + GetLengths(); } + /*! + * \brief Gets a Vector3 for the minimum point + * \return The BoxCorner_FarLeftBottom of the box + * + * \see GetCorner, GetPosition + */ + template Vector3 Box::GetMinimum() const { - ///DOC: Alias de GetPosition() return GetPosition(); } + /*! + * \brief Computes the negative vertex of one direction + * \return The position of the vertex on the box in the opposite way of the normal while considering the center. It means that if the normal has one component negative, the component is set to width, height or depth corresponding to the sign + * + * \param normal Vector indicating a direction + * + * \see GetPositiveVertex + */ + template Vector3 Box::GetNegativeVertex(const Vector3& normal) const { @@ -200,12 +368,28 @@ namespace Nz return neg; } + /*! + * \brief Gets a Vector3 for the position + * \return The BoxCorner_FarLeftBottom of the box + * + * \see GetCorner, GetMinimum + */ + template Vector3 Box::GetPosition() const { return Vector3(x, y, z); } + /*! + * \brief Computes the positive vertex of one direction + * \return The position of the vertex on the box in the same way of the normal while considering the center. It means that if the normal has one component positive, the component is set to width or height corresponding to the sign + * + * \param normal Vector indicating a direction + * + * \see GetNegativeVertex + */ + template Vector3 Box::GetPositiveVertex(const Vector3& normal) const { @@ -223,27 +407,52 @@ namespace Nz return pos; } + /*! + * \brief Gets the radius of the box + * \return Value of the radius which is the biggest distance between a corner and the center + */ + template T Box::GetRadius() const { return std::sqrt(GetSquaredRadius()); } + /*! + * \brief Gets the squared bounding sphere for the box + * \return A sphere containing the box + * + * \see GetBoundingSphere + */ + template Sphere Box::GetSquaredBoundingSphere() const { return Sphere(GetCenter(), GetSquaredRadius()); } + /*! + * \brief Gets the squared radius of the box + * \return Value of the squared radius which is the squared of biggest distance between a corner and the center + */ + template T Box::GetSquaredRadius() const { Vector3 size(GetLengths()); - size /= F(2.0); // La taille étant relative à la position (minimum) de la boite et non pas à son centre + size /= F(2.0); // The size only depends on the lengths and not the center return size.GetSquaredLength(); } + /*! + * \brief Checks whether or not this box intersects another one + * \return true if the box intersects + * + * \param box Box to check + * \param intersection Optional argument for the box which represent the intersection + */ + template bool Box::Intersect(const Box& box, Box* intersection) const { @@ -275,12 +484,24 @@ namespace Nz return true; } + /*! + * \brief Checks whether this box is valid + * \return true if the box has a strictly positive width, height and depth + */ + template bool Box::IsValid() const { return width > F(0.0) && height > F(0.0) && depth > F(0.0); } + /*! + * \brief Makes the box position (0, 0, 0) and lengths (0, 0, 0) + * \return A reference to this box with position (0, 0, 0) and lengths (0, 0, 0) + * + * \see Zero + */ + template Box& Box::MakeZero() { @@ -294,6 +515,17 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the box with width, height and depth + * \return A reference to this box + * + * \param Width Width of the box (following X) + * \param Height Height of the box (following Y) + * \param Depth Depth of the box (following Z) + * + * \remark Position will be (0, 0, 0) + */ + template Box& Box::Set(T Width, T Height, T Depth) { @@ -307,6 +539,17 @@ namespace Nz return *this; } + /*! + * \brief Constructs a Box object from its position and sizes + * + * \param X X component of position + * \param Y Y component of position + * \param Z Z component of position + * \param Width Width of the box (following X) + * \param Height Height of the box (following Y) + * \param Depth Depth of the box (following Z) + */ + template Box& Box::Set(T X, T Y, T Z, T Width, T Height, T Depth) { @@ -320,6 +563,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the box from an array of six elements + * \return A reference to this box + * + * \param box[6] box[0] is X position, box[1] is Y position, box[2] is Z position, box[3] is width, box[4] is height and box[5] is depth + */ + template Box& Box::Set(const T box[6]) { @@ -333,6 +583,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the box with components from another + * \return A reference to this box + * + * \param box The other box + */ + template Box& Box::Set(const Box& box) { @@ -341,6 +598,15 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the box with components from a Rect + * \return A reference to this box + * + * \param rect Rectangle which describes (X, Y) position and (width, height) lenghts + * + * \remark Z position is 0 and depth is 1 + */ + template Box& Box::Set(const Rect& rect) { @@ -354,25 +620,50 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the box from a vector representing width, height and depth + * \return A reference to this box + * + * \param lengths (Width, Height, depth) of the box + * + * \remark Position will be (0, 0, 0) + */ + template Box& Box::Set(const Vector3& lengths) { return Set(lengths.x, lengths.y, lengths.z); } + /*! + * \brief Sets the components of the box from two vectors representing point of the space + * (X, Y, Z) will be the components minimum of the two vectors and the (width, height, depth) will be the components maximum - minimum + * \return A reference to this box + * + * \param vec1 First point + * \param vec2 Second point + */ + template Box& Box::Set(const Vector3& vec1, const Vector3& vec2) { x = std::min(vec1.x, vec2.x); y = std::min(vec1.y, vec2.y); z = std::min(vec1.z, vec2.z); - width = (vec2.x > vec1.x) ? vec2.x-vec1.x : vec1.x-vec2.x; - height = (vec2.y > vec1.y) ? vec2.y-vec1.y : vec1.y-vec2.y; - depth = (vec2.z > vec1.z) ? vec2.z-vec1.z : vec1.z-vec2.z; + width = (vec2.x > vec1.x) ? vec2.x - vec1.x : vec1.x - vec2.x; + height = (vec2.y > vec1.y) ? vec2.y - vec1.y : vec1.y - vec2.y; + depth = (vec2.z > vec1.z) ? vec2.z - vec1.z : vec1.z - vec2.z; return *this; } + /*! + * \brief Sets the components of the box from another type of Box + * \return A reference to this box + * + * \param box Box of type U to convert its components + */ + template template Box& Box::Set(const Box& box) @@ -387,6 +678,11 @@ namespace Nz return *this; } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "Box(x, y, z, width, height, depth)" + */ + template String Box::ToString() const { @@ -395,19 +691,34 @@ namespace Nz return ss << "Box(" << x << ", " << y << ", " << z << ", " << width << ", " << height << ", " << depth << ')'; } + /*! + * \brief Transforms the box according to the matrix + * \return A reference to this box transformed + * + * \param matrix Matrix4 representing the transformation + * \param applyTranslation Should transform the position or the direction + */ + template Box& Box::Transform(const Matrix4& matrix, bool applyTranslation) { - Vector3 center = matrix.Transform(GetCenter(), (applyTranslation) ? F(1.0) : F(0.0)); // Valeur multipliant la translation - Vector3 halfSize = GetLengths()/F(2.0); + Vector3 center = matrix.Transform(GetCenter(), (applyTranslation) ? F(1.0) : F(0.0)); // Value multiplying the translation + Vector3 halfSize = GetLengths() / F(2.0); - halfSize.Set(std::abs(matrix(0,0))*halfSize.x + std::abs(matrix(1,0))*halfSize.y + std::abs(matrix(2,0))*halfSize.z, - std::abs(matrix(0,1))*halfSize.x + std::abs(matrix(1,1))*halfSize.y + std::abs(matrix(2,1))*halfSize.z, - std::abs(matrix(0,2))*halfSize.x + std::abs(matrix(1,2))*halfSize.y + std::abs(matrix(2,2))*halfSize.z); + halfSize.Set(std::abs(matrix(0,0)) * halfSize.x + std::abs(matrix(1,0)) * halfSize.y + std::abs(matrix(2,0)) * halfSize.z, + std::abs(matrix(0,1)) * halfSize.x + std::abs(matrix(1,1)) * halfSize.y + std::abs(matrix(2,1)) * halfSize.z, + std::abs(matrix(0,2)) * halfSize.x + std::abs(matrix(1,2)) * halfSize.y + std::abs(matrix(2,2)) * halfSize.z); return Set(center - halfSize, center + halfSize); } + /*! + * \brief Translates the box + * \return A reference to this box translated + * + * \param translation Vector3 which is the translation for the position + */ + template Box& Box::Translate(const Vector3& translation) { @@ -418,6 +729,15 @@ namespace Nz return *this; } + /*! + * \brief Returns the ith element of the box + * \return A reference to the ith element of the box + * + * \remark Access to index greather than 6 is undefined behavior + * \remark Produce a NazaraError if you try to acces to index greather than 6 with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 6 + */ + template T& Box::operator[](unsigned int i) { @@ -435,6 +755,15 @@ namespace Nz return *(&x+i); } + /*! + * \brief Returns the ith element of the box + * \return A value to the ith element of the box + * + * \remark Access to index greather than 6 is undefined behavior + * \remark Produce a NazaraError if you try to acces to index greather than 6 with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 6 + */ + template T Box::operator[](unsigned int i) const { @@ -452,18 +781,39 @@ namespace Nz return *(&x+i); } + /*! + * \brief Multiplies the lengths with the scalar + * \return A box where the position is the same and width, height and depth are the product of the old width, height and depth and the scalar + * + * \param scale The scalar to multiply width, height and depth with + */ + template Box Box::operator*(T scalar) const { - return Box(x, y, z, width*scalar, height*scalar, depth*scalar); + return Box(x, y, z, width * scalar, height * scalar, depth * scalar); } + /*! + * \brief Multiplies the lengths with the vector + * \return A box where the position is the same and width, height and depth are the product of the old width, height and depth with the vec + * + * \param vec The vector where component one multiply width, two height and three depth + */ + template Box Box::operator*(const Vector3& vec) const { - return Box(x, y, z, width*vec.x, height*vec.y, depth*vec.z); + return Box(x, y, z, width * vec.x, height * vec.y, depth * vec.z); } + /*! + * \brief Multiplies the lengths of this box with the scalar + * \return A reference to this box where lengths are the product of these lengths and the scalar + * + * \param scalar The scalar to multiply width, height and depth with + */ + template Box& Box::operator*=(T scalar) { @@ -474,6 +824,13 @@ namespace Nz return *this; } + /*! + * \brief Multiplies the lengths of this box with the vector + * \return A reference to this box where width, height and depth are the product of the old width, height and depth with the vec + * + * \param vec The vector where component one multiply width, two height and three depth + */ + template Box& Box::operator*=(const Vector3& vec) { @@ -484,19 +841,47 @@ namespace Nz return *this; } + /*! + * \brief Compares the box to other one + * \return true if the boxes are the same + * + * \param box Other box to compare with + */ + template bool Box::operator==(const Box& box) const { return NumberEquals(x, box.x) && NumberEquals(y, box.y) && NumberEquals(z, box.z) && - NumberEquals(width, box.width) && NumberEquals(height, box.height) && NumberEquals(depth, box.depth); + NumberEquals(width, box.width) && NumberEquals(height, box.height) && NumberEquals(depth, box.depth); } + /*! + * \brief Compares the box to other one + * \return false if the boxes are the same + * + * \param box Other box to compare with + */ + template bool Box::operator!=(const Box& box) const { return !operator==(box); } + /*! + * \brief Interpolates the box to other one with a factor of interpolation + * \return A new box which is the interpolation of two rectangles + * + * \param from Initial box + * \param to Target box + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * \remark With NAZARA_DEBUG, a NazaraError is thrown and Zero() is returned + * + * \see Lerp + */ + template Box Box::Lerp(const Box& from, const Box& to, T interpolation) { @@ -519,6 +904,13 @@ namespace Nz return box; } + /*! + * \brief Shorthand for the box (0, 0, 0, 0, 0, 0) + * \return A box with position (0, 0, 0) and lengths (0, 0, 0) + * + * \see MakeZero + */ + template Box Box::Zero() { @@ -529,6 +921,14 @@ namespace Nz } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param box The box to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::Box& box) { diff --git a/include/Nazara/Math/Config.hpp b/include/Nazara/Math/Config.hpp index f265fdd52..3d27848af 100644 --- a/include/Nazara/Math/Config.hpp +++ b/include/Nazara/Math/Config.hpp @@ -28,15 +28,15 @@ #ifndef NAZARA_CONFIG_MATH_HPP #define NAZARA_CONFIG_MATH_HPP -/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci +/// Each modification of a paramater of the module needs a recompilation of the unit -// Définit le radian comme l'unité utilisée pour les angles +// Define the radian as unit for angles #define NAZARA_MATH_ANGLE_RADIAN 0 -// Optimise automatiquement les opérations entre matrices affines (Demande plusieurs comparaisons pour déterminer si une matrice est affine) +// Optimize automatically the operation on affine matrices (Ask several comparisons to determine if the matrix is affine) #define NAZARA_MATH_MATRIX4_CHECK_AFFINE 0 -// Active les tests de sécurité basés sur le code (Conseillé pour le développement) +// Enable tests of security based on the code (Advised for the developpement) #define NAZARA_MATH_SAFE 1 #endif // NAZARA_CONFIG_MATH_HPP diff --git a/include/Nazara/Math/EulerAngles.hpp b/include/Nazara/Math/EulerAngles.hpp index d323fe641..3c9a6b684 100644 --- a/include/Nazara/Math/EulerAngles.hpp +++ b/include/Nazara/Math/EulerAngles.hpp @@ -28,14 +28,14 @@ namespace Nz void MakeZero(); - void Normalize(); + EulerAngles& Normalize(); - void Set(T P, T Y, T R); - void Set(const T angles[3]); - void Set(const EulerAngles& angles); - //void Set(const Matrix3& mat); - void Set(const Quaternion& quat); - template void Set(const EulerAngles& angles); + EulerAngles& Set(T P, T Y, T R); + EulerAngles& Set(const T angles[3]); + EulerAngles& Set(const EulerAngles& angles); + //EulerAngles& Set(const Matrix3& mat); + EulerAngles& Set(const Quaternion& quat); + template EulerAngles& Set(const EulerAngles& angles); //Matrix3 ToRotationMatrix() const; Quaternion ToQuaternion() const; diff --git a/include/Nazara/Math/EulerAngles.inl b/include/Nazara/Math/EulerAngles.inl index 79e3c1ded..3e4eabc6a 100644 --- a/include/Nazara/Math/EulerAngles.inl +++ b/include/Nazara/Math/EulerAngles.inl @@ -14,24 +14,58 @@ namespace Nz { + + /*! + * \class Nz::Vector4 + * \brief Math class that represents an Euler angle. Those describe a rotation transformation by rotating an object on its various axes in specified amounts per axis, and a specified axis order + * + * \remark Rotation are "left-handed", it means that you take your left hand, put your thumb finger in the direction you want and you other fingers represent the way of rotating + */ + + /*! + * \brief Constructs a EulerAngles object from its components + * + * \param P Pitch component = X axis + * \param Y Yaw component = Y axis + * \param R Roll component = Z axis + */ + template EulerAngles::EulerAngles(T P, T Y, T R) { Set(P, Y, R); } + /*! + * \brief Constructs a EulerAngles object from an array of three elements + * + * \param angles[3] angles[0] is pitch component, angles[1] is yaw component and angles[2] is roll component + */ + template EulerAngles::EulerAngles(const T angles[3]) { Set(angles); } + /*! + * \brief Constructs a EulerAngles object from a quaternion + * + * \param quat Quaternion representing a rotation of space + */ + template EulerAngles::EulerAngles(const Quaternion& quat) { Set(quat); } + /*! + * \brief Constructs a EulerAngles object from another type of EulerAngles + * + * \param angles EulerAngles of type U to convert to type T + */ + template template EulerAngles::EulerAngles(const EulerAngles& angles) @@ -39,57 +73,125 @@ namespace Nz Set(angles); } + /*! + * \brief Makes the euler angle (0, 0, 0) + * \return A reference to this euler angle with components (0, 0, 0) + * + * \see Zero + */ + template void EulerAngles::MakeZero() { Set(F(0.0), F(0.0), F(0.0)); } + /*! + * \brief Normalizes the euler angle + * \return A reference to this euler angle with has been normalized + * + * \remark Normalization depends on NAZARA_MATH_ANGLE_RADIAN, between 0..2*pi + * + * \see NormalizeAngle + */ + template - void EulerAngles::Normalize() + EulerAngles& EulerAngles::Normalize() { pitch = NormalizeAngle(pitch); yaw = NormalizeAngle(yaw); roll = NormalizeAngle(roll); + + return *this; } + /*! + * \brief Sets the components of the euler angle + * \return A reference to this euler angle + * + * \param P Pitch component = X axis + * \param Y Yaw component = Y axis + * \param R Roll component = Z axis + */ + template - void EulerAngles::Set(T P, T Y, T R) + EulerAngles& EulerAngles::Set(T P, T Y, T R) { pitch = P; yaw = Y; roll = R; + + return *this; } + /*! + * \brief Sets the components of the euler angle from an array of three elements + * \return A reference to this euler angle + * + * \param angles[3] angles[0] is pitch component, angles[1] is yaw component and angles[2] is roll component + */ + template - void EulerAngles::Set(const T angles[3]) + EulerAngles& EulerAngles::Set(const T angles[3]) { pitch = angles[0]; yaw = angles[1]; roll = angles[2]; + + return *this; } + /*! + * \brief Sets the components of the euler angle from another euler angle + * \return A reference to this euler angle + * + * \param angles The other euler angle + */ + template - void EulerAngles::Set(const EulerAngles& angles) + EulerAngles& EulerAngles::Set(const EulerAngles& angles) { std::memcpy(this, &angles, sizeof(EulerAngles)); + + return *this; } + /*! + * \brief Sets the components of the euler angle from a quaternion + * \return A reference to this euler angle + * + * \param quat Quaternion representing a rotation of space + */ + template - void EulerAngles::Set(const Quaternion& quat) + EulerAngles& EulerAngles::Set(const Quaternion& quat) { - Set(quat.ToEulerAngles()); + return Set(quat.ToEulerAngles()); } + /*! + * \brief Sets the components of the euler angle from another type of EulerAngles + * \return A reference to this euler angle + * + * \param angles EulerAngles of type U to convert its components + */ + template template - void EulerAngles::Set(const EulerAngles& angles) + EulerAngles& EulerAngles::Set(const EulerAngles& angles) { pitch = F(angles.pitch); yaw = F(angles.yaw); roll = F(angles.roll); + + return *this; } + /*! + * \brief Converts the euler angle to quaternion + * \return A Quaternion which represents the rotation of this euler angle + */ + template Quaternion EulerAngles::ToQuaternion() const { @@ -102,11 +204,16 @@ namespace Nz T s3 = std::sin(ToRadians(pitch) / F(2.0)); return Quaternion(c1 * c2 * c3 - s1 * s2 * s3, - s1 * s2 * c3 + c1 * c2 * s3, - s1 * c2 * c3 + c1 * s2 * s3, - c1 * s2 * c3 - s1 * c2 * s3); + s1 * s2 * c3 + c1 * c2 * s3, + s1 * c2 * c3 + c1 * s2 * s3, + c1 * s2 * c3 - s1 * c2 * s3); } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "EulerAngles(pitch, yaw, roll)" + */ + template String EulerAngles::ToString() const { @@ -115,22 +222,43 @@ namespace Nz return ss << "EulerAngles(" << pitch << ", " << yaw << ", " << roll << ')'; } + /*! + * \brief Adds the components of the euler angle with other euler angle + * \return A euler angle where components are the sum of this euler angle and the other one + * + * \param angles The other euler angle to add components with + */ + template EulerAngles EulerAngles::operator+(const EulerAngles& angles) const { return EulerAngles(pitch + angles.pitch, - yaw + angles.yaw, - roll + angles.roll); + yaw + angles.yaw, + roll + angles.roll); } + /*! + * \brief Substracts the components of the euler angle with other euler angle + * \return A euler angle where components are the difference of this euler angle and the other one + * + * \param angles The other euler angle to substract components with + */ + template EulerAngles EulerAngles::operator-(const EulerAngles& angles) const { return EulerAngles(pitch - angles.pitch, - yaw - angles.yaw, - roll - angles.roll); + yaw - angles.yaw, + roll - angles.roll); } + /*! + * \brief Adds the components of other euler angle to this euler angle + * \return A reference to this euler angle where components are the sum of this euler angle and the other one + * + * \param angles The other euler angle to add components with + */ + template EulerAngles& EulerAngles::operator+=(const EulerAngles& angles) { @@ -141,6 +269,13 @@ namespace Nz return *this; } + /*! + * \brief Substracts the components of other euler angle to this euler angle + * \return A reference to this euler angle where components are the difference of this euler angle and the other one + * + * \param angle The other euler angle to substract components with + */ + template EulerAngles& EulerAngles::operator-=(const EulerAngles& angles) { @@ -151,20 +286,41 @@ namespace Nz return *this; } + /*! + * \brief Compares the euler angle to other one + * \return true if the euler angles are the same + * + * \param angles Other euler angle to compare with + */ + template bool EulerAngles::operator==(const EulerAngles& angles) const { return NumberEquals(pitch, angles.pitch) && - NumberEquals(yaw, angles.yaw) && - NumberEquals(roll, angles.roll); + NumberEquals(yaw, angles.yaw) && + NumberEquals(roll, angles.roll); } + /*! + * \brief Compares the euler angle to other one + * \return false if the euler angles are the same + * + * \param angles Other euler angle to compare with + */ + template bool EulerAngles::operator!=(const EulerAngles& angles) const { return !operator==(angles); } + /*! + * \brief Shorthand for the euler angle (0, 0, 0) + * \return A euler angle with components (0, 0, 0) + * + * \see MakeZero + */ + template EulerAngles EulerAngles::Zero() { @@ -175,6 +331,14 @@ namespace Nz } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param angles The euler angle to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::EulerAngles& angles) { diff --git a/include/Nazara/Math/Frustum.inl b/include/Nazara/Math/Frustum.inl index e5bc2081b..35e63ca98 100644 --- a/include/Nazara/Math/Frustum.inl +++ b/include/Nazara/Math/Frustum.inl @@ -15,6 +15,20 @@ namespace Nz { + + /*! + * \class Nz::Frustum + * \brief Math class that represents a frustum in the three dimensional vector space + * + * Frustums are used to determine what is inside the camera's field of view. They help speed up the rendering process + */ + + /*! + * \brief Constructs a Frustum object from another type of Frustum + * + * \param frustum Frustum of type U to convert to type T + */ + template template Frustum::Frustum(const Frustum& frustum) @@ -22,6 +36,19 @@ namespace Nz Set(frustum); } + /*! + * \brief Builds the frustum object + * \return A reference to this frustum which is the build up camera's field of view + * + * \param angle Unit depends on NAZARA_MATH_ANGLE_RADIAN + * \param ratio Rendering ratio (typically 16/9 or 4/3) + * \param zNear Distance where 'vision' begins + * \param zFar Distance where 'vision' ends + * \param eye Position of the camera + * \param target Position of the target of the camera + * \param up Direction of up vector according to the orientation of camera + */ + template Frustum& Frustum::Build(T angle, T ratio, T zNear, T zFar, const Vector3& eye, const Vector3& target, const Vector3& up) { @@ -45,18 +72,18 @@ namespace Nz Vector3 nc = eye + f * zNear; Vector3 fc = eye + f * zFar; - // Calcul du frustum - m_corners[BoxCorner_FarLeftBottom] = fc - u*farH - s*farW; - m_corners[BoxCorner_FarLeftTop] = fc + u*farH - s*farW; - m_corners[BoxCorner_FarRightTop] = fc + u*farH + s*farW; - m_corners[BoxCorner_FarRightBottom] = fc - u*farH + s*farW; + // Computing the frustum + m_corners[BoxCorner_FarLeftBottom] = fc - u * farH - s * farW; + m_corners[BoxCorner_FarLeftTop] = fc + u * farH - s * farW; + m_corners[BoxCorner_FarRightTop] = fc + u * farH + s * farW; + m_corners[BoxCorner_FarRightBottom] = fc - u * farH + s * farW; - m_corners[BoxCorner_NearLeftBottom] = nc - u*nearH - s*nearW; - m_corners[BoxCorner_NearLeftTop] = nc + u*nearH - s*nearW; - m_corners[BoxCorner_NearRightTop] = nc + u*nearH + s*nearW; - m_corners[BoxCorner_NearRightBottom] = nc - u*nearH + s*nearW; + m_corners[BoxCorner_NearLeftBottom] = nc - u * nearH - s * nearW; + m_corners[BoxCorner_NearLeftTop] = nc + u * nearH - s * nearW; + m_corners[BoxCorner_NearRightTop] = nc + u * nearH + s * nearW; + m_corners[BoxCorner_NearRightBottom] = nc - u * nearH + s * nearW; - // Construction des plans du frustum + // Construction of frustum's planes m_planes[FrustumPlane_Bottom].Set(m_corners[BoxCorner_NearLeftBottom], m_corners[BoxCorner_NearRightBottom], m_corners[BoxCorner_FarRightBottom]); m_planes[FrustumPlane_Far].Set(m_corners[BoxCorner_FarRightTop], m_corners[BoxCorner_FarLeftTop], m_corners[BoxCorner_FarLeftBottom]); m_planes[FrustumPlane_Left].Set(m_corners[BoxCorner_NearLeftTop], m_corners[BoxCorner_NearLeftBottom], m_corners[BoxCorner_FarLeftBottom]); @@ -67,6 +94,18 @@ namespace Nz return *this; } + /*! + * \brief Checks whether or not a bounding volume is contained in the frustum + * \return true if the bounding volume is entirely in the frustum + * + * \param volume Volume to check + * + * \remark If volume is infinite, true is returned + * \remark If volume is null, false is returned + * \remark If enumeration of the volume is not defined in Extend, a NazaraError is thrown and false is returned + * \remark If enumeration of the intersection is not defined in IntersectionSide, a NazaraError is thrown and false is returned. This should not never happen for a user of the library + */ + template bool Frustum::Contains(const BoundingVolume& volume) const { @@ -102,11 +141,18 @@ namespace Nz return false; } + /*! + * \brief Checks whether or not a box is contained in the frustum + * \return true if the box is entirely in the frustum + * + * \param box Box to check + */ + template bool Frustum::Contains(const Box& box) const { // http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/ - for(unsigned int i = 0; i <= FrustumPlane_Max; i++) + for (unsigned int i = 0; i <= FrustumPlane_Max; i++) { if (m_planes[i].Distance(box.GetPositiveVertex(m_planes[i].normal)) < F(0.0)) return false; @@ -115,16 +161,30 @@ namespace Nz return true; } + /*! + * \brief Checks whether or not an oriented box is contained in the frustum + * \return true if the oriented box is entirely in the frustum + * + * \param orientedbox Oriented box to check + */ + template bool Frustum::Contains(const OrientedBox& orientedbox) const { return Contains(&orientedbox[0], 8); } + /*! + * \brief Checks whether or not a sphere is contained in the frustum + * \return true if the sphere is entirely in the frustum + * + * \param sphere Sphere to check + */ + template bool Frustum::Contains(const Sphere& sphere) const { - for(unsigned int i = 0; i <= FrustumPlane_Max; i++) + for (unsigned int i = 0; i <= FrustumPlane_Max; i++) { if (m_planes[i].Distance(sphere.GetPosition()) < -sphere.radius) return false; @@ -133,10 +193,17 @@ namespace Nz return true; } + /*! + * \brief Checks whether or not a Vector3 is contained in the frustum + * \return true if the Vector3 is in the frustum + * + * \param point Vector3 which represents a point in the space + */ + template bool Frustum::Contains(const Vector3& point) const { - for(unsigned int i = 0; i <= FrustumPlane_Max; ++i) + for (unsigned int i = 0; i <= FrustumPlane_Max; ++i) { if (m_planes[i].Distance(point) < F(0.0)) return false; @@ -145,6 +212,14 @@ namespace Nz return true; } + /*! + * \brief Checks whether or not a set of Vector3 is contained in the frustum + * \return true if the set of Vector3 is in the frustum + * + * \param points Pointer to Vector3 which represents a set of points in the space + * \param pointCount Number of points to check + */ + template bool Frustum::Contains(const Vector3* points, unsigned int pointCount) const { @@ -164,6 +239,15 @@ namespace Nz return true; } + /*! + * \brief Constructs the frustum from a Matrix4 + * \return A reference to this frustum which is the build up of projective matrix + * + * \param clipMatrix Matrix which represents the transformation of the frustum + * + * \remark A NazaraWarning is produced if clipMatrix is not inversible and corners are unchanged + */ + template Frustum& Frustum::Extract(const Matrix4& clipMatrix) { @@ -178,7 +262,7 @@ namespace Nz plane[3] = clipMatrix[15] - clipMatrix[12]; // Normalize the result - invLength = F(1.0) / std::sqrt(plane[0]*plane[0] + plane[1]*plane[1] + plane[2]*plane[2]); + invLength = F(1.0) / std::sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]); plane[0] *= invLength; plane[1] *= invLength; plane[2] *= invLength; @@ -193,7 +277,7 @@ namespace Nz plane[3] = clipMatrix[15] + clipMatrix[12]; // Normalize the result - invLength = F(1.0) / std::sqrt(plane[0]*plane[0] + plane[1]*plane[1] + plane[2]*plane[2]); + invLength = F(1.0) / std::sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]); plane[0] *= invLength; plane[1] *= invLength; plane[2] *= invLength; @@ -208,7 +292,7 @@ namespace Nz plane[3] = clipMatrix[15] + clipMatrix[13]; // Normalize the result - invLength = F(1.0) / std::sqrt(plane[0]*plane[0] + plane[1]*plane[1] + plane[2]*plane[2]); + invLength = F(1.0) / std::sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]); plane[0] *= invLength; plane[1] *= invLength; plane[2] *= invLength; @@ -223,7 +307,7 @@ namespace Nz plane[3] = clipMatrix[15] - clipMatrix[13]; // Normalize the result - invLength = F(1.0) / std::sqrt(plane[0]*plane[0] + plane[1]*plane[1] + plane[2]*plane[2]); + invLength = F(1.0) / std::sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]); plane[0] *= invLength; plane[1] *= invLength; plane[2] *= invLength; @@ -238,7 +322,7 @@ namespace Nz plane[3] = clipMatrix[15] - clipMatrix[14]; // Normalize the result - invLength = F(1.0) / std::sqrt(plane[0]*plane[0] + plane[1]*plane[1] + plane[2]*plane[2]); + invLength = F(1.0) / std::sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]); plane[0] *= invLength; plane[1] *= invLength; plane[2] *= invLength; @@ -253,7 +337,7 @@ namespace Nz plane[3] = clipMatrix[15] + clipMatrix[14]; // Normalize the result - invLength = F(1.0) / std::sqrt(plane[0]*plane[0] + plane[1]*plane[1] + plane[2]*plane[2]); + invLength = F(1.0) / std::sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]); plane[0] *= invLength; plane[1] *= invLength; plane[2] *= invLength; @@ -261,8 +345,8 @@ namespace Nz m_planes[FrustumPlane_Near].Set(plane); - // Une fois les plans extraits, il faut extraire les points du frustum - // Je me base sur cette page: http://www.gamedev.net/topic/393309-calculating-the-view-frustums-vertices/ + // Once planes have been extracted, we must extract points of the frustum + // Based on: http://www.gamedev.net/topic/393309-calculating-the-view-frustums-vertices/ Matrix4 invClipMatrix; if (clipMatrix.GetInverse(&invClipMatrix)) @@ -331,12 +415,31 @@ namespace Nz return *this; } + /*! + * \brief Constructs the frustum from the view matrix and the projection matrix + * \return A reference to this frustum which is the build up of projective matrix + * + * \param view Matrix which represents the view + * \param projection Matrix which represents the projection (the perspective) + * + * \remark A NazaraWarning is produced if the product of these matrices is not inversible and corners are unchanged + */ + template Frustum& Frustum::Extract(const Matrix4& view, const Matrix4& projection) { return Extract(Matrix4::Concatenate(view, projection)); } + /*! + * \brief Gets the Vector3 for the corner + * \return The position of the corner of the frustum according to enum BoxCorner + * + * \param corner Enumeration of type BoxCorner + * + * \remark If enumeration is not defined in BoxCorner and NAZARA_DEBUG defined, a NazaraError is thrown and a Vector3 uninitialised is returned + */ + template const Vector3& Frustum::GetCorner(BoxCorner corner) const { @@ -353,6 +456,15 @@ namespace Nz return m_corners[corner]; } + /*! + * \brief Gets the Plane for the face + * \return The face of the frustum according to enum FrustumPlane + * + * \param plane Enumeration of type FrustumPlane + * + * \remark If enumeration is not defined in FrustumPlane and NAZARA_DEBUG defined, a NazaraError is thrown and a Plane uninitialised is returned + */ + template const Plane& Frustum::GetPlane(FrustumPlane plane) const { @@ -369,6 +481,18 @@ namespace Nz return m_planes[plane]; } + /*! + * \brief Checks whether or not a bounding volume intersects with the frustum + * \return IntersectionSide How the bounding volume is intersecting with the frustum + * + * \param volume Volume to check + * + * \remark If volume is infinite, IntersectionSide_Intersecting is returned + * \remark If volume is null, IntersectionSide_Outside is returned + * \remark If enumeration of the volume is not defined in Extend, a NazaraError is thrown and false is returned + * \remark If enumeration of the intersection is not defined in IntersectionSide, a NazaraError is thrown and false is returned. This should not never happen for a user of the library + */ + template IntersectionSide Frustum::Intersect(const BoundingVolume& volume) const { @@ -394,7 +518,7 @@ namespace Nz } case Extend_Infinite: - return IntersectionSide_Intersecting; // On ne peut pas contenir l'infini + return IntersectionSide_Intersecting; // We can not contain infinity case Extend_Null: return IntersectionSide_Outside; @@ -404,13 +528,20 @@ namespace Nz return IntersectionSide_Outside; } + /*! + * \brief Checks whether or not a box intersects with the frustum + * \return IntersectionSide How the box is intersecting with the frustum + * + * \param box Box to check + */ + template IntersectionSide Frustum::Intersect(const Box& box) const { // http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/ IntersectionSide side = IntersectionSide_Inside; - for(unsigned int i = 0; i <= FrustumPlane_Max; i++) + for (unsigned int i = 0; i <= FrustumPlane_Max; i++) { if (m_planes[i].Distance(box.GetPositiveVertex(m_planes[i].normal)) < F(0.0)) return IntersectionSide_Outside; @@ -421,19 +552,33 @@ namespace Nz return side; } + /*! + * \brief Checks whether or not an oriented box intersects with the frustum + * \return IntersectionSide How the oriented box is intersecting with the frustum + * + * \param oriented box OrientedBox to check + */ + template IntersectionSide Frustum::Intersect(const OrientedBox& orientedbox) const { return Intersect(&orientedbox[0], 8); } + /*! + * \brief Checks whether or not a sphere intersects with the frustum + * \return IntersectionSide How the sphere is intersecting with the frustum + * + * \param sphere Sphere to check + */ + template IntersectionSide Frustum::Intersect(const Sphere& sphere) const { // http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-points-and-spheres/ IntersectionSide side = IntersectionSide_Inside; - for(unsigned int i = 0; i <= FrustumPlane_Max; i++) + for (unsigned int i = 0; i <= FrustumPlane_Max; i++) { T distance = m_planes[i].Distance(sphere.GetPosition()); if (distance < -sphere.radius) @@ -445,6 +590,14 @@ namespace Nz return side; } + /*! + * \brief Checks whether or not a set of Vector3 intersects with the frustum + * \return IntersectionSide How the set of Vector3 is intersecting with the frustum + * + * \param points Pointer to Vector3 which represents a set of points in the space + * \param pointCount Number of points to check + */ + template IntersectionSide Frustum::Intersect(const Vector3* points, unsigned int pointCount) const { @@ -468,6 +621,13 @@ namespace Nz return (c == 6) ? IntersectionSide_Inside : IntersectionSide_Intersecting; } + /*! + * \brief Sets the components of the frustum from another frustum + * \return A reference to this frustum + * + * \param frustum The other frustum + */ + template Frustum& Frustum::Set(const Frustum& frustum) { @@ -476,6 +636,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the frustum from another type of Frustum + * \return A reference to this frustum + * + * \param frustum Frustum of type U to convert its components + */ + template template Frustum& Frustum::Set(const Frustum& frustum) @@ -489,20 +656,33 @@ namespace Nz return *this; } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "Frustum(Plane ...)" + */ + template String Frustum::ToString() const { StringStream ss; return ss << "Frustum(Bottom: " << m_planes[FrustumPlane_Bottom].ToString() << "\n" - << " Far: " << m_planes[FrustumPlane_Far].ToString() << "\n" - << " Left: " << m_planes[FrustumPlane_Left].ToString() << "\n" - << " Near: " << m_planes[FrustumPlane_Near].ToString() << "\n" - << " Right: " << m_planes[FrustumPlane_Right].ToString() << "\n" - << " Top: " << m_planes[FrustumPlane_Top].ToString() << ")\n"; + << " Far: " << m_planes[FrustumPlane_Far].ToString() << "\n" + << " Left: " << m_planes[FrustumPlane_Left].ToString() << "\n" + << " Near: " << m_planes[FrustumPlane_Near].ToString() << "\n" + << " Right: " << m_planes[FrustumPlane_Right].ToString() << "\n" + << " Top: " << m_planes[FrustumPlane_Top].ToString() << ")\n"; } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param frustum The frustum to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::Frustum& frustum) { diff --git a/include/Nazara/Math/Matrix4.hpp b/include/Nazara/Math/Matrix4.hpp index d72529d92..211e8eedb 100644 --- a/include/Nazara/Math/Matrix4.hpp +++ b/include/Nazara/Math/Matrix4.hpp @@ -26,9 +26,9 @@ namespace Nz public: Matrix4() = default; Matrix4(T r11, T r12, T r13, T r14, - T r21, T r22, T r23, T r24, - T r31, T r32, T r33, T r34, - T r41, T r42, T r43, T r44); + T r21, T r22, T r23, T r24, + T r31, T r32, T r33, T r34, + T r41, T r42, T r43, T r44); //Matrix4(const Matrix3& matrix); Matrix4(const T matrix[16]); template explicit Matrix4(const Matrix4& matrix); @@ -77,9 +77,9 @@ namespace Nz Matrix4& MakeZero(); Matrix4& Set(T r11, T r12, T r13, T r14, - T r21, T r22, T r23, T r24, - T r31, T r32, T r33, T r34, - T r41, T r42, T r43, T r44); + T r21, T r22, T r23, T r24, + T r31, T r32, T r33, T r34, + T r41, T r42, T r43, T r44); Matrix4& Set(const T matrix[16]); //Matrix4(const Matrix3& matrix); Matrix4& Set(const Matrix4& matrix); @@ -96,8 +96,8 @@ namespace Nz Matrix4& Transpose(); - operator T*(); - operator const T*() const; + operator T* (); + operator const T* () const; T& operator()(unsigned int x, unsigned int y); T operator()(unsigned int x, unsigned int y) const; @@ -131,9 +131,9 @@ namespace Nz static Matrix4 Zero(); T m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44; + m21, m22, m23, m24, + m31, m32, m33, m34, + m41, m42, m43, m44; }; typedef Matrix4 Matrix4d; diff --git a/include/Nazara/Math/Matrix4.inl b/include/Nazara/Math/Matrix4.inl index 834a3fb70..e2f604aed 100644 --- a/include/Nazara/Math/Matrix4.inl +++ b/include/Nazara/Math/Matrix4.inl @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Mathematics module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -20,24 +20,50 @@ namespace Nz { + + /*! + * \class Nz::Matrix4 + * \brief Math class that represents a transformation of the four dimensional vector space with the notion of projectivity + * + * \remark Matrix4 is said to be "row-major" and affine if last column is made of (0, 0, 0, 1) + */ + + /*! + * \brief Constructs a Matrix4 object from its components + * + * \param rIJ Matrix components at index(I, J) + */ + template Matrix4::Matrix4(T r11, T r12, T r13, T r14, - T r21, T r22, T r23, T r24, - T r31, T r32, T r33, T r34, - T r41, T r42, T r43, T r44) + T r21, T r22, T r23, T r24, + T r31, T r32, T r33, T r34, + T r41, T r42, T r43, T r44) { Set(r11, r12, r13, r14, - r21, r22, r23, r24, - r31, r32, r33, r34, - r41, r42, r43, r44); + r21, r22, r23, r24, + r31, r32, r33, r34, + r41, r42, r43, r44); } + /*! + * \brief Constructs a Matrix4 object from an array of sixteen elements + * + * \param matrix[16] Matrix components + */ + template Matrix4::Matrix4(const T matrix[16]) { Set(matrix); } + /*! + * \brief Constructs a Matrix4 object from another type of Matrix4 + * + * \param matrix Matrix4 of type U to convert to type T + */ + template template Matrix4::Matrix4(const Matrix4& matrix) @@ -45,12 +71,26 @@ namespace Nz Set(matrix); } + /*! + * \brief Apply the rotation represented by the quaternion to this matrix + * \return A reference to this matrix which has been rotated + * + * \param rotation Quaternion representing a rotation of space + */ + template Matrix4& Matrix4::ApplyRotation(const Quaternion& rotation) { return Concatenate(Matrix4::Rotate(rotation)); } + /*! + * \brief Apply the scale represented by the vector to this matrix + * \return A reference to this matrix which has been scaled + * + * \param scale Vector3 representing the homothety + */ + template Matrix4& Matrix4::ApplyScale(const Vector3& scale) { @@ -69,6 +109,13 @@ namespace Nz return *this; } + /*! + * \brief Apply the translation represented by the vector to this matrix + * \return A reference to this matrix which has been translated + * + * \param translation Vector3 representing the translation + */ + template Matrix4& Matrix4::ApplyTranslation(const Vector3& translation) { @@ -79,6 +126,17 @@ namespace Nz return *this; } + /*! + * \brief Concatenates this matrix to other one + * \return A reference to this matrix which is the product with other one + * + * \param matrix Matrix to multiply with + * + * \remark if NAZARA_MATH_MATRIX4_CHECK_AFFINE is defined, ConcatenateAffine is called + * + * \see ConcatenateAffine + */ + template Matrix4& Matrix4::Concatenate(const Matrix4& matrix) { @@ -88,26 +146,37 @@ namespace Nz #endif return Set(m11*matrix.m11 + m12*matrix.m21 + m13*matrix.m31 + m14*matrix.m41, - m11*matrix.m12 + m12*matrix.m22 + m13*matrix.m32 + m14*matrix.m42, - m11*matrix.m13 + m12*matrix.m23 + m13*matrix.m33 + m14*matrix.m43, - m11*matrix.m14 + m12*matrix.m24 + m13*matrix.m34 + m14*matrix.m44, + m11*matrix.m12 + m12*matrix.m22 + m13*matrix.m32 + m14*matrix.m42, + m11*matrix.m13 + m12*matrix.m23 + m13*matrix.m33 + m14*matrix.m43, + m11*matrix.m14 + m12*matrix.m24 + m13*matrix.m34 + m14*matrix.m44, - m21*matrix.m11 + m22*matrix.m21 + m23*matrix.m31 + m24*matrix.m41, - m21*matrix.m12 + m22*matrix.m22 + m23*matrix.m32 + m24*matrix.m42, - m21*matrix.m13 + m22*matrix.m23 + m23*matrix.m33 + m24*matrix.m43, - m21*matrix.m14 + m22*matrix.m24 + m23*matrix.m34 + m24*matrix.m44, + m21*matrix.m11 + m22*matrix.m21 + m23*matrix.m31 + m24*matrix.m41, + m21*matrix.m12 + m22*matrix.m22 + m23*matrix.m32 + m24*matrix.m42, + m21*matrix.m13 + m22*matrix.m23 + m23*matrix.m33 + m24*matrix.m43, + m21*matrix.m14 + m22*matrix.m24 + m23*matrix.m34 + m24*matrix.m44, - m31*matrix.m11 + m32*matrix.m21 + m33*matrix.m31 + m34*matrix.m41, - m31*matrix.m12 + m32*matrix.m22 + m33*matrix.m32 + m34*matrix.m42, - m31*matrix.m13 + m32*matrix.m23 + m33*matrix.m33 + m34*matrix.m43, - m31*matrix.m14 + m32*matrix.m24 + m33*matrix.m34 + m34*matrix.m44, + m31*matrix.m11 + m32*matrix.m21 + m33*matrix.m31 + m34*matrix.m41, + m31*matrix.m12 + m32*matrix.m22 + m33*matrix.m32 + m34*matrix.m42, + m31*matrix.m13 + m32*matrix.m23 + m33*matrix.m33 + m34*matrix.m43, + m31*matrix.m14 + m32*matrix.m24 + m33*matrix.m34 + m34*matrix.m44, - m41*matrix.m11 + m42*matrix.m21 + m43*matrix.m31 + m44*matrix.m41, - m41*matrix.m12 + m42*matrix.m22 + m43*matrix.m32 + m44*matrix.m42, - m41*matrix.m13 + m42*matrix.m23 + m43*matrix.m33 + m44*matrix.m43, - m41*matrix.m14 + m42*matrix.m24 + m43*matrix.m34 + m44*matrix.m44); + m41*matrix.m11 + m42*matrix.m21 + m43*matrix.m31 + m44*matrix.m41, + m41*matrix.m12 + m42*matrix.m22 + m43*matrix.m32 + m44*matrix.m42, + m41*matrix.m13 + m42*matrix.m23 + m43*matrix.m33 + m44*matrix.m43, + m41*matrix.m14 + m42*matrix.m24 + m43*matrix.m34 + m44*matrix.m44); } + /*! + * \brief Concatenates this matrix to other one + * \return A reference to this matrix which is the product with other one + * + * \param matrix Matrix to multiply with + * + * \remark if NAZARA_DEBUG is defined and matrices are not affine, a NazaraWarning is produced and Concatenate is called + * + * \see Concatenate + */ + template Matrix4& Matrix4::ConcatenateAffine(const Matrix4& matrix) { @@ -126,26 +195,36 @@ namespace Nz #endif return Set(m11*matrix.m11 + m12*matrix.m21 + m13*matrix.m31, - m11*matrix.m12 + m12*matrix.m22 + m13*matrix.m32, - m11*matrix.m13 + m12*matrix.m23 + m13*matrix.m33, - F(0.0), + m11*matrix.m12 + m12*matrix.m22 + m13*matrix.m32, + m11*matrix.m13 + m12*matrix.m23 + m13*matrix.m33, + F(0.0), - m21*matrix.m11 + m22*matrix.m21 + m23*matrix.m31, - m21*matrix.m12 + m22*matrix.m22 + m23*matrix.m32, - m21*matrix.m13 + m22*matrix.m23 + m23*matrix.m33, - F(0.0), + m21*matrix.m11 + m22*matrix.m21 + m23*matrix.m31, + m21*matrix.m12 + m22*matrix.m22 + m23*matrix.m32, + m21*matrix.m13 + m22*matrix.m23 + m23*matrix.m33, + F(0.0), - m31*matrix.m11 + m32*matrix.m21 + m33*matrix.m31, - m31*matrix.m12 + m32*matrix.m22 + m33*matrix.m32, - m31*matrix.m13 + m32*matrix.m23 + m33*matrix.m33, - F(0.0), + m31*matrix.m11 + m32*matrix.m21 + m33*matrix.m31, + m31*matrix.m12 + m32*matrix.m22 + m33*matrix.m32, + m31*matrix.m13 + m32*matrix.m23 + m33*matrix.m33, + F(0.0), - m41*matrix.m11 + m42*matrix.m21 + m43*matrix.m31 + matrix.m41, - m41*matrix.m12 + m42*matrix.m22 + m43*matrix.m32 + matrix.m42, - m41*matrix.m13 + m42*matrix.m23 + m43*matrix.m33 + matrix.m43, - F(1.0)); + m41*matrix.m11 + m42*matrix.m21 + m43*matrix.m31 + matrix.m41, + m41*matrix.m12 + m42*matrix.m22 + m43*matrix.m32 + matrix.m42, + m41*matrix.m13 + m42*matrix.m23 + m43*matrix.m33 + matrix.m43, + F(1.0)); } + /*! + * \brief Gets the ith column of the matrix + * \return Vector4 which is the transformation of this axis + * + * \param column Index of the column you want + * + * \remark Produce a NazaraError if you try to access index greater than 3 with NAZARA_MATH_SAFE defined + * \throw std::out_of_range if NAZARA_MATH_SAFE is defined and if you try to access index greater than 3 + */ + template Vector4 Matrix4::GetColumn(unsigned int column) const { @@ -154,10 +233,10 @@ namespace Nz #if NAZARA_MATH_SAFE if (column > 3) { - StringStream ss; - ss << "Row out of range: (" << column << ") > 3"; + String error("Column out of range: (" + String::Number(column) + ") > 3"); - throw std::out_of_range(ss.ToString()); + NazaraError(error); + throw std::out_of_range(error); } #endif @@ -165,9 +244,23 @@ namespace Nz return Vector4(ptr); } + /*! + * \brief Calcultes the determinant of this matrix + * \return The value of the determinant + * + * \remark if NAZARA_MATH_MATRIX4_CHECK_AFFINE is defined, GetDeterminantAffine is called + * + * \see GetDeterminantAffine + */ + template T Matrix4::GetDeterminant() const { + #if NAZARA_MATH_MATRIX4_CHECK_AFFINE + if (IsAffine()) + return GetDeterminantAffine(); + #endif + T A = m22*(m33*m44 - m43*m34) - m32*(m23*m44 - m43*m24) + m42*(m23*m34 - m33*m24); T B = m12*(m33*m44 - m43*m34) - m32*(m13*m44 - m43*m14) + m42*(m13*m34 - m33*m14); T C = m12*(m23*m44 - m43*m24) - m22*(m13*m44 - m43*m14) + m42*(m13*m24 - m23*m14); @@ -176,9 +269,26 @@ namespace Nz return m11*A - m21*B + m31*C - m41*D; } + /*! + * \brief Calcultes the determinant of this matrix + * \return The value of the determinant + * + * \remark if NAZARA_DEBUG is defined and matrix is not affine, a NazaraWarning is produced and GetDeterminant is called + * + * \see GetDeterminant + */ + template T Matrix4::GetDeterminantAffine() const { + #ifdef NAZARA_DEBUG + if (!IsAffine()) + { + NazaraWarning("First matrix not affine"); + return GetDeterminant(); + } + #endif + T A = m22*m33 - m32*m23; T B = m12*m33 - m32*m13; T C = m12*m23 - m22*m13; @@ -186,10 +296,27 @@ namespace Nz return m11*A - m21*B + m31*C; } + /*! + * \brief Gets the inverse of this matrix + * \return true if matrix can be inverted + * + * \param dest Matrix to put the result + * + * \remark You can call this method on the same object + * \remark if NAZARA_MATH_MATRIX4_CHECK_AFFINE is defined, GetInverseAffine is called + * \remark if NAZARA_DEBUG is defined, a NazaraError is produced if dest is null and false is returned + * + * \see GetInverseAffine + */ + template bool Matrix4::GetInverse(Matrix4* dest) const { - ///DOC: Il est possible d'appeler cette méthode avec la même matrice en argument qu'en appelant + #if NAZARA_MATH_MATRIX4_CHECK_AFFINE + if (IsAffine()) + return GetInverseAffine(dest); + #endif + #ifdef NAZARA_DEBUG if (!dest) { @@ -204,116 +331,116 @@ namespace Nz // http://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix T inv[16]; inv[0] = m22 * m33 * m44 - - m22 * m34 * m43 - - m32 * m23 * m44 + - m32 * m24 * m43 + - m42 * m23 * m34 - - m42 * m24 * m33; + m22 * m34 * m43 - + m32 * m23 * m44 + + m32 * m24 * m43 + + m42 * m23 * m34 - + m42 * m24 * m33; inv[1] = -m12 * m33 * m44 + - m12 * m34 * m43 + - m32 * m13 * m44 - - m32 * m14 * m43 - - m42 * m13 * m34 + - m42 * m14 * m33; + m12 * m34 * m43 + + m32 * m13 * m44 - + m32 * m14 * m43 - + m42 * m13 * m34 + + m42 * m14 * m33; inv[2] = m12 * m23 * m44 - - m12 * m24 * m43 - - m22 * m13 * m44 + - m22 * m14 * m43 + - m42 * m13 * m24 - - m42 * m14 * m23; + m12 * m24 * m43 - + m22 * m13 * m44 + + m22 * m14 * m43 + + m42 * m13 * m24 - + m42 * m14 * m23; inv[3] = -m12 * m23 * m34 + - m12 * m24 * m33 + - m22 * m13 * m34 - - m22 * m14 * m33 - - m32 * m13 * m24 + - m32 * m14 * m23; + m12 * m24 * m33 + + m22 * m13 * m34 - + m22 * m14 * m33 - + m32 * m13 * m24 + + m32 * m14 * m23; inv[4] = -m21 * m33 * m44 + - m21 * m34 * m43 + - m31 * m23 * m44 - - m31 * m24 * m43 - - m41 * m23 * m34 + - m41 * m24 * m33; + m21 * m34 * m43 + + m31 * m23 * m44 - + m31 * m24 * m43 - + m41 * m23 * m34 + + m41 * m24 * m33; inv[5] = m11 * m33 * m44 - - m11 * m34 * m43 - - m31 * m13 * m44 + - m31 * m14 * m43 + - m41 * m13 * m34 - - m41 * m14 * m33; + m11 * m34 * m43 - + m31 * m13 * m44 + + m31 * m14 * m43 + + m41 * m13 * m34 - + m41 * m14 * m33; inv[6] = -m11 * m23 * m44 + - m11 * m24 * m43 + - m21 * m13 * m44 - - m21 * m14 * m43 - - m41 * m13 * m24 + - m41 * m14 * m23; + m11 * m24 * m43 + + m21 * m13 * m44 - + m21 * m14 * m43 - + m41 * m13 * m24 + + m41 * m14 * m23; inv[7] = m11 * m23 * m34 - - m11 * m24 * m33 - - m21 * m13 * m34 + - m21 * m14 * m33 + - m31 * m13 * m24 - - m31 * m14 * m23; + m11 * m24 * m33 - + m21 * m13 * m34 + + m21 * m14 * m33 + + m31 * m13 * m24 - + m31 * m14 * m23; inv[8] = m21 * m32 * m44 - - m21 * m34 * m42 - - m31 * m22 * m44 + - m31 * m24 * m42 + - m41 * m22 * m34 - - m41 * m24 * m32; + m21 * m34 * m42 - + m31 * m22 * m44 + + m31 * m24 * m42 + + m41 * m22 * m34 - + m41 * m24 * m32; inv[9] = -m11 * m32 * m44 + - m11 * m34 * m42 + - m31 * m12 * m44 - - m31 * m14 * m42 - - m41 * m12 * m34 + - m41 * m14 * m32; + m11 * m34 * m42 + + m31 * m12 * m44 - + m31 * m14 * m42 - + m41 * m12 * m34 + + m41 * m14 * m32; inv[10] = m11 * m22 * m44 - - m11 * m24 * m42 - - m21 * m12 * m44 + - m21 * m14 * m42 + - m41 * m12 * m24 - - m41 * m14 * m22; + m11 * m24 * m42 - + m21 * m12 * m44 + + m21 * m14 * m42 + + m41 * m12 * m24 - + m41 * m14 * m22; inv[11] = -m11 * m22 * m34 + - m11 * m24 * m32 + - m21 * m12 * m34 - - m21 * m14 * m32 - - m31 * m12 * m24 + - m31 * m14 * m22; + m11 * m24 * m32 + + m21 * m12 * m34 - + m21 * m14 * m32 - + m31 * m12 * m24 + + m31 * m14 * m22; inv[12] = -m21 * m32 * m43 + - m21 * m33 * m42 + - m31 * m22 * m43 - - m31 * m23 * m42 - - m41 * m22 * m33 + - m41 * m23 * m32; + m21 * m33 * m42 + + m31 * m22 * m43 - + m31 * m23 * m42 - + m41 * m22 * m33 + + m41 * m23 * m32; inv[13] = m11 * m32 * m43 - - m11 * m33 * m42 - - m31 * m12 * m43 + - m31 * m13 * m42 + - m41 * m12 * m33 - - m41 * m13 * m32; + m11 * m33 * m42 - + m31 * m12 * m43 + + m31 * m13 * m42 + + m41 * m12 * m33 - + m41 * m13 * m32; inv[14] = -m11 * m22 * m43 + - m11 * m23 * m42 + - m21 * m12 * m43 - - m21 * m13 * m42 - - m41 * m12 * m23 + - m41 * m13 * m22; + m11 * m23 * m42 + + m21 * m12 * m43 - + m21 * m13 * m42 - + m41 * m12 * m23 + + m41 * m13 * m22; inv[15] = m11 * m22 * m33 - - m11 * m23 * m32 - - m21 * m12 * m33 + - m21 * m13 * m32 + - m31 * m12 * m23 - - m31 * m13 * m22; + m11 * m23 * m32 - + m21 * m12 * m33 + + m21 * m13 * m32 + + m31 * m12 * m23 - + m31 * m13 * m22; T invDet = F(1.0) / det; for (unsigned int i = 0; i < 16; ++i) @@ -326,15 +453,27 @@ namespace Nz return false; } + /*! + * \brief Gets the inverse of this matrix + * \return true if matrix can be inverted + * + * \param dest Matrix to put the result + * + * \remark You can call this method on the same object + * \remark if NAZARA_DEBUG is defined and matrix is not affine, a NazaraWarning is produced and GetInverse is called + * \remark if NAZARA_DEBUG is defined, a NazaraError is produced if dest is null and false is returned + * + * \see GetInverse + */ + template bool Matrix4::GetInverseAffine(Matrix4* dest) const { - ///DOC: Il est possible d'appeler cette méthode avec la même matrice en argument qu'en appelant - #if NAZARA_MATH_SAFE + #ifdef NAZARA_DEBUG if (!IsAffine()) { - NazaraError("Matrix is not affine"); - return false; + NazaraWarning("Matrix is not affine"); + return GetInverse(dest); } if (!dest) @@ -350,58 +489,58 @@ namespace Nz // http://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix T inv[16]; inv[0] = m22 * m33 - - m32 * m23; + m32 * m23; inv[1] = -m12 * m33 + - m32 * m13; + m32 * m13; inv[2] = m12 * m23 - - m22 * m13; + m22 * m13; inv[3] = F(0.0); inv[4] = -m21 * m33 + - m31 * m23; + m31 * m23; inv[5] = m11 * m33 - - m31 * m13; + m31 * m13; inv[6] = -m11 * m23 + - m21 * m13; + m21 * m13; inv[7] = F(0.0); inv[8] = m21 * m32 - - m31 * m22; + m31 * m22; inv[9] = -m11 * m32 + - m31 * m12; + m31 * m12; inv[10] = m11 * m22 - - m21 * m12; + m21 * m12; inv[11] = F(0.0); inv[12] = -m21 * m32 * m43 + - m21 * m33 * m42 + - m31 * m22 * m43 - - m31 * m23 * m42 - - m41 * m22 * m33 + - m41 * m23 * m32; + m21 * m33 * m42 + + m31 * m22 * m43 - + m31 * m23 * m42 - + m41 * m22 * m33 + + m41 * m23 * m32; inv[13] = m11 * m32 * m43 - - m11 * m33 * m42 - - m31 * m12 * m43 + - m31 * m13 * m42 + - m41 * m12 * m33 - - m41 * m13 * m32; + m11 * m33 * m42 - + m31 * m12 * m43 + + m31 * m13 * m42 + + m41 * m12 * m33 - + m41 * m13 * m32; inv[14] = -m11 * m22 * m43 + - m11 * m23 * m42 + - m21 * m12 * m43 - - m21 * m13 * m42 - - m41 * m12 * m23 + - m41 * m13 * m22; + m11 * m23 * m42 + + m21 * m12 * m43 - + m21 * m13 * m42 - + m41 * m12 * m23 + + m41 * m13 * m22; T invDet = F(1.0) / det; for (unsigned int i = 0; i < 16; ++i) @@ -416,6 +555,11 @@ namespace Nz return false; } + /*! + * \brief Gets the rotation from this matrix + * \return Quaternion which is the representation of the rotation in this matrix + */ + template Quaternion Matrix4::GetRotation() const { @@ -425,7 +569,7 @@ namespace Nz T trace = m11 + m22 + m33; if (trace > F(0.0)) { - T s = F(0.5)/std::sqrt(trace + F(1.0)); + T s = F(0.5) / std::sqrt(trace + F(1.0)); quat.w = F(0.25) / s; quat.x = (m23 - m32) * s; quat.y = (m31 - m13) * s; @@ -465,6 +609,16 @@ namespace Nz return quat; } + /*! + * \brief Gets the ith row of the matrix + * \return Vector4 which is the ith row of the matrix + * + * \param row Index of the row you want + * + * \remark Produce a NazaraError if you try to access index greater than 3 with NAZARA_MATH_SAFE defined + * \throw std::out_of_range if NAZARA_MATH_SAFE is defined and if you try to access index greater than 3 + */ + template Vector4 Matrix4::GetRow(unsigned int row) const { @@ -473,10 +627,10 @@ namespace Nz #if NAZARA_MATH_SAFE if (row > 3) { - StringStream ss; - ss << "Column out of range: (" << row << ") > 3"; + String error("Row out of range: (" + String::Number(row) + ") > 3"); - throw std::out_of_range(ss.ToString()); + NazaraError(error); + throw std::out_of_range(error); } #endif @@ -484,6 +638,13 @@ namespace Nz return Vector4(ptr[row], ptr[row+4], ptr[row+8], ptr[row+12]); } + /*! + * \brief Gets the scale from this matrix + * \return Vector3 which is the representation of the scale in this matrix + * + * \see GetSquaredScale + */ + template Vector3 Matrix4::GetScale() const { @@ -491,35 +652,80 @@ namespace Nz return Vector3(std::sqrt(squaredScale.x), std::sqrt(squaredScale.y), std::sqrt(squaredScale.z)); } + /*! + * \brief Gets the squared scale from this matrix + * \return Vector3 which is the representation of the squared scale in this matrix + * + * \see GetScale + */ + template Vector3 Matrix4::GetSquaredScale() const { return Vector3(m11*m11 + m21*m21 + m31*m31, - m12*m12 + m22*m22 + m32*m32, - m13*m13 + m23*m23 + m33*m33); + m12*m12 + m22*m22 + m32*m32, + m13*m13 + m23*m23 + m33*m33); } + /*! + * \brief Gets the translation from this matrix + * \return Vector3 which is the representation of the translation in this matrix + */ + template Vector3 Matrix4::GetTranslation() const { return Vector3(m41, m42, m43); } + /*! + * \brief Gets the transposed of this matrix + * + * \param dest Matrix to put the result + * + * \remark You can call this method on the same object + * \remark if NAZARA_DEBUG is defined, a NazaraError is produced if dest is null and dest is not changed + * + * \see Transpose + */ + template void Matrix4::GetTransposed(Matrix4* dest) const { + #ifdef NAZARA_DEBUG + if (!dest) + { + NazaraError("Destination matrix must be valid"); + return; + } + #endif + dest->Set(m11, m21, m31, m41, - m12, m22, m32, m42, - m13, m23, m33, m43, - m14, m24, m34, m44); + m12, m22, m32, m42, + m13, m23, m33, m43, + m14, m24, m34, m44); } + /*! + * \brief Checks whetever matrix has negative scale + * \return true if determinant is negative + * + * \see GetDeterminant + */ + template bool Matrix4::HasNegativeScale() const { return GetDeterminant() < F(0.0); } + /*! + * \brief Checks whetever matrix has scale + * \return true if determinant has scale + * + * \see HasNegativeScale + */ + template bool Matrix4::HasScale() const { @@ -538,6 +744,15 @@ namespace Nz return false; } + /*! + * \brief Inverts this matrix + * \return A reference to this matrix inverted + * + * \param bool Optional argument to know if matrix has been successfully inverted + * + * \see InverseAffine + */ + template Matrix4& Matrix4::Inverse(bool* succeeded) { @@ -548,6 +763,15 @@ namespace Nz return *this; } + /*! + * \brief Inverts this matrix + * \return A reference to this matrix inverted + * + * \param bool Optional argument to know if matrix has been successfully inverted + * + * \see Inverse + */ + template Matrix4& Matrix4::InverseAffine(bool* succeeded) { @@ -558,35 +782,63 @@ namespace Nz return *this; } + /*! + * \brief Checks whether the matrix is affine + * \return true if matrix is affine + */ + template bool Matrix4::IsAffine() const { return NumberEquals(m14, F(0.0)) && - NumberEquals(m24, F(0.0)) && - NumberEquals(m34, F(0.0)) && - NumberEquals(m44, F(1.0)); + NumberEquals(m24, F(0.0)) && + NumberEquals(m34, F(0.0)) && + NumberEquals(m44, F(1.0)); } + /*! + * \brief Checks whether the matrix is identity + * \return true if matrix is identity + */ + template bool Matrix4::IsIdentity() const { return (NumberEquals(m11, F(1.0)) && NumberEquals(m12, F(0.0)) && NumberEquals(m13, F(0.0)) && NumberEquals(m14, F(0.0)) && - NumberEquals(m21, F(0.0)) && NumberEquals(m22, F(1.0)) && NumberEquals(m23, F(0.0)) && NumberEquals(m24, F(0.0)) && - NumberEquals(m31, F(0.0)) && NumberEquals(m32, F(0.0)) && NumberEquals(m33, F(1.0)) && NumberEquals(m34, F(0.0)) && - NumberEquals(m41, F(0.0)) && NumberEquals(m42, F(0.0)) && NumberEquals(m43, F(0.0)) && NumberEquals(m44, F(1.0))); + NumberEquals(m21, F(0.0)) && NumberEquals(m22, F(1.0)) && NumberEquals(m23, F(0.0)) && NumberEquals(m24, F(0.0)) && + NumberEquals(m31, F(0.0)) && NumberEquals(m32, F(0.0)) && NumberEquals(m33, F(1.0)) && NumberEquals(m34, F(0.0)) && + NumberEquals(m41, F(0.0)) && NumberEquals(m42, F(0.0)) && NumberEquals(m43, F(0.0)) && NumberEquals(m44, F(1.0))); } + /*! + * \brief Makes the matrix identity (with 1 on diagonal and 0 for others) + * \return A reference to this matrix with components (1 on diagonal and 0 for others) + * + * \see Identity + */ + template Matrix4& Matrix4::MakeIdentity() { Set(F(1.0), F(0.0), F(0.0), F(0.0), - F(0.0), F(1.0), F(0.0), F(0.0), - F(0.0), F(0.0), F(1.0), F(0.0), - F(0.0), F(0.0), F(0.0), F(1.0)); + F(0.0), F(1.0), F(0.0), F(0.0), + F(0.0), F(0.0), F(1.0), F(0.0), + F(0.0), F(0.0), F(0.0), F(1.0)); return *this; } + /*! + * \brief Makes the matrix a 'look at matrix' + * \return A reference to this matrix transformed in 'look at matrix' + * + * \param eye Position of the camera + * \param target Position of the target of the camera + * \param up Direction of up vector according to the orientation of camera + * + * \see LookAt + */ + template Matrix4& Matrix4::MakeLookAt(const Vector3& eye, const Vector3& target, const Vector3& up) { @@ -595,25 +847,51 @@ namespace Nz Vector3 u = s.CrossProduct(f); Set(s.x, u.x, -f.x, T(0.0), - s.y, u.y, -f.y, T(0.0), - s.z, u.z, -f.z, T(0.0), - -s.DotProduct(eye), -u.DotProduct(eye), f.DotProduct(eye), T(1.0)); + s.y, u.y, -f.y, T(0.0), + s.z, u.z, -f.z, T(0.0), + -s.DotProduct(eye), -u.DotProduct(eye), f.DotProduct(eye), T(1.0)); return *this; } + /*! + * \brief Makes the matrix a 'orthographic matrix' + * \return A reference to this matrix transformed in 'orthographic matrix' + * + * \param left Distance between center and left + * \param right Distance between center and right + * \param top Distance between center and top + * \param bottom Distance between center and bottom + * \param zNear Distance where 'vision' begins + * \param zFar Distance where 'vision' ends + * + * \see Ortho + */ + template Matrix4& Matrix4::MakeOrtho(T left, T right, T top, T bottom, T zNear, T zFar) { // http://msdn.microsoft.com/en-us/library/windows/desktop/bb204942(v=vs.85).aspx Set(F(2.0) / (right - left), F(0.0), F(0.0), F(0.0), - F(0.0), F(2.0) / (top - bottom), F(0.0), F(0.0), - F(0.0), F(0.0), F(1.0) / (zNear - zFar), F(0.0), - (left + right) / (left - right), (top + bottom) / (bottom - top), zNear/(zNear - zFar), F(1.0)); + F(0.0), F(2.0) / (top - bottom), F(0.0), F(0.0), + F(0.0), F(0.0), F(1.0) / (zNear - zFar), F(0.0), + (left + right) / (left - right), (top + bottom) / (bottom - top), zNear/(zNear - zFar), F(1.0)); return *this; } + /*! + * \brief Makes the matrix a 'perspective matrix' + * \return A reference to this matrix transformed in 'perspective matrix' + * + * \param angle Unit depends on NAZARA_MATH_ANGLE_RADIAN + * \param ratio Rendering ratio (typically 16/9 or 4/3) + * \param zNear Distance where 'vision' begins + * \param zFar Distance where 'vision' ends + * + * \see Perspective + */ + template Matrix4& Matrix4::MakePerspective(T angle, T ratio, T zNear, T zFar) { @@ -627,19 +905,28 @@ namespace Nz T yScale = std::tan(static_cast(M_PI_2) - angle); Set(yScale / ratio, F(0.0), F(0.0), F(0.0), - F(0.0), yScale, F(0.0), F(0.0), - F(0.0), F(0.0), - (zFar + zNear) / (zFar - zNear), F(-1.0), - F(0.0), F(0.0), F(-2.0) * (zNear * zFar) / (zFar - zNear), F(0.0)); + F(0.0), yScale, F(0.0), F(0.0), + F(0.0), F(0.0), - (zFar + zNear) / (zFar - zNear), F(-1.0), + F(0.0), F(0.0), F(-2.0) * (zNear * zFar) / (zFar - zNear), F(0.0)); return *this; } + /*! + * \brief Makes the matrix the representation of the quaternion + * \return A reference to this matrix which is the rotation of the quaternion + * + * \param rotation Quaternion representing a rotation of space + * + * \see Rotate + */ + template Matrix4& Matrix4::MakeRotation(const Quaternion& rotation) { SetRotation(rotation); - // On complète la matrice + // We complete the matrix m14 = F(0.0); m24 = F(0.0); m34 = F(0.0); @@ -651,36 +938,66 @@ namespace Nz return *this; } + /*! + * \brief Makes the matrix with the scale + * \return A reference to this matrix which is the scale + * + * \param scale Vector3 representing the homothety + * + * \see Scale + */ + template Matrix4& Matrix4::MakeScale(const Vector3& scale) { Set(scale.x, F(0.0), F(0.0), F(0.0), - F(0.0), scale.y, F(0.0), F(0.0), - F(0.0), F(0.0), scale.z, F(0.0), - F(0.0), F(0.0), F(0.0), F(1.0)); + F(0.0), scale.y, F(0.0), F(0.0), + F(0.0), F(0.0), scale.z, F(0.0), + F(0.0), F(0.0), F(0.0), F(1.0)); return *this; } + /*! + * \brief Makes the matrix with the translation + * \return A reference to this matrix which is the translation + * + * \param translation Vector3 representing the translation + * + * \see Translate + */ + template Matrix4& Matrix4::MakeTranslation(const Vector3& translation) { Set(F(1.0), F(0.0), F(0.0), F(0.0), - F(0.0), F(1.0), F(0.0), F(0.0), - F(0.0), F(0.0), F(1.0), F(0.0), - translation.x, translation.y, translation.z, F(1.0)); + F(0.0), F(1.0), F(0.0), F(0.0), + F(0.0), F(0.0), F(1.0), F(0.0), + translation.x, translation.y, translation.z, F(1.0)); return *this; } + /*! + * \brief Makes the matrix with the translation and the rotation + * \return A reference to this matrix which is transformation obtained by the translation and the rotation + * + * \param translation Vector3 representing the translation + * \param rotation Quaternion representing a rotation of space + * + * \remark Rotation is applied first + * + * \see Transform + */ + template Matrix4& Matrix4::MakeTransform(const Vector3& translation, const Quaternion& rotation) { - // La rotation et la translation peuvent être appliquées directement + // The rotation and the translation may be directly applied SetRotation(rotation); SetTranslation(translation); - // On complète la matrice (les transformations sont affines) + // We complete the matrix (the transformations are affine) m14 = F(0.0); m24 = F(0.0); m34 = F(0.0); @@ -689,40 +1006,77 @@ namespace Nz return *this; } + /*! + * \brief Makes the matrix with the translation, the rotation and the scale + * \return A reference to this matrix which is transformation obtained by the translation, the rotation and the scale + * + * \param translation Vector3 representing the translation + * \param rotation Quaternion representing a rotation of space + * \param scale Vector3 representing the homothety + * + * \remark Rotation is applied first, then translation + * + * \see Transform + */ + template Matrix4& Matrix4::MakeTransform(const Vector3& translation, const Quaternion& rotation, const Vector3& scale) { MakeTransform(translation, rotation); - // Ensuite on fait une mise à l'échelle des valeurs déjà présentes + // Then we apply the homothety to current values return ApplyScale(scale); } + /*! + * \brief Makes the matrix a 'view matrix' + * \return A reference to this matrix transformed in 'view matrix' + * + * \param translation Vector3 representing the translation + * \param rotation Quaternion representing a rotation of space + * + * \see ViewMatrix + */ + template Matrix4& Matrix4::MakeViewMatrix(const Vector3& translation, const Quaternion& rotation) { - // Une matrice de vue doit appliquer une transformation opposée à la matrice "monde" - Quaternion invRot = rotation.GetConjugate(); // Inverse de la rotation + // A view matrix must apply an inverse transformation of the 'world' matrix + Quaternion invRot = rotation.GetConjugate(); // Inverse of the rotation return MakeTransform(-(invRot * translation), invRot); } + /*! + * \brief Makes the matrix zero (with 0 everywhere) + * \return A reference to this matrix with components (0 everywhere) + * + * \see Zero + */ + template Matrix4& Matrix4::MakeZero() { Set(F(0.0), F(0.0), F(0.0), F(0.0), - F(0.0), F(0.0), F(0.0), F(0.0), - F(0.0), F(0.0), F(0.0), F(0.0), - F(0.0), F(0.0), F(0.0), F(0.0)); + F(0.0), F(0.0), F(0.0), F(0.0), + F(0.0), F(0.0), F(0.0), F(0.0), + F(0.0), F(0.0), F(0.0), F(0.0)); return *this; } + /*! + * \brief Sets the components of the matrix + * \return A reference to this matrix + * + * \param rIJ Matrix components at index(I, J) + */ + template Matrix4& Matrix4::Set(T r11, T r12, T r13, T r14, - T r21, T r22, T r23, T r24, - T r31, T r32, T r33, T r34, - T r41, T r42, T r43, T r44) + T r21, T r22, T r23, T r24, + T r31, T r32, T r33, T r34, + T r41, T r42, T r43, T r44) { m11 = r11; m12 = r12; @@ -744,15 +1098,29 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the matrix from an array of sixteen elements + * \return A reference to this matrix + * + * \param matrix[16] Matrix components + */ + template Matrix4& Matrix4::Set(const T matrix[16]) { - // Ici nous sommes certains de la continuité des éléments en mémoire - std::memcpy(&m11, matrix, 16*sizeof(T)); + // Here we are confident of the continuity of memory elements + std::memcpy(&m11, matrix, 16 * sizeof(T)); return *this; } + /*! + * \brief Sets the components of the matrix from another matrix + * \return A reference to this matrix + * + * \param matrix The other matrix + */ + template Matrix4& Matrix4::Set(const Matrix4& matrix) { @@ -761,18 +1129,34 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the matrix from another type of Matrix4 + * \return A reference to this matrix + * + * \param matrix Matrix4 of type U to convert its components + */ + template template Matrix4& Matrix4::Set(const Matrix4& matrix) { Set(F(matrix[ 0]), F(matrix[ 1]), F(matrix[ 2]), F(matrix[ 3]), - F(matrix[ 4]), F(matrix[ 5]), F(matrix[ 6]), F(matrix[ 7]), - F(matrix[ 8]), F(matrix[ 9]), F(matrix[10]), F(matrix[11]), - F(matrix[12]), F(matrix[13]), F(matrix[14]), F(matrix[15])); + F(matrix[ 4]), F(matrix[ 5]), F(matrix[ 6]), F(matrix[ 7]), + F(matrix[ 8]), F(matrix[ 9]), F(matrix[10]), F(matrix[11]), + F(matrix[12]), F(matrix[13]), F(matrix[14]), F(matrix[15])); return *this; } + /*! + * \brief Sets the components of the matrix from a quaternion + * \return A reference to this matrix which is the rotation of the quaternion + * + * \param rotation Quaternion representing a rotation of space + * + * \remark 3rd column and row are unchanged + */ + template Matrix4& Matrix4::SetRotation(const Quaternion& rotation) { @@ -804,6 +1188,15 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the matrix from a scale + * \return A reference to this matrix which is the scale of the Vector3 + * + * \param scale Vector3 representing the homothety + * + * \remark Components are unchanged, except the three first on the diagonal + */ + template Matrix4& Matrix4::SetScale(const Vector3& scale) { @@ -814,6 +1207,15 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the matrix from a translation + * \return A reference to this matrix which is the translation of the Vector3 + * + * \param translation Vector3 representing the translation + * + * \remark Components are unchanged, except the three first on the third row + */ + template Matrix4& Matrix4::SetTranslation(const Vector3& translation) { @@ -824,40 +1226,76 @@ namespace Nz return *this; } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "Matrix4(m11, m12, m13, m14,\n ...)" + */ + template String Matrix4::ToString() const { StringStream ss; return ss << "Matrix4(" << m11 << ", " << m12 << ", " << m13 << ", " << m14 << ",\n" - << " " << m21 << ", " << m22 << ", " << m23 << ", " << m24 << ",\n" - << " " << m31 << ", " << m32 << ", " << m33 << ", " << m34 << ",\n" - << " " << m41 << ", " << m42 << ", " << m43 << ", " << m44 << ')'; + << " " << m21 << ", " << m22 << ", " << m23 << ", " << m24 << ",\n" + << " " << m31 << ", " << m32 << ", " << m33 << ", " << m34 << ",\n" + << " " << m41 << ", " << m42 << ", " << m43 << ", " << m44 << ')'; } + /*! + * \brief Transforms the Vector2 and two components by the matrix + * \return Vector2 transformed by the matrix + * + * \param vector To transform + * \param z Z Component of the imaginary Vector4 + * \param w W Component of the imaginary Vector4 + */ + template Vector2 Matrix4::Transform(const Vector2& vector, T z, T w) const { - return Vector2(m11*vector.x + m21*vector.y + m31*z + m41*w, - m12*vector.x + m22*vector.y + m32*z + m42*w); + return Vector2(m11 * vector.x + m21 * vector.y + m31 * z + m41 * w, + m12 * vector.x + m22 * vector.y + m32 * z + m42 * w); } + /*! + * \brief Transforms the Vector3 and one component by the matrix + * \return Vector3 transformed by the matrix + * + * \param vector To transform + * \param w W Component of the imaginary Vector4 + */ + template Vector3 Matrix4::Transform(const Vector3& vector, T w) const { - return Vector3(m11*vector.x + m21*vector.y + m31*vector.z + m41*w, - m12*vector.x + m22*vector.y + m32*vector.z + m42*w, - m13*vector.x + m23*vector.y + m33*vector.z + m43*w); + return Vector3(m11 * vector.x + m21 * vector.y + m31 * vector.z + m41 * w, + m12 * vector.x + m22 * vector.y + m32 * vector.z + m42 * w, + m13 * vector.x + m23 * vector.y + m33 * vector.z + m43 * w); } + /*! + * \brief Transforms the Vector4 by the matrix + * \return Vector4 transformed by the matrix + * + * \param vector To transform + */ + template Vector4 Matrix4::Transform(const Vector4& vector) const { - return Vector4(m11*vector.x + m21*vector.y + m31*vector.z + m41*vector.w, - m12*vector.x + m22*vector.y + m32*vector.z + m42*vector.w, - m13*vector.x + m23*vector.y + m33*vector.z + m43*vector.w, - m14*vector.x + m24*vector.y + m34*vector.z + m44*vector.w); + return Vector4(m11 * vector.x + m21 * vector.y + m31 * vector.z + m41 * vector.w, + m12 * vector.x + m22 * vector.y + m32 * vector.z + m42 * vector.w, + m13 * vector.x + m23 * vector.y + m33 * vector.z + m43 * vector.w, + m14 * vector.x + m24 * vector.y + m34 * vector.z + m44 * vector.w); } + /*! + * \brief Transposes the matrix + * \return A reference to this matrix transposed + * + * \see GetTransposed + */ + template Matrix4& Matrix4::Transpose() { @@ -871,51 +1309,87 @@ namespace Nz return *this; } + /*! + * \brief Converts matrix to pointer to its own data + * \return A pointer to the own data + * + * \remark Access to index greather than 15 is undefined behavior + */ + template - Matrix4::operator T*() + Matrix4::operator T* () { return &m11; } + /*! + * \brief Converts matrix to pointer to its own data + * \return A constant pointer to the own data + * + * \remark Access to index greather than 15 is undefined behavior + */ + template - Matrix4::operator const T*() const + Matrix4::operator const T* () const { return &m11; } + /*! + * \brief Gets the component (x, y) of the matrix + * \return A reference to the component (x, y) + * + * \remark Produce a NazaraError if you try to access index greater than 3 for x or y with NAZARA_MATH_SAFE defined + * \throw std::out_of_range if NAZARA_MATH_SAFE is defined and if you try to access index greater than 3 for x or y + */ + template T& Matrix4::operator()(unsigned int x, unsigned int y) { #if NAZARA_MATH_SAFE if (x > 3 || y > 3) { - StringStream ss; - ss << "Index out of range: (" << x << ", " << y << ") > (3,3)"; + String error("Index out of range: (" + String::Number(x) + ", " + String::Number(y) +") > (3, 3)"); - throw std::out_of_range(ss.ToString()); + NazaraError(error); + throw std::out_of_range(error); } #endif return (&m11)[y*4+x]; } + /*! + * \brief Gets the component (x, y) of the matrix + * \return The value of the component (x, y) + * + * \remark Produce a NazaraError if you try to access index greater than 3 for x or y with NAZARA_MATH_SAFE defined + * \throw std::out_of_range if NAZARA_MATH_SAFE is defined and if you try to access index greater than 3 for x or y + */ + template T Matrix4::operator()(unsigned int x, unsigned int y) const { #if NAZARA_MATH_SAFE if (x > 3 || y > 3) { - StringStream ss; - ss << "Index out of range: (" << x << ", " << y << ") > (3,3)"; + String error("Index out of range: (" + String::Number(x) + ", " + String::Number(y) +") > (3, 3)"); - NazaraError(ss); - throw std::out_of_range(ss.ToString()); + NazaraError(error); + throw std::out_of_range(error); } #endif return (&m11)[y*4+x]; } + /*! + * \brief Multiplies the components of the matrix with other matrix + * \return A matrix where components are the product of this matrix and the other one according to matrix product + * + * \param matrix The other matrix to multiply components with + */ + template Matrix4 Matrix4::operator*(const Matrix4& matrix) const { @@ -923,24 +1397,52 @@ namespace Nz return result.Concatenate(matrix); } + /*! + * \brief Multiplies the components of the matrix with a vector + * \return A vector transposed by this matrix + * + * \param vector The vector to multiply the matrix with + */ + template Vector2 Matrix4::operator*(const Vector2& vector) const { return Transform(vector); } + /*! + * \brief Multiplies the components of the matrix with a vector + * \return A vector transposed by this matrix + * + * \param vector The vector to multiply the matrix with + */ + template Vector3 Matrix4::operator*(const Vector3& vector) const { return Transform(vector); } + /*! + * \brief Multiplies the components of the matrix with a vector + * \return A vector transposed by this matrix + * + * \param vector The vector to multiply the matrix with + */ + template Vector4 Matrix4::operator*(const Vector4& vector) const { return Transform(vector); } + /*! + * \brief Multiplies the components of the matrix with a scalar + * \return A Matrix4 where components are the product of matrix'components and the scalar + * + * \param scalar The scalar to multiply the matrix'components with + */ + template Matrix4 Matrix4::operator*(T scalar) const { @@ -951,6 +1453,13 @@ namespace Nz return mat; } + /*! + * \brief Multiplies this matrix with another one + * \return A reference to this matrix which is the product with the other one + * + * \param matrix The matrix to multiply with + */ + template Matrix4& Matrix4::operator*=(const Matrix4& matrix) { @@ -959,6 +1468,13 @@ namespace Nz return *this; } + /*! + * \brief Multiplies the components of the matrix with a scalar + * \return A reference to this matrix where components are the product with the scalar + * + * \param scalar The scalar to multiply with + */ + template Matrix4& Matrix4::operator*=(T scalar) { @@ -968,6 +1484,13 @@ namespace Nz return *this; } + /*! + * \brief Compares the matrix to other one + * \return true if the matrices are the same + * + * \param matrix Other matrix to compare with + */ + template bool Matrix4::operator==(const Matrix4& mat) const { @@ -978,30 +1501,64 @@ namespace Nz return true; } + /*! + * \brief Compares the matrix to other one + * \return false if the matrices are the same + * + * \param matrix Other matrix to compare with + */ + template bool Matrix4::operator!=(const Matrix4& mat) const { return !operator==(mat); } + /*! + * \brief Shorthand for the concatenation of two matrices + * \return A Matrix4 which is the product of two + * + * \param left Left-hand side matrix + * \param right Right-hand side matrix + * + * \see Concatenate + */ + template Matrix4 Matrix4::Concatenate(const Matrix4& left, const Matrix4& right) { - Matrix4 matrix(left); // Copie de la matrice de gauche - matrix.Concatenate(right); // Concaténation avec la matrice de droite + Matrix4 matrix(left); // Copy of left-hand side matrix + matrix.Concatenate(right); // Concatenation with right-hand side - return matrix; // Et on renvoie la matrice + return matrix; } + /*! + * \brief Shorthand for the concatenation of two affine matrices + * \return A Matrix4 which is the product of two + * + * \param left Left-hand side matrix + * \param right Right-hand side matrix + * + * \see ConcatenateAffine + */ + template Matrix4 Matrix4::ConcatenateAffine(const Matrix4& left, const Matrix4& right) { - Matrix4 matrix(left); // Copie de la matrice de gauche - matrix.ConcatenateAffine(right); // Concaténation (affine) avec la matrice de droite + Matrix4 matrix(left); // Copy of left-hand side matrix + matrix.ConcatenateAffine(right); // Affine concatenation with right-hand side - return matrix; // Et on renvoie la matrice + return matrix; } + /*! + * \brief Shorthand for the identity matrix + * \return A Matrix4 which is the identity matrix + * + * \see MakeIdentity + */ + template Matrix4 Matrix4::Identity() { @@ -1011,6 +1568,17 @@ namespace Nz return matrix; } + /*! + * \brief Shorthand for the 'look at' matrix + * \return A Matrix4 which is the 'look at' matrix + * + * \param eye Position of the camera + * \param target Position of the target of the camera + * \param up Direction of up vector according to the orientation of camera + * + * \see MakeLookAt + */ + template Matrix4 Matrix4::LookAt(const Vector3& eye, const Vector3& target, const Vector3& up) { @@ -1020,6 +1588,20 @@ namespace Nz return matrix; } + /*! + * \brief Shorthand for the 'orthographic' matrix + * \return A Matrix4 which is the 'orthographic' matrix + * + * \param left Distance between center and left + * \param right Distance between center and right + * \param top Distance between center and top + * \param bottom Distance between center and bottom + * \param zNear Distance where 'vision' begins + * \param zFar Distance where 'vision' ends + * + * \see MakeOrtho + */ + template Matrix4 Matrix4::Ortho(T left, T right, T top, T bottom, T zNear, T zFar) { @@ -1029,6 +1611,18 @@ namespace Nz return matrix; } + /*! + * \brief Shorthand for the 'perspective' matrix + * \return A Matrix4 which is the 'perspective' matrix + * + * \param angle Unit depends on NAZARA_MATH_ANGLE_RADIAN + * \param ratio Rendering ratio (typically 16/9 or 4/3) + * \param zNear Distance where 'vision' begins + * \param zFar Distance where 'vision' ends + * + * \see MakePerspective + */ + template Matrix4 Matrix4::Perspective(T angle, T ratio, T zNear, T zFar) { @@ -1038,6 +1632,15 @@ namespace Nz return matrix; } + /*! + * \brief Shorthand for the 'rotation' matrix + * \return A Matrix4 which is the rotation of the quaternion + * + * \param rotation Quaternion representing a rotation of space + * + * \see MakeRotation + */ + template Matrix4 Matrix4::Rotate(const Quaternion& rotation) { @@ -1047,6 +1650,15 @@ namespace Nz return matrix; } + /*! + * \brief Shorthand for the 'scale' matrix + * \return A Matrix4 which is is the scale + * + * \param scale Vector3 representing the homothety + * + * \see MakeScale + */ + template Matrix4 Matrix4::Scale(const Vector3& scale) { @@ -1056,6 +1668,15 @@ namespace Nz return matrix; } + /*! + * \brief Shorthand for the 'translation' matrix + * \return A Matrix4 which is is the translation + * + * \param translation Vector3 representing the translation + * + * \see MakeTranslation + */ + template Matrix4 Matrix4::Translate(const Vector3& translation) { @@ -1065,6 +1686,18 @@ namespace Nz return mat; } + /*! + * \brief Shorthand for the 'transform' matrix + * \return A Matrix4 which is transformation obtained by the translation and the rotation + * + * \param translation Vector3 representing the translation + * \param rotation Quaternion representing a rotation of space + * + * \remark Rotation is applied first + * + * \see MakeTransform + */ + template Matrix4 Matrix4::Transform(const Vector3& translation, const Quaternion& rotation) { @@ -1074,6 +1707,19 @@ namespace Nz return mat; } + /*! + * \brief Shorthand for the 'transform' matrix + * \return A Matrix4 which is transformation obtained by the translation, the rotation and the scale + * + * \param translation Vector3 representing the translation + * \param rotation Quaternion representing a rotation of space + * \param scale Vector3 representing the homothety + * + * \remark Rotation is applied first, then translation + * + * \see MakeTransform + */ + template Matrix4 Matrix4::Transform(const Vector3& translation, const Quaternion& rotation, const Vector3& scale) { @@ -1083,6 +1729,16 @@ namespace Nz return mat; } + /*! + * \brief Shorthand for the 'view' matrix + * \return A Matrix4 which is the 'view matrix' + * + * \param translation Vector3 representing the translation + * \param rotation Quaternion representing a rotation of space + * + * \see MakeViewMatrix + */ + template Matrix4 Matrix4::ViewMatrix(const Vector3& translation, const Quaternion& rotation) { @@ -1092,6 +1748,13 @@ namespace Nz return mat; } + /*! + * \brief Shorthand for the 'zero' matrix + * \return A Matrix4 with components (0 everywhere) + * + * \see MakeZero + */ + template Matrix4 Matrix4::Zero() { @@ -1102,12 +1765,28 @@ namespace Nz } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param matrix The matrix to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::Matrix4& matrix) { return out << matrix.ToString(); } +/*! +* \brief Multiplies the components of the matrix with a scalar +* \return A Matrix4 where components are the product of matrix'components and the scalar +* +* \param scale The scalar to multiply the matrix'components with +* \param matrix Matrix to multiply with +*/ + template Nz::Matrix4 operator*(T scale, const Nz::Matrix4& matrix) { diff --git a/include/Nazara/Math/OrientedBox.hpp b/include/Nazara/Math/OrientedBox.hpp index 0b579fcba..627f4cbe9 100644 --- a/include/Nazara/Math/OrientedBox.hpp +++ b/include/Nazara/Math/OrientedBox.hpp @@ -43,8 +43,8 @@ namespace Nz void Update(const Matrix4& transformMatrix); void Update(const Vector3& transformMatrix); - operator Vector3*(); - operator const Vector3*() const; + operator Vector3* (); + operator const Vector3* () const; Vector3& operator()(unsigned int i); Vector3 operator()(unsigned int i) const; diff --git a/include/Nazara/Math/OrientedBox.inl b/include/Nazara/Math/OrientedBox.inl index a54cdae79..c1668118c 100644 --- a/include/Nazara/Math/OrientedBox.inl +++ b/include/Nazara/Math/OrientedBox.inl @@ -13,24 +13,62 @@ namespace Nz { + /*! + * \class Nz::OrientedBox + * \brief Math class that represents an oriented three dimensional box + * + * \remark You need to call Update not to have undefined behaviour + */ + + /*! + * \brief Constructs a OrientedBox object from its position and sizes + * + * \param X X component of position + * \param Y Y component of position + * \param Z Z component of position + * \param Width Width of the box (following X) + * \param Height Height of the box (following Y) + * \param Depth Depth of the box (following Z) + */ + template OrientedBox::OrientedBox(T X, T Y, T Z, T Width, T Height, T Depth) { Set(X, Y, Z, Width, Height, Depth); } + /*! + * \brief Constructs a OrientedBox object from a box + * + * \param box Box object + */ + template OrientedBox::OrientedBox(const Box& box) { Set(box); } + /*! + * \brief Constructs a OrientedBox object from two vectors representing point of the space + * (X, Y, Z) will be the components minimum of the two vectors and the (width, height, depth) will be the components maximum - minimum + * + * \param vec1 First point + * \param vec2 Second point + */ + template OrientedBox::OrientedBox(const Vector3& vec1, const Vector3& vec2) { Set(vec1, vec2); } + /*! + * \brief Constructs a OrientedBox object from another type of OrientedBox + * + * \param orientedBox OrientedBox of type U to convert to type T + */ + template template OrientedBox::OrientedBox(const OrientedBox& orientedBox) @@ -38,6 +76,15 @@ namespace Nz Set(orientedBox); } + /*! + * \brief Gets the Vector3 for the corner + * \return The position of the corner of the oriented box according to enum BoxCorner + * + * \param corner Enumeration of type BoxCorner + * + * \remark If enumeration is not defined in BoxCorner, a NazaraError is thrown and a Vector3 uninitialised is returned + */ + template const Vector3& OrientedBox::GetCorner(BoxCorner corner) const { @@ -54,12 +101,24 @@ namespace Nz return m_corners[corner]; } + /*! + * \brief Checks whether this oriented box is valid + * \return true if the oriented box has a strictly positive width, height and depth + */ + template bool OrientedBox::IsValid() const { return localBox.IsValid(); } + /*! + * \brief Makes the oriented box position (0, 0, 0) and lengths (0, 0, 0) + * \return A reference to this oriented box with position (0, 0, 0) and lengths (0, 0, 0) + * + * \see Zero + */ + template OrientedBox& OrientedBox::MakeZero() { @@ -68,6 +127,18 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the oriented box + * \return A reference to this oriented box + * + * \param X X position + * \param Y Y position + * \param Z Z position + * \param Width Width of the oriented box (following X) + * \param Height Height of the oriented box (following Y) + * \param Depth Depth of the oriented box (following Z) + */ + template OrientedBox& OrientedBox::Set(T X, T Y, T Z, T Width, T Height, T Depth) { @@ -76,6 +147,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the oriented box from a box + * \return A reference to this oriented box + * + * \param box Box object + */ + template OrientedBox& OrientedBox::Set(const Box& box) { @@ -84,6 +162,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the oriented box with components from another + * \return A reference to this oriented box + * + * \param orientedBox The other OrientedBox + */ + template OrientedBox& OrientedBox::Set(const OrientedBox& orientedBox) { @@ -92,6 +177,14 @@ namespace Nz return *this; } + /*! + * \brief Sets a OrientedBox object from two vectors representing point of the space + * (X, Y, Z) will be the components minimum of the two vectors and the (width, height, depth) will be the components maximum - minimum + * + * \param vec1 First point + * \param vec2 Second point + */ + template OrientedBox& OrientedBox::Set(const Vector3& vec1, const Vector3& vec2) { @@ -100,6 +193,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the orientedBox from another type of OrientedBox + * \return A reference to this orientedBox + * + * \param orientedBox OrientedBox of type U to convert its components + */ + template template OrientedBox& OrientedBox::Set(const OrientedBox& orientedBox) @@ -112,21 +212,32 @@ namespace Nz return *this; } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "OrientedBox(...)" + */ + template String OrientedBox::ToString() const { StringStream ss; return ss << "OrientedBox(FLB: " << m_corners[BoxCorner_FarLeftBottom].ToString() << "\n" - << " FLT: " << m_corners[BoxCorner_FarLeftTop].ToString() << "\n" - << " FRB: " << m_corners[BoxCorner_FarRightBottom].ToString() << "\n" - << " FRT: " << m_corners[BoxCorner_FarRightTop].ToString() << "\n" - << " NLB: " << m_corners[BoxCorner_NearLeftBottom].ToString() << "\n" - << " NLT: " << m_corners[BoxCorner_NearLeftTop].ToString() << "\n" - << " NRB: " << m_corners[BoxCorner_NearRightBottom].ToString() << "\n" - << " NRT: " << m_corners[BoxCorner_NearRightTop].ToString() << ")\n"; + << " FLT: " << m_corners[BoxCorner_FarLeftTop].ToString() << "\n" + << " FRB: " << m_corners[BoxCorner_FarRightBottom].ToString() << "\n" + << " FRT: " << m_corners[BoxCorner_FarRightTop].ToString() << "\n" + << " NLB: " << m_corners[BoxCorner_NearLeftBottom].ToString() << "\n" + << " NLT: " << m_corners[BoxCorner_NearLeftTop].ToString() << "\n" + << " NRB: " << m_corners[BoxCorner_NearRightBottom].ToString() << "\n" + << " NRT: " << m_corners[BoxCorner_NearRightTop].ToString() << ")\n"; } + /*! + * \brief Updates the corners of the box + * + * \param transformMatrix Matrix4 which represents the transformation to apply on the local box + */ + template void OrientedBox::Update(const Matrix4& transformMatrix) { @@ -134,6 +245,12 @@ namespace Nz m_corners[i] = transformMatrix.Transform(localBox.GetCorner(static_cast(i))); } + /*! + * \brief Updates the corners of the box + * + * \param translation Vector3 which represents the translation to apply on the local box + */ + template void OrientedBox::Update(const Vector3& translation) { @@ -141,18 +258,40 @@ namespace Nz m_corners[i] = localBox.GetCorner(static_cast(i)) + translation; } + /*! + * \brief Converts oriented box to pointer of Vector3 to its own corners + * \return A pointer to the own corners + * + * \remark Access to index greather than BoxCorner_Max is undefined behavior + */ + template - OrientedBox::operator Vector3*() + OrientedBox::operator Vector3* () { return &m_corners[0]; } + /*! + * \brief Converts oriented box to pointer of Vector3 to its own corners + * \return A const pointer to the own corners + * + * \remark Access to index greather than BoxCorner_Max is undefined behavior + */ + template - OrientedBox::operator const Vector3*() const + OrientedBox::operator const Vector3* () const { return &m_corners[0]; } + /*! + * \brief Gets the ith corner of the oriented box + * \return A reference to this corner + * + * \remark Produce a NazaraError if you try to access to index greather than BoxCorner_Max with NAZARA_MATH_SAFE defined. If not, it is undefined behaviour + * \throw std::out_of_range if NAZARA_MATH_SAFE is defined and you try to acces to index greather than BoxCorner_Max + */ + template Vector3& OrientedBox::operator()(unsigned int i) { @@ -170,6 +309,14 @@ namespace Nz return m_corners[i]; } + /*! + * \brief Gets the ith corner of the oriented box + * \return A reference to this corner + * + * \remark Produce a NazaraError if you try to access to index greather than BoxCorner_Max with NAZARA_MATH_SAFE defined. If not, it is undefined behaviour + * \throw std::out_of_range if NAZARA_MATH_SAFE is defined and you try to acces to index greather than BoxCorner_Max + */ + template Vector3 OrientedBox::operator()(unsigned int i) const { @@ -187,6 +334,13 @@ namespace Nz return m_corners[i]; } + /*! + * \brief Multiplies the lengths with the scalar + * \return A OrientedBox where the position is the same and width, height and depth are the product of the old width, height and depth and the scalar + * + * \param scale The scalar to multiply width, height and depth with + */ + template OrientedBox OrientedBox::operator*(T scalar) const { @@ -196,6 +350,13 @@ namespace Nz return box; } + /*! + * \brief Multiplies the lengths of this oriented box with the scalar + * \return A reference to this oriented box where lengths are the product of these lengths and the scalar + * + * \param scalar The scalar to multiply width, height and depth with + */ + template OrientedBox& OrientedBox::operator*=(T scalar) { @@ -204,18 +365,46 @@ namespace Nz return *this; } + /*! + * \brief Compares the oriented box to other one + * \return true if the two oriented boxes are the same + * + * \param box Other oriented box to compare with + */ + template bool OrientedBox::operator==(const OrientedBox& box) const { return localBox == box.localBox; } + /*! + * \brief Compares the oriented box to other one + * \return false if the two oriented boxes are the same + * + * \param box Other oriented box to compare with + */ + template bool OrientedBox::operator!=(const OrientedBox& box) const { return !operator==(box); } + /*! + * \brief Interpolates the oriented box to other one with a factor of interpolation + * \return A new oriented box which is the interpolation of two oriented boxes + * + * \param from Initial oriented box + * \param to Target oriented box + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * \remark With NAZARA_DEBUG, a NazaraError is thrown and Zero() is returned + * + * \see Lerp + */ + template OrientedBox OrientedBox::Lerp(const OrientedBox& from, const OrientedBox& to, T interpolation) { @@ -225,6 +414,13 @@ namespace Nz return orientedBox; } + /*! + * \brief Shorthand for the oriented box (0, 0, 0, 0, 0, 0) + * \return A oriented box with position (0, 0, 0) and lengths (0, 0, 0) + * + * \see MakeZero + */ + template OrientedBox OrientedBox::Zero() { @@ -235,6 +431,14 @@ namespace Nz } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param orientedBox The orientedBox to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::OrientedBox& orientedBox) { diff --git a/include/Nazara/Math/Plane.hpp b/include/Nazara/Math/Plane.hpp index cd0856aa5..70bc06051 100644 --- a/include/Nazara/Math/Plane.hpp +++ b/include/Nazara/Math/Plane.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Mathematics module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -26,8 +26,12 @@ namespace Nz Plane(const Plane& plane) = default; ~Plane() = default; - T Distance(const Vector3& point) const; T Distance(T x, T y, T z) const; + T Distance(const Vector3& point) const; + + Plane& MakeXY(); + Plane& MakeXZ(); + Plane& MakeYZ(); Plane& Set(T normalX, T normalY, T normalZ, T Distance); Plane& Set(const T plane[4]); diff --git a/include/Nazara/Math/Plane.inl b/include/Nazara/Math/Plane.inl index fceeb9cc3..9b29ab48a 100644 --- a/include/Nazara/Math/Plane.inl +++ b/include/Nazara/Math/Plane.inl @@ -11,36 +11,88 @@ namespace Nz { + /*! + * \class Nz::Vector4 + * \brief Math class that represents a plane in 3D + * + * \remark The convention used in this class is: If you ask for plane with normal (0, 1, 0) and distance 1, you will get 0 * X + 1 * Y + 0 * Z - 1 = 0 or Y = 1. Notice the sign minus before the distance on the left side of the equation + */ + + /*! + * \brief Constructs a Plane object from its components + * + * \param normalX X component of the normal + * \param normalY Y component of the normal + * \param normalZ Z component of the normal + * \param D Distance to origin + */ + template Plane::Plane(T normalX, T normalY, T normalZ, T D) { Set(normalX, normalY, normalZ, D); } + /*! + * \brief Constructs a Plane object from an array of four elements + * + * \param plane[4] plane[0] is X component, plane[1] is Y component, plane[2] is Z component and plane[3] is D + */ + template Plane::Plane(const T plane[4]) { Set(plane); } + /*! + * \brief Constructs a Plane object from a normal and a distance + * + * \param Normal normal of the vector + * \param D Distance to origin + */ + template Plane::Plane(const Vector3& Normal, T D) { Set(Normal, D); } + /*! + * \brief Constructs a Plane object from a normal and a point + * + * \param Normal Normal of the plane + * \param point Point which verifies the equation of the plane + */ + template Plane::Plane(const Vector3& Normal, const Vector3& point) { Set(Normal, point); } + /*! + * \brief Constructs a Plane object from three points + * + * \param point1 First point + * \param point2 Second point + * \param point3 Third point + * + * \remark They are expected not to be colinear + */ + template Plane::Plane(const Vector3& point1, const Vector3& point2, const Vector3& point3) { Set(point1, point2, point3); } + /*! + * \brief Constructs a Plane object from another type of Plane + * + * \param plane Plane of type U to convert to type T + */ + template template Plane::Plane(const Plane& plane) @@ -48,11 +100,18 @@ namespace Nz Set(plane); } - template - T Plane::Distance(const Vector3& point) const - { - return normal.DotProduct(point) - distance; // ax + by + cd - d = 0. - } + /*! + * \brief Returns the distance from the plane to the point + * \return Distance to the point + * + * \param X X position of the point + * \param Y Y position of the point + * \param Z Z position of the point + * + * \remark If T is negative, it means that the point is in the opposite direction of the normal + * + * \see Distance + */ template T Plane::Distance(T x, T y, T z) const @@ -60,6 +119,72 @@ namespace Nz return Distance(Vector3(x, y, z)); } + /*! + * \brief Returns the distance from the plane to the point + * \return Distance to the point + * + * \param point Position of the point + * + * \remark If T is negative, it means that the point is in the opposite direction of the normal + * + * \see Distance + */ + + template + T Plane::Distance(const Vector3& point) const + { + return normal.DotProduct(point) - distance; // ax + by + cd - d = 0. + } + + /*! + * \brief Makes the plane (0, 0, 1, 0) + * \return A reference to this plane with components (0, 0, 1, 0) + * + * \see XY + */ + + template + Plane& Plane::MakeXY() + { + return Set(F(0.0), F(0.0), F(1.0), F(0.0)); + } + + /*! + * \brief Makes the plane (0, 1, 0, 0) + * \return A reference to this plane with components (0, 1, 0, 0) + * + * \see XZ + */ + + template + Plane& Plane::MakeXZ() + { + return Set(F(0.0), F(1.0), F(0.0), F(0.0)); + } + + /*! + * \brief Makes the plane (1, 0, 0, 0) + * \return A reference to this plane with components (1, 0, 0, 0) + * + * \see YZ + */ + + template + Plane& Plane::MakeYZ() + { + return Set(F(1.0), F(0.0), F(0.0), F(0.0)); + } + + /*! + * \brief Sets the components of the plane + * \return A reference to this plane + * + * \param normalX X component of the normal + * \param normalY Y component of the normal + * \param normalZ Z component of the normal + * \param D Distance to origin + */ + template Plane& Plane::Set(T normalX, T normalY, T normalZ, T D) { @@ -69,6 +194,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the plane from an array of four elements + * \return A reference to this plane + * + * \param plane[4] plane[0] is X component, plane[1] is Y component, plane[2] is Z component and plane[3] is D + */ + template Plane& Plane::Set(const T plane[4]) { @@ -78,6 +210,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the plane from another plane + * \return A reference to this plane + * + * \param plane The other plane + */ + template Plane& Plane::Set(const Plane& plane) { @@ -86,6 +225,14 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the plane from a normal and a distance + * \return A reference to this plane + * + * \param Normal Normal of the vector + * \param D Distance to origin + */ + template Plane& Plane::Set(const Vector3& Normal, T D) { @@ -95,6 +242,14 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the plane from a normal and a point + * \return A reference to this plane + * + * \param Normal Normal of the plane + * \param point Point which verifies the equation of the plane + */ + template Plane& Plane::Set(const Vector3& Normal, const Vector3& point) { @@ -104,6 +259,17 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the plane from three points + * \return A reference to this plane + * + * \param point1 First point + * \param point2 Second point + * \param point3 Third point + * + * \remark They are expected not to be colinear + */ + template Plane& Plane::Set(const Vector3& point1, const Vector3& point2, const Vector3& point3) { @@ -117,6 +283,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the plane from another type of Plane + * \return A reference to this plane + * + * \param plane Plane of type U to convert its components + */ + template template Plane& Plane::Set(const Plane& plane) @@ -127,6 +300,11 @@ namespace Nz return *this; } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "Plane(Normal: Vector3(x, y, z); Distance: w)" + */ + template String Plane::ToString() const { @@ -135,18 +313,50 @@ namespace Nz return ss << "Plane(Normal: " << normal.ToString() << "; Distance: " << distance << ')'; } + /*! + * \brief Compares the plane to other one + * \return true if the planes are the same + * + * \param vec Other vector to compare with + * + * \remark Plane with normal N and distance D is the same than with normal -N et distance -D + */ + template bool Plane::operator==(const Plane& plane) const { return (normal == plane.normal && NumberEquals(distance, plane.distance)) || (normal == -plane.normal && NumberEquals(distance, -plane.distance)); } + /*! + * \brief Compares the plane to other one + * \return false if the planes are the same + * + * \param plane Other plane to compare with + * + * \remark Plane with normal N and distance D is the same than with normal -N et distance -D + */ + template bool Plane::operator!=(const Plane& plane) const { return !operator==(plane); } + /*! + * \brief Interpolates the plane to other one with a factor of interpolation + * \return A new plane which is the interpolation of two planes + * + * \param from Initial plane + * \param to Target plane + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * \remark With NAZARA_DEBUG, a NazaraError is thrown and Plane() is returned + * + * \see Lerp + */ + template Plane Plane::Lerp(const Plane& from, const Plane& to, T interpolation) { @@ -159,32 +369,70 @@ namespace Nz #endif Plane plane; - plane.distance = Lerp(from.distance, to.distance, interpolation); + plane.distance = Nz::Lerp(from.distance, to.distance, interpolation); plane.normal = Vector3::Lerp(from.normal, to.normal, interpolation); plane.normal.Normalize(); return plane; } + /*! + * \brief Shorthand for the plane (0, 0, 1, 0) + * \return A plane with components (0, 0, 1, 0) + * + * \see MakeXY + */ + template Plane Plane::XY() { - return Plane(F(0.0), F(0.0), F(1.0), F(0.0)); + Plane plane; + plane.MakeXY(); + + return plane; } + /*! + * \brief Shorthand for the plane (0, 1, 0, 0) + * \return A plane with components (0, 1, 0, 0) + * + * \see MakeXZ + */ + template Plane Plane::XZ() { - return Plane(F(0.0), F(1.0), F(0.0), F(0.0)); + Plane plane; + plane.MakeXZ(); + + return plane; } + /*! + * \brief Shorthand for the plane (1, 0, 0, 0) + * \return A plane with components (1, 0, 0, 0) + * + * \see MakeYZ + */ + template Plane Plane::YZ() { - return Plane(F(1.0), F(0.0), F(0.0), F(0.0)); + Plane plane; + plane.MakeYZ(); + + return plane; } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param plane The plane to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::Plane& plane) { diff --git a/include/Nazara/Math/Quaternion.hpp b/include/Nazara/Math/Quaternion.hpp index b8ca310c1..f33dec0b6 100644 --- a/include/Nazara/Math/Quaternion.hpp +++ b/include/Nazara/Math/Quaternion.hpp @@ -19,9 +19,9 @@ namespace Nz public: Quaternion() = default; Quaternion(T W, T X, T Y, T Z); - Quaternion(const T quat[4]); - Quaternion(T angle, const Vector3& axis); Quaternion(const EulerAngles& angles); + Quaternion(T angle, const Vector3& axis); + Quaternion(const T quat[4]); //Quaternion(const Matrix3& mat); template explicit Quaternion(const Quaternion& quat); Quaternion(const Quaternion& quat) = default; @@ -47,9 +47,9 @@ namespace Nz Quaternion& Normalize(T* length = nullptr); Quaternion& Set(T W, T X, T Y, T Z); - Quaternion& Set(const T quat[4]); - Quaternion& Set(T angle, const Vector3& normalizedAxis); Quaternion& Set(const EulerAngles& angles); + Quaternion& Set(T angle, const Vector3& normalizedAxis); + Quaternion& Set(const T quat[4]); //Quaternion& Set(const Matrix3& mat); Quaternion& Set(const Quaternion& quat); template Quaternion& Set(const Quaternion& quat); @@ -60,7 +60,7 @@ namespace Nz //Matrix3 ToRotationMatrix() const; String ToString() const; - Quaternion& operator=(const Quaternion& quat); + Quaternion& operator=(const Quaternion& quat) = default; Quaternion operator+(const Quaternion& quat) const; Quaternion operator*(const Quaternion& quat) const; diff --git a/include/Nazara/Math/Quaternion.inl b/include/Nazara/Math/Quaternion.inl index 50c8ec8e3..ea1ce4d3e 100644 --- a/include/Nazara/Math/Quaternion.inl +++ b/include/Nazara/Math/Quaternion.inl @@ -15,29 +15,67 @@ namespace Nz { + /*! + * \class Nz::Quaternion + * \brief Math class that represents an element of the quaternions + * + * \remark The quaternion is meant to be 'unit' to represent rotations in a three dimensional space + */ + + /*! + * \brief Constructs a Quaternion object from its components + * + * \param W W component + * \param X X component + * \param Y Y component + * \param Z Z component + */ + template Quaternion::Quaternion(T W, T X, T Y, T Z) { Set(W, X, Y, Z); } + /*! + * \brief Constructs a Quaternion object from a EulerAngles + * + * \param angles Easier representation of rotation of space + * + * \see EulerAngles + */ + template - Quaternion::Quaternion(const T quat[4]) + Quaternion::Quaternion(const EulerAngles& angles) { - Set(quat); + Set(angles); } + /*! + * \brief Constructs a Quaternion object from an angle and a direction + * + * \param angle Unit depends of NAZARA_MATH_ANGLE_RADIAN + * \param axis Vector3 which represents a direction, no need to be normalized + */ + template Quaternion::Quaternion(T angle, const Vector3& axis) { Set(angle, axis); } + /*! + * \brief Constructs a Quaternion object from an array of four elements + * + * \param quat[4] quat[0] is W component, quat[1] is X component, quat[2] is Y component and quat[3] is Z component + */ + template - Quaternion::Quaternion(const EulerAngles& angles) + Quaternion::Quaternion(const T quat[4]) { - Set(angles); + Set(quat); } + /* template Quaternion::Quaternion(const Matrix3& mat) @@ -45,6 +83,13 @@ namespace Nz Set(mat); } */ + + /*! + * \brief Constructs a Quaternion object from another type of Quaternion + * + * \param quat Quaternion of type U to convert to type T + */ + template template Quaternion::Quaternion(const Quaternion& quat) @@ -52,6 +97,11 @@ namespace Nz Set(quat); } + /*! + * \brief Computes the w component of the quaternion to make it unit + * \return A reference to this quaternion + */ + template Quaternion& Quaternion::ComputeW() { @@ -65,6 +115,15 @@ namespace Nz return *this; } + /*! + * \brief Returns the rotational conjugate of this quaternion + * \return A reference to this quaternion + * + * The conjugate of a quaternion represents the same rotation in the opposite direction about the rotational axis + * + * \see GetConjugate + */ + template Quaternion& Quaternion::Conjugate() { @@ -75,12 +134,28 @@ namespace Nz return *this; } + /*! + * \brief Calculates the dot (scalar) product with two quaternions + * \return The value of the dot product + * + * \param quat The other quaternion to calculate the dot product with + */ + template T Quaternion::DotProduct(const Quaternion& quat) const { - return w*quat.w + x*quat.x + y*quat.y + z*quat.z; + return w * quat.w + x * quat.x + y * quat.y + z * quat.z; } + /*! + * \brief Gets the rotational conjugate of this quaternion + * \return A new quaternion which is the conjugate of this quaternion + * + * The conjugate of a quaternion represents the same rotation in the opposite direction about the rotational axis + * + * \see Conjugate + */ + template Quaternion Quaternion::GetConjugate() const { @@ -90,6 +165,15 @@ namespace Nz return quat; } + /*! + * \brief Gets the inverse of this quaternion + * \return A new quaternion which is the inverse of this quaternion + * + * \remark If this quaternion is (0, 0, 0, 0), then it returns (0, 0, 0, 0) + * + * \see Inverse + */ + template Quaternion Quaternion::GetInverse() const { @@ -99,6 +183,17 @@ namespace Nz return quat; } + /*! + * \brief Gets the normalization of this quaternion + * \return A new quaternion which is the normalization of this quaternion + * + * \param length Optional argument to obtain the length's ratio of the quaternion and the unit-length + * + * \remark If this quaternion is (0, 0, 0, 0), then it returns (0, 0, 0, 0) and length is 0 + * + * \see Normalize + */ + template Quaternion Quaternion::GetNormal(T* length) const { @@ -108,6 +203,15 @@ namespace Nz return quat; } + /*! + * \brief Inverts this quaternion + * \return A reference to this quaternion which is now inverted + * + * \remark If this quaternion is (0, 0, 0, 0), then it returns (0, 0, 0, 0) + * + * \see GetInverse + */ + template Quaternion& Quaternion::Inverse() { @@ -125,15 +229,34 @@ namespace Nz return *this; } + /*! + * \brief Makes the quaternion (1, 0, 0, 0) + * \return A reference to this vector with components (1, 0, 0, 0) + * + * \see Unit + */ + template Quaternion& Quaternion::MakeIdentity() { return Set(F(1.0), F(0.0), F(0.0), F(0.0)); } + /*! + * \brief Makes this quaternion to the rotation required to rotate direction Vector3 from to direction Vector3 to + * \return A reference to this vector which is the rotation needed + * + * \param from Initial vector + * \param to Target vector + * + * \see RotationBetween + */ + template Quaternion& Quaternion::MakeRotationBetween(const Vector3& from, const Vector3& to) { + // TODO (Gawaboumga): Replace by http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors ? + T dot = from.DotProduct(to); if (NumberEquals(dot, F(-1.0))) { @@ -157,28 +280,55 @@ namespace Nz } } + /*! + * \brief Makes the quaternion (0, 0, 0, 0) + * \return A reference to this vector with components (0, 0, 0, 0) + * + * \see Zero + */ + template Quaternion& Quaternion::MakeZero() { return Set(F(0.0), F(0.0), F(0.0), F(0.0)); } + /*! + * \brief Calculates the magnitude (length) of the quaternion + * \return The magnitude + * + * \see SquaredMagnitude + */ + template T Quaternion::Magnitude() const { return std::sqrt(SquaredMagnitude()); } + /*! + * \brief Normalizes the current quaternion + * \return A reference to this quaternion which is now normalized + * + * \param length Optional argument to obtain the length's ratio of the quaternion and the unit-length + * + * \remark If the quaternion is (0, 0, 0, 0), then it returns (0, 0, 0, 0) and length is 0 + * + * \see GetNormal + */ + template Quaternion& Quaternion::Normalize(T* length) { T norm = std::sqrt(SquaredMagnitude()); - T invNorm = F(1.0) / norm; - - w *= invNorm; - x *= invNorm; - y *= invNorm; - z *= invNorm; + if (norm > F(0.0)) + { + T invNorm = F(1.0) / norm; + w *= invNorm; + x *= invNorm; + y *= invNorm; + z *= invNorm; + } if (length) *length = norm; @@ -186,6 +336,16 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the quaternion + * \return A reference to this quaternion + * + * \param W W component + * \param X X component + * \param Y Y component + * \param Z Z component + */ + template Quaternion& Quaternion::Set(T W, T X, T Y, T Z) { @@ -197,17 +357,29 @@ namespace Nz return *this; } - template - Quaternion& Quaternion::Set(const T quat[4]) - { - w = quat[0]; - x = quat[1]; - y = quat[2]; - z = quat[3]; + /*! + * \brief Sets this quaternion from rotation specified by Euler angle + * \return A reference to this quaternion + * + * \param angles Easier representation of rotation of space + * + * \see EulerAngles + */ - return *this; + template + Quaternion& Quaternion::Set(const EulerAngles& angles) + { + return Set(angles.ToQuaternion()); } + /*! + * \brief Sets this quaternion from rotation specified by axis and angle + * \return A reference to this quaternion + * + * \param angle Unit depends of NAZARA_MATH_ANGLE_RADIAN + * \param axis Vector3 which represents a direction, no need to be normalized + */ + template Quaternion& Quaternion::Set(T angle, const Vector3& axis) { @@ -229,12 +401,46 @@ namespace Nz return Normalize(); } + /*! + * \brief Sets the components of the quaternion from an array of four elements + * \return A reference to this quaternion + * + * \param quat[4] quat[0] is W component, quat[1] is X component, quat[2] is Y component and quat[3] is Z component + */ + template - Quaternion& Quaternion::Set(const EulerAngles& angles) + Quaternion& Quaternion::Set(const T quat[4]) { - return Set(angles.ToQuaternion()); + w = quat[0]; + x = quat[1]; + y = quat[2]; + z = quat[3]; + + return *this; } + /*! + * \brief Sets the components of the quaternion from another quaternion + * \return A reference to this quaternion + * + * \param vec The other quaternion + */ + + template + Quaternion& Quaternion::Set(const Quaternion& quat) + { + std::memcpy(this, &quat, sizeof(Quaternion)); + + return *this; + } + + /*! + * \brief Sets the components of the quaternion from another type of Quaternion + * \return A reference to this quaternion + * + * \param quat Quaternion of type U to convert its components + */ + template template Quaternion& Quaternion::Set(const Quaternion& quat) @@ -247,36 +453,48 @@ namespace Nz return *this; } - template - Quaternion& Quaternion::Set(const Quaternion& quat) - { - std::memcpy(this, &quat, sizeof(Quaternion)); - - return *this; - } + /*! + * \brief Calculates the squared magnitude (length) of the quaternion + * \return The squared magnitude + * + * \see Magnitude + */ template T Quaternion::SquaredMagnitude() const { - return w*w + x*x + y*y + z*z; + return w * w + x * x + y * y + z * z; } + /*! + * \brief Converts this quaternion to Euler angles representation + * \return EulerAngles which is the representation of this rotation + * + * \remark Rotation are "left-handed" + */ + template EulerAngles Quaternion::ToEulerAngles() const { - T test = x*y + z*w; + T test = x * y + z * w; if (test > F(0.499)) // singularity at north pole return EulerAngles(FromDegrees(F(90.0)), FromRadians(F(2.0) * std::atan2(x, w)), F(0.0)); if (test < F(-0.499)) + // singularity at south pole return EulerAngles(FromDegrees(F(-90.0)), FromRadians(F(-2.0) * std::atan2(x, w)), F(0.0)); - return EulerAngles(FromRadians(std::atan2(F(2.0)*x*w - F(2.0)*y*z, F(1.0) - F(2.0)*x*x - F(2.0)*z*z)), - FromRadians(std::atan2(F(2.0)*y*w - F(2.0)*x*z, F(1.0) - F(2.0)*y*y - F(2.0)*z*z)), - FromRadians(std::asin(F(2.0)*test))); + return EulerAngles(FromRadians(std::atan2(F(2.0) * x * w - F(2.0) * y * z, F(1.0) - F(2.0) * x * x - F(2.0) * z * z)), + FromRadians(std::atan2(F(2.0) * y * w - F(2.0) * x * z, F(1.0) - F(2.0) * y * y - F(2.0) * z * z)), + FromRadians(std::asin(F(2.0) * test))); } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "Quaternion(w | x, y, z)" + */ + template String Quaternion::ToString() const { @@ -285,11 +503,12 @@ namespace Nz return ss << "Quaternion(" << w << " | " << x << ", " << y << ", " << z << ')'; } - template - Quaternion& Quaternion::operator=(const Quaternion& quat) - { - return Set(quat); - } + /*! + * \brief Adds the components of the quaternion with other quaternion + * \return A quaternion where components are the sum of this quaternion and the other one + * + * \param quat The other quaternion to add components with + */ template Quaternion Quaternion::operator+(const Quaternion& quat) const @@ -303,18 +522,32 @@ namespace Nz return result; } + /*! + * \brief Multiplies of the quaternion with other quaternion + * \return A quaternion which is the product of those two according to operator* in quaternions + * + * \param quat The other quaternion to multiply with + */ + template Quaternion Quaternion::operator*(const Quaternion& quat) const { Quaternion result; - result.w = w*quat.w - x*quat.x - y*quat.y - z*quat.z; - result.x = w*quat.x + x*quat.w + y*quat.z - z*quat.y; - result.y = w*quat.y + y*quat.w + z*quat.x - x*quat.z; - result.z = w*quat.z + z*quat.w + x*quat.y - y*quat.x; + result.w = w * quat.w - x * quat.x - y * quat.y - z * quat.z; + result.x = w * quat.x + x * quat.w + y * quat.z - z * quat.y; + result.y = w * quat.y + y * quat.w + z * quat.x - x * quat.z; + result.z = w * quat.z + z * quat.w + x * quat.y - y * quat.x; return result; } + /*! + * \brief Apply the quaternion to the Vector3 + * \return A Vector3f which is the vector rotated by this quaternion + * + * \param vec The vector to multiply with + */ + template Vector3 Quaternion::operator*(const Vector3& vec) const { @@ -327,60 +560,123 @@ namespace Nz return vec + uv + uuv; } + /*! + * \brief Multiplies the components of the quaternion with a scalar + * \return A quaternion where components are the product of this quaternion and the scalar + * + * \param scale The scalar to multiply components with + */ + template Quaternion Quaternion::operator*(T scale) const { return Quaternion(w * scale, - x * scale, - y * scale, - z * scale); + x * scale, + y * scale, + z * scale); } + /*! + * \brief Divides the quaternion with other quaternion + * \return A quaternion which is the quotient of those two according to operator* in quaternions + * + * \param quat The other quaternion to divide with + */ + template Quaternion Quaternion::operator/(const Quaternion& quat) const { return quat.GetConjugate() * (*this); } + /*! + * \brief Adds the components of the quaternion with other quaternion + * \return A reference to this quaternion where components are the sum of this quaternion and the other one + * + * \param quat The other quaternion to add components with + */ + template Quaternion& Quaternion::operator+=(const Quaternion& quat) { return operator=(operator+(quat)); } + /*! + * \brief Multiplies of the quaternion with other quaternion + * \return A reference to this quaternion which is the product of those two according to operator* in quaternions + * + * \param quat The other quaternion to multiply with + */ + template Quaternion& Quaternion::operator*=(const Quaternion& quat) { return operator=(operator*(quat)); } + /*! + * \brief Multiplies the components of the quaternion with a scalar + * \return A reference to this quaternion where components are the product of this quaternion and the scalar + * + * \param scale The scalar to multiply components with + */ + template Quaternion& Quaternion::operator*=(T scale) { return operator=(operator*(scale)); } + /*! + * \brief Divides the quaternion with other quaternion + * \return A reference to this quaternion which is the quotient of those two according to operator* in quaternions + * + * \param quat The other quaternion to divide with + */ + template Quaternion& Quaternion::operator/=(const Quaternion& quat) { return operator=(operator/(quat)); } + /*! + * \brief Compares the quaternion to other one + * \return true if the quaternions are the same + * + * \param vec Other quaternion to compare with + */ + template bool Quaternion::operator==(const Quaternion& quat) const { return NumberEquals(w, quat.w) && - NumberEquals(x, quat.x) && - NumberEquals(y, quat.y) && - NumberEquals(z, quat.z); + NumberEquals(x, quat.x) && + NumberEquals(y, quat.y) && + NumberEquals(z, quat.z); } + /*! + * \brief Compares the quaternion to other one + * \return false if the quaternions are the same + * + * \param vec Other quaternion to compare with + */ + template bool Quaternion::operator!=(const Quaternion& quat) const { return !operator==(quat); } + /*! + * \brief Shorthand for the quaternion (1, 0, 0, 0) + * \return A quaternion with components (1, 0, 0, 0) + * + * \see MakeIdentity + */ + template Quaternion Quaternion::Identity() { @@ -390,6 +686,20 @@ namespace Nz return quaternion; } + /*! + * \brief Interpolates the quaternion to other one with a factor of interpolation + * \return A new quaternion which is the interpolation of two quaternions + * + * \param from Initial quaternion + * \param to Target quaternion + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * \remark With NAZARA_DEBUG, a NazaraError is thrown and Zero() is returned + * + * \see Lerp, Slerp + */ + template Quaternion Quaternion::Lerp(const Quaternion& from, const Quaternion& to, T interpolation) { @@ -410,12 +720,32 @@ namespace Nz return interpolated; } + /*! + * \brief Gives the normalized quaternion + * \return A normalized quaternion from the quat + * + * \param quat Quaternion to normalize + * \param length Optional argument to obtain the length's ratio of the vector and the unit-length + * + * \see GetNormal + */ + template Quaternion Quaternion::Normalize(const Quaternion& quat, T* length) { return quat.GetNormal(length); } + /*! + * \brief Gets the rotation required to rotate direction Vector3 from to direction Vector3 to + * \return A quaternion which is the rotation needed between those two Vector3 + * + * \param from Initial vector + * \param to Target vector + * + * \see MakeRotationBetween + */ + template Quaternion Quaternion::RotationBetween(const Vector3& from, const Vector3& to) { @@ -425,6 +755,20 @@ namespace Nz return quaternion; } + /*! + * \brief Interpolates spherically the quaternion to other one with a factor of interpolation + * \return A new quaternion which is the interpolation of two quaternions + * + * \param from Initial quaternion + * \param to Target quaternion + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * \remark With NAZARA_DEBUG, a NazaraError is thrown and Zero() is returned + * + * \see Lerp + */ + template Quaternion Quaternion::Slerp(const Quaternion& from, const Quaternion& to, T interpolation) { @@ -441,7 +785,7 @@ namespace Nz T cosOmega = from.DotProduct(to); if (cosOmega < F(0.0)) { - // On inverse tout + // We invert everything q.Set(-to.w, -to.x, -to.y, -to.z); cosOmega = -cosOmega; } @@ -451,7 +795,7 @@ namespace Nz T k0, k1; if (cosOmega > F(0.9999)) { - // Interpolation linéaire pour éviter une division par zéro + // Linear interpolation to avoid division by zero k0 = F(1.0) - interpolation; k1 = interpolation; } @@ -460,7 +804,7 @@ namespace Nz T sinOmega = std::sqrt(F(1.0) - cosOmega*cosOmega); T omega = std::atan2(sinOmega, cosOmega); - // Pour éviter deux divisions + // To avoid two divisions sinOmega = F(1.0)/sinOmega; k0 = std::sin((F(1.0) - interpolation) * omega) * sinOmega; @@ -468,9 +812,16 @@ namespace Nz } Quaternion result(k0 * from.w, k0 * from.x, k0 * from.y, k0 * from.z); - return result += q*k1; + return result += q * k1; } + /*! + * \brief Shorthand for the quaternion (0, 0, 0, 0) + * \return A quaternion with components (0, 0, 0, 0) + * + * \see MakeZero + */ + template Quaternion Quaternion::Zero() { @@ -481,6 +832,14 @@ namespace Nz } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param quat The quaternion to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::Quaternion& quat) { diff --git a/include/Nazara/Math/Ray.hpp b/include/Nazara/Math/Ray.hpp index e0ae68363..c4c53664d 100644 --- a/include/Nazara/Math/Ray.hpp +++ b/include/Nazara/Math/Ray.hpp @@ -24,9 +24,9 @@ namespace Nz public: Ray() = default; Ray(T X, T Y, T Z, T directionX, T directionY, T directionZ); + Ray(const Vector3& origin, const Vector3& direction); Ray(const T origin[3], const T direction[3]); Ray(const Plane& planeOne, const Plane& planeTwo); - Ray(const Vector3& origin, const Vector3& direction); template explicit Ray(const Ray& ray); template explicit Ray(const Vector3& origin, const Vector3& direction); Ray(const Ray& ray) = default; @@ -42,16 +42,17 @@ namespace Nz bool Intersect(const OrientedBox& orientedBox, T* closestHit = nullptr, T* furthestHit = nullptr) const; bool Intersect(const Plane& plane, T* hit = nullptr) const; bool Intersect(const Sphere& sphere, T* closestHit = nullptr, T* furthestHit = nullptr) const; + bool Intersect(const Vector3& firstPoint, const Vector3& secondPoint, const Vector3& thirdPoint, T* hit = nullptr) const; Ray& MakeAxisX(); Ray& MakeAxisY(); Ray& MakeAxisZ(); Ray& Set(T X, T Y, T Z, T directionX, T directionY, T directionZ); + Ray& Set(const Vector3& origin, const Vector3& direction); Ray& Set(const T origin[3], const T direction[3]); Ray& Set(const Plane& planeOne, const Plane& planeTwo); Ray& Set(const Ray& ray); - Ray& Set(const Vector3& origin, const Vector3& direction); template Ray& Set(const Ray& ray); template Ray& Set(const Vector3& origin, const Vector3& direction); diff --git a/include/Nazara/Math/Ray.inl b/include/Nazara/Math/Ray.inl index 9f65b5382..de2b2d726 100644 --- a/include/Nazara/Math/Ray.inl +++ b/include/Nazara/Math/Ray.inl @@ -10,29 +10,77 @@ namespace Nz { + /*! + * \class Nz::Ray + * \brief Math class that represents a ray or a straight line in 3D space + * + * This ray is meant to be understood like origin + lambda * direction, where lambda is a real positive parameter + */ + + /*! + * \brief Constructs a Ray object from its position and direction + * + * \param X X position + * \param Y Y position + * \param Z Z position + * \param DirectionX X component of the vector direction + * \param DirectionY Y component of the vector direction + * \param DirectionY Y component of the vector direction + */ + template Ray::Ray(T X, T Y, T Z, T DirectionX, T DirectionY, T DirectionZ) { Set(X, Y, Z, DirectionX, DirectionY, DirectionZ); } + /*! + * \brief Constructs a Ray object from two Vector3 + * + * \param Origin Vector which represents the origin of the ray + * \param Direction Vector which represents the direction of the ray + */ + + template + Ray::Ray(const Vector3& Origin, const Vector3& Direction) + { + Set(Origin, Direction); + } + + /*! + * \brief Constructs a Ray object from two arrays of three elements + * + * \param Origin[3] Origin[0] is X position, Origin[1] is Y position and Origin[2] is Z position + * \param Direction[3] Direction[0] is X direction, Direction[1] is Y direction and Direction[2] is Z direction + */ + template Ray::Ray(const T Origin[3], const T Direction[3]) { Set(Origin, Direction); } + /*! + * \brief Constructs a Ray object from the intersection of two planes + * + * \param planeOne First plane + * \param planeTwo Second secant plane + * + * \remark Produce a NazaraError if planes are parallel with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and planes are parallel + */ + template Ray::Ray(const Plane& planeOne, const Plane& planeTwo) { Set(planeOne, planeTwo); } - template - Ray::Ray(const Vector3& Origin, const Vector3& Direction) - { - Set(Origin, Direction); - } + /*! + * \brief Constructs a Ray object from another type of Ray + * + * \param ray Ray of type U to convert to type T + */ template template @@ -41,6 +89,13 @@ namespace Nz Set(ray); } + /*! + * \brief Constructs a Ray object from two Vector3 from another type of Ray + * + * \param Origin Origin of type U to convert to type T + * \param Direction Direction of type U to convert to type T + */ + template template Ray::Ray(const Vector3& Origin, const Vector3& Direction) @@ -48,6 +103,13 @@ namespace Nz Set(Origin, Direction); } + /*! + * \brief Finds the closest point of the ray from point + * \return The parameter where the point along this ray that is closest to the point provided + * + * \param point The point to get the closest approach to + */ + template T Ray::ClosestPoint(const Vector3& point) const { @@ -55,15 +117,37 @@ namespace Nz T vsq = direction.GetSquaredLength(); T proj = delta.DotProduct(direction); - return proj/vsq; + return proj / vsq; } + /*! + * \brief Gets the point along the ray for this parameter + * \return The point on the ray + * + * \param lambda Parameter to obtain a particular point on the ray + */ + template Vector3 Ray::GetPoint(T lambda) const { return origin + lambda * direction; } + /*! + * \brief Checks whether or not this ray intersects with the BoundingVolume + * \return true if it intersects + * + * \param volume BoundingVolume to check + * \param closestHit Optional argument to get the closest parameter where the intersection is only if it happened + * \param furthestHit Optional argument to get the furthest parameter where the intersection is only if it happened + * + * \remark If BoundingVolume is Extend_Infinite, then closestHit and furthestHit are equal to 0 et infinity + * \remark If BoundingVolume is Extend_Null, then closestHit and furthestHit are unchanged + * \remark If enumeration of BoundingVolume is not defined in Extend, a NazaraError is thrown and closestHit and furthestHit are unchanged + * + * \see Intersect + */ + template bool Ray::Intersect(const BoundingVolume& volume, T* closestHit, T* furthestHit) const { @@ -96,6 +180,17 @@ namespace Nz return false; } + /*! + * \brief Checks whether or not this ray intersects with the Box + * \return true if it intersects + * + * \param box Box to check + * \param closestHit Optional argument to get the closest parameter where the intersection is only if it happened + * \param furthestHit Optional argument to get the furthest parameter where the intersection is only if it happened + * + * \see Intersect + */ + template bool Ray::Intersect(const Box& box, T* closestHit, T* furthestHit) const { @@ -142,6 +237,18 @@ namespace Nz return true; } + /*! + * \brief Checks whether or not this ray intersects with the transform Matrix4 applied to the Box + * \return true if it intersects + * + * \param box Box to check + * \param transform Matrix4 which represents the transformation of the box + * \param closestHit Optional argument to get the closest parameter where the intersection is only if it happened + * \param furthestHit Optional argument to get the furthest parameter where the intersection is only if it happened + * + * \see Intersect + */ + template bool Ray::Intersect(const Box& box, const Matrix4& transform, T* closestHit, T* furthestHit) const { @@ -200,6 +307,17 @@ namespace Nz return true; } + /*! + * \brief Checks whether or not this ray intersects with the OrientedBox + * \return true if it intersects + * + * \param orientedBox OrientedBox to check + * \param closestHit Optional argument to get the closest parameter where the intersection is only if it happened + * \param furthestHit Optional argument to get the furthest parameter where the intersection is only if it happened + * + * \see Intersect + */ + template bool Ray::Intersect(const OrientedBox& orientedBox, T* closestHit, T* furthestHit) const { @@ -212,9 +330,9 @@ namespace Nz // Construction de la matrice de transformation de l'OBB Matrix4 matrix(width.x, height.x, depth.x, corner.x, - width.y, height.y, depth.y, corner.y, - width.z, height.z, depth.z, corner.z, - F(0.0), F(0.0), F(0.0), F(1.0)); + width.y, height.y, depth.y, corner.y, + width.z, height.z, depth.z, corner.z, + F(0.0), F(0.0), F(0.0), F(1.0)); matrix.InverseAffine(); @@ -227,12 +345,22 @@ namespace Nz return tmpRay.Intersect(tmpBox, closestHit, furthestHit); } + /*! + * \brief Checks whether or not this ray intersects with the plane + * \return true if it intersects + * + * \param plane Plane to check + * \param hit Optional argument to get the parameter where the intersection is only if it happened + * + * \see Intersect + */ + template bool Ray::Intersect(const Plane& plane, T* hit) const { T divisor = plane.normal.DotProduct(direction); if (NumberEquals(divisor, F(0.0))) - return false; // perpendicular + return false; // Perpendicular T lambda = -(plane.normal.DotProduct(origin) - plane.distance) / divisor; // The plane is ax + by + cz = d if (lambda < F(0.0)) @@ -244,6 +372,17 @@ namespace Nz return true; } + /*! + * \brief Checks whether or not this ray intersects with the sphere + * \return true if it intersects + * + * \param sphere Sphere to check + * \param closestHit Optional argument to get the closest parameter where the intersection is only if it happened + * \param furthestHit Optional argument to get the furthest parameter where the intersection is only if it happened + * + * \see Intersect + */ + template bool Ray::Intersect(const Sphere& sphere, T* closestHit, T* furthestHit) const { @@ -253,8 +392,8 @@ namespace Nz if (length < F(0.0)) return false; // ray is perpendicular to the vector origin - center - T squaredDistance = sphereRay.GetSquaredLength() - length*length; - T squaredRadius = sphere.radius*sphere.radius; + T squaredDistance = sphereRay.GetSquaredLength() - length * length; + T squaredRadius = sphere.radius * sphere.radius; if (squaredDistance > squaredRadius) return false; // if the ray is further than the radius @@ -274,24 +413,102 @@ namespace Nz return true; } + /*! + * \brief Checks whether or not this ray intersects with the triangle + * \return true if it intersects + * + * \param firstPoint First vertex of the triangle + * \param secondPoint Second vertex of the triangle + * \param thirdPoint Third vertex of the triangle + * \param hit Optional argument to get the parameter where the intersection is only if it happened + * + * \see Intersect + */ + + template + bool Ray::Intersect(const Vector3& firstPoint, const Vector3& secondPoint, const Vector3& thirdPoint, T* hit) const + { + // https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm + Vector3 firstEdge = secondPoint - firstPoint; + Vector3 secondEdge = thirdPoint - firstPoint; + + Vector3 P = Vector3::CrossProduct(direction, secondEdge); + const T divisor = firstEdge.DotProduct(P); + if (NumberEquals(divisor, F(0.0))) + return false; // Ray lies in plane of triangle + + Vector3 directionToPoint = origin - firstPoint; + T u = directionToPoint.DotProduct(P) / divisor; + if (u < F(0.0) || u > F(1.0)) + return 0; // The intersection lies outside of the triangle + + Vector3 Q = Vector3::CrossProduct(directionToPoint, firstEdge); + T v = directionToPoint.DotProduct(Q) / divisor; + if (v < F(0.0) || u + v > F(1.0)) + return 0; // The intersection lies outside of the triangle + + T t = secondEdge.DotProduct(Q) / divisor; + if (t > F(0.0)) + { + if (hit) + *hit = t; + return true; + } + + return false; + } + + /*! + * \brief Makes the ray with position (0, 0, 0) and direction (1, 0, 0) + * \return A reference to this ray with position (0, 0, 0) and direction (1, 0, 0) + * + * \see AxisX + */ + template Ray& Ray::MakeAxisX() { return Set(Vector3::Zero(), Vector3::UnitX()); } + /*! + * \brief Makes the ray with position (0, 0, 0) and direction (0, 1, 0) + * \return A reference to this ray with position (0, 0, 0) and direction (0, 1, 0) + * + * \see AxisY + */ + template Ray& Ray::MakeAxisY() { return Set(Vector3::Zero(), Vector3::UnitY()); } + /*! + * \brief Makes the ray with position (0, 0, 0) and direction (0, 0, 1) + * \return A reference to this ray with position (0, 0, 0) and direction (0, 0, 1) + * + * \see AxisZ + */ + template Ray& Ray::MakeAxisZ() { return Set(Vector3::Zero(), Vector3::UnitZ()); } + /*! + * \brief Sets the components of the ray with position and direction + * \return A reference to this ray + * + * \param X X position + * \param Y Y position + * \param Z Z position + * \param DirectionX X component of the vector direction + * \param DirectionY Y component of the vector direction + * \param DirectionY Y component of the vector direction + */ + template Ray& Ray::Set(T X, T Y, T Z, T directionX, T directionY, T directionZ) { @@ -301,6 +518,31 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the ray with position and direction + * \return A reference to this ray + * + * \param Origin Vector which represents the origin of the ray + * \param Direction Vector which represents the direction of the ray + */ + + template + Ray& Ray::Set(const Vector3& Origin, const Vector3& Direction) + { + direction = Direction; + origin = Origin; + + return *this; + } + + /*! + * \brief Sets the components of this ray from two arrays of three elements + * \return A reference to this ray + * + * \param Origin[3] Origin[0] is X position, Origin[1] is Y position and Origin[2] is Z position + * \param Direction[3] Direction[0] is X direction, Direction[1] is Y direction and Direction[2] is Z direction + */ + template Ray& Ray::Set(const T Origin[3], const T Direction[3]) { @@ -310,6 +552,17 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of this ray from the intersection of two planes + * \return A reference to this ray + * + * \param planeOne First plane + * \param planeTwo Second secant plane + * + * \remark Produce a NazaraError if planes are parallel with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and planes are parallel + */ + template Ray& Ray::Set(const Plane& planeOne, const Plane& planeTwo) { @@ -321,7 +574,7 @@ namespace Nz #if NAZARA_MATH_SAFE if (NumberEquals(det, F(0.0))) { - String error("Planes are parallel."); + String error("Planes are parallel"); NazaraError(error); throw std::domain_error(error); @@ -338,6 +591,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the ray with components from another + * \return A reference to this ray + * + * \param ray The other ray + */ + template Ray& Ray::Set(const Ray& ray) { @@ -346,14 +606,12 @@ namespace Nz return *this; } - template - Ray& Ray::Set(const Vector3& Origin, const Vector3& Direction) - { - direction = Direction; - origin = Origin; - - return *this; - } + /*! + * \brief Sets the components of the ray from another type of Ray + * \return A reference to this ray + * + * \param ray Ray of type U to convert its components + */ template template @@ -365,6 +623,14 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the ray from another type of Ray + * \return A reference to this ray + * + * \param Origin Origin of type U to convert to type T + * \param Direction Direction of type U to convert to type T + */ + template template Ray& Ray::Set(const Vector3& Origin, const Vector3& Direction) @@ -375,6 +641,11 @@ namespace Nz return *this; } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "Ray(origin: Vector3(origin.x, origin.y, origin.z), direction: Vector3(direction.x, direction.y, direction.z))" + */ + template String Ray::ToString() const { @@ -383,24 +654,54 @@ namespace Nz return ss << "Ray(origin: " << origin.ToString() << ", direction: " << direction.ToString() << ")"; } + /*! + * \brief Multiplies the direction ray with the lambda to get the point along the ray for this parameter + * \return The point on the ray + * + * \param lambda Parameter to obtain a particular point on the ray + * + * \see GetPoint + */ + template Vector3 Ray::operator*(T lambda) const { return GetPoint(lambda); } + /*! + * \brief Compares the ray to other one + * \return true if the ray are the same + * + * \param rec Other ray to compare with + */ + template bool Ray::operator==(const Ray& ray) const { return direction == ray.direction && origin == ray.origin; } + /*! + * \brief Compares the ray to other one + * \return false if the ray are the same + * + * \param rec Other ray to compare with + */ + template bool Ray::operator!=(const Ray& ray) const { return !operator==(ray); } + /*! + * \brief Shorthand for the ray (0, 0, 0), (1, 0, 0) + * \return A ray with position (0, 0, 0) and direction (1, 0, 0) + * + * \see MakeAxisX + */ + template Ray Ray::AxisX() { @@ -410,6 +711,13 @@ namespace Nz return axis; } + /*! + * \brief Shorthand for the ray (0, 0, 0), (0, 1, 0) + * \return A ray with position (0, 0, 0) and direction (0, 1, 0) + * + * \see MakeAxisY + */ + template Ray Ray::AxisY() { @@ -419,6 +727,13 @@ namespace Nz return axis; } + /*! + * \brief Shorthand for the ray (0, 0, 0), (0, 0, 1) + * \return A ray with position (0, 0, 0) and direction (0, 0, 1) + * + * \see MakeAxisZ + */ + template Ray Ray::AxisZ() { @@ -428,13 +743,34 @@ namespace Nz return axis; } + /*! + * \brief Interpolates the ray to other one with a factor of interpolation + * \return A new ray which is the interpolation of two rectangles + * + * \param from Initial ray + * \param to Target ray + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * + * \see Lerp + */ + template Ray Ray::Lerp(const Ray& from, const Ray& to, T interpolation) { - return Ray(from.origin.Lerp(to.origin, interpolation), from.direction.Lerp(to.direction, interpolation)); + return Ray(Nz::Vector3::Lerp(from.origin, to.origin, interpolation), Nz::Vector3::Lerp(from.direction, to.direction, interpolation)); } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param ray The ray to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::Ray& ray) { diff --git a/include/Nazara/Math/Rect.hpp b/include/Nazara/Math/Rect.hpp index ea468966c..ec203848f 100644 --- a/include/Nazara/Math/Rect.hpp +++ b/include/Nazara/Math/Rect.hpp @@ -28,12 +28,12 @@ namespace Nz ~Rect() = default; bool Contains(T X, T Y) const; - bool Contains(const Vector2& point) const; bool Contains(const Rect& rect) const; + bool Contains(const Vector2& point) const; Rect& ExtendTo(T X, T Y); - Rect& ExtendTo(const Vector2& point); Rect& ExtendTo(const Rect& rect); + Rect& ExtendTo(const Vector2& point); Vector2 GetCenter() const; Vector2 GetCorner(RectCorner corner) const; diff --git a/include/Nazara/Math/Rect.inl b/include/Nazara/Math/Rect.inl index 80c47ae29..82c9e9f3f 100644 --- a/include/Nazara/Math/Rect.inl +++ b/include/Nazara/Math/Rect.inl @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Mathematics module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -12,36 +12,89 @@ namespace Nz { + /*! + * \class Nz::Rect + * \brief Math class that represents an axis-aligned rectangle in two dimensions + * + * \remark The basis is said to be "left-hand". It means that with your left hand, the thumb is X positive, the index finger Y positive pointing to the bottom + */ + + /*! + * \brief Constructs a Rect object from its width and height + * + * \param Width Width of the rectangle (following X) + * \param Height Height of the rectangle (following Y) + * + * \remark Position will be (0, 0) + */ + template Rect::Rect(T Width, T Height) { Set(Width, Height); } + /*! + * \brief Constructs a Rect object from its position, width and height + * + * \param X X position + * \param Y Y position + * \param Width Width of the rectangle (following X) + * \param Height Height of the rectangle (following Y) + */ + template Rect::Rect(T X, T Y, T Width, T Height) { Set(X, Y, Width, Height); } + /*! + * \brief Constructs a Rect object from an array of four elements + * + * \param vec[4] vec[0] is X position, vec[1] is Y position, vec[2] is width and vec[3] is height + */ + template Rect::Rect(const T vec[4]) { Set(vec); } + /*! + * \brief Constructs a Rect object from a vector representing width and height + * + * \param lengths (Width, Height) of the rectangle + * + * \remark X and Y will be (0, 0) + */ + template Rect::Rect(const Vector2& lengths) { Set(lengths); } + /*! + * \brief Constructs a Rect object from two vectors representing point of the space + * (X, Y) will be the components minimum of the two vectors and the width and height will be the components maximum - minimum + * + * \param vec1 First point + * \param vec2 Second point + */ + template Rect::Rect(const Vector2& vec1, const Vector2& vec2) { Set(vec1, vec2); } + /*! + * \brief Constructs a Rect object from another type of Rect + * + * \param rect Rect of type U to convert to type T + */ + template template Rect::Rect(const Rect& rect) @@ -49,25 +102,63 @@ namespace Nz Set(rect); } + /*! + * \brief Tests whether the rectangle contains the provided point inclusive of the edge of the rectangle + * \return true if inclusive + * + * \param X X position of the point + * \param Y Y position of the point + * + * \see Contains + */ + template bool Rect::Contains(T X, T Y) const { - return X >= x && X <= x+width && - Y >= y && Y <= y+height; + return X >= x && X <= (x + width) && + Y >= y && Y <= (y + height); } + /*! + * \brief Tests whether the rectangle contains the provided rectangle inclusive of the edge of the rectangle + * \return true if inclusive + * + * \param rect Other rectangle to test + * + * \see Contains + */ + + template + bool Rect::Contains(const Rect& rect) const + { + return Contains(rect.x, rect.y) && + Contains(rect.x + rect.width, rect.y + rect.height); + } + + /*! + * \brief Tests whether the rectangle contains the provided point inclusive of the edge of the rectangle + * \return true if inclusive + * + * \param point Position of the point + * + * \see Contains + */ + template bool Rect::Contains(const Vector2& point) const { return Contains(point.x, point.y); } - template - bool Rect::Contains(const Rect& rect) const - { - return Contains(rect.x, rect.y) && - Contains(rect.x + rect.width, rect.y + rect.height); - } + /*! + * \brief Extends the rectangle to contain the point in the boundary + * \return A reference to this rectangle extended + * + * \param X X position of the point + * \param Y Y position of the point + * + * \see ExtendTo + */ template Rect& Rect::ExtendTo(T X, T Y) @@ -84,11 +175,14 @@ namespace Nz return *this; } - template - Rect& Rect::ExtendTo(const Vector2& point) - { - return ExtendTo(point.x, point.y); - } + /*! + * \brief Extends the rectangle to contain the rectangle + * \return A reference to this rectangle extended + * + * \param rect Other rectangle to contain + * + * \see ExtendTo + */ template Rect& Rect::ExtendTo(const Rect& rect) @@ -105,12 +199,41 @@ namespace Nz return *this; } + /*! + * \brief Extends the rectangle to contain the point in the boundary + * \return A reference to this rectangle extended + * + * \param point Position of the point + * + * \see ExtendTo + */ + + template + Rect& Rect::ExtendTo(const Vector2& point) + { + return ExtendTo(point.x, point.y); + } + + /*! + * \brief Gets a Vector2 for the center + * \return The position of the center of the rectangle + */ + template Vector2 Rect::GetCenter() const { return GetPosition() + GetLengths() / F(2.0); } + /*! + * \brief Gets the Vector2 for the corner + * \return The position of the corner of the rectangle according to enum RectCorner + * + * \param corner Enumeration of type RectCorner + * + * \remark If enumeration is not defined in RectCorner, a NazaraError is thrown and a Vector2 uninitialised is returned + */ + template Vector2 Rect::GetCorner(RectCorner corner) const { @@ -133,25 +256,52 @@ namespace Nz return Vector2(); } + /*! + * \brief Gets a Vector2 for the lengths + * \return The lengths of the rectangle (width, height) + */ + template Vector2 Rect::GetLengths() const { return Vector2(width, height); } + /*! + * \brief Gets a Vector2 for the maximum point + * \return The RectCorner_RightBottom of the rectangle + * + * \see GetCorner + */ + template Vector2 Rect::GetMaximum() const { return GetPosition() + GetLengths(); } + /*! + * \brief Gets a Vector2 for the minimum point + * \return The RectCorner_LeftTop of the rectangle + * + * \see GetCorner, GetPosition + */ + template Vector2 Rect::GetMinimum() const { - ///DOC: Alias de GetPosition() return GetPosition(); } + /*! + * \brief Computes the negative vertex of one direction + * \return The position of the vertex on the rectangle in the opposite way of the normal while considering the center. It means that if the normal has one component negative, the component is set to width or height corresponding to the sign + * + * \param normal Vector indicating a direction + * + * \see GetPositiveVertex + */ + template Vector2 Rect::GetNegativeVertex(const Vector2& normal) const { @@ -166,12 +316,28 @@ namespace Nz return neg; } + /*! + * \brief Gets a Vector2 for the position + * \return The RectCorner_LeftTop of the rectangle + * + * \see GetCorner, GetMinimum + */ + template Vector2 Rect::GetPosition() const { return Vector2(x, y); } + /*! + * \brief Computes the positive vertex of one direction + * \return The position of the vertex on the rectangle in the same way of the normal while considering the center. It means that if the normal has one component positive, the component is set to width or height corresponding to the sign + * + * \param normal Vector indicating a direction + * + * \see GetNegativeVertex + */ + template Vector2 Rect::GetPositiveVertex(const Vector2& normal) const { @@ -186,6 +352,14 @@ namespace Nz return pos; } + /*! + * \brief Checks whether or not this rectangle intersects another one + * \return true if the rectangle intersects + * + * \param rect Rectangle to check + * \param intersection Optional argument for the rectangle which represent the intersection + */ + template bool Rect::Intersect(const Rect& rect, Rect* intersection) const { @@ -210,12 +384,24 @@ namespace Nz return true; } + /*! + * \brief Checks whether this rectangle is valid + * \return true if the rectangle has a strictly positive width and height + */ + template bool Rect::IsValid() const { return width > F(0.0) && height > F(0.0); } + /*! + * \brief Makes the rectangle position (0, 0) and lengths (0, 0) + * \return A reference to this box with position (0, 0) and lengths (0, 0) + * + * \see Zero + */ + template Rect& Rect::MakeZero() { @@ -227,6 +413,16 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the rectangle with width and height + * \return A reference to this rectangle + * + * \param Width Width of the rectangle (following X) + * \param Height Height of the rectangle (following Y) + * + * \remark Position will be (0, 0) + */ + template Rect& Rect::Set(T Width, T Height) { @@ -238,6 +434,16 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the rectangle + * \return A reference to this rectangle + * + * \param X X position + * \param Y Y position + * \param Width Width of the rectangle (following X) + * \param Height Height of the rectangle (following Y) + */ + template Rect& Rect::Set(T X, T Y, T Width, T Height) { @@ -249,6 +455,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the rectangle from an array of four elements + * \return A reference to this rectangle + * + * \param rect[4] rect[0] is X position, rect[1] is Y position, rect[2] is width and rect[3] is height + */ + template Rect& Rect::Set(const T rect[4]) { @@ -260,6 +473,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the rectangle with components from another + * \return A reference to this rectangle + * + * \param rect The other Rect + */ + template Rect& Rect::Set(const Rect& rect) { @@ -268,23 +488,48 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the rectange from a vector representing width and height + * \return A reference to this rectangle + * + * \param lengths (Width, Height) of the rectangle + * + * \remark Position will be (0, 0) + */ + template Rect& Rect::Set(const Vector2& lengths) { return Set(lengths.x, lengths.y); } + /*! + * \brief Sets a Rect object from two vectors representing point of the space + * (X, Y) will be the components minimum of the two vectors and the width and height will be the components maximum - minimum + * \return A reference to this rectangle + * + * \param vec1 First point + * \param vec2 Second point + */ + template Rect& Rect::Set(const Vector2& vec1, const Vector2& vec2) { x = std::min(vec1.x, vec2.x); y = std::min(vec1.y, vec2.y); - width = (vec2.x > vec1.x) ? vec2.x-vec1.x : vec1.x-vec2.x; - height = (vec2.y > vec1.y) ? vec2.y-vec1.y : vec1.y-vec2.y; + width = (vec2.x > vec1.x) ? vec2.x - vec1.x : vec1.x - vec2.x; + height = (vec2.y > vec1.y) ? vec2.y - vec1.y : vec1.y - vec2.y; return *this; } + /*! + * \brief Sets the components of the rectangle from another type of Rect + * \return A reference to this rectangle + * + * \param rect Rectangle of type U to convert its components + */ + template template Rect& Rect::Set(const Rect& rect) @@ -297,6 +542,11 @@ namespace Nz return *this; } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "Rect(x, y, width, height)" + */ + template String Rect::ToString() const { @@ -305,6 +555,13 @@ namespace Nz return ss << "Rect(" << x << ", " << y << ", " << width << ", " << height << ')'; } + /*! + * \brief Translates the rectangle + * \return A reference to this rectangle translated + * + * \param translation Vector2 which is the translation for the position + */ + template Rect& Rect::Translate(const Vector2& translation) { @@ -314,6 +571,15 @@ namespace Nz return *this; } + /*! + * \brief Returns the ith element of the rectangle + * \return A reference to the ith element of the rectangle + * + * \remark Access to index greather than 4 is undefined behavior + * \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4 + */ + template T& Rect::operator[](unsigned int i) { @@ -331,6 +597,15 @@ namespace Nz return *(&x+i); } + /*! + * \brief Returns the ith element of the rectangle + * \return A value to the ith element of the rectangle + * + * \remark Access to index greather than 4 is undefined behavior + * \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4 + */ + template T Rect::operator[](unsigned int i) const { @@ -348,30 +623,65 @@ namespace Nz return *(&x+i); } + /*! + * \brief Multiplies the lengths with the scalar + * \return A rectangle where the position is the same and width and height are the product of the old width and height and the scalar + * + * \param scale The scalar to multiply width and height with + */ + template Rect Rect::operator*(T scalar) const { - return Rect(x, y, width*scalar, height*scalar); + return Rect(x, y, width * scalar, height * scalar); } + /*! + * \brief Multiplies the lengths with the vector + * \return A rectangle where the position is the same and width and height are the product of the old width and height with the vec + * + * \param vec The vector where component one multiply width and two height + */ + template Rect Rect::operator*(const Vector2& vec) const { return Rect(x, y, width*vec.x, height*vec.y); } + /*! + * \brief Divides the lengths with the scalar + * \return A rectangle where the position is the same and width and height are the quotient of the old width and height and the scalar + * + * \param scale The scalar to divide width and height with + */ + template Rect Rect::operator/(T scalar) const { return Rect(x, y, width/scalar, height/scalar); } + /*! + * \brief Divides the lengths with the vector + * \return A rectangle where the position is the same and width and height are the quotient of the old width and height with the vec + * + * \param vec The vector where component one divide width and two height + */ + template Rect Rect::operator/(const Vector2& vec) const { return Rect(x, y, width/vec.x, height/vec.y); } + /*! + * \brief Multiplies the lengths of this rectangle with the scalar + * \return A reference to this rectangle where lengths are the product of these lengths and the scalar + * + * \param scalar The scalar to multiply width and height with + */ + template Rect& Rect::operator*=(T scalar) { @@ -381,6 +691,13 @@ namespace Nz return *this; } + /*! + * \brief Multiplies the lengths of this rectangle with the vector + * \return A reference to this rectangle where width and height are the product of the old width and height with the vec + * + * \param vec The vector where component one multiply width and two height + */ + template Rect& Rect::operator*=(const Vector2& vec) { @@ -390,6 +707,13 @@ namespace Nz return *this; } + /*! + * \brief Divides the lengths of this rectangle with the scalar + * \return A reference to this rectangle where lengths are the quotient of these lengths and the scalar + * + * \param scalar The scalar to divide width and height with + */ + template Rect& Rect::operator/=(T scalar) { @@ -399,6 +723,13 @@ namespace Nz return *this; } + /*! + * \brief Divives the lengths of this rectangle with the vector + * \return A reference to this rectangle where width and height are the quotient of the old width and height with the vec + * + * \param vec The vector where component one divide width and two height + */ + template Rect& Rect::operator/=(const Vector2& vec) { @@ -408,19 +739,47 @@ namespace Nz return *this; } + /*! + * \brief Compares the rectangle to other one + * \return true if the rectangles are the same + * + * \param rec Other rectangle to compare with + */ + template bool Rect::operator==(const Rect& rect) const { return NumberEquals(x, rect.x) && NumberEquals(y, rect.y) && - NumberEquals(width, rect.width) && NumberEquals(height, rect.height); + NumberEquals(width, rect.width) && NumberEquals(height, rect.height); } + /*! + * \brief Compares the rectangle to other one + * \return false if the rectangles are the same + * + * \param rec Other rectangle to compare with + */ + template bool Rect::operator!=(const Rect& rect) const { return !operator==(rect); } + /*! + * \brief Interpolates the rectangle to other one with a factor of interpolation + * \return A new rectangle which is the interpolation of two rectangles + * + * \param from Initial rectangle + * \param to Target rectangle + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * \remark With NAZARA_DEBUG, a NazaraError is thrown and Zero() is returned + * + * \see Lerp + */ + template Rect Rect::Lerp(const Rect& from, const Rect& to, T interpolation) { @@ -433,14 +792,21 @@ namespace Nz #endif Rect rect; - rect.x = Lerp(from.x, to.x, interpolation); - rect.y = Lerp(from.y, to.y, interpolation); - rect.width = Lerp(from.width, to.width, interpolation); - rect.height = Lerp(from.height, to.height, interpolation); + rect.x = Nz::Lerp(from.x, to.x, interpolation); + rect.y = Nz::Lerp(from.y, to.y, interpolation); + rect.width = Nz::Lerp(from.width, to.width, interpolation); + rect.height = Nz::Lerp(from.height, to.height, interpolation); return rect; } + /*! + * \brief Shorthand for the rectangle (0, 0, 0, 0) + * \return A rectangle with position (0, 0) and lengths (0, 0) + * + * \see MakeZero + */ + template Rect Rect::Zero() { @@ -451,6 +817,14 @@ namespace Nz } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param rect The rectangle to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::Rect& rect) { diff --git a/include/Nazara/Math/Sphere.hpp b/include/Nazara/Math/Sphere.hpp index d3d6daf81..65203c4b0 100644 --- a/include/Nazara/Math/Sphere.hpp +++ b/include/Nazara/Math/Sphere.hpp @@ -46,6 +46,7 @@ namespace Nz bool IsValid() const; + Sphere& MakeUnit(); Sphere& MakeZero(); Sphere& Set(T X, T Y, T Z, T Radius); @@ -71,6 +72,7 @@ namespace Nz bool operator!=(const Sphere& sphere) const; static Sphere Lerp(const Sphere& from, const Sphere& to, T interpolation); + static Sphere Unit(); static Sphere Zero(); T x, y, z, radius; diff --git a/include/Nazara/Math/Sphere.inl b/include/Nazara/Math/Sphere.inl index fb7297d7a..062a7b271 100644 --- a/include/Nazara/Math/Sphere.inl +++ b/include/Nazara/Math/Sphere.inl @@ -13,6 +13,20 @@ namespace Nz { + /*! + * \class Nz::Sphere + * \brief Math class that represents a sphere "S2" in a three dimensional euclidean space + */ + + /*! + * \brief Constructs a Sphere object from its center position and radius + * + * \param X X position + * \param Y Y position + * \param Z Z position + * \param Radius half of the diameter + */ + template Sphere::Sphere(T X, T Y, T Z, T Radius) { @@ -25,18 +39,38 @@ namespace Nz Set(rect); } */ + + /*! + * \brief Constructs a Sphere object from its position and radius + * + * \param center Center of the sphere + * \param Radius Half of the diameter + */ + template Sphere::Sphere(const Vector3& center, T Radius) { Set(center, Radius); } + /*! + * \brief Constructs a Sphere object from an array of four elements + * + * \param sphere[4] sphere[0] is X component, sphere[1] is Y component, sphere[2] is Z component and sphere[3] is radius + */ + template Sphere::Sphere(const T sphere[4]) { Set(sphere); } + /*! + * \brief Constructs a Sphere object from another type of Sphere + * + * \param sphere Sphere of type U to convert to type T + */ + template template Sphere::Sphere(const Sphere& sphere) @@ -44,12 +78,32 @@ namespace Nz Set(sphere); } + /*! + * \brief Tests whether the sphere contains the provided point inclusive of the edge of the sphere + * \return true if inclusive + * + * \param X X position of the point + * \param Y Y position of the point + * \param Z Z position of the point + * + * \see Contains + */ + template bool Sphere::Contains(T X, T Y, T Z) const { - return SquaredDistance(X, Y, Z) <= radius*radius; + return SquaredDistance(X, Y, Z) <= radius * radius; } + /*! + * \brief Tests whether the sphere contains the provided box inclusive of the edge of the sphere + * \return true if all inclusive + * + * \param box Three dimensional box + * + * \see Contains + */ + template bool Sphere::Contains(const Box& box) const { @@ -61,12 +115,31 @@ namespace Nz return false; } + + /*! + * \brief Tests whether the sphere contains the provided point inclusive of the edge of the sphere + * \return true if inclusive + * + * \param point Position of the point + */ + template bool Sphere::Contains(const Vector3& point) const { return Contains(point.x, point.y, point.z); } + /*! + * \brief Returns the distance from the center of the sphere to the point + * \return Distance to the point + * + * \param X X position of the point + * \param Y Y position of the point + * \param Z Z position of the point + * + * \see SquaredDistance + */ + template T Sphere::Distance(T X, T Y, T Z) const { @@ -74,12 +147,32 @@ namespace Nz return distance.GetLength(); } + /*! + * \brief Returns the distance from the center of the sphere to the point + * \return Distance to the point + * + * \param point Position of the point + * + * \see SquaredDistance + */ + template T Sphere::Distance(const Vector3& point) const { return Distance(point.x, point.y, point.z); } + /*! + * \brief Extends the sphere to contain the point in the boundary + * \return A reference to this sphere extended + * + * \param X X position of the point + * \param Y Y position of the point + * \param Z Z position of the point + * + * \see ExtendTo + */ + template Sphere& Sphere::ExtendTo(T X, T Y, T Z) { @@ -90,12 +183,30 @@ namespace Nz return *this; } + /*! + * \brief Extends the sphere to contain the point in the boundary + * \return A reference to this sphere extended + * + * \param point Position of the point + * + * \see ExtendTo + */ + template Sphere& Sphere::ExtendTo(const Vector3& point) { return ExtendTo(point.x, point.y, point.z); } + /*! + * \brief Computes the negative vertex of one direction + * \return The position of the vertex on the sphere in the opposite way of the normal while considering the center + * + * \param normal Vector normalized indicating a direction + * + * \see GetPositiveVertex + */ + template Vector3 Sphere::GetNegativeVertex(const Vector3& normal) const { @@ -105,12 +216,26 @@ namespace Nz return neg; } + /*! + * \brief Gets a Vector3 of the position + * \return The position of the center of the sphere + */ + template Vector3 Sphere::GetPosition() const { return Vector3(x, y, z); } + /*! + * \brief Computes the positive vertex of one direction + * \return The position of the vertex on the sphere in the same way of the normal while considering the center + * + * \param normal Vector normalized indicating a direction + * + * \see GetNegativeVertex + */ + template Vector3 Sphere::GetPositiveVertex(const Vector3& normal) const { @@ -120,6 +245,13 @@ namespace Nz return pos; } + /*! + * \brief Checks whether or not this sphere intersects a box + * \return true if the box intersects + * + * \param box Box to check + */ + template bool Sphere::Intersect(const Box& box) const { @@ -128,51 +260,88 @@ namespace Nz if (x < box.x) { T diff = x - box.x; - squaredDistance += diff*diff; + squaredDistance += diff * diff; } else if (x > box.x + box.width) { T diff = x - (box.x + box.width); - squaredDistance += diff*diff; + squaredDistance += diff * diff; } if (y < box.y) { T diff = y - box.y; - squaredDistance += diff*diff; + squaredDistance += diff * diff; } else if (y > box.y + box.height) { T diff = y - (box.y + box.height); - squaredDistance += diff*diff; + squaredDistance += diff * diff; } if (z < box.z) { T diff = z - box.z; - squaredDistance += diff*diff; + squaredDistance += diff * diff; } else if (z > box.z + box.depth) { T diff = z - (box.z + box.depth); - squaredDistance += diff*diff; + squaredDistance += diff * diff; } return squaredDistance <= radius * radius; } + /*! + * \brief Checks whether or not this sphere intersects another sphere + * \return true if the spheres intersect or if one is in the other + * + * \param sphere Sphere to check + */ + template bool Sphere::Intersect(const Sphere& sphere) const { - return SquaredDistance(sphere.x, sphere.y, sphere.z) - radius*radius <= sphere.radius*sphere.radius; + return SquaredDistance(sphere.x, sphere.y, sphere.z) - radius * radius <= sphere.radius * sphere.radius; } + /*! + * \brief Checks whether this sphere is valid + * \return true if the sphere has a strictly positive radius + */ + template bool Sphere::IsValid() const { return radius > F(0.0); } + /*! + * \brief Makes the sphere position (0, 0, 0) and radius 1 + * \return A reference to this vector with position (0, 0, 0) and radius 1 + * + * \see Unit + */ + + template + Sphere& Sphere::MakeUnit() + { + x = F(0.0); + y = F(0.0); + z = F(0.0); + radius = F(1.0); + + return *this; + } + + /*! + * \brief Makes the sphere position (0, 0, 0) and radius 0 + * \return A reference to this vector with position (0, 0, 0) and radius 0 + * + * \see Zero + */ + template Sphere& Sphere::MakeZero() { @@ -184,6 +353,16 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the sphere with center and radius + * \return A reference to this sphere + * + * \param X X position + * \param Y Y position + * \param Z Z position + * \param Radius half of the diameter + */ + template Sphere& Sphere::Set(T X, T Y, T Z, T Radius) { @@ -195,6 +374,14 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the sphere with center and radius + * \return A reference to this sphere + * + * \param center Center of the sphere + * \param Radius Half of the diameter + */ + template Sphere& Sphere::Set(const Vector3& center, T Radius) { @@ -217,6 +404,14 @@ namespace Nz return *this; } */ + + /*! + * \brief Sets the components of the sphere with center and radius from another + * \return A reference to this sphere + * + * \param sphere The other sphere + */ + template Sphere& Sphere::Set(const Sphere& sphere) { @@ -225,6 +420,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the sphere from an array of four elements + * \return A reference to this sphere + * + * \param sphere[4] sphere[0] is X position, sphere[1] is Y position, sphere[2] is Z position and sphere[3] is radius + */ + template Sphere& Sphere::Set(const T sphere[4]) { @@ -236,6 +438,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the sphere from another type of Sphere + * \return A reference to this sphere + * + * \param sphere Sphere of type U to convert its components + */ + template template Sphere& Sphere::Set(const Sphere& sphere) @@ -248,19 +457,44 @@ namespace Nz return *this; } + /*! + * \brief Returns the squared distance from the center of the sphere to the point + * \return Squared distance to the point + * + * \param X X position of the point + * \param Y Y position of the point + * \param Z Z position of the point + * + * \see Distance + */ + template T Sphere::SquaredDistance(T X, T Y, T Z) const { - Vector3 distance(X-x, Y-y, Z-z); + Vector3 distance(X - x, Y - y, Z - z); return distance.GetSquaredLength(); } + /*! + * \brief Returns the squared distance from the center of the sphere to the point + * \return Squared distance to the point + * + * \param point Position of the point + * + * \see Distance + */ + template T Sphere::SquaredDistance(const Vector3& point) const { return SquaredDistance(point.x, point.y, point.z); } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "Sphere(x, y, z; radius)" + */ + template String Sphere::ToString() const { @@ -269,6 +503,15 @@ namespace Nz return ss << "Sphere(" << x << ", " << y << ", " << z << "; " << radius << ')'; } + /*! + * \brief Returns the ith element of the sphere + * \return A reference to the ith element of the sphere + * + * \remark Access to index greather than 4 is undefined behavior + * \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4 + */ + template T& Sphere::operator[](unsigned int i) { @@ -286,6 +529,15 @@ namespace Nz return *(&x+i); } + /*! + * \brief Returns the ith element of the sphere + * \return A value to the ith element of the sphere + * + * \remark Access to index greather than 4 is undefined behavior + * \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4 + */ + template T Sphere::operator[](unsigned int i) const { @@ -303,31 +555,89 @@ namespace Nz return *(&x+i); } + /*! + * \brief Multiplies the radius of the sphere with a scalar + * \return A sphere where the center is the same and radius is the product of this radius and the scalar + * + * \param scale The scalar to multiply radius with + */ + template Sphere Sphere::operator*(T scalar) const { - return Sphere(x, y, z, radius*scalar); + return Sphere(x, y, z, radius * scalar); } + /*! + * \brief Multiplies the radius of other sphere with a scalar + * \return A reference to this sphere where the center is the same and radius is the product of this radius and the scalar + * + * \param scale The scalar to multiply radius with + */ + template Sphere& Sphere::operator*=(T scalar) { radius *= scalar; } + /*! + * \brief Compares the sphere to other one + * \return true if the spheres are the same + * + * \param sphere Other sphere to compare with + */ + template bool Sphere::operator==(const Sphere& sphere) const { return NumberEquals(x, sphere.x) && NumberEquals(y, sphere.y) && NumberEquals(z, sphere.z) && - NumberEquals(radius, sphere.radius); + NumberEquals(radius, sphere.radius); } + /*! + * \brief Compares the sphere to other one + * \return false if the spheres are the same + * + * \param sphere Other sphere to compare with + */ + template bool Sphere::operator!=(const Sphere& sphere) const { return !operator==(sphere); } + /*! + * \brief Shorthand for the sphere (0, 0, 0, 1) + * \return A sphere with center (0, 0, 0) and radius 1 + * + * \see MakeUnit + */ + + template + Sphere Sphere::Unit() + { + Sphere sphere; + sphere.MakeUnit(); + + return sphere; + } + + /*! + * \brief Interpolates the sphere to other one with a factor of interpolation + * \return A new sphere which is the interpolation of two spheres + * + * \param from Initial sphere + * \param to Target sphere + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * \remark With NAZARA_DEBUG, a NazaraError is thrown and Zero() is returned + * + * \see Lerp + */ + template Sphere Sphere::Lerp(const Sphere& from, const Sphere& to, T interpolation) { @@ -340,14 +650,21 @@ namespace Nz #endif Sphere sphere; - sphere.x = Lerp(from.x, to.x, interpolation); - sphere.y = Lerp(from.y, to.y, interpolation); - sphere.z = Lerp(from.z, to.z, interpolation); - sphere.radius = Lerp(from.radius, to.radius, interpolation); + sphere.x = Nz::Lerp(from.x, to.x, interpolation); + sphere.y = Nz::Lerp(from.y, to.y, interpolation); + sphere.z = Nz::Lerp(from.z, to.z, interpolation); + sphere.radius = Nz::Lerp(from.radius, to.radius, interpolation); return sphere; } + /*! + * \brief Shorthand for the sphere (0, 0, 0, 0) + * \return A sphere with center (0, 0, 0) and radius 0 + * + * \see MakeZero + */ + template Sphere Sphere::Zero() { @@ -358,6 +675,14 @@ namespace Nz } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param sphere The sphere to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::Sphere& sphere) { diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index 28ea44468..3712f0d09 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -62,8 +62,8 @@ namespace Nz String ToString() const; - operator T*(); - operator const T*() const; + operator T* (); + operator const T* () const; const Vector2& operator+() const; Vector2 operator-() const; @@ -89,7 +89,9 @@ namespace Nz bool operator>(const Vector2& vec) const; bool operator>=(const Vector2& vec) const; + static T DotProduct(const Vector2& vec1, const Vector2& vec2); static Vector2 Lerp(const Vector2& from, const Vector2& to, T interpolation); + static Vector2 Normalize(const Vector2& vec); static Vector2 Unit(); static Vector2 UnitX(); static Vector2 UnitY(); diff --git a/include/Nazara/Math/Vector2.inl b/include/Nazara/Math/Vector2.inl index 514aa3344..1876087f5 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -13,24 +13,54 @@ namespace Nz { + /*! + * \class Nz::Vector2 + * \brief Math class that represents an element of the two dimensional vector space + */ + + /*! + * \brief Constructs a Vector2 object from its coordinates + * + * \param X X component + * \param Y Y component + */ + template Vector2::Vector2(T X, T Y) { Set(X, Y); } + /*! + * \brief Constructs explicitely a Vector2 object from its "scale" + * + * \param scale X component = Y component + */ + template Vector2::Vector2(T scale) { Set(scale); } + /*! + * \brief Constructs a Vector2 object from an array of two elements + * + * \param vec[2] vec[0] is X component and vec[1] is Y component + */ + template Vector2::Vector2(const T vec[2]) { Set(vec); } + /*! + * \brief Constructs a Vector2 object from another type of Vector2 + * + * \param vec Vector of type U to convert to type T + */ + template template Vector2::Vector2(const Vector2& vec) @@ -38,60 +68,140 @@ namespace Nz Set(vec); } + /*! + * \brief Constructs a Vector2 object from a Vector3 + * + * \param vec Vector3 where only the first two components are taken + */ + template Vector2::Vector2(const Vector3& vec) { Set(vec); } + /*! + * \brief Constructs a Vector2 object from a Vector4 + * + * \param vec Vector4 where only the first two components are taken + */ + template Vector2::Vector2(const Vector4& vec) { Set(vec); } + /*! + * \brief Calculates the absolute dot (scalar) product with two vectors + * \return The dot product with absolutes values on each component + * + * \param vec The other vector to calculate the absolute dot product with + * + * \see DotProduct + */ + template T Vector2::AbsDotProduct(const Vector2& vec) const { return std::abs(x * vec.x) + std::abs(y * vec.y); } + /*! + * \brief Calculates the angle between two vectors in orthonormal basis + * \return The angle unit depends of NAZARA_MATH_ANGLE_RADIAN, you may want to normalize it to the range 0..2*pi with NormalizeAngle + * + * \param vec The other vector to measure the angle with + * + * \remark The vectors do not need to be normalised and if the angle is normalised, it represents the rotation from *this to vec in anti-clockwise direction + * + * \see NormalizeAngle + */ + template T Vector2::AngleBetween(const Vector2& vec) const { return FromRadians(std::atan2(vec.y, vec.x) - std::atan2(y, x)); } + /*! + * \brief Calculates the distance between two vectors + * \return The metric distance between two vectors with euclidean norm + * + * \param vec The other vector to measure the distance with + * + * \see SquaredDistance + */ + template T Vector2::Distance(const Vector2& vec) const { return std::sqrt(SquaredDistance(vec)); } + /*! + * \brief Calculates the distance between two vectors + * \return The metric distance in float between two vectors with euclidean norm + * + * \param vec The other vector to measure the distance with + */ + template float Vector2::Distancef(const Vector2& vec) const { return std::sqrt(static_cast(SquaredDistance(vec))); } + /*! + * \brief Calculates the dot (scalar) product with two vectors + * \return The value of the dot product + * + * \param vec The other vector to calculate the dot product with + * + * \see AbsDotProduct, DotProduct + */ + template T Vector2::DotProduct(const Vector2& vec) const { return x*vec.x + y*vec.y; } + /*! + * \brief Calculates the length (magnitude) of the vector + * \return The length of the vector + * + * \see GetSquaredLength + */ + template T Vector2::GetLength() const { - return std::sqrt(GetSquaredLength()); + return static_cast(std::sqrt(GetSquaredLength())); } + /*! + * \brief Calculates the length (magnitude) of the vector + * \return The length in float of the vector + */ + template float Vector2::GetLengthf() const { return std::sqrt(static_cast(GetSquaredLength())); } + /*! + * \brief Gets a copy normalized of the vector + * \return A new vector which is the vector normalized + * + * \param length Optional argument to obtain the length's ratio of the vector and the unit-length + * + * \remark If this vector is (0, 0), then it returns (0, 0) and length is 0 + * + * \see Normalize + */ + template Vector2 Vector2::GetNormal(T* length) const { @@ -101,36 +211,80 @@ namespace Nz return vec; } + /*! + * \brief Calculates the squared length (magnitude) of the vector + * \return The squared length of the vector + * + * \see GetLength + */ + template T Vector2::GetSquaredLength() const { return x*x + y*y; } + /*! + * \brief Makes the vector (1, 1) + * \return A reference to this vector with components (1, 1) + * + * \see Unit + */ + template Vector2& Vector2::MakeUnit() { return Set(F(1.0), F(1.0)); } + /*! + * \brief Makes the vector (1, 0) + * \return A reference to this vector with components (1, 0) + * + * \see UnitX + */ + template Vector2& Vector2::MakeUnitX() { return Set(F(1.0), F(0.0)); } + /*! + * \brief Makes the vector (0, 1) + * \return A reference to this vector with components (0, 1) + * + * \see UnitY + */ + template Vector2& Vector2::MakeUnitY() { return Set(F(0.0), F(1.0)); } + /*! + * \brief Makes the vector (0, 0) + * \return A reference to this vector with components (0, 0) + * + * \see Zero + */ + template Vector2& Vector2::MakeZero() { return Set(F(0.0), F(0.0)); } + /*! + * \brief Sets this vector's components to the maximum of its own and other components + * \return A reference to this vector with replaced values with the corresponding max value + * + * \param vec Other vector to compare the components with + * + * \see Minimize + */ + template Vector2& Vector2::Maximize(const Vector2& vec) { @@ -143,6 +297,15 @@ namespace Nz return *this; } + /*! + * \brief Sets this vector's components to the minimum of its own and other components + * \return A reference to this vector with replaced values with the corresponding min value + * + * \param vec Other vector to compare the components with + * + * \see Maximize + */ + template Vector2& Vector2::Minimize(const Vector2& vec) { @@ -155,6 +318,17 @@ namespace Nz return *this; } + /*! + * \brief Normalizes the current vector + * \return A reference to this vector + * + * \param length Optional argument to obtain the length's ratio of the vector and the unit-length + * + * \remark If the vector is (0, 0), then it returns (0, 0) and length is 0 + * + * \see GetNormal + */ + template Vector2& Vector2::Normalize(T* length) { @@ -172,6 +346,14 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector + * \return A reference to this vector + * + * \param X X component + * \param Y Y component + */ + template Vector2& Vector2::Set(T X, T Y) { @@ -181,6 +363,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from a "scale" + * \return A reference to this vector + * + * \param scale X component = Y component + */ + template Vector2& Vector2::Set(T scale) { @@ -190,6 +379,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from an array of two elements + * \return A reference to this vector + * + * \param vec[2] vec[0] is X component and vec[1] is Y component + */ + template Vector2& Vector2::Set(const T vec[2]) { @@ -198,6 +394,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from another vector + * \return A reference to this vector + * + * \param vec The other vector + */ + template Vector2& Vector2::Set(const Vector2& vec) { @@ -206,6 +409,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from another type of Vector2 + * \return A reference to this vector + * + * \param vec Vector of type U to convert its components + */ + template template Vector2& Vector2::Set(const Vector2& vec) @@ -216,6 +426,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from a Vector3 + * \return A reference to this vector + * + * \param vec Vector3 where only the first two components are taken + */ + template Vector2& Vector2::Set(const Vector3& vec) { @@ -225,6 +442,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from a Vector4 + * \return A reference to this vector + * + * \param vec Vector4 where only the first two components are taken + */ + template Vector2& Vector2::Set(const Vector4& vec) { @@ -234,12 +458,26 @@ namespace Nz return *this; } + /*! + * \brief Calculates the squared distance between two vectors + * \return The metric distance between two vectors with the squared euclidean norm + * + * \param vec The other vector to measure the distance with + * + * \see Distance + */ + template T Vector2::SquaredDistance(const Vector2& vec) const { return (*this - vec).GetSquaredLength(); } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "Vector2(x, y)" + */ + template String Vector2::ToString() const { @@ -248,54 +486,116 @@ namespace Nz return ss << "Vector2(" << x << ", " << y << ')'; } + /*! + * \brief Converts vector to pointer to its own data + * \return A pointer to the own data + * + * \remark Access to index greather than 1 is undefined behavior + */ + template - Vector2::operator T*() + Vector2::operator T* () { return &x; } + /*! + * \brief Converts vector to const pointer to its own data + * \return A constant pointer to the own data + * + * \remark Access to index greather than 1 is undefined behavior + */ + template - Vector2::operator const T*() const + Vector2::operator const T* () const { return &x; } + /*! + * \brief Helps to represent the sign of the vector + * \return A constant reference to this vector + */ + template const Vector2& Vector2::operator+() const { return *this; } + /*! + * \brief Negates the components of the vector + * \return A constant reference to this vector with negate components + */ + template Vector2 Vector2::operator-() const { return Vector2(-x, -y); } + /*! + * \brief Adds the components of the vector with other vector + * \return A vector where components are the sum of this vector and the other one + * + * \param vec The other vector to add components with + */ + template Vector2 Vector2::operator+(const Vector2& vec) const { return Vector2(x + vec.x, y + vec.y); } + /*! + * \brief Substracts the components of the vector with other vector + * \return A vector where components are the difference of this vector and the other one + * + * \param vec The other vector to substract components with + */ + template Vector2 Vector2::operator-(const Vector2& vec) const { return Vector2(x - vec.x, y - vec.y); } + /*! + * \brief Multiplies the components of the vector with other vector + * \return A vector where components are the product of this vector and the other one + * + * \param vec The other vector to multiply components with + */ + template Vector2 Vector2::operator*(const Vector2& vec) const { return Vector2(x * vec.x, y * vec.y); } + /*! + * \brief Multiplies the components of the vector with a scalar + * \return A vector where components are the product of this vector and the scalar + * + * \param scale The scalar to multiply components with + */ + template Vector2 Vector2::operator*(T scale) const { return Vector2(x * scale, y * scale); } + /*! + * \brief Divides the components of the vector with other vector + * \return A vector where components are the quotient of this vector and the other one + * + * \param vec The other vector to divide components with + * + * \remark Produce a NazaraError if one of the vec components is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of the vec components is null + */ + template Vector2 Vector2::operator/(const Vector2& vec) const { @@ -312,6 +612,16 @@ namespace Nz return Vector2(x / vec.x, y / vec.y); } + /*! + * \brief Divides the components of the vector with a scalar + * \return A vector where components are the quotient of this vector and the scalar + * + * \param scale The scalar to divide components with + * + * \remark Produce a NazaraError if scale is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and scale is null + */ + template Vector2 Vector2::operator/(T scale) const { @@ -328,6 +638,13 @@ namespace Nz return Vector2(x / scale, y / scale); } + /*! + * \brief Adds the components of other vector to this vector + * \return A reference to this vector where components are the sum of this vector and the other one + * + * \param vec The other vector to add components with + */ + template Vector2& Vector2::operator+=(const Vector2& vec) { @@ -337,6 +654,13 @@ namespace Nz return *this; } + /*! + * \brief Substracts the components of other vector to this vector + * \return A reference to this vector where components are the difference of this vector and the other one + * + * \param vec The other vector to substract components with + */ + template Vector2& Vector2::operator-=(const Vector2& vec) { @@ -346,6 +670,13 @@ namespace Nz return *this; } + /*! + * \brief Multiplies the components of other vector to this vector + * \return A reference to this vector where components are the product of this vector and the other one + * + * \param vec The other vector to multiply components with + */ + template Vector2& Vector2::operator*=(const Vector2& vec) { @@ -355,6 +686,13 @@ namespace Nz return *this; } + /*! + * \brief Multiplies the components of other vector with a scalar + * \return A reference to this vector where components are the product of this vector and the scalar + * + * \param vec The other vector to multiply components with + */ + template Vector2& Vector2::operator*=(T scale) { @@ -364,6 +702,16 @@ namespace Nz return *this; } + /*! + * \brief Multiplies the components of other vector to this vector + * \return A reference to this vector where components are the quotient of this vector and the other one + * + * \param vec The other vector to multiply components with + * + * \remark Produce a NazaraError if one of the vec components is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of the vec components is null + */ + template Vector2& Vector2::operator/=(const Vector2& vec) { @@ -383,6 +731,16 @@ namespace Nz return *this; } + /*! + * \brief Divides the components of other vector with a scalar + * \return A reference to this vector where components are the quotient of this vector and the scalar + * + * \param vec The other vector to divide components with + * + * \remark Produce a NazaraError if scale is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and scale is null + */ + template Vector2& Vector2::operator/=(T scale) { @@ -402,19 +760,40 @@ namespace Nz return *this; } + /*! + * \brief Compares the vector to other one + * \return true if the vectors are the same + * + * \param vec Other vector to compare with + */ + template bool Vector2::operator==(const Vector2& vec) const { return NumberEquals(x, vec.x) && - NumberEquals(y, vec.y); + NumberEquals(y, vec.y); } + /*! + * \brief Compares the vector to other one + * \return false if the vectors are the same + * + * \param vec Other vector to compare with + */ + template bool Vector2::operator!=(const Vector2& vec) const { return !operator==(vec); } + /*! + * \brief Compares the vector to other one + * \return true if this vector has its first components inferior to the other ones + * + * \param vec Other vector to compare with + */ + template bool Vector2::operator<(const Vector2& vec) const { @@ -424,6 +803,13 @@ namespace Nz return x < vec.x; } + /*! + * \brief Compares the vector to other one + * \return true if this vector has its first components inferior or equal to the other ones + * + * \param vec Other vector to compare with + */ + template bool Vector2::operator<=(const Vector2& vec) const { @@ -433,24 +819,95 @@ namespace Nz return x < vec.x; } + /*! + * \brief Compares the vector to other one + * \return true if this vector has its first components superior to the other ones + * + * \param vec Other vector to compare with + */ + template bool Vector2::operator>(const Vector2& vec) const { return !operator<=(vec); } + /*! + * \brief Compares the vector to other one + * \return true if this vector has its first components superior or equal to the other ones + * + * \param vec Other vector to compare with + */ + template bool Vector2::operator>=(const Vector2& vec) const { return !operator<(vec); } + /*! + * \brief Calculates the dot (scalar) product with two vectors + * \return The value of the dot product + * + * \param vec1 The first vector to calculate the dot product with + * \param vec2 The second vector to calculate the dot product with + * + * \see AbsDotProduct, DotProduct + */ + + template + T Vector2::DotProduct(const Vector2& vec1, const Vector2& vec2) + { + return vec1.DotProduct(vec2); + } + + /*! + * \brief Interpolates the vector to other one with a factor of interpolation + * \return A new vector which is the interpolation of two vectors + * + * \param from Initial vector + * \param to Target vector + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * + * \see Lerp + */ + template Vector2 Vector2::Lerp(const Vector2& from, const Vector2& to, T interpolation) { - return Lerp(from, to, interpolation); + Vector2 dummy; + dummy.x = Nz::Lerp(from.x, to.x, interpolation); + dummy.y = Nz::Lerp(from.y, to.y, interpolation); + + return dummy; } + /*! + * \brief Gives the normalized vector + * \return A normalized vector from the vec + * + * \param vec Vector to normalize + * + * \remark If the vector is (0, 0), then it returns (0, 0) + * + * \see GetNormal + */ + + template + Vector2 Vector2::Normalize(const Vector2& vec) + { + return vec.GetNormal(); + } + + /*! + * \brief Shorthand for the vector (1, 1) + * \return A vector with components (1, 1) + * + * \see MakeUnit + */ + template Vector2 Vector2::Unit() { @@ -460,6 +917,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (1, 0) + * \return A vector with components (1, 0) + * + * \see MakeUnitX + */ + template Vector2 Vector2::UnitX() { @@ -469,6 +933,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (0, 1) + * \return A vector with components (0, 1) + * + * \see MakeUnitY + */ + template Vector2 Vector2::UnitY() { @@ -478,6 +949,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (0, 0) + * \return A vector with components (0, 0) + * + * \see MakeZero + */ + template Vector2 Vector2::Zero() { @@ -488,18 +966,43 @@ namespace Nz } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param vec The vector to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::Vector2& vec) { return out << vec.ToString(); } +/*! +* \brief Multiplies the components of the vector with a scalar +* \return A vector where components are the product of this vector and the scalar +* +* \param scale The scalar to multiply components with +*/ + template Nz::Vector2 operator*(T scale, const Nz::Vector2& vec) { return Nz::Vector2(scale * vec.x, scale * vec.y); } +/*! +* \brief Divides the components of the vector with a scalar +* \return A vector where components are the quotient of this vector and the scalar +* +* \param scale The scalar to divide components with +* +* \remark Produce a NazaraError if scale is null with NAZARA_MATH_SAFE defined +* \throw std::domain_error if NAZARA_MATH_SAFE is defined and scale is null +*/ + template Nz::Vector2 operator/(T scale, const Nz::Vector2& vec) { @@ -513,7 +1016,7 @@ Nz::Vector2 operator/(T scale, const Nz::Vector2& vec) } #endif - return Nz::Vector2(scale/vec.x, scale/vec.y); + return Nz::Vector2(scale / vec.x, scale / vec.y); } #undef F diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index 5f14f8be7..0ab620406 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -73,8 +73,8 @@ namespace Nz String ToString() const; - operator T*(); - operator const T*() const; + operator T* (); + operator const T* () const; const Vector3& operator+() const; Vector3 operator-() const; diff --git a/include/Nazara/Math/Vector3.inl b/include/Nazara/Math/Vector3.inl index 9a04ad97b..a1807c902 100644 --- a/include/Nazara/Math/Vector3.inl +++ b/include/Nazara/Math/Vector3.inl @@ -13,36 +13,83 @@ namespace Nz { + /*! + * \class Nz::Vector2 + * \brief Math class that represents an element of the three dimensional vector space + * + * \remark The basis is said to be "right-hand". It means that with your right hand, the thumb is X positive, the index finger Y positive and the middle finger (pointing to you) Z positive + */ + + /*! + * \brief Constructs a Vector3 object from its coordinates + * + * \param X X component + * \param Y Y component + * \param Z Z component + */ + template Vector3::Vector3(T X, T Y, T Z) { Set(X, Y, Z); } + /*! + * \brief Constructs a Vector3 object from a component and a Vector2 + * + * \param X X component + * \param vec vec.X = Y component and vec.y = Z component + */ + template Vector3::Vector3(T X, const Vector2& vec) { Set(X, vec); } + /*! + * \brief Constructs explicitely a Vector3 object from its "scale" + * + * \param scale X component = Y component = Z component + */ + template Vector3::Vector3(T scale) { Set(scale); } + /*! + * \brief Constructs a Vector3 object from an array of three elements + * + * \param vec[3] vec[0] is X component, vec[1] is Y component and vec[2] is Z component + */ + template Vector3::Vector3(const T vec[3]) { Set(vec); } + /*! + * \brief Constructs a Vector3 object from a Vector2 and a component + * + * \param vec vec.X = X component and vec.y = Y component + * \param Z Z component + */ + template Vector3::Vector3(const Vector2& vec, T Z) { Set(vec, Z); } + /*! + * \brief Constructs a Vector3 object from another type of Vector3 + * + * \param vec Vector of type U to convert to type T + */ + template template Vector3::Vector3(const Vector3& vec) @@ -50,18 +97,46 @@ namespace Nz Set(vec); } + /*! + * \brief Constructs a Vector3 object from a Vector4 + * + * \param vec Vector4 where only the first three components are taken + */ + template Vector3::Vector3(const Vector4& vec) { Set(vec); } + /*! + * \brief Calculates the absolute dot (scalar) product with two vectors + * \return The dot product with absolutes values on each component + * + * \param vec The other vector to calculate the absolute dot product with + * + * \see DotProduct + */ + template T Vector3::AbsDotProduct(const Vector3& vec) const { return std::abs(x * vec.x) + std::abs(y * vec.y) + std::abs(z * vec.z); } + /*! + * \brief Calculates the angle between two vectors in orthonormal basis + * \return The angle unit depends of NAZARA_MATH_ANGLE_RADIAN in the range 0..pi + * + * \param vec The other vector to measure the angle with + * + * \remark The vectors do not need to be normalised + * \remark Produce a NazaraError if one of the vec components is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of the vec components is null + * + * \see NormalizeAngle + */ + template T Vector3::AngleBetween(const Vector3& vec) const { @@ -78,46 +153,103 @@ namespace Nz } #endif - T alpha = DotProduct(vec)/divisor; + T alpha = DotProduct(vec) / divisor; return FromRadians(std::acos(Clamp(alpha, F(-1.0), F(1.0)))); } + /*! + * \brief Calculates the cross (scalar) product with two vectors + * \return The vector of the cross product according to "right-hand" rule + * + * \param vec The other vector to calculate the cross product with + * + * \see CrossProduct + */ + template Vector3 Vector3::CrossProduct(const Vector3& vec) const { return Vector3(y * vec.z - z * vec.y, z * vec.x - x * vec.z, x * vec.y - y * vec.x); } + /*! + * \brief Calculates the distance between two vectors + * \return The metric distance between two vectors with euclidean norm + * + * \param vec The other vector to measure the distance with + * + * \see SquaredDistance + */ + template T Vector3::Distance(const Vector3& vec) const { return std::sqrt(SquaredDistance(vec)); } + /*! + * \brief Calculates the distance between two vectors + * \return The metric distance in float between two vectors with euclidean norm + * + * \param vec The other vector to measure the distance with + */ + template float Vector3::Distancef(const Vector3& vec) const { return std::sqrt(static_cast(SquaredDistance(vec))); } + /*! + * \brief Calculates the dot (scalar) product with two vectors + * \return The value of the dot product + * + * \param vec The other vector to calculate the dot product with + * + * \see AbsDotProduct, DotProduct + */ + template T Vector3::DotProduct(const Vector3& vec) const { - return x*vec.x + y*vec.y + z*vec.z; + return x * vec.x + y * vec.y + z * vec.z; } + /*! + * \brief Calculates the length (magnitude) of the vector + * \return The length of the vector + * + * \see GetSquaredLength + */ + template T Vector3::GetLength() const { return static_cast(std::sqrt(GetSquaredLength())); } + /*! + * \brief Calculates the length (magnitude) of the vector + * \return The length in float of the vector + */ + template float Vector3::GetLengthf() const { return std::sqrt(static_cast(GetSquaredLength())); } + /*! + * \brief Gets a copy normalized of the vector + * \return A new vector which is the vector normalized + * + * \param length Optional argument to obtain the length's ratio of the vector and the unit-length + * + * \remark If ths vector is (0, 0, 0), then it returns (0, 0, 0) and length is 0 + * + * \see Normalize + */ + template Vector3 Vector3::GetNormal(T* length) const { @@ -127,78 +259,171 @@ namespace Nz return vec; } + /*! + * \brief Calculates the squared length (magnitude) of the vector + * \return The squared length of the vector + * + * \see GetLength + */ + template T Vector3::GetSquaredLength() const { return x*x + y*y + z*z; } + /*! + * \brief Makes the vector (0, 0, 1) + * \return A reference to this vector with components (0, 0, 1) + * + * \see Backward + */ + template Vector3& Vector3::MakeBackward() { return Set(F(0.0), F(0.0), F(1.0)); } + /*! + * \brief Makes the vector (0, -1, 0) + * \return A reference to this vector with components (0, -1, 0) + * + * \see Down + */ + template Vector3& Vector3::MakeDown() { return Set(F(0.0), F(-1.0), F(0.0)); } + /*! + * \brief Makes the vector (0, 0, -1) + * \return A reference to this vector with components (0, 0, -1) + * + * \see Forward + */ + template Vector3& Vector3::MakeForward() { return Set(F(0.0), F(0.0), F(-1.0)); } + /*! + * \brief Makes the vector (-1, 0, 0) + * \return A reference to this vector with components (-1, 0, 0) + * + * \see Left + */ + template Vector3& Vector3::MakeLeft() { return Set(F(-1.0), F(0.0), F(0.0)); } + /*! + * \brief Makes the vector (1, 0, 0) + * \return A reference to this vector with components (1, 0, 0) + * + * \see Right + */ + template Vector3& Vector3::MakeRight() { return Set(F(1.0), F(0.0), F(0.0)); } + /*! + * \brief Makes the vector (1, 1, 1) + * \return A reference to this vector with components (1, 1, 1) + * + * \see Unit + */ + template Vector3& Vector3::MakeUnit() { return Set(F(1.0), F(1.0), F(1.0)); } + /*! + * \brief Makes the vector (1, 0, 0) + * \return A reference to this vector with components (1, 0, 0) + * + * \see UnitX + */ + template Vector3& Vector3::MakeUnitX() { return Set(F(1.0), F(0.0), F(0.0)); } + /*! + * \brief Makes the vector (0, 1, 0) + * \return A reference to this vector with components (0, 1, 0) + * + * \see UnitY + */ + template Vector3& Vector3::MakeUnitY() { return Set(F(0.0), F(1.0), F(0.0)); } + /*! + * \brief Makes the vector (0, 0, 1) + * \return A reference to this vector with components (0, 0, 1) + * + * \see UnitZ + */ + template Vector3& Vector3::MakeUnitZ() { return Set(F(0.0), F(0.0), F(1.0)); } + /*! + * \brief Makes the vector (0, 1, 0) + * \return A reference to this vector with components (0, 1, 0) + * + * \see Up + */ + template Vector3& Vector3::MakeUp() { return Set(F(0.0), F(1.0), F(0.0)); } + /*! + * \brief Makes the vector (0, 0, 0) + * \return A reference to this vector with components (0, 0, 0) + * + * \see Zero + */ + template Vector3& Vector3::MakeZero() { return Set(F(0.0), F(0.0), F(0.0)); } + /*! + * \brief Sets this vector's components to the maximum of its own and other components + * \return A reference to this vector with replaced values with the corresponding max value + * + * \param vec Other vector to compare the components with + * + * \see Minimize + */ + template Vector3& Vector3::Maximize(const Vector3& vec) { @@ -214,6 +439,15 @@ namespace Nz return *this; } + /*! + * \brief Sets this vector's components to the minimum of its own and other components + * \return A reference to this vector with replaced values with the corresponding min value + * + * \param vec Other vector to compare the components with + * + * \see Maximize + */ + template Vector3& Vector3::Minimize(const Vector3& vec) { @@ -229,6 +463,17 @@ namespace Nz return *this; } + /*! + * \brief Normalizes the current vector + * \return A reference to this vector + * + * \param length Optional argument to obtain the length's ratio of the vector and the unit-length + * + * \remark If the vector is (0, 0, 0), then it returns (0, 0, 0) and length is 0 + * + * \see GetNormal + */ + template Vector3& Vector3::Normalize(T* length) { @@ -247,6 +492,15 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector + * \return A reference to this vector + * + * \param X X component + * \param Y Y component + * \param Z Z component + */ + template Vector3& Vector3::Set(T X, T Y, T Z) { @@ -257,6 +511,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from a component and a Vector2 + * + * \param X X component + * \param vec vec.X = Y component and vec.y = Z component + */ + template Vector3& Vector3::Set(T X, const Vector2& vec) { @@ -267,6 +528,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from a "scale" + * \return A reference to this vector + * + * \param scale X component = Y component = Z component + */ + template Vector3& Vector3::Set(T scale) { @@ -277,6 +545,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from an array of three elements + * \return A reference to this vector + * + * \param vec[3] vec[0] is X component, vec[1] is Y component and vec[2] is Z component + */ + template Vector3& Vector3::Set(const T vec[3]) { @@ -285,6 +560,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from a Vector2 and a component + * + * \param vec vec.X = X component and vec.y = Y component + * \param Z Z component + */ + template Vector3& Vector3::Set(const Vector2& vec, T Z) { @@ -295,6 +577,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from another vector + * \return A reference to this vector + * + * \param vec The other vector + */ + template Vector3& Vector3::Set(const Vector3& vec) { @@ -303,6 +592,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from another type of Vector3 + * \return A reference to this vector + * + * \param vec Vector of type U to convert its components + */ + template template Vector3& Vector3::Set(const Vector3& vec) @@ -314,6 +610,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from a Vector4 + * \return A reference to this vector + * + * \param vec Vector4 where only the first three components are taken + */ + template Vector3& Vector3::Set(const Vector4& vec) { @@ -324,12 +627,26 @@ namespace Nz return *this; } + /*! + * \brief Calculates the squared distance between two vectors + * \return The metric distance between two vectors with the squared euclidean norm + * + * \param vec The other vector to measure the distance with + * + * \see Distance + */ + template T Vector3::SquaredDistance(const Vector3& vec) const { return (*this - vec).GetSquaredLength(); } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "Vector3(x, y, z)" + */ + template String Vector3::ToString() const { @@ -338,54 +655,116 @@ namespace Nz return ss << "Vector3(" << x << ", " << y << ", " << z <<')'; } + /*! + * \brief Converts vector to pointer to its own data + * \return A pointer to the own data + * + * \remark Access to index greather than 2 is undefined behavior + */ + template - Vector3::operator T*() + Vector3::operator T* () { return &x; } + /*! + * \brief Converts vector to const pointer to its own data + * \return A constant pointer to the own data + * + * \remark Access to index greather than 2 is undefined behavior + */ + template - Vector3::operator const T*() const + Vector3::operator const T* () const { return &x; } + /*! + * \brief Helps to represent the sign of the vector + * \return A constant reference to this vector + */ + template const Vector3& Vector3::operator+() const { return *this; } + /*! + * \brief Negates the components of the vector + * \return A constant reference to this vector with negate components + */ + template Vector3 Vector3::operator-() const { return Vector3(-x, -y, -z); } + /*! + * \brief Adds the components of the vector with other vector + * \return A vector where components are the sum of this vector and the other one + * + * \param vec The other vector to add components with + */ + template Vector3 Vector3::operator+(const Vector3& vec) const { return Vector3(x + vec.x, y + vec.y, z + vec.z); } + /*! + * \brief Substracts the components of the vector with other vector + * \return A vector where components are the difference of this vector and the other one + * + * \param vec The other vector to substract components with + */ + template Vector3 Vector3::operator-(const Vector3& vec) const { return Vector3(x - vec.x, y - vec.y, z - vec.z); } + /*! + * \brief Multiplies the components of the vector with other vector + * \return A vector where components are the product of this vector and the other one + * + * \param vec The other vector to multiply components with + */ + template Vector3 Vector3::operator*(const Vector3& vec) const { return Vector3(x * vec.x, y * vec.y, z * vec.z); } + /*! + * \brief Multiplies the components of the vector with a scalar + * \return A vector where components are the product of this vector and the scalar + * + * \param scale The scalar to multiply components with + */ + template Vector3 Vector3::operator*(T scale) const { return Vector3(x * scale, y * scale, z * scale); } + /*! + * \brief Divides the components of the vector with other vector + * \return A vector where components are the quotient of this vector and the other one + * + * \param vec The other vector to divide components with + * + * \remark Produce a NazaraError if one of the vec components is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of the vec components is null + */ + template Vector3 Vector3::operator/(const Vector3& vec) const { @@ -402,6 +781,16 @@ namespace Nz return Vector3(x / vec.x, y / vec.y, z / vec.z); } + /*! + * \brief Divides the components of the vector with a scalar + * \return A vector where components are the quotient of this vector and the scalar + * + * \param scale The scalar to divide components with + * + * \remark Produce a NazaraError if scale is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and scale is null + */ + template Vector3 Vector3::operator/(T scale) const { @@ -418,6 +807,13 @@ namespace Nz return Vector3(x / scale, y / scale, z / scale); } + /*! + * \brief Adds the components of other vector to this vector + * \return A reference to this vector where components are the sum of this vector and the other one + * + * \param vec The other vector to add components with + */ + template Vector3& Vector3::operator+=(const Vector3& vec) { @@ -428,6 +824,13 @@ namespace Nz return *this; } + /*! + * \brief Substracts the components of other vector to this vector + * \return A reference to this vector where components are the difference of this vector and the other one + * + * \param vec The other vector to substract components with + */ + template Vector3& Vector3::operator-=(const Vector3& vec) { @@ -438,6 +841,13 @@ namespace Nz return *this; } + /*! + * \brief Multiplies the components of other vector to this vector + * \return A reference to this vector where components are the product of this vector and the other one + * + * \param vec The other vector to multiply components with + */ + template Vector3& Vector3::operator*=(const Vector3& vec) { @@ -448,6 +858,13 @@ namespace Nz return *this; } + /*! + * \brief Multiplies the components of other vector with a scalar + * \return A reference to this vector where components are the product of this vector and the scalar + * + * \param vec The other vector to multiply components with + */ + template Vector3& Vector3::operator*=(T scale) { @@ -458,6 +875,16 @@ namespace Nz return *this; } + /*! + * \brief Multiplies the components of other vector to this vector + * \return A reference to this vector where components are the quotient of this vector and the other one + * + * \param vec The other vector to multiply components with + * + * \remark Produce a NazaraError if one of the vec components is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of the vec components is null + */ + template Vector3& Vector3::operator/=(const Vector3& vec) { @@ -476,6 +903,16 @@ namespace Nz return *this; } + /*! + * \brief Divides the components of other vector with a scalar + * \return A reference to this vector where components are the quotient of this vector and the scalar + * + * \param vec The other vector to divide components with + * + * \remark Produce a NazaraError if scale is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and scale is null + */ + template Vector3& Vector3::operator/=(T scale) { @@ -494,20 +931,41 @@ namespace Nz return *this; } + /*! + * \brief Compares the vector to other one + * \return true if the vectors are the same + * + * \param vec Other vector to compare with + */ + template bool Vector3::operator==(const Vector3& vec) const { return NumberEquals(x, vec.x) && - NumberEquals(y, vec.y) && - NumberEquals(z, vec.z); + NumberEquals(y, vec.y) && + NumberEquals(z, vec.z); } + /*! + * \brief Compares the vector to other one + * \return false if the vectors are the same + * + * \param vec Other vector to compare with + */ + template bool Vector3::operator!=(const Vector3& vec) const { return !operator==(vec); } + /*! + * \brief Compares the vector to other one + * \return true if this vector has its first components inferior to the other ones + * + * \param vec Other vector to compare with + */ + template bool Vector3::operator<(const Vector3& vec) const { @@ -522,6 +980,13 @@ namespace Nz return x < vec.x; } + /*! + * \brief Compares the vector to other one + * \return true if this vector has its first components inferior or equal to the other ones + * + * \param vec Other vector to compare with + */ + template bool Vector3::operator<=(const Vector3& vec) const { @@ -536,30 +1001,71 @@ namespace Nz return x < vec.x; } + /*! + * \brief Compares the vector to other one + * \return true if this vector has its first components superior to the other ones + * + * \param vec Other vector to compare with + */ + template bool Vector3::operator>(const Vector3& vec) const { return !operator<=(vec); } + /*! + * \brief Compares the vector to other one + * \return true if this vector has its first components superior or equal to the other ones + * + * \param vec Other vector to compare with + */ + template bool Vector3::operator>=(const Vector3& vec) const { return !operator<(vec); } + /*! + * \brief Calculates the cross product with two vectors + * \return A vector which is the cross product according to "right-hand" rule + * + * \param vec1 The first vector to calculate the cross product with + * \param vec2 The second vector to calculate the cross product with + * + * \see CrossProduct + */ + template Vector3 Vector3::CrossProduct(const Vector3& vec1, const Vector3& vec2) { return vec1.CrossProduct(vec2); } + /*! + * \brief Calculates the dot (scalar) product with two vectors + * \return The value of the dot product + * + * \param vec1 The first vector to calculate the dot product with + * \param vec2 The second vector to calculate the dot product with + * + * \see AbsDotProduct, DotProduct + */ + template T Vector3::DotProduct(const Vector3& vec1, const Vector3& vec2) { return vec1.DotProduct(vec2); } + /*! + * \brief Shorthand for the vector (0, 0, 1) + * \return A vector with components (0, 0, 1) + * + * \see MakeBackward + */ + template Vector3 Vector3::Backward() { @@ -569,6 +1075,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (0, -1, 0) + * \return A vector with components (0, -1, 0) + * + * \see MakeDown + */ + template Vector3 Vector3::Down() { @@ -578,6 +1091,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (0, 0, -1) + * \return A vector with components (0, 0, -1) + * + * \see Forward + */ + template Vector3 Vector3::Forward() { @@ -587,6 +1107,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (-1, 0, 0) + * \return A vector with components (-1, 0, 0) + * + * \see MakeLeft + */ + template Vector3 Vector3::Left() { @@ -596,18 +1123,54 @@ namespace Nz return vector; } + /*! + * \brief Interpolates the vector to other one with a factor of interpolation + * \return A new vector which is the interpolation of two vectors + * + * \param from Initial vector + * \param to Target vector + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * + * \see Lerp + */ + template Vector3 Vector3::Lerp(const Vector3& from, const Vector3& to, T interpolation) { - return Nz::Lerp(from, to, interpolation); + Vector3 dummy; + dummy.x = Nz::Lerp(from.x, to.x, interpolation); + dummy.y = Nz::Lerp(from.y, to.y, interpolation); + dummy.z = Nz::Lerp(from.z, to.z, interpolation); + + return dummy; } + /*! + * \brief Gives the normalized vector + * \return A normalized vector from the vec + * + * \param vec Vector to normalize + * + * \remark If the vector is (0, 0, 0), then it returns (0, 0, 0) + * + * \see GetNormal + */ + template Vector3 Vector3::Normalize(const Vector3& vec) { return vec.GetNormal(); } + /*! + * \brief Shorthand for the vector (1, 0, 0) + * \return A vector with components (1, 0, 0) + * + * \see MakeRight + */ + template Vector3 Vector3::Right() { @@ -617,6 +1180,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (1, 1, 1) + * \return A vector with components (1, 1, 1) + * + * \see MakeUnit + */ + template Vector3 Vector3::Unit() { @@ -626,6 +1196,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (1, 0, 0) + * \return A vector with components (1, 0, 0) + * + * \see MakeUnitX + */ + template Vector3 Vector3::UnitX() { @@ -635,6 +1212,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (0, 1, 0) + * \return A vector with components (0, 1, 0) + * + * \see MakeUnitY + */ + template Vector3 Vector3::UnitY() { @@ -644,6 +1228,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (0, 0, 1) + * \return A vector with components (0, 0, 1) + * + * \see MakeUnitZ + */ + template Vector3 Vector3::UnitZ() { @@ -653,6 +1244,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (0, 1, 0) + * \return A vector with components (0, 1, 0) + * + * \see MakeUp + */ + template Vector3 Vector3::Up() { @@ -662,6 +1260,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (0, 0, 0) + * \return A vector with components (0, 0, 0) + * + * \see MakeZero + */ + template Vector3 Vector3::Zero() { @@ -672,18 +1277,43 @@ namespace Nz } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param vec The vector to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::Vector3& vec) { return out << vec.ToString(); } +/*! +* \brief Multiplies the components of the vector with a scalar +* \return A vector where components are the product of this vector and the scalar +* +* \param scale The scalar to multiply components with +*/ + template Nz::Vector3 operator*(T scale, const Nz::Vector3& vec) { return Nz::Vector3(scale * vec.x, scale * vec.y, scale * vec.z); } +/*! +* \brief Divides the components of the vector with a scalar +* \return A vector where components are the quotient of this vector and the scalar +* +* \param scale The scalar to divide components with +* +* \remark Produce a NazaraError if scale is null with NAZARA_MATH_SAFE defined +* \throw std::domain_error if NAZARA_MATH_SAFE is defined and scale is null +*/ + template Nz::Vector3 operator/(T scale, const Nz::Vector3& vec) { diff --git a/include/Nazara/Math/Vector4.hpp b/include/Nazara/Math/Vector4.hpp index ac953f6ab..319f18e3b 100644 --- a/include/Nazara/Math/Vector4.hpp +++ b/include/Nazara/Math/Vector4.hpp @@ -60,8 +60,8 @@ namespace Nz String ToString() const; - operator T*(); - operator const T*() const; + operator T* (); + operator const T* () const; const Vector4& operator+() const; Vector4 operator-() const; @@ -87,6 +87,9 @@ namespace Nz bool operator>(const Vector4& vec) const; bool operator>=(const Vector4& vec) const; + static T DotProduct(const Vector4& vec1, const Vector4& vec2); + static Vector4 Lerp(const Vector4& from, const Vector4& to, T interpolation); + static Vector4 Normalize(const Vector4& vec); static Vector4 UnitX(); static Vector4 UnitY(); static Vector4 UnitZ(); diff --git a/include/Nazara/Math/Vector4.inl b/include/Nazara/Math/Vector4.inl index 9193d6f06..c5127b34e 100644 --- a/include/Nazara/Math/Vector4.inl +++ b/include/Nazara/Math/Vector4.inl @@ -14,54 +14,125 @@ namespace Nz { + + /*! + * \class Nz::Vector4 + * \brief Math class that represents an element of the three dimensional vector space with the notion of projectivity. When the fourth component is 1, it describes an 'usual' point and when it is 0, it represents the point at infinity + */ + + /*! + * \brief Constructs a Vector4 object from its coordinates + * + * \param X X component + * \param Y Y component + * \param Z Z component + * \param W W component + */ + template Vector4::Vector4(T X, T Y, T Z, T W) { Set(X, Y, Z, W); } + /*! + * \brief Constructs a Vector4 object from two components and a Vector2 + * + * \param X X component + * \param Y Y component + * \param vec vec.X = Z component and vec.y = W component + */ + template Vector4::Vector4(T X, T Y, const Vector2& vec) { Set(X, Y, vec); } + /*! + * \brief Constructs a Vector4 object from one component, a Vector2 and one component + * + * \param X X component + * \param vec vec.X = Y component and vec.y = Z component + * \param W W component + */ + template Vector4::Vector4(T X, const Vector2& vec, T W) { Set(X, vec, W); } + /*! + * \brief Constructs a Vector4 object from one component and a Vector3 + * + * \param X X component + * \param vec vec.X = Y component, vec.y = Z component and vec.z = W component + */ + template Vector4::Vector4(T X, const Vector3& vec) { Set(X, vec); } + /*! + * \brief Constructs explicitely a Vector4 object from its "scale" + * + * \param scale X component = Y component = Z component = W component + */ + template Vector4::Vector4(T scale) { Set(scale); } + /*! + * \brief Constructs a Vector4 object from an array of four elements + * + * \param vec[4] vec[0] is X component, vec[1] is Y component, vec[2] is Z component and vec[3] is W component + */ + template Vector4::Vector4(const T vec[4]) { Set(vec); } + /*! + * \brief Constructs a Vector4 object from a Vector2 and two components + * + * \param vec vec.X = X component and vec.y = Y component + * \param Z Z component + * \param W W component + */ + template Vector4::Vector4(const Vector2& vec, T Z, T W) { Set(vec, Z, W); } + /*! + * \brief Constructs a Vector4 object from one component and a Vector3 + * + * \param vec vec.X = X component, vec.y = Y component and vec.z = Z component + * \param W W component + */ + template Vector4::Vector4(const Vector3& vec, T W) { Set(vec, W); } + /*! + * \brief Constructs a Vector4 object from another type of Vector4 + * + * \param vec Vector of type U to convert to type T + */ + template template Vector4::Vector4(const Vector4& vec) @@ -69,18 +140,45 @@ namespace Nz Set(vec); } + /*! + * \brief Calculates the absolute dot (scalar) product with two vectors + * \return The dot product with absolutes values on each component + * + * \param vec The other vector to calculate the absolute dot product with + * + * \see DotProduct + */ + template T Vector4::AbsDotProduct(const Vector4& vec) const { return std::abs(x * vec.x) + std::abs(y * vec.y) + std::abs(z * vec.z) + std::abs(w * vec.w); } + /*! + * \brief Calculates the dot (scalar) product with two vectors + * \return The value of the dot product + * + * \param vec The other vector to calculate the dot product with + * + * \see AbsDotProduct, DotProduct + */ + template T Vector4::DotProduct(const Vector4& vec) const { return x*vec.x + y*vec.y + z*vec.z + w*vec.w; } + /*! + * \brief Gets a copy normalized of the vector + * \return A new vector which is the vector normalized + * + * \param length Optional argument to obtain the length's ratio of the vector and the unit-length in this case w + * + * \see Normalize + */ + template Vector4 Vector4::GetNormal(T* length) const { @@ -90,30 +188,67 @@ namespace Nz return vec; } + /*! + * \brief Makes the vector (1, 0, 0, 1) + * \return A reference to this vector with components (1, 0, 0, 1) + * + * \see UnitX + */ + template Vector4& Vector4::MakeUnitX() { return Set(F(1.0), F(0.0), F(0.0), F(1.0)); } + /*! + * \brief Makes the vector (0, 1, 0, 1) + * \return A reference to this vector with components (0, 1, 0, 1) + * + * \see UnitY + */ + template Vector4& Vector4::MakeUnitY() { return Set(F(0.0), F(1.0), F(0.0), F(1.0)); } + /*! + * \brief Makes the vector (0, 0, 1, 1) + * \return A reference to this vector with components (0, 0, 1, 1) + * + * \see UnitZ + */ + template Vector4& Vector4::MakeUnitZ() { return Set(F(0.0), F(0.0), F(1.0), F(1.0)); } + /*! + * \brief Makes the vector (0, 0, 0, 1) + * \return A reference to this vector with components (0, 0, 0, 1) + * + * \see Zero + */ + template Vector4& Vector4::MakeZero() { - return Set(F(0.0), F(0.0), F(0.0), F(0.0)); + return Set(F(0.0), F(0.0), F(0.0), F(1.0)); } + /*! + * \brief Sets this vector's components to the maximum of its own and other components + * \return A reference to this vector with replaced values with the corresponding max value + * + * \param vec Other vector to compare the components with + * + * \see Minimize + */ + template Vector4& Vector4::Maximize(const Vector4& vec) { @@ -132,6 +267,15 @@ namespace Nz return *this; } + /*! + * \brief Sets this vector's components to the minimum of its own and other components + * \return A reference to this vector with replaced values with the corresponding min value + * + * \param vec Other vector to compare the components with + * + * \see Maximize + */ + template Vector4& Vector4::Minimize(const Vector4& vec) { @@ -150,11 +294,20 @@ namespace Nz return *this; } + /*! + * \brief Gives the normalized vector + * \return A normalized vector from the vec with w = 1 + * + * \param length Optional argument to obtain the length's ratio of the vector in this case w + * + * \see GetNormal + */ + template Vector4& Vector4::Normalize(T* length) { T invLength = F(1.0)/w; - x *= invLength; // Attention, briser cette logique casserait Frustum::Extract + x *= invLength; // Warning, change this logic will break Frustum::Extract y *= invLength; z *= invLength; @@ -166,6 +319,16 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector + * \return A reference to this vector + * + * \param X X component + * \param Y Y component + * \param Z Z component + * \param W W component + */ + template Vector4& Vector4::Set(T X, T Y, T Z, T W) { @@ -177,6 +340,15 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from two components and a Vector2 + * \return A reference to this vector + * + * \param X X component + * \param Y Y component + * \param vec vec.X = Z component and vec.y = W component + */ + template Vector4& Vector4::Set(T X, T Y, const Vector2& vec) { @@ -188,6 +360,15 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from one component, a Vector2 and one component + * \return A reference to this vector + * + * \param X X component + * \param vec vec.X = Y component and vec.y = Z component + * \param W W component + */ + template Vector4& Vector4::Set(T X, const Vector2& vec, T W) { @@ -199,6 +380,14 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from one component and a Vector3 + * \return A reference to this vector + * + * \param X X component + * \param vec vec.X = Y component, vec.y = Z component and vec.z = W component + */ + template Vector4& Vector4::Set(T X, const Vector3& vec) { @@ -210,6 +399,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from a "scale" + * \return A reference to this vector + * + * \param scale X component = Y component = Z component = W component + */ + template Vector4& Vector4::Set(T scale) { @@ -221,6 +417,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from an array of four elements + * \return A reference to this vector + * + * \param vec[4] vec[0] is X component, vec[1] is Y component, vec[2] is Z component and vec[3] is W component + */ + template Vector4& Vector4::Set(const T vec[4]) { @@ -229,6 +432,14 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from a Vector2 and two components + * + * \param vec vec.X = X component and vec.y = Y component + * \param Z Z component + * \param W W component + */ + template Vector4& Vector4::Set(const Vector2& vec, T Z, T W) { @@ -240,6 +451,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from a Vector3 and one components + * + * \param vec vec.X = X component, vec.y = Y component and vec.z = Z component + * \param W W component + */ + template Vector4& Vector4::Set(const Vector3& vec, T W) { @@ -251,6 +469,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from another vector + * \return A reference to this vector + * + * \param vec The other vector + */ + template Vector4& Vector4::Set(const Vector4& vec) { @@ -259,6 +484,13 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the vector from another type of Vector4 + * \return A reference to this vector + * + * \param vec Vector of type U to convert its components + */ + template template Vector4& Vector4::Set(const Vector4& vec) @@ -271,6 +503,11 @@ namespace Nz return *this; } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "Vector4(x, y, z, w)" + */ + template String Vector4::ToString() const { @@ -279,54 +516,116 @@ namespace Nz return ss << "Vector4(" << x << ", " << y << ", " << z << ", " << w << ')'; } + /*! + * \brief Converts vector to pointer to its own data + * \return A pointer to the own data + * + * \remark Access to index greather than 3 is undefined behavior + */ + template - Vector4::operator T*() + Vector4::operator T* () { return &x; } + /*! + * \brief Converts vector to const pointer to its own data + * \return A constant pointer to the own data + * + * \remark Access to index greather than 3 is undefined behavior + */ + template - Vector4::operator const T*() const + Vector4::operator const T* () const { return &x; } + /*! + * \brief Helps to represent the sign of the vector + * \return A constant reference to this vector + */ + template const Vector4& Vector4::operator+() const { return *this; } + /*! + * \brief Negates the components of the vector + * \return A constant reference to this vector with negate components + */ + template Vector4 Vector4::operator-() const { return Vector4(-x, -y, -z, -w); } + /*! + * \brief Adds the components of the vector with other vector + * \return A vector where components are the sum of this vector and the other one + * + * \param vec The other vector to add components with + */ + template Vector4 Vector4::operator+(const Vector4& vec) const { return Vector4(x + vec.x, y + vec.y, z + vec.z, w + vec.w); } + /*! + * \brief Substracts the components of the vector with other vector + * \return A vector where components are the difference of this vector and the other one + * + * \param vec The other vector to substract components with + */ + template Vector4 Vector4::operator-(const Vector4& vec) const { return Vector4(x - vec.x, y - vec.y, z - vec.z, w - vec.w); } + /*! + * \brief Multiplies the components of the vector with other vector + * \return A vector where components are the product of this vector and the other one + * + * \param vec The other vector to multiply components with + */ + template Vector4 Vector4::operator*(const Vector4& vec) const { return Vector4(x * vec.x, y * vec.y, z * vec.z, w * vec.w); } + /*! + * \brief Multiplies the components of the vector with a scalar + * \return A vector where components are the product of this vector and the scalar + * + * \param scale The scalar to multiply components with + */ + template Vector4 Vector4::operator*(T scale) const { return Vector4(x * scale, y * scale, z * scale, w * scale); } + /*! + * \brief Divides the components of the vector with other vector + * \return A vector where components are the quotient of this vector and the other one + * + * \param vec The other vector to divide components with + * + * \remark Produce a NazaraError if one of the vec components is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of the vec components is null + */ + template Vector4 Vector4::operator/(const Vector4& vec) const { @@ -343,6 +642,16 @@ namespace Nz return Vector4(x / vec.x, y / vec.y, z / vec.z, w / vec.w); } + /*! + * \brief Divides the components of the vector with a scalar + * \return A vector where components are the quotient of this vector and the scalar + * + * \param scale The scalar to divide components with + * + * \remark Produce a NazaraError if scale is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and scale is null + */ + template Vector4 Vector4::operator/(T scale) const { @@ -359,6 +668,13 @@ namespace Nz return Vector4(x / scale, y / scale, z / scale, w / scale); } + /*! + * \brief Adds the components of other vector to this vector + * \return A reference to this vector where components are the sum of this vector and the other one + * + * \param vec The other vector to add components with + */ + template Vector4& Vector4::operator+=(const Vector4& vec) { @@ -370,6 +686,13 @@ namespace Nz return *this; } + /*! + * \brief Substracts the components of other vector to this vector + * \return A reference to this vector where components are the difference of this vector and the other one + * + * \param vec The other vector to substract components with + */ + template Vector4& Vector4::operator-=(const Vector4& vec) { @@ -381,6 +704,13 @@ namespace Nz return *this; } + /*! + * \brief Multiplies the components of other vector to this vector + * \return A reference to this vector where components are the product of this vector and the other one + * + * \param vec The other vector to multiply components with + */ + template Vector4& Vector4::operator*=(const Vector4& vec) { @@ -392,6 +722,13 @@ namespace Nz return *this; } + /*! + * \brief Multiplies the components of other vector with a scalar + * \return A reference to this vector where components are the product of this vector and the scalar + * + * \param vec The other vector to multiply components with + */ + template Vector4& Vector4::operator*=(T scale) { @@ -403,6 +740,16 @@ namespace Nz return *this; } + /*! + * \brief Multiplies the components of other vector to this vector + * \return A reference to this vector where components are the quotient of this vector and the other one + * + * \param vec The other vector to multiply components with + * + * \remark Produce a NazaraError if one of the vec components is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of the vec components is null + */ + template Vector4& Vector4::operator/=(const Vector4& vec) { @@ -424,6 +771,16 @@ namespace Nz return *this; } + /*! + * \brief Divides the components of other vector with a scalar + * \return A reference to this vector where components are the quotient of this vector and the scalar + * + * \param vec The other vector to divide components with + * + * \remark Produce a NazaraError if scale is null with NAZARA_MATH_SAFE defined + * \throw std::domain_error if NAZARA_MATH_SAFE is defined and scale is null + */ + template Vector4& Vector4::operator/=(T scale) { @@ -445,21 +802,42 @@ namespace Nz return *this; } + /*! + * \brief Compares the vector to other one + * \return true if the vectors are the same + * + * \param vec Other vector to compare with + */ + template bool Vector4::operator==(const Vector4& vec) const { return NumberEquals(x, vec.x) && - NumberEquals(y, vec.y) && - NumberEquals(z, vec.z) && - NumberEquals(w, vec.w); + NumberEquals(y, vec.y) && + NumberEquals(z, vec.z) && + NumberEquals(w, vec.w); } + /*! + * \brief Compares the vector to other one + * \return false if the vectors are the same + * + * \param vec Other vector to compare with + */ + template bool Vector4::operator!=(const Vector4& vec) const { return !operator==(vec); } + /*! + * \brief Compares the vector to other one + * \return true if this vector has its first components inferior to the other ones + * + * \param vec Other vector to compare with + */ + template bool Vector4::operator<(const Vector4& vec) const { @@ -479,6 +857,13 @@ namespace Nz return x < vec.x; } + /*! + * \brief Compares the vector to other one + * \return true if this vector has its first components inferior or equal to the other ones + * + * \param vec Other vector to compare with + */ + template bool Vector4::operator<=(const Vector4& vec) const { @@ -498,18 +883,79 @@ namespace Nz return x < vec.x; } + /*! + * \brief Compares the vector to other one + * \return true if this vector has its first components superior to the other ones + * + * \param vec Other vector to compare with + */ + template bool Vector4::operator>(const Vector4& vec) const { return !operator<=(vec); } + /*! + * \brief Compares the vector to other one + * \return true if this vector has its first components superior or equal to the other ones + * + * \param vec Other vector to compare with + */ + template bool Vector4::operator>=(const Vector4& vec) const { return !operator<(vec); } + /*! + * \brief Interpolates the vector to other one with a factor of interpolation + * \return A new vector which is the interpolation of two vectors + * + * \param from Initial vector + * \param to Target vector + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * + * \see Lerp + */ + + template + Vector4 Vector4::Lerp(const Vector4& from, const Vector4& to, T interpolation) + { + Vector4 dummy; + dummy.x = Nz::Lerp(from.x, to.x, interpolation); + dummy.y = Nz::Lerp(from.y, to.y, interpolation); + dummy.z = Nz::Lerp(from.z, to.z, interpolation); + dummy.w = Nz::Lerp(from.w, to.w, interpolation); + + return dummy; + } + + /*! + * \brief Gives the normalized vector + * \return A normalized vector from the vec with w = 1 + * + * \param vec Vector to normalize + * + * \see GetNormal + */ + + template + Vector4 Vector4::Normalize(const Vector4& vec) + { + return vec.GetNormal(); + } + + /*! + * \brief Shorthand for the vector (1, 0, 0, 1) + * \return A vector with components (1, 0, 0, 1) + * + * \see MakeUnitX + */ + template Vector4 Vector4::UnitX() { @@ -519,6 +965,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (0, 1, 0, 1) + * \return A vector with components (0, 1, 0, 1) + * + * \see MakeUnitY + */ + template Vector4 Vector4::UnitY() { @@ -528,6 +981,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (0, 0, 1, 1) + * \return A vector with components (0, 0, 1, 1) + * + * \see MakeUnitZ + */ + template Vector4 Vector4::UnitZ() { @@ -537,6 +997,13 @@ namespace Nz return vector; } + /*! + * \brief Shorthand for the vector (0, 0, 0, 1) + * \return A vector with components (0, 0, 0, 1) + * + * \see MakeZero + */ + template Vector4 Vector4::Zero() { @@ -547,18 +1014,44 @@ namespace Nz } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param vec The vector to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::Vector4& vec) { return out << vec.ToString(); } +/*! +* \brief Multiplies the components of the vector with a scalar +* \return A vector where components are the product of this vector and the scalar +* +* \param scale The scalar to multiply components with +*/ + + template Nz::Vector4 operator*(T scale, const Nz::Vector4& vec) { return Nz::Vector4(scale * vec.x, scale * vec.y, scale * vec.z, scale * vec.w); } +/*! +* \brief Divides the components of the vector with a scalar +* \return A vector where components are the quotient of this vector and the scalar +* +* \param scale The scalar to divide components with +* +* \remark Produce a NazaraError if scale is null with NAZARA_MATH_SAFE defined +* \throw std::domain_error if NAZARA_MATH_SAFE is defined and scale is null +*/ + template Nz::Vector4 operator/(T scale, const Nz::Vector4& vec) { diff --git a/include/Nazara/Physics/Geom.hpp b/include/Nazara/Physics/Geom.hpp index 3db143292..3e3d14164 100644 --- a/include/Nazara/Physics/Geom.hpp +++ b/include/Nazara/Physics/Geom.hpp @@ -225,7 +225,7 @@ namespace Nz public: NullGeom(); - void ComputeInertialMatrix(Vector3f* inertia, Vector3f* center) const; + void ComputeInertialMatrix(Vector3f* inertia, Vector3f* center) const override; GeomType GetType() const override; diff --git a/include/Nazara/Renderer/RenderTexture.hpp b/include/Nazara/Renderer/RenderTexture.hpp index c197f50c0..798e441ee 100644 --- a/include/Nazara/Renderer/RenderTexture.hpp +++ b/include/Nazara/Renderer/RenderTexture.hpp @@ -43,12 +43,12 @@ namespace Nz void Detach(AttachmentPoint attachmentPoint, UInt8 index); unsigned int GetHeight() const override; - RenderTargetParameters GetParameters() const; + RenderTargetParameters GetParameters() const override; Vector2ui GetSize() const; unsigned int GetWidth() const override; bool IsComplete() const; - bool IsRenderable() const; + bool IsRenderable() const override; inline bool IsValid() const; bool Lock() const; diff --git a/include/Nazara/Renderer/RenderWindow.hpp b/include/Nazara/Renderer/RenderWindow.hpp index 0e283151b..d9889d803 100644 --- a/include/Nazara/Renderer/RenderWindow.hpp +++ b/include/Nazara/Renderer/RenderWindow.hpp @@ -46,11 +46,11 @@ namespace Nz void EnableVerticalSync(bool enabled); - unsigned int GetHeight() const; - RenderTargetParameters GetParameters() const; - unsigned int GetWidth() const; + unsigned int GetHeight() const override; + RenderTargetParameters GetParameters() const override; + unsigned int GetWidth() const override; - bool IsRenderable() const; + bool IsRenderable() const override; bool IsValid() const; void SetFramerateLimit(unsigned int limit); diff --git a/include/Nazara/Utility/SimpleTextDrawer.hpp b/include/Nazara/Utility/SimpleTextDrawer.hpp index 22b52f293..68fdc1daa 100644 --- a/include/Nazara/Utility/SimpleTextDrawer.hpp +++ b/include/Nazara/Utility/SimpleTextDrawer.hpp @@ -24,7 +24,7 @@ namespace Nz SimpleTextDrawer(SimpleTextDrawer&& drawer); virtual ~SimpleTextDrawer(); - const Rectui& GetBounds() const; + const Rectui& GetBounds() const override; unsigned int GetCharacterSize() const; const Color& GetColor() const; Font* GetFont() const; diff --git a/src/Nazara/Audio/Formats/sndfileLoader.cpp b/src/Nazara/Audio/Formats/sndfileLoader.cpp index 4cf99fee7..2aca17976 100644 --- a/src/Nazara/Audio/Formats/sndfileLoader.cpp +++ b/src/Nazara/Audio/Formats/sndfileLoader.cpp @@ -180,7 +180,7 @@ namespace Nz return true; } - unsigned int Read(void* buffer, unsigned int sampleCount) + unsigned int Read(void* buffer, unsigned int sampleCount) override { // Si la musique a été demandée en mono, nous devons la convertir à la volée lors de la lecture if (m_mixToMono) diff --git a/src/Nazara/Core/Posix/DirectoryImpl.cpp b/src/Nazara/Core/Posix/DirectoryImpl.cpp index 4abf575b3..e3add7fd5 100644 --- a/src/Nazara/Core/Posix/DirectoryImpl.cpp +++ b/src/Nazara/Core/Posix/DirectoryImpl.cpp @@ -70,9 +70,8 @@ namespace Nz bool DirectoryImpl::Create(const String& dirPath) { - mode_t permissions; // TODO: check permissions - - return mkdir(dirPath.GetConstBuffer(), permissions) != -1;; + mode_t permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; // TODO: check permissions, no right to execute but read and write for every others. + return mkdir(dirPath.GetConstBuffer(), permissions) != -1; } bool DirectoryImpl::Exists(const String& dirPath) diff --git a/src/Nazara/Network/AbstractSocket.cpp b/src/Nazara/Network/AbstractSocket.cpp index d86f93501..1406741ff 100644 --- a/src/Nazara/Network/AbstractSocket.cpp +++ b/src/Nazara/Network/AbstractSocket.cpp @@ -9,6 +9,8 @@ #if defined(NAZARA_PLATFORM_WINDOWS) #include +#elif defined(NAZARA_PLATFORM_POSIX) +#include #else #error Missing implementation: Socket #endif @@ -105,4 +107,4 @@ namespace Nz m_handle = handle; OnOpened(); } -} \ No newline at end of file +} diff --git a/src/Nazara/Network/IpAddress.cpp b/src/Nazara/Network/IpAddress.cpp index b44412aca..d40e2a581 100644 --- a/src/Nazara/Network/IpAddress.cpp +++ b/src/Nazara/Network/IpAddress.cpp @@ -12,6 +12,8 @@ #if defined(NAZARA_PLATFORM_WINDOWS) #include +#elif defined(NAZARA_PLATFORM_POSIX) +#include #else #error Missing implementation: Network #endif diff --git a/src/Nazara/Network/Network.cpp b/src/Nazara/Network/Network.cpp index ffe4842ca..d2f0d0d51 100644 --- a/src/Nazara/Network/Network.cpp +++ b/src/Nazara/Network/Network.cpp @@ -12,6 +12,8 @@ #if defined(NAZARA_PLATFORM_WINDOWS) #include +#elif defined(NAZARA_PLATFORM_POSIX) +#include #else #error Missing implementation: Network #endif diff --git a/src/Nazara/Network/Posix/IpAddressImpl.cpp b/src/Nazara/Network/Posix/IpAddressImpl.cpp new file mode 100644 index 000000000..1e4f6a89e --- /dev/null +++ b/src/Nazara/Network/Posix/IpAddressImpl.cpp @@ -0,0 +1,309 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + namespace Detail + { + using addrinfoImpl = addrinfo; + + int GetAddressInfo(const String& hostname, const String& service, const addrinfoImpl* hints, addrinfoImpl** results) + { + return getaddrinfo(hostname.GetConstBuffer(), service.GetConstBuffer(), hints, results); + } + + int GetHostnameInfo(sockaddr* socketAddress, socklen_t socketLen, String* hostname, String* service, int flags) + { + std::array hostnameBuffer; + std::array serviceBuffer; + + int result = getnameinfo(socketAddress, socketLen, hostnameBuffer.data(), hostnameBuffer.size(), serviceBuffer.data(), serviceBuffer.size(), flags); + if (result == 0) + { + if (hostname) + hostname->Set(hostnameBuffer.data()); + + if (service) + service->Set(serviceBuffer.data()); + } + + return result; + } + + void FreeAddressInfo(addrinfoImpl* results) + { + freeaddrinfo(results); + } + + IpAddress::IPv4 convertSockaddrToIPv4(const in_addr& addr) + { + union byteToInt + { + UInt8 b[sizeof(uint32_t)]; + uint32_t i; + }; + + byteToInt hostOrder; + hostOrder.i = ntohl(addr.s_addr); + + return { hostOrder.b[3], hostOrder.b[2], hostOrder.b[1], hostOrder.b[0] }; + } + + IpAddress::IPv6 convertSockaddr6ToIPv6(const in6_addr& addr) + { + union byteToInt + { + UInt8 b[sizeof(uint32_t)]; + uint32_t i; + }; + + IpAddress::IPv6 ipv6Addr; + + for (auto i = 0; i < 4; ++i) + { + byteToInt hostOrder; + hostOrder.i = 0; + std::copy(addr.s6_addr + 4 * i, addr.s6_addr + 4 * (i + 1), hostOrder.b); + ipv6Addr[2 * i] = (hostOrder.b[3] << 8) + hostOrder.b[2]; + ipv6Addr[2 * i + 1] = (hostOrder.b[1] << 8) + hostOrder.b[0]; + } + + return ipv6Addr; + } + } + + IpAddress IpAddressImpl::FromAddrinfo(const addrinfo* info) + { + switch (info->ai_family) + { + case AF_INET: + { + sockaddr_in* ipv4 = reinterpret_cast(info->ai_addr); + + return FromSockAddr(ipv4); + } + + case AF_INET6: + { + sockaddr_in6* ipv6 = reinterpret_cast(info->ai_addr); + + return FromSockAddr(ipv6); + } + } + + return IpAddress::Invalid; + } + + IpAddress IpAddressImpl::FromSockAddr(const sockaddr* address) + { + switch (address->sa_family) + { + case AF_INET: + return FromSockAddr(reinterpret_cast(address)); + + case AF_INET6: + return FromSockAddr(reinterpret_cast(address)); + } + + return IpAddress::Invalid; + } + + IpAddress IpAddressImpl::FromSockAddr(const sockaddr_in* addressv4) + { + IpAddress::IPv4 ip4Address = Detail::convertSockaddrToIPv4(addressv4->sin_addr); + return IpAddress(ip4Address, ntohs(addressv4->sin_port)); + } + + IpAddress IpAddressImpl::FromSockAddr(const sockaddr_in6* addressv6) + { + IpAddress::IPv6 ip6Address = Detail::convertSockaddr6ToIPv6(addressv6->sin6_addr); + return IpAddress(ip6Address, ntohs(addressv6->sin6_port)); + } + + bool IpAddressImpl::ResolveAddress(const IpAddress& ipAddress, String* hostname, String* service, ResolveError* error) + { + SockAddrBuffer socketAddress; + socklen_t socketAddressLen = ToSockAddr(ipAddress, socketAddress.data()); + + if (Detail::GetHostnameInfo(reinterpret_cast(socketAddress.data()), socketAddressLen, hostname, service, NI_NUMERICSERV) != 0) + { + if (error) + *error = TranslateEAIErrorToResolveError(errno); + + return false; + } + + if (error) + *error = ResolveError_NoError; + + return true; + } + + std::vector IpAddressImpl::ResolveHostname(NetProtocol procol, const String& hostname, const String& service, ResolveError* error) + { + std::vector results; + + Detail::addrinfoImpl hints; + std::memset(&hints, 0, sizeof(Detail::addrinfoImpl)); + hints.ai_family = SocketImpl::TranslateNetProtocolToAF(procol); + hints.ai_flags = AI_CANONNAME; + hints.ai_socktype = SOCK_STREAM; + + Detail::addrinfoImpl* servinfo; + if (Detail::GetAddressInfo(hostname, service, &hints, &servinfo) != 0) + { + if (error) + *error = TranslateEAIErrorToResolveError(errno); + + return results; + } + + CallOnExit onExit([servinfo]() + { + Detail::FreeAddressInfo(servinfo); + }); + + // loop through all the results and connect to the first we can + for (Detail::addrinfoImpl* p = servinfo; p != nullptr; p = p->ai_next) + { + HostnameInfo result; + result.address = FromAddrinfo(p); + result.canonicalName = String::Unicode(p->ai_canonname); + result.protocol = TranslatePFToNetProtocol(p->ai_family); + result.socketType = TranslateSockToNetProtocol(p->ai_socktype); + + results.push_back(result); + } + + if (error) + *error = ResolveError_NoError; + + return results; + } + + socklen_t IpAddressImpl::ToSockAddr(const IpAddress& ipAddress, void* buffer) + { + if (ipAddress.IsValid()) + { + switch (ipAddress.GetProtocol()) + { + case NetProtocol_IPv4: + { + sockaddr_in* socketAddress = reinterpret_cast(buffer); + + std::memset(socketAddress, 0, sizeof(sockaddr_in)); + socketAddress->sin_family = AF_INET; + socketAddress->sin_port = htons(ipAddress.GetPort()); + socketAddress->sin_addr.s_addr = htonl(ipAddress.ToUInt32()); + + return sizeof(sockaddr_in); + } + + case NetProtocol_IPv6: + { + sockaddr_in6* socketAddress = reinterpret_cast(buffer); + + std::memset(socketAddress, 0, sizeof(sockaddr_in6)); + socketAddress->sin6_family = AF_INET6; + socketAddress->sin6_port = htons(ipAddress.GetPort()); + + IpAddress::IPv6 address = ipAddress.ToIPv6(); + for (unsigned int i = 0; i < 8; ++i) + { + UInt16 networkOrder = htons(address[i]); + socketAddress->sin6_addr.s6_addr[2 * i] = networkOrder / 256; + socketAddress->sin6_addr.s6_addr[2 * i + 1] = networkOrder % 256; + } + + return sizeof(sockaddr_in6); + } + + default: + NazaraInternalError("Unhandled ip protocol (0x" + String::Number(ipAddress.GetProtocol()) + ')'); + break; + } + } + + NazaraError("Invalid ip address"); + return 0; + } + + NetProtocol IpAddressImpl::TranslatePFToNetProtocol(int family) + { + switch (family) + { + case PF_INET: + return NetProtocol_IPv4; + + case PF_INET6: + return NetProtocol_IPv6; + + default: + return NetProtocol_Unknown; + } + } + + SocketType IpAddressImpl::TranslateSockToNetProtocol(int socketType) + { + switch (socketType) + { + case SOCK_STREAM: + return SocketType_TCP; + + case SOCK_DGRAM: + return SocketType_UDP; + + case SOCK_RAW: + return SocketType_Raw; + + default: + return SocketType_Unknown; + } + } + + ResolveError IpAddressImpl::TranslateEAIErrorToResolveError(int error) + { + // http://man7.org/linux/man-pages/man3/gai_strerror.3.html + switch (error) + { + case 0: + return ResolveError_NoError; + + // Engine error + case EAI_BADFLAGS: + case EAI_SYSTEM: + return ResolveError_Internal; + + case EAI_FAMILY: + case EAI_SERVICE: + case EAI_SOCKTYPE: + return ResolveError_ProtocolNotSupported; + + case EAI_NONAME: + return ResolveError_NotFound; + + case EAI_FAIL: + return ResolveError_NonRecoverable; + + case EAI_NODATA: + return ResolveError_NotInitialized; + + case EAI_MEMORY: + return ResolveError_ResourceError; + + case EAI_AGAIN: + return ResolveError_TemporaryFailure; + } + + NazaraWarning("Unhandled EAI error: " + Error::GetLastSystemError(error) + " (" + String::Number(error) + ") as " + gai_strerror(error)); + return ResolveError_Unknown; + } +} diff --git a/src/Nazara/Network/Posix/IpAddressImpl.hpp b/src/Nazara/Network/Posix/IpAddressImpl.hpp new file mode 100644 index 000000000..6ca919e78 --- /dev/null +++ b/src/Nazara/Network/Posix/IpAddressImpl.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + class IpAddressImpl + { + public: + using SockAddrBuffer = std::array; + + IpAddressImpl() = delete; + ~IpAddressImpl() = delete; + + static IpAddress FromAddrinfo(const addrinfo* info); + static IpAddress FromSockAddr(const sockaddr* address); + static IpAddress FromSockAddr(const sockaddr_in* addressv4); + static IpAddress FromSockAddr(const sockaddr_in6* addressv6); + + static bool ResolveAddress(const IpAddress& ipAddress, String* hostname, String* service, ResolveError* error); + static std::vector ResolveHostname(NetProtocol procol, const String& hostname, const String& service, ResolveError* error); + + static socklen_t ToSockAddr(const IpAddress& ipAddress, void* buffer); + static NetProtocol TranslatePFToNetProtocol(int family); + static SocketType TranslateSockToNetProtocol(int socketType); + static ResolveError TranslateEAIErrorToResolveError(int error); + }; +} diff --git a/src/Nazara/Network/Posix/SocketImpl.cpp b/src/Nazara/Network/Posix/SocketImpl.cpp new file mode 100644 index 000000000..cf5a638cf --- /dev/null +++ b/src/Nazara/Network/Posix/SocketImpl.cpp @@ -0,0 +1,746 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + constexpr int SOCKET_ERROR = -1; + + SocketHandle SocketImpl::Accept(SocketHandle handle, IpAddress* address, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + + IpAddressImpl::SockAddrBuffer nameBuffer; + socklen_t bufferLength = sizeof(sockaddr_in); + + SocketHandle newClient = accept(handle, reinterpret_cast(&nameBuffer), &bufferLength); + if (newClient != InvalidHandle) + { + if (address) + *address = IpAddressImpl::FromSockAddr(reinterpret_cast(&nameBuffer)); + + if (error) + *error = SocketError_NoError; + } + else + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + } + + return newClient; + } + + SocketState SocketImpl::Bind(SocketHandle handle, const IpAddress& address, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + NazaraAssert(address.IsValid(), "Invalid address"); + + IpAddressImpl::SockAddrBuffer nameBuffer; + int bufferLength = IpAddressImpl::ToSockAddr(address, nameBuffer.data()); + + if (bind(handle, reinterpret_cast(&nameBuffer), bufferLength) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return SocketState_NotConnected; + } + + if (error) + *error = SocketError_NoError; + + return SocketState_Bound; + } + + SocketHandle SocketImpl::Create(NetProtocol protocol, SocketType type, SocketError* error) + { + NazaraAssert(protocol != NetProtocol_Any, "Any protocol is not supported for socket creation"); + NazaraAssert(type <= SocketType_Max, "Type has value out of enum"); + + SocketHandle handle = socket(TranslateNetProtocolToAF(protocol), TranslateSocketTypeToSock(type), 0); + if (handle == InvalidHandle && error != nullptr) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return handle; + } + + void SocketImpl::Close(SocketHandle handle) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + + if (close(handle) == SOCKET_ERROR) + NazaraWarning("Failed to close socket: " + Error::GetLastSystemError(GetLastErrorCode())); + } + + void SocketImpl::ClearErrorCode(SocketHandle handle) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + + if (GetLastError(handle, nullptr) < 0) + NazaraWarning("Failed to clear socket error code: " + Error::GetLastSystemError(GetLastErrorCode())); + } + + SocketState SocketImpl::Connect(SocketHandle handle, const IpAddress& address, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + NazaraAssert(address.IsValid(), "Invalid address"); + + IpAddressImpl::SockAddrBuffer nameBuffer; + int bufferLength = IpAddressImpl::ToSockAddr(address, nameBuffer.data()); + + if (error) + *error = SocketError_NoError; + + // Clear socket error status + ClearErrorCode(handle); + + if (connect(handle, reinterpret_cast(nameBuffer.data()), bufferLength) == SOCKET_ERROR) + { + int errorCode = GetLastErrorCode(); + switch (errorCode) //< Check for "normal errors" first + { + case EALREADY: + case EINPROGRESS: + return SocketState_Connecting; + + case EISCONN: + return SocketState_Connected; + } + + if (error) + { + if (errorCode == EADDRNOTAVAIL) + *error = SocketError_ConnectionRefused; //< ConnectionRefused seems more legit than AddressNotAvailable in connect case + else + *error = TranslateErrnoToResolveError(errorCode); + } + + return SocketState_NotConnected; + } + + return SocketState_Connected; + } + + SocketState SocketImpl::Connect(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error) + { + SocketState state = Connect(handle, address, error); + if (state == SocketState_Connecting) + { + // http://developerweb.net/viewtopic.php?id=3196 + fd_set localSet; + FD_ZERO(&localSet); + FD_SET(handle, &localSet); + + timeval tv; + tv.tv_sec = static_cast(msTimeout / 1000ULL); + tv.tv_usec = static_cast((msTimeout % 1000ULL) * 1000ULL); + + int ret = select(0, nullptr, &localSet, &localSet, (msTimeout > 0) ? &tv : nullptr); + if (ret == SOCKET_ERROR) + { + int code = GetLastErrorCode(handle, error); + if (code < 0) //< GetLastErrorCode() failed + return SocketState_NotConnected; + + if (code) + { + if (error) + *error = TranslateErrnoToResolveError(code); + + return SocketState_NotConnected; + } + } + else if (ret == 0) + { + if (error) + *error = SocketError_TimedOut; + + return SocketState_NotConnected; + } + else + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return SocketState_NotConnected; + } + + if (error) + *error = SocketError_NoError; + + state = SocketState_Connected; + } + + return state; + } + + bool SocketImpl::Initialize() + { + return true; + } + + SocketError SocketImpl::GetLastError(SocketHandle handle, SocketError* error) + { + int code = GetLastErrorCode(handle, error); + if (code < 0) + return SocketError_Internal; + + return TranslateErrnoToResolveError(code); + } + + int SocketImpl::GetLastErrorCode() + { + return errno; + } + + int SocketImpl::GetLastErrorCode(SocketHandle handle, SocketError* error) + { + int code; + unsigned int codeLength = sizeof(code); + + if (getsockopt(handle, SOL_SOCKET, SO_ERROR, &code, &codeLength) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return -1; + } + + if (error) + *error = SocketError_NoError; + + return code; + } + + SocketState SocketImpl::Listen(SocketHandle handle, const IpAddress& address, unsigned queueSize, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + NazaraAssert(address.IsValid(), "Invalid address"); + + IpAddressImpl::SockAddrBuffer nameBuffer; + int bufferLength = IpAddressImpl::ToSockAddr(address, nameBuffer.data()); + + if (bind(handle, reinterpret_cast(&nameBuffer), bufferLength) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return SocketState_NotConnected; + } + + if (listen(handle, queueSize) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return SocketState_NotConnected; + } + + if (error) + *error = SocketError_NoError; + + return SocketState_Bound; + } + + unsigned int SocketImpl::QueryAvailableBytes(SocketHandle handle, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + + u_long availableBytes; + if (ioctl(handle, FIONREAD, &availableBytes) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return 0; + } + + if (error) + *error = SocketError_NoError; + + return availableBytes; + } + + bool SocketImpl::QueryBroadcasting(SocketHandle handle, SocketError* error) + { + bool code; + unsigned int codeLength = sizeof(code); + + if (getsockopt(handle, SOL_SOCKET, SO_BROADCAST, &code, &codeLength) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return false; + } + + if (error) + *error = SocketError_NoError; + + return code; + } + + bool SocketImpl::QueryKeepAlive(SocketHandle handle, SocketError* error) + { + bool code; + unsigned int codeLength = sizeof(code); + + if (getsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &code, &codeLength) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return false; + } + + if (error) + *error = SocketError_NoError; + + return code; + } + + unsigned int SocketImpl::QueryMaxDatagramSize(SocketHandle handle, SocketError* error) + { + unsigned int code; + unsigned int codeLength = sizeof(code); + + if (getsockopt(handle, IPPROTO_IP, IP_MTU, &code, &codeLength) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return -1; + } + + if (error) + *error = SocketError_NoError; + + return code; + } + + bool SocketImpl::QueryNoDelay(SocketHandle handle, SocketError* error) + { + bool code; + unsigned int codeLength = sizeof(code); + + if (getsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &code, &codeLength) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return false; + } + + if (error) + *error = SocketError_NoError; + + return code; + } + + IpAddress SocketImpl::QueryPeerAddress(SocketHandle handle, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + + IpAddressImpl::SockAddrBuffer nameBuffer; + socklen_t bufferLength = sizeof(sockaddr_in); + + if (getpeername(handle, reinterpret_cast(nameBuffer.data()), &bufferLength) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return IpAddress(); + } + + if (error) + *error = SocketError_NoError; + + return IpAddressImpl::FromSockAddr(reinterpret_cast(nameBuffer.data())); + } + + IpAddress SocketImpl::QuerySocketAddress(SocketHandle handle, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + + IpAddressImpl::SockAddrBuffer nameBuffer; + socklen_t bufferLength = sizeof(sockaddr_in); + + if (getsockname(handle, reinterpret_cast(nameBuffer.data()), &bufferLength) == SOCKET_ERROR) + { + if (error) + { + int errorCode = GetLastErrorCode(); + if (errorCode == EINVAL) + *error = SocketError_NoError; + else + *error = TranslateErrnoToResolveError(errorCode); + } + + return IpAddress(); + } + + if (error) + *error = SocketError_NoError; + + return IpAddressImpl::FromSockAddr(reinterpret_cast(nameBuffer.data())); + } + + + bool SocketImpl::Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + NazaraAssert(buffer && length > 0, "Invalid buffer"); + + int byteRead = recv(handle, reinterpret_cast(buffer), length, 0); + if (byteRead == SOCKET_ERROR) + { + int errorCode = GetLastErrorCode(); + switch (errorCode) + { + case EWOULDBLOCK: + { + // If we have no data and are not blocking, return true with 0 byte read + byteRead = 0; + break; + } + + default: + { + if (error) + *error = TranslateErrnoToResolveError(errorCode); + + return false; //< Error + } + } + } + else if (byteRead == 0) + { + if (error) + *error = SocketError_ConnectionClosed; + + return false; //< Connection has been closed + } + + if (read) + *read = byteRead; + + if (error) + *error = SocketError_NoError; + + return true; + } + + bool SocketImpl::ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + NazaraAssert(buffer && length > 0, "Invalid buffer"); + + IpAddressImpl::SockAddrBuffer nameBuffer; + socklen_t bufferLength = sizeof(sockaddr_in); + + IpAddress senderIp; + + int byteRead = recvfrom(handle, buffer, length, 0, reinterpret_cast(&nameBuffer), &bufferLength); + if (byteRead == SOCKET_ERROR) + { + int errorCode = GetLastErrorCode(); + switch (errorCode) + { + case EWOULDBLOCK: + { + // If we have no data and are not blocking, return true with 0 byte read + byteRead = 0; + senderIp = IpAddress::Invalid; + break; + } + + default: + { + if (error) + *error = TranslateErrnoToResolveError(errorCode); + + return false; //< Error + } + } + } + else if (byteRead == 0) + { + if (error) + *error = SocketError_ConnectionClosed; + + return false; //< Connection closed + } + else // else we received something + senderIp = IpAddressImpl::FromSockAddr(reinterpret_cast(&nameBuffer)); + + if (from) + *from = senderIp; + + if (read) + *read = byteRead; + + if (error) + *error = SocketError_NoError; + + return true; + } + + bool SocketImpl::Send(SocketHandle handle, const void* buffer, int length, int* sent, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + NazaraAssert(buffer && length > 0, "Invalid buffer"); + + int byteSent = send(handle, reinterpret_cast(buffer), length, 0); + if (byteSent == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return false; //< Error + } + + if (sent) + *sent = byteSent; + + if (error) + *error = SocketError_NoError; + + return true; + } + + bool SocketImpl::SendTo(SocketHandle handle, const void* buffer, int length, const IpAddress& to, int* sent, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + NazaraAssert(buffer && length > 0, "Invalid buffer"); + + IpAddressImpl::SockAddrBuffer nameBuffer; + int bufferLength = IpAddressImpl::ToSockAddr(to, nameBuffer.data()); + + int byteSent = sendto(handle, reinterpret_cast(buffer), length, 0, reinterpret_cast(nameBuffer.data()), bufferLength); + if (byteSent == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return false; //< Error + } + + if (sent) + *sent = byteSent; + + if (error) + *error = SocketError_NoError; + + return true; + } + + bool SocketImpl::SetBlocking(SocketHandle handle, bool blocking, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + + u_long block = (blocking) ? 0 : 1; + if (ioctl(handle, FIONBIO, &block) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return false; //< Error + } + + if (error) + *error = SocketError_NoError; + + return true; + } + + bool SocketImpl::SetBroadcasting(SocketHandle handle, bool broadcasting, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + + bool option = broadcasting; + if (setsockopt(handle, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&option), sizeof(option)) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return false; //< Error + } + + if (error) + *error = SocketError_NoError; + + return true; + } + + bool SocketImpl::SetKeepAlive(SocketHandle handle, bool enabled, UInt64 msTime, UInt64 msInterval, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + + int keepAlive = enabled ? 1 : 0; + int keepIdle = msTime / 1000; // Linux works with seconds. + int keepInterval = msInterval / 1000; // Linux works with seconds. + + if (setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &keepAlive , sizeof(keepAlive)) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return false; //< Error + } + + if (setsockopt(handle, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(keepIdle)) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return false; //< Error + } + + if (setsockopt(handle, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(keepInterval)) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return false; //< Error + } + + if (error) + *error = SocketError_NoError; + + return true; + } + + bool SocketImpl::SetNoDelay(SocketHandle handle, bool nodelay, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + + int option = nodelay ? 1 : 0; + if (setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option)) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return false; //< Error + } + + if (error) + *error = SocketError_NoError; + + return true; + } + + SocketError SocketImpl::TranslateErrnoToResolveError(int error) + { + switch (error) + { + case 0: + return SocketError_NoError; + + // Engine error + case EACCES: + case EBADF: + case EINVAL: + case EFAULT: + case ENOTSOCK: + case EPROTOTYPE: + return SocketError_Internal; + + case EADDRNOTAVAIL: + case EADDRINUSE: + return SocketError_AddressNotAvailable; + + case EAFNOSUPPORT: + case EPFNOSUPPORT: + case EOPNOTSUPP: + case EPROTONOSUPPORT: + case ESOCKTNOSUPPORT: + return SocketError_NotSupported; + + // Those are not errors and should have been handled before the call + case EALREADY: + case EISCONN: + case EWOULDBLOCK: + return SocketError_Internal; + + case ECONNREFUSED: + return SocketError_ConnectionRefused; + + case EMSGSIZE: + return SocketError_DatagramSize; + + case EMFILE: + case ENOBUFS: + case ENOMEM: + return SocketError_ResourceError; + + case ENOTCONN: + case ESHUTDOWN: + return SocketError_ConnectionClosed; + + case EHOSTUNREACH: + return SocketError_UnreachableHost; + + case ENETDOWN: + case ENETUNREACH: + return SocketError_NetworkError; + + case ENODATA: + return SocketError_NotInitialized; + + case ETIMEDOUT: + return SocketError_TimedOut; + } + + NazaraWarning("Unhandled POSIX error: " + Error::GetLastSystemError(error) + " (" + String::Number(error) + ')'); + return SocketError_Unknown; + } + + int SocketImpl::TranslateNetProtocolToAF(NetProtocol protocol) + { + NazaraAssert(protocol <= NetProtocol_Max, "Protocol has value out of enum"); + + static int addressFamily[] = { + AF_UNSPEC, //< NetProtocol_Any + AF_INET, //< NetProtocol_IPv4 + AF_INET6, //< NetProtocol_IPv6 + -1 //< NetProtocol_Unknown + }; + static_assert(sizeof(addressFamily) / sizeof(int) == NetProtocol_Max + 1, "Address family array is incomplete"); + + return addressFamily[protocol]; + } + + int SocketImpl::TranslateSocketTypeToSock(SocketType type) + { + NazaraAssert(type <= SocketType_Max, "Socket type has value out of enum"); + + static int socketType[] = { + SOCK_RAW, //< SocketType_Raw + SOCK_STREAM, //< SocketType_TCP + SOCK_DGRAM, //< SocketType_UDP + -1 //< SocketType_Unknown + }; + static_assert(sizeof(socketType) / sizeof(int) == SocketType_Max + 1, "Socket type array is incomplete"); + + return socketType[type]; + } + + void SocketImpl::Uninitialize() + { + } + + SocketHandle SocketImpl::InvalidHandle = -1; + SocketImpl::socketID SocketImpl::s_socket; +} diff --git a/src/Nazara/Network/Posix/SocketImpl.hpp b/src/Nazara/Network/Posix/SocketImpl.hpp new file mode 100644 index 000000000..c23b4d3e4 --- /dev/null +++ b/src/Nazara/Network/Posix/SocketImpl.hpp @@ -0,0 +1,68 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + class SocketImpl + { + public: + SocketImpl() = delete; + ~SocketImpl() = delete; + + static SocketHandle Accept(SocketHandle handle, IpAddress* address, SocketError* error); + + static SocketState Bind(SocketHandle handle, const IpAddress& address, SocketError* error); + + static SocketHandle Create(NetProtocol protocol, SocketType type, SocketError* error); + + static void ClearErrorCode(SocketHandle handle); + static void Close(SocketHandle handle); + + static SocketState Connect(SocketHandle handle, const IpAddress& address, SocketError* error); + static SocketState Connect(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error); + + static bool Initialize(); + + static SocketError GetLastError(SocketHandle handle, SocketError* error = nullptr); + static int GetLastErrorCode(); + static int GetLastErrorCode(SocketHandle handle, SocketError* error = nullptr); + + static SocketState Listen(SocketHandle handle, const IpAddress& address, unsigned queueSize, SocketError* error); + + static unsigned int QueryAvailableBytes(SocketHandle handle, SocketError* error = nullptr); + static bool QueryBroadcasting(SocketHandle handle, SocketError* error = nullptr); + static bool QueryKeepAlive(SocketHandle handle, SocketError* error = nullptr); + static unsigned int QueryMaxDatagramSize(SocketHandle handle, SocketError* error = nullptr); + static bool QueryNoDelay(SocketHandle handle, SocketError* error = nullptr); + static IpAddress QueryPeerAddress(SocketHandle handle, SocketError* error = nullptr); + static IpAddress QuerySocketAddress(SocketHandle handle, SocketError* error = nullptr); + + static bool Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error); + static bool ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error); + + static bool Send(SocketHandle handle, const void* buffer, int length, int* sent, SocketError* error); + static bool SendTo(SocketHandle handle, const void* buffer, int length, const IpAddress& to, int* sent, SocketError* error); + + static bool SetBlocking(SocketHandle handle, bool blocking, SocketError* error = nullptr); + static bool SetBroadcasting(SocketHandle handle, bool broadcasting, SocketError* error = nullptr); + static bool SetKeepAlive(SocketHandle handle, bool enabled, UInt64 msTime, UInt64 msInterval, SocketError* error = nullptr); + static bool SetNoDelay(SocketHandle handle, bool nodelay, SocketError* error = nullptr); + + static SocketError TranslateErrnoToResolveError(int error); + static int TranslateNetProtocolToAF(NetProtocol protocol); + static int TranslateSocketTypeToSock(SocketType type); + + static void Uninitialize(); + + static SocketHandle InvalidHandle; + + private: + using socketID = int; + static socketID s_socket; + }; +} diff --git a/src/Nazara/Network/TcpClient.cpp b/src/Nazara/Network/TcpClient.cpp index b91dfaffd..6bb26aef8 100644 --- a/src/Nazara/Network/TcpClient.cpp +++ b/src/Nazara/Network/TcpClient.cpp @@ -10,6 +10,8 @@ #if defined(NAZARA_PLATFORM_WINDOWS) #include +#elif defined(NAZARA_PLATFORM_POSIX) +#include #else #error Missing implementation: Socket #endif diff --git a/src/Nazara/Network/TcpServer.cpp b/src/Nazara/Network/TcpServer.cpp index 096603b8f..b5995b6f5 100644 --- a/src/Nazara/Network/TcpServer.cpp +++ b/src/Nazara/Network/TcpServer.cpp @@ -11,6 +11,8 @@ #if defined(NAZARA_PLATFORM_WINDOWS) #include +#elif defined(NAZARA_PLATFORM_POSIX) +#include #else #error Missing implementation: Socket #endif @@ -60,4 +62,4 @@ namespace Nz m_boundAddress = IpAddress::Invalid; } -} \ No newline at end of file +} diff --git a/src/Nazara/Network/UdpSocket.cpp b/src/Nazara/Network/UdpSocket.cpp index fb813b3d6..0ecd423bb 100644 --- a/src/Nazara/Network/UdpSocket.cpp +++ b/src/Nazara/Network/UdpSocket.cpp @@ -7,6 +7,8 @@ #if defined(NAZARA_PLATFORM_WINDOWS) #include +#elif defined(NAZARA_PLATFORM_POSIX) +#include #else #error Missing implementation: Socket #endif diff --git a/src/Nazara/Utility/X11/Display.cpp b/src/Nazara/Utility/X11/Display.cpp index d61543dfd..2ec41ff0d 100644 --- a/src/Nazara/Utility/X11/Display.cpp +++ b/src/Nazara/Utility/X11/Display.cpp @@ -136,7 +136,7 @@ namespace Nz OpenEWMHConnection(sharedConnection); } - NazaraNotice("Initialized: Utility module"); + NazaraNotice("Initialized: Display module"); return true; } diff --git a/src/Nazara/Utility/X11/Display.hpp b/src/Nazara/Utility/X11/Display.hpp index 95177e2d2..88f80f2ee 100644 --- a/src/Nazara/Utility/X11/Display.hpp +++ b/src/Nazara/Utility/X11/Display.hpp @@ -17,7 +17,7 @@ namespace Nz { class String; - class X11 + class NAZARA_UTILITY_API X11 { public: X11() = delete; diff --git a/tests/Engine/Math/Algorithm.cpp b/tests/Engine/Math/Algorithm.cpp index 38080c576..c42b90d11 100644 --- a/tests/Engine/Math/Algorithm.cpp +++ b/tests/Engine/Math/Algorithm.cpp @@ -1,7 +1,7 @@ #include #include -TEST_CASE("Approach", "[MATH][ALGORITHM]" ) +TEST_CASE("Approach", "[MATH][ALGORITHM]") { SECTION("Approach 8 with 5 by 2") { @@ -19,7 +19,7 @@ TEST_CASE("Approach", "[MATH][ALGORITHM]" ) } } -TEST_CASE("Clamp", "[ALGORITHM]" ) +TEST_CASE("Clamp", "[ALGORITHM]") { SECTION("Clamp 8 between 5 and 10") { @@ -37,7 +37,20 @@ TEST_CASE("Clamp", "[ALGORITHM]" ) } } -TEST_CASE("DegreeToRadian", "[ALGORITHM]" ) +TEST_CASE("CountBits", "[ALGORITHM]") +{ + SECTION("Number 10 has 2 bits set to 1") + { + REQUIRE(Nz::CountBits(10) == 2); + } + + SECTION("Number 0 has 0 bit set to 1") + { + REQUIRE(Nz::CountBits(0) == 0); + } +} + +TEST_CASE("DegreeToRadian", "[ALGORITHM]") { SECTION("Convert 45.f degree to radian") { @@ -45,8 +58,13 @@ TEST_CASE("DegreeToRadian", "[ALGORITHM]" ) } } -TEST_CASE("GetNearestPowerOfTwo", "[ALGORITHM]" ) +TEST_CASE("GetNearestPowerOfTwo", "[ALGORITHM]") { + SECTION("Nearest power of two of 0 = 1") + { + REQUIRE(Nz::GetNearestPowerOfTwo(0) == 1); + } + SECTION("Nearest power of two of 16 = 16") { REQUIRE(Nz::GetNearestPowerOfTwo(16) == 16); @@ -58,7 +76,7 @@ TEST_CASE("GetNearestPowerOfTwo", "[ALGORITHM]" ) } } -TEST_CASE("GetNumberLength", "[ALGORITHM]" ) +TEST_CASE("GetNumberLength", "[ALGORITHM]") { SECTION("GetNumberLength of -127 signed char") { @@ -115,7 +133,48 @@ TEST_CASE("GetNumberLength", "[ALGORITHM]" ) } } -TEST_CASE("IntegralPow", "[ALGORITHM]" ) +TEST_CASE("IntegralLog2", "[ALGORITHM]") +{ + SECTION("According to implementation, log in base 2 of 0 = 0") + { + REQUIRE(Nz::IntegralLog2(0) == 0); + } + + SECTION("Log in base 2 of 1 = 0") + { + REQUIRE(Nz::IntegralLog2(1) == 0); + } + + SECTION("Log in base 2 of 4 = 2") + { + REQUIRE(Nz::IntegralLog2(4) == 2); + } + + SECTION("Log in base 2 of 5 = 2") + { + REQUIRE(Nz::IntegralLog2(5) == 2); + } +} + +TEST_CASE("IntegralLog2Pot", "[ALGORITHM]") +{ + SECTION("According to implementation, log in base 2 of 0 = 0") + { + REQUIRE(Nz::IntegralLog2Pot(0) == 0); + } + + SECTION("Log in base 2 of 1 = 0") + { + REQUIRE(Nz::IntegralLog2Pot(1) == 0); + } + + SECTION("Log in base 2 of 4 = 2") + { + REQUIRE(Nz::IntegralLog2Pot(4) == 2); + } +} + +TEST_CASE("IntegralPow", "[ALGORITHM]") { SECTION("2 to power 4") { @@ -123,7 +182,7 @@ TEST_CASE("IntegralPow", "[ALGORITHM]" ) } } -TEST_CASE("Lerp", "[ALGORITHM]" ) +TEST_CASE("Lerp", "[ALGORITHM]") { SECTION("Lerp 2 to 6 with 0.5") { @@ -131,7 +190,7 @@ TEST_CASE("Lerp", "[ALGORITHM]" ) } } -TEST_CASE("MultiplyAdd", "[ALGORITHM]" ) +TEST_CASE("MultiplyAdd", "[ALGORITHM]") { SECTION("2 * 3 + 1") { @@ -139,7 +198,7 @@ TEST_CASE("MultiplyAdd", "[ALGORITHM]" ) } } -TEST_CASE("NumberEquals", "[ALGORITHM]" ) +TEST_CASE("NumberEquals", "[ALGORITHM]") { SECTION("2.35 and 2.351 should be the same at 0.01") { @@ -152,7 +211,7 @@ TEST_CASE("NumberEquals", "[ALGORITHM]" ) } } -TEST_CASE("NumberToString", "[ALGORITHM]" ) +TEST_CASE("NumberToString", "[ALGORITHM]") { SECTION("235 to string") { @@ -170,7 +229,7 @@ TEST_CASE("NumberToString", "[ALGORITHM]" ) } } -TEST_CASE("RadianToDegree", "[ALGORITHM]" ) +TEST_CASE("RadianToDegree", "[ALGORITHM]") { SECTION("PI / 4 to degree") { @@ -178,7 +237,7 @@ TEST_CASE("RadianToDegree", "[ALGORITHM]" ) } } -TEST_CASE("StringToNumber", "[ALGORITHM]" ) +TEST_CASE("StringToNumber", "[ALGORITHM]") { SECTION("235 in string") { diff --git a/tests/Engine/Math/BoundingVolume.cpp b/tests/Engine/Math/BoundingVolume.cpp index 05af375bc..9fd552863 100644 --- a/tests/Engine/Math/BoundingVolume.cpp +++ b/tests/Engine/Math/BoundingVolume.cpp @@ -99,5 +99,20 @@ SCENARIO("BoundingVolume", "[MATH][BOUNDINGVOLUME]") REQUIRE(firstCenterAndUnit.aabb != secondCenterAndUnit.aabb); } } + + WHEN("We try to lerp") + { + THEN("Compilation should be fine") + { + Nz::BoundingVolumef nullBoundingVolume = Nz::BoundingVolumef(Nz::Vector3f::Zero(), Nz::Vector3f::Zero()); + Nz::BoundingVolumef centerAndUnit = firstCenterAndUnit; + nullBoundingVolume.Update(Nz::Matrix4f::Identity()); + centerAndUnit.Update(Nz::Matrix4f::Identity()); + Nz::BoundingVolumef result(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 0.5f); + result.Update(Nz::Matrix4f::Identity()); + + REQUIRE(Nz::BoundingVolumef::Lerp(nullBoundingVolume, centerAndUnit, 0.5f) == result); + } + } } } diff --git a/tests/Engine/Math/Box.cpp b/tests/Engine/Math/Box.cpp index e39e0654c..7d9b42a51 100644 --- a/tests/Engine/Math/Box.cpp +++ b/tests/Engine/Math/Box.cpp @@ -64,6 +64,18 @@ SCENARIO("Box", "[MATH][BOX]") REQUIRE(tmp == firstCenterAndUnit); } } + + WHEN("We try to lerp") + { + THEN("Compilation should be fine") + { + Nz::Boxf nullBox = Nz::Boxf::Zero(); + Nz::Boxf centerAndUnit = firstCenterAndUnit; + Nz::Boxf result(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 0.5f); + + REQUIRE(Nz::Boxf::Lerp(nullBox, centerAndUnit, 0.5f) == result); + } + } } GIVEN("Two wrong box (negative width, height and depth") diff --git a/tests/Engine/Math/EulerAngles.cpp b/tests/Engine/Math/EulerAngles.cpp index a44efb361..6a6f7f77e 100644 --- a/tests/Engine/Math/EulerAngles.cpp +++ b/tests/Engine/Math/EulerAngles.cpp @@ -15,8 +15,8 @@ SCENARIO("EulerAngles", "[MATH][EULERANGLES]") WHEN("We do some operations") { - Nz::EulerAnglesf euler90(90.f, 90.f, 90.f); - Nz::EulerAnglesf euler270(270.f, 270.f, 270.f); + Nz::EulerAnglesf euler90(Nz::FromDegrees(90.f), Nz::FromDegrees(90.f), Nz::FromDegrees(90.f)); + Nz::EulerAnglesf euler270(Nz::FromDegrees(270.f), Nz::FromDegrees(270.f), Nz::FromDegrees(270.f)); Nz::EulerAnglesf euler360 = euler90 + euler270; euler360.Normalize(); @@ -42,6 +42,27 @@ SCENARIO("EulerAngles", "[MATH][EULERANGLES]") } } + GIVEN("Three rotation of 90 on each axis") + { + Nz::EulerAnglesf euler90P(Nz::FromDegrees(90.f), 0.f, 0.f); + Nz::EulerAnglesf euler90Y(0.f, Nz::FromDegrees(90.f), 0.f); + Nz::EulerAnglesf euler90R(0.f, 0.f, Nz::FromDegrees(90.f)); + + WHEN("We transform the axis") + { + THEN("This is supposed to be left-handed") + { + Nz::Vector3f rotation90P = euler90P.ToQuaternion() * Nz::Vector3f::UnitY(); + Nz::Vector3f rotation90Y = euler90Y.ToQuaternion() * Nz::Vector3f::UnitZ(); + Nz::Vector3f rotation90R = euler90R.ToQuaternion() * Nz::Vector3f::UnitX(); + + REQUIRE(rotation90P == Nz::Vector3f::UnitZ()); + REQUIRE(rotation90Y == Nz::Vector3f::UnitX()); + REQUIRE(rotation90R == Nz::Vector3f::UnitY()); + } + } + } + GIVEN("Euler angles with rotation 45 on each axis") { WHEN("We convert to quaternion") diff --git a/tests/Engine/Math/Frustum.cpp b/tests/Engine/Math/Frustum.cpp index 98715940d..d9fedebdd 100644 --- a/tests/Engine/Math/Frustum.cpp +++ b/tests/Engine/Math/Frustum.cpp @@ -78,5 +78,18 @@ SCENARIO("Frustum", "[MATH][FRUSTUM]") CHECK(frustum.Contains(&tmp, 1)); } } + + WHEN("We test for edge cases") + { + THEN("Implementation defined these") + { + Nz::BoundingVolumef nullVolume = Nz::BoundingVolumef::Null(); + CHECK(!frustum.Contains(nullVolume)); + Nz::BoundingVolumef infiniteVolume = Nz::BoundingVolumef::Infinite(); + CHECK(frustum.Contains(infiniteVolume)); + REQUIRE(frustum.Intersect(nullVolume) == Nz::IntersectionSide_Outside); + REQUIRE(frustum.Intersect(infiniteVolume) == Nz::IntersectionSide_Intersecting); + } + } } } diff --git a/tests/Engine/Math/Matrix4.cpp b/tests/Engine/Math/Matrix4.cpp index 24a56658b..eec10aacd 100644 --- a/tests/Engine/Math/Matrix4.cpp +++ b/tests/Engine/Math/Matrix4.cpp @@ -37,19 +37,29 @@ SCENARIO("Matrix4", "[MATH][Matrix4]") REQUIRE(firstIdentity.Inverse() == secondIdentity.InverseAffine()); } } + + WHEN("We transpose one of this matrix") + { + THEN("Identity transposed is the same than identity") + { + Nz::Matrix4f transposedIdentity; + firstIdentity.GetTransposed(&transposedIdentity); + REQUIRE(firstIdentity == transposedIdentity); + } + } } GIVEN("Two different matrix") { Nz::Matrix4f matrix1(1.0f, 0.0f, 0.0f, 0.0f, - 7.0f, 2.0f, 0.0f, 0.0f, - 1.0f, 5.0f, 3.0f, 0.0f, - 8.0f, 9.0f, 2.0f, 4.0f); + 7.0f, 2.0f, 0.0f, 0.0f, + 1.0f, 5.0f, 3.0f, 0.0f, + 8.0f, 9.0f, 2.0f, 4.0f); Nz::Matrix4f matrix2(1.0f, 1.0f, 2.0f, -1.0f, - -2.0f, -1.0f, -2.0f, 2.0f, - 4.0f, 2.0f, 5.0f, -4.0f, - 5.0f, -3.0f, -7.0f, -6.0f); + -2.0f, -1.0f, -2.0f, 2.0f, + 4.0f, 2.0f, 5.0f, -4.0f, + 5.0f, -3.0f, -7.0f, -6.0f); WHEN("We ask for determinant") { @@ -92,9 +102,9 @@ SCENARIO("Matrix4", "[MATH][Matrix4]") { transformedMatrix.MakeTransform(Nz::Vector3f::Zero(), Nz::EulerAnglesf(Nz::FromDegrees(45.f), 0.f, 0.f).ToQuaternion()); Nz::Matrix4f rotation45X(1.f, 0.f, 0.f, 0.f, - 0.f, std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, - 0.f, -std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, - 0.f, 0.f, 0.f, 1.f); + 0.f, std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, + 0.f, -std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, + 0.f, 0.f, 0.f, 1.f); REQUIRE(transformedMatrix == rotation45X); transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(Nz::FromDegrees(45.f), 0.f, 0.f).ToQuaternion()); @@ -106,9 +116,9 @@ SCENARIO("Matrix4", "[MATH][Matrix4]") { transformedMatrix.MakeTransform(Nz::Vector3f::Zero(), Nz::EulerAnglesf(0.f, Nz::FromDegrees(45.f), 0.f).ToQuaternion()); Nz::Matrix4f rotation45Y(std::sqrt(2.f) / 2.f, 0.f, -std::sqrt(2.f) / 2.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - std::sqrt(2.f) / 2.f, 0.f, std::sqrt(2.f) / 2.f, 0.f, - 0.f, 0.f, 0.f, 1.f); + 0.f, 1.f, 0.f, 0.f, + std::sqrt(2.f) / 2.f, 0.f, std::sqrt(2.f) / 2.f, 0.f, + 0.f, 0.f, 0.f, 1.f); REQUIRE(transformedMatrix == rotation45Y); transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(0.f, Nz::FromDegrees(45.f), 0.f).ToQuaternion()); @@ -120,9 +130,9 @@ SCENARIO("Matrix4", "[MATH][Matrix4]") { transformedMatrix.MakeTransform(Nz::Vector3f::Zero(), Nz::EulerAnglesf(0.f, 0.f, Nz::FromDegrees(45.f)).ToQuaternion()); Nz::Matrix4f rotation45Z( std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, 0.f, - -std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f); + -std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f); REQUIRE(transformedMatrix == rotation45Z); transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(Nz::EulerAnglesf(0.f, 0.f, Nz::FromDegrees(45.f)).ToQuaternion())); diff --git a/tests/Engine/Math/OrientedBox.cpp b/tests/Engine/Math/OrientedBox.cpp index bd11f58ef..7a1035ee2 100644 --- a/tests/Engine/Math/OrientedBox.cpp +++ b/tests/Engine/Math/OrientedBox.cpp @@ -43,5 +43,20 @@ SCENARIO("OrientedBox", "[MATH][ORIENTEDBOX]") } } } + + WHEN("We try to lerp") + { + THEN("Compilation should be fine") + { + Nz::OrientedBoxf nullOrientedBox = Nz::OrientedBoxf::Zero(); + Nz::OrientedBoxf centerAndUnit = firstCenterAndUnit; + nullOrientedBox.Update(Nz::Matrix4f::Identity()); + centerAndUnit.Update(Nz::Matrix4f::Identity()); + Nz::OrientedBoxf result(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 0.5f); + result.Update(Nz::Matrix4f::Identity()); + + REQUIRE(Nz::OrientedBoxf::Lerp(nullOrientedBox, centerAndUnit, 0.5f) == result); + } + } } } diff --git a/tests/Engine/Math/Plane.cpp b/tests/Engine/Math/Plane.cpp index 1cab6f385..44377bf67 100644 --- a/tests/Engine/Math/Plane.cpp +++ b/tests/Engine/Math/Plane.cpp @@ -49,6 +49,18 @@ SCENARIO("Plane", "[MATH][PLANE]") REQUIRE(Nz::Planef(-Nz::Vector3f::UnitY(), -1000.f).Distance(Nz::Vector3f::UnitY() * 1500.f) == Approx(-500.f)); } } + + WHEN("We try to lerp") + { + THEN("Compilation should be fine") + { + Nz::Planef planeXY = Nz::Planef::XY(); + Nz::Planef planeXZ = Nz::Planef::XZ(); + Nz::Vector3f result = Nz::Vector3f(0.f, 1.f, 1.f) * 0.5f; + result.Normalize(); + REQUIRE(Nz::Planef::Lerp(planeXY, planeXZ, 0.5f) == Nz::Planef(result, 0.f)); + } + } } GIVEN("The plane XZ, distance 1 with 3 points (0, 1, 0), (1, 1, 1), (-1, 1, 0)") diff --git a/tests/Engine/Math/Quaternion.cpp b/tests/Engine/Math/Quaternion.cpp index 65ab201bf..7ebf6ede5 100644 --- a/tests/Engine/Math/Quaternion.cpp +++ b/tests/Engine/Math/Quaternion.cpp @@ -32,6 +32,22 @@ SCENARIO("Quaternion", "[MATH][QUATERNION]") REQUIRE((firstQuaternion * Nz::Vector3f::UnitZ()) == -Nz::Vector3f::UnitZ()); } } + + WHEN("We invert or normalize Zero quaternion") + { + Nz::Quaternionf zero = Nz::Quaternionf::Zero(); + + THEN("It's meant not to be changed") + { + Nz::Quaternionf inverted = zero.GetInverse(); + float tmp = -1.f; + Nz::Quaternionf normalized = zero.GetNormal(&tmp); + + REQUIRE(inverted == zero); + REQUIRE(normalized == zero); + REQUIRE(tmp == Approx(0.f)); + } + } } GIVEN("The four unit quaternions") @@ -154,5 +170,18 @@ SCENARIO("Quaternion", "[MATH][QUATERNION]") REQUIRE(quaternionC.z == Approx(unitZ225.z)); } } + + WHEN("We get the rotation between two vectors") + { + /*TODO + * Nz::Quaternionf rotationBetweenXY = Nz::Quaternionf::RotationBetween(Nz::Vector3f::UnitX(), Nz::Vector3f::UnitY()); + + THEN("The rotation in left-handed is 270 degree on z") + { + Nz::Quaternionf rotation270Z(Nz::FromDegrees(270.f), Nz::Vector3f::UnitZ()); + Nz::Quaternionf rotation90Z(Nz::FromDegrees(90.f), Nz::Vector3f::UnitZ()); + REQUIRE(rotation90Z == rotationBetweenXY); + }*/ + } } } diff --git a/tests/Engine/Math/Ray.cpp b/tests/Engine/Math/Ray.cpp index df77a34ac..286a358c2 100644 --- a/tests/Engine/Math/Ray.cpp +++ b/tests/Engine/Math/Ray.cpp @@ -86,10 +86,37 @@ SCENARIO("Ray", "[MATH][RAY]") Nz::BoundingVolumef nullVolume(Nz::Extend_Null); CHECK(!ray.Intersect(nullVolume)); + float tmpClosest = -1.f; + float tmpFurthest = -1.f; Nz::BoundingVolumef infiniteVolume(Nz::Extend_Infinite); - CHECK(ray.Intersect(infiniteVolume)); + CHECK(ray.Intersect(infiniteVolume, &tmpClosest, &tmpFurthest)); + CHECK(tmpClosest == Approx(0.f)); + CHECK(tmpFurthest == std::numeric_limits::infinity()); } + THEN("For the triangle collision's") + { + Nz::Vector3f firstPoint(0.f, 1.f, 1.f); + Nz::Vector3f secondPoint(-1.f, 1.f, -1.f); + Nz::Vector3f thidPoint(1.f, 1.f, -1.f); + float tmpHit = -1.f; + + CHECK(ray.Intersect(firstPoint, secondPoint, thidPoint, &tmpHit)); + REQUIRE(ray.GetPoint(tmpHit) == Nz::Vector3f::UnitY()); + + Nz::Vector3f offset = Nz::Vector3f(10.f, 0.f, 10.f); + CHECK(!ray.Intersect(firstPoint + offset, secondPoint + offset, thidPoint + offset, &tmpHit)); + } + } + + WHEN("We try to lerp") + { + THEN("Compilation should be fine") + { + Nz::Rayf AxisX = Nz::Rayf::AxisX(); + Nz::Rayf AxisY = Nz::Rayf::AxisY(); + REQUIRE(Nz::Rayf::Lerp(AxisX, AxisY, 0.5f) == (Nz::Rayf(Nz::Vector3f::Zero(), Nz::Vector3f(0.5f, 0.5f, 0.f)))); + } } } } diff --git a/tests/Engine/Math/Rect.cpp b/tests/Engine/Math/Rect.cpp index 7a1035f79..b119d76c9 100644 --- a/tests/Engine/Math/Rect.cpp +++ b/tests/Engine/Math/Rect.cpp @@ -52,5 +52,17 @@ SCENARIO("Rect", "[MATH][RECT]") } } + + WHEN("We try to lerp") + { + THEN("Compilation should be fine") + { + Nz::Rectf nullRect = Nz::Rectf::Zero(); + Nz::Rectf centerAndUnit = firstCenterAndUnit; + Nz::Rectf result(Nz::Vector2f::Zero(), Nz::Vector2f::Unit() * 0.5f); + + REQUIRE(Nz::Rectf::Lerp(nullRect, centerAndUnit, 0.5f) == result); + } + } } } diff --git a/tests/Engine/Math/Sphere.cpp b/tests/Engine/Math/Sphere.cpp index 0f0e509ca..1820acd35 100644 --- a/tests/Engine/Math/Sphere.cpp +++ b/tests/Engine/Math/Sphere.cpp @@ -59,5 +59,45 @@ SCENARIO("Sphere", "[MATH][SPHERE]") REQUIRE(centerUnitBox.GetSquaredBoundingSphere() == Nz::Spheref(Nz::Vector3f::Zero(), 0.75f)); } } + + WHEN("We ask for positive and negative vertex") + { + Nz::Vector3f positiveVector = Nz::Vector3f::UnitY(); + + THEN("Positive vertex should be the same with centered and unit sphere") + { + REQUIRE(positiveVector == firstCenterAndUnit.GetPositiveVertex(positiveVector)); + } + + AND_THEN("Negative vertex should be the opposite") + { + REQUIRE(-positiveVector == firstCenterAndUnit.GetNegativeVertex(positiveVector)); + } + } + + WHEN("We extend the unit sphere to one point") + { + Nz::Vector3f point = Nz::Vector3f::UnitY() * 2.f; + + firstCenterAndUnit.ExtendTo(point); + + THEN("Sphere must contain it and distance should be good") + { + CHECK(firstCenterAndUnit.Contains(point)); + REQUIRE(firstCenterAndUnit.Distance(point) == 2.f); + } + } + + WHEN("We try to lerp") + { + THEN("Compilation should be fine") + { + Nz::Spheref nullRect = Nz::Spheref::Zero(); + Nz::Spheref centerAndUnit = firstCenterAndUnit; + Nz::Spheref result(Nz::Vector3f::Zero(), 0.5f); + + REQUIRE(Nz::Spheref::Lerp(nullRect, centerAndUnit, 0.5f) == result); + } + } } } diff --git a/tests/Engine/Math/Vector2.cpp b/tests/Engine/Math/Vector2.cpp index 17ae62e72..45ca1468c 100644 --- a/tests/Engine/Math/Vector2.cpp +++ b/tests/Engine/Math/Vector2.cpp @@ -15,6 +15,7 @@ SCENARIO("Vector2", "[MATH][VECTOR2]") THEN("They are the same") { REQUIRE(firstUnit == secondUnit); + REQUIRE(firstUnit <= secondUnit); } } @@ -22,11 +23,13 @@ SCENARIO("Vector2", "[MATH][VECTOR2]") { Nz::Vector2f tmp(-1.f, 1.f); - THEN("These results are expected") + THEN("These are perpendicular") { REQUIRE(firstUnit.AbsDotProduct(tmp) == Approx(2.f)); REQUIRE(firstUnit.DotProduct(tmp) == Approx(0.f)); - REQUIRE(firstUnit.AngleBetween(tmp) == Approx(90.f)); + REQUIRE(firstUnit.AngleBetween(tmp) == Approx(Nz::FromDegrees(90.f))); + Nz::Vector2f negativeUnitX = -Nz::Vector2f::UnitX(); + REQUIRE(negativeUnitX.AngleBetween(negativeUnitX + Nz::Vector2f(0, 0.0000001f)) == Approx(Nz::FromDegrees(360.f))); } } @@ -45,5 +48,49 @@ SCENARIO("Vector2", "[MATH][VECTOR2]") REQUIRE(firstUnit.GetLength() == Approx(std::sqrt(2.f))); } } + + WHEN("We nomalize the vectors") + { + float ratio = 0.f; + THEN("For normal cases should be normal") + { + Nz::Vector2f normalized = firstUnit.GetNormal(&ratio); + REQUIRE(normalized == (Nz::Vector2f::Unit() / std::sqrt(2.f))); + REQUIRE(ratio == Approx(std::sqrt(2.f))); + } + + THEN("For null vector") + { + Nz::Vector2f zero = Nz::Vector2f::Zero(); + REQUIRE(zero.GetNormal(&ratio) == Nz::Vector2f::Zero()); + REQUIRE(ratio == Approx(0.f)); + } + } + + WHEN("We try to maximize and minimize") + { + Nz::Vector2f maximize(2.f, 1.f); + Nz::Vector2f minimize(1.f, 2.f); + + THEN("The minimised and maximised should be (1, 1) and (2, 2)") + { + Nz::Vector2f maximized = maximize; + Nz::Vector2f minimized = minimize; + REQUIRE(minimized.Minimize(maximized) == Nz::Vector2f::Unit()); + REQUIRE(maximize.Maximize(minimize) == (2.f * Nz::Vector2f::Unit())); + } + + } + + WHEN("We try to lerp") + { + THEN("Compilation should be fine") + { + Nz::Vector2f zero = Nz::Vector2f::Zero(); + Nz::Vector2f unit = Nz::Vector2f::Unit(); + REQUIRE(Nz::Vector2f::Lerp(zero, unit, 0.5f) == (Nz::Vector2f::Unit() * 0.5f)); + } + } + } } diff --git a/tests/Engine/Math/Vector3.cpp b/tests/Engine/Math/Vector3.cpp index a61016e82..84c6a01ae 100644 --- a/tests/Engine/Math/Vector3.cpp +++ b/tests/Engine/Math/Vector3.cpp @@ -26,7 +26,8 @@ SCENARIO("Vector3", "[MATH][VECTOR3]") { REQUIRE(firstUnit.AbsDotProduct(tmp) == Approx(2.f)); REQUIRE(firstUnit.DotProduct(tmp) == Approx(0.f)); - REQUIRE(firstUnit.AngleBetween(tmp) == Approx(90.f)); + REQUIRE(firstUnit.AngleBetween(tmp) == Approx(Nz::FromDegrees(90.f))); + REQUIRE(firstUnit.AngleBetween(-firstUnit) == Approx(Nz::FromDegrees(180.f))); } } @@ -52,5 +53,48 @@ SCENARIO("Vector3", "[MATH][VECTOR3]") REQUIRE(firstUnit.GetLength() == Approx(std::sqrt(3.f))); } } + + WHEN("We nomalize the vectors") + { + float ratio = 0.f; + THEN("For normal cases should be normal") + { + Nz::Vector3f normalized = firstUnit.GetNormal(&ratio); + REQUIRE(normalized == (Nz::Vector3f::Unit() / std::sqrt(3.f))); + REQUIRE(ratio == Approx(std::sqrt(3.f))); + } + + THEN("For null vector") + { + Nz::Vector3f zero = Nz::Vector3f::Zero(); + REQUIRE(zero.GetNormal(&ratio) == Nz::Vector3f::Zero()); + REQUIRE(ratio == Approx(0.f)); + } + } + + WHEN("We try to maximize and minimize") + { + Nz::Vector3f maximize(2.f, 1.f, 2.f); + Nz::Vector3f minimize(1.f, 2.f, 1.f); + + THEN("The minimised and maximised should be (1, 1, 1) and (2, 2, 2)") + { + Nz::Vector3f maximized = maximize; + Nz::Vector3f minimized = minimize; + REQUIRE(minimized.Minimize(maximized) == Nz::Vector3f::Unit()); + REQUIRE(maximize.Maximize(minimize) == (2.f * Nz::Vector3f::Unit())); + } + + } + + WHEN("We try to lerp") + { + THEN("Compilation should be fine") + { + Nz::Vector3f zero = Nz::Vector3f::Zero(); + Nz::Vector3f unit = Nz::Vector3f::Unit(); + REQUIRE(Nz::Vector3f::Lerp(zero, unit, 0.5f) == (Nz::Vector3f::Unit() * 0.5f)); + } + } } } diff --git a/tests/Engine/Math/Vector4.cpp b/tests/Engine/Math/Vector4.cpp index cfe91eab7..85c321ac1 100644 --- a/tests/Engine/Math/Vector4.cpp +++ b/tests/Engine/Math/Vector4.cpp @@ -39,5 +39,15 @@ SCENARIO("Vector4", "[MATH][VECTOR4]") REQUIRE(tmp.Normalize() == Nz::Vector4f(Nz::Vector3f::Unit() * (1.f / 3.f), 1.f)); } } + + WHEN("We try to lerp") + { + THEN("Compilation should be fine") + { + Nz::Vector4f zero = Nz::Vector4f::Zero(); + Nz::Vector4f unitX = Nz::Vector4f::UnitX(); + REQUIRE(Nz::Vector4f::Lerp(zero, unitX, 0.5f) == Nz::Vector4f(Nz::Vector3f::UnitX() * 0.5f, 1.f)); + } + } } }