Merge pull request #51 from Gawaboumga/Documentation-Update

Documentation update

Former-commit-id: f0921d7927aeb09f19523757ad2ef071140cd5b3
This commit is contained in:
Lynix 2015-12-31 11:53:09 +01:00
commit 0a9e6fcda3
73 changed files with 7541 additions and 632 deletions

View File

@ -20,6 +20,6 @@ namespace Ndk
template<typename SystemType, typename S> bool IsSystem(S& system); template<typename SystemType, typename S> bool IsSystem(S& system);
} }
#include <Ndk/Algorithm.inl> #include <NDK/Algorithm.inl>
#endif // NDK_ALGORITHM_HPP #endif // NDK_ALGORITHM_HPP

View File

@ -2,7 +2,7 @@
// This file is part of the "Nazara Development Kit" // This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp // For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <Ndk/Algorithm.hpp> #include <NDK/Algorithm.hpp>
#include <type_traits> #include <type_traits>
namespace Ndk namespace Ndk

View File

@ -33,20 +33,20 @@ namespace Ndk
inline void EnsureViewMatrixUpdate() const; inline void EnsureViewMatrixUpdate() const;
inline void EnsureViewportUpdate() const; inline void EnsureViewportUpdate() const;
inline float GetAspectRatio() const; inline float GetAspectRatio() const override;
inline Nz::Vector3f GetEyePosition() const; inline Nz::Vector3f GetEyePosition() const override;
inline Nz::Vector3f GetForward() const; inline Nz::Vector3f GetForward() const override;
inline float GetFOV() const; inline float GetFOV() const;
inline const Nz::Frustumf& GetFrustum() const; inline const Nz::Frustumf& GetFrustum() const override;
inline unsigned int GetLayer() const; inline unsigned int GetLayer() const;
inline const Nz::Matrix4f& GetProjectionMatrix() const; inline const Nz::Matrix4f& GetProjectionMatrix() const override;
inline Nz::ProjectionType GetProjectionType() const; 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::Rectf& GetTargetRegion() const;
inline const Nz::Matrix4f& GetViewMatrix() const; inline const Nz::Matrix4f& GetViewMatrix() const override;
inline const Nz::Recti& GetViewport() const; inline const Nz::Recti& GetViewport() const override;
inline float GetZFar() const; inline float GetZFar() const override;
inline float GetZNear() const; inline float GetZNear() const override;
inline void SetFOV(float fov); inline void SetFOV(float fov);
inline void SetLayer(unsigned int layer); inline void SetLayer(unsigned int layer);

View File

@ -2,7 +2,7 @@
// This file is part of the "Nazara Development Kit" // This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp // For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <Ndk/Algorithm.hpp> #include <NDK/Algorithm.hpp>
#include <type_traits> #include <type_traits>
namespace Ndk namespace Ndk

View File

@ -13,12 +13,13 @@
#include <Nazara/Core/Thread.hpp> // Thread::Sleep #include <Nazara/Core/Thread.hpp> // Thread::Sleep
#include <Nazara/Math/Vector3.hpp> #include <Nazara/Math/Vector3.hpp>
#include <Nazara/Utility/Keyboard.hpp> #include <Nazara/Utility/Keyboard.hpp>
#include <Nazara/Utility/Utility.hpp>
#include <iostream> #include <iostream>
int main() int main()
{ {
// NzKeyboard ne nécessite pas l'initialisation du module Utilitaire // NzKeyboard nécessite l'initialisation du module Utilitaire
Nz::Initializer<Nz::Audio> audio; Nz::Initializer<Nz::Audio, Nz::Utility> audio;
if (!audio) if (!audio)
{ {
std::cout << "Failed to initialize audio module" << std::endl; std::cout << "Failed to initialize audio module" << std::endl;

View File

@ -23,8 +23,8 @@ namespace Nz
void Begin() override; void Begin() override;
ByteArray End() override; ByteArray End() override;
std::size_t GetDigestLength() const; std::size_t GetDigestLength() const override;
const char* GetHashName() const; const char* GetHashName() const override;
private: private:
HashWhirlpool_state* m_state; HashWhirlpool_state* m_state;

View File

@ -42,7 +42,7 @@ namespace Nz
void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override; 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 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 struct MeshDataComparator
{ {

View File

@ -44,7 +44,7 @@ namespace Nz
void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override; 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 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); void Sort(const AbstractViewer* viewer);

View File

@ -19,7 +19,7 @@ namespace Nz
GuillotineTextureAtlas() = default; GuillotineTextureAtlas() = default;
~GuillotineTextureAtlas() = default; ~GuillotineTextureAtlas() = default;
UInt32 GetStorage() const; UInt32 GetStorage() const override;
private: private:
AbstractImage* ResizeImage(AbstractImage* oldImage, const Vector2ui& size) const override; AbstractImage* ResizeImage(AbstractImage* oldImage, const Vector2ui& size) const override;

View File

@ -33,7 +33,7 @@ namespace Nz
void AddController(ParticleControllerRef controller); void AddController(ParticleControllerRef controller);
void AddEmitter(ParticleEmitter* emitter); void AddEmitter(ParticleEmitter* emitter);
void AddGenerator(ParticleGeneratorRef generator); 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); void ApplyControllers(ParticleMapper& mapper, unsigned int particleCount, float elapsedTime);

View File

@ -54,7 +54,7 @@ namespace Nz
bool HasAnimation() const; bool HasAnimation() const;
bool IsAnimated() const; bool IsAnimated() const override;
bool IsAnimationEnabled() const; bool IsAnimationEnabled() const;
bool LoadFromFile(const String& filePath, const SkeletalModelParameters& params = SkeletalModelParameters()); bool LoadFromFile(const String& filePath, const SkeletalModelParameters& params = SkeletalModelParameters());

View File

@ -30,32 +30,32 @@
namespace Nz namespace Nz
{ {
template<typename T> T Approach(T value, T objective, T increment); template<typename T> constexpr T Approach(T value, T objective, T increment);
template<typename T> constexpr T Clamp(T value, T min, T max); template<typename T> constexpr T Clamp(T value, T min, T max);
template<typename T> T CountBits(T value); template<typename T> constexpr T CountBits(T value);
template<typename T> constexpr T FromDegrees(T degrees); template<typename T> constexpr T FromDegrees(T degrees);
template<typename T> constexpr T FromRadians(T radians); template<typename T> constexpr T FromRadians(T radians);
template<typename T> constexpr T DegreeToRadian(T degrees); template<typename T> constexpr T DegreeToRadian(T degrees);
template<typename T> T GetNearestPowerOfTwo(T number); template<typename T> constexpr T GetNearestPowerOfTwo(T number);
unsigned int GetNumberLength(signed char number); constexpr unsigned int GetNumberLength(signed char number);
unsigned int GetNumberLength(unsigned char number); constexpr unsigned int GetNumberLength(unsigned char number);
unsigned int GetNumberLength(int 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(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(float number, UInt8 precision = NAZARA_CORE_DECIMAL_DIGITS);
unsigned int GetNumberLength(double 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); unsigned int GetNumberLength(long double number, UInt8 precision = NAZARA_CORE_DECIMAL_DIGITS);
template<typename T> unsigned int IntegralLog2(T number); template<typename T> constexpr unsigned int IntegralLog2(T number);
template<typename T> unsigned int IntegralLog2Pot(T pot); template<typename T> constexpr unsigned int IntegralLog2Pot(T pot);
unsigned int IntegralPow(unsigned int base, unsigned int exponent); constexpr unsigned int IntegralPow(unsigned int base, unsigned int exponent);
template<typename T, typename T2> T Lerp(T from, T to, T2 interpolation); template<typename T, typename T2> constexpr T Lerp(const T& from, const T& to, const T2& interpolation);
template<typename T> T MultiplyAdd(T x, T y, T z); template<typename T> constexpr T MultiplyAdd(T x, T y, T z);
template<typename T> T NormalizeAngle(T angle); template<typename T> constexpr T NormalizeAngle(T angle);
template<typename T> bool NumberEquals(T a, T b); template<typename T> constexpr bool NumberEquals(T a, T b);
template<typename T> bool NumberEquals(T a, T b, T maxDifference); template<typename T> constexpr bool NumberEquals(T a, T b, T maxDifference);
String NumberToString(long long number, UInt8 radix = 10); String NumberToString(long long number, UInt8 radix = 10);
template<typename T> T RadianToDegree(T radians); template<typename T> constexpr T RadianToDegree(T radians);
long long StringToNumber(String str, UInt8 radix = 10, bool* ok = nullptr); long long StringToNumber(String str, UInt8 radix = 10, bool* ok = nullptr);
template<typename T> constexpr T ToDegrees(T angle); template<typename T> constexpr T ToDegrees(T angle);
template<typename T> constexpr T ToRadians(T angle); template<typename T> constexpr T ToRadians(T angle);

View File

@ -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<typename T> template<typename T>
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) if (value < objective)
return std::min(value + increment, objective); return std::min(value + increment, objective);
else if (value > objective) else if (value > objective)
@ -110,14 +118,30 @@ namespace Nz
return value; 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<typename T> template<typename T>
constexpr T Clamp(T value, T min, T max) constexpr T Clamp(T value, T min, T max)
{ {
return std::max(std::min(value, max), min); 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<typename T> template<typename T>
T CountBits(T value) constexpr T CountBits(T value)
{ {
// https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
unsigned int count = 0; unsigned int count = 0;
@ -130,12 +154,26 @@ namespace Nz
return count; 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<typename T> template<typename T>
constexpr T DegreeToRadian(T degrees) constexpr T DegreeToRadian(T degrees)
{ {
return degrees * T(M_PI/180.0); 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<typename T> template<typename T>
constexpr T FromDegrees(T degrees) constexpr T FromDegrees(T degrees)
{ {
@ -146,6 +184,13 @@ namespace Nz
#endif #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<typename T> template<typename T>
constexpr T FromRadians(T radians) constexpr T FromRadians(T radians)
{ {
@ -156,22 +201,33 @@ namespace Nz
#endif #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<typename T> template<typename T>
T GetNearestPowerOfTwo(T number) constexpr T GetNearestPowerOfTwo(T number)
{ {
///TODO: Marquer comme constexpr en C++14
T x = 1; 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) while (x < number)
x <<= 1; x <<= 1; // We multiply by 2
return x; 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 // Char is expected to be 1 byte
// Le standard définit le char comme étant codé sur un octet
static_assert(sizeof(number) == 1, "Signed char must be one byte-sized"); static_assert(sizeof(number) == 1, "Signed char must be one byte-sized");
if (number >= 100) if (number >= 100)
@ -188,10 +244,16 @@ namespace Nz
return 4; 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 // Char is expected to be 1 byte
// Le standard définit le char comme étant codé sur un octet
static_assert(sizeof(number) == 1, "Unsigned char must be one byte-sized"); static_assert(sizeof(number) == 1, "Unsigned char must be one byte-sized");
if (number >= 100) if (number >= 100)
@ -202,6 +264,13 @@ namespace Nz
return 1; 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) inline unsigned int GetNumberLength(int number)
{ {
if (number == 0) if (number == 0)
@ -210,7 +279,14 @@ namespace Nz
return static_cast<unsigned int>(std::log10(std::abs(number))) + (number < 0 ? 2 : 1); return static_cast<unsigned int>(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) if (number == 0)
return 1; return 1;
@ -218,6 +294,13 @@ namespace Nz
return static_cast<unsigned int>(std::log10(number))+1; return static_cast<unsigned int>(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) inline unsigned int GetNumberLength(long long number)
{ {
if (number == 0) if (number == 0)
@ -226,7 +309,14 @@ namespace Nz
return static_cast<unsigned int>(std::log10(std::abs(number))) + (number < 0 ? 2 : 1); return static_cast<unsigned int>(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) if (number == 0)
return 1; return 1;
@ -234,40 +324,90 @@ namespace Nz
return static_cast<unsigned int>(std::log10(number)) + 1; return static_cast<unsigned int>(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) inline unsigned int GetNumberLength(float number, UInt8 precision)
{ {
// L'imprécision des flottants nécessite un cast (log10(9.99999) = 0.99999) // The imprecision of floats need a cast (log10(9.99999) = 0.99999)
return GetNumberLength(static_cast<long long>(number)) + precision + 1; // Plus un pour le point return GetNumberLength(static_cast<long long>(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) inline unsigned int GetNumberLength(double number, UInt8 precision)
{ {
// L'imprécision des flottants nécessite un cast (log10(9.99999) = 0.99999) // The imprecision of floats need a cast (log10(9.99999) = 0.99999)
return GetNumberLength(static_cast<long long>(number)) + precision + 1; // Plus un pour le point return GetNumberLength(static_cast<long long>(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) inline unsigned int GetNumberLength(long double number, UInt8 precision)
{ {
// L'imprécision des flottants nécessite un cast (log10(9.99999) = 0.99999) // The imprecision of floats need a cast (log10(9.99999) = 0.99999)
return GetNumberLength(static_cast<long long>(number)) + precision + 1; // Plus un pour le point return GetNumberLength(static_cast<long long>(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<typename T> template<typename T>
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<T>(number); return Detail::IntegralLog2<T>(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<typename T> template<typename T>
unsigned int IntegralLog2Pot(T pot) constexpr unsigned int IntegralLog2Pot(T pot)
{ {
return Detail::IntegralLog2Pot<T>(pot); return Detail::IntegralLog2Pot<T>(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; unsigned int r = 1;
for (unsigned int i = 0; i < exponent; ++i) for (unsigned int i = 0; i < exponent; ++i)
r *= base; r *= base;
@ -275,8 +415,22 @@ namespace Nz
return r; 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<typename T, typename T2> template<typename T, typename T2>
T Lerp(T from, T to, T2 interpolation) constexpr T Lerp(const T& from, const T& to, const T2& interpolation)
{ {
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
if (interpolation < T2(0.0) || interpolation > T2(1.0)) if (interpolation < T2(0.0) || interpolation > T2(1.0))
@ -286,15 +440,26 @@ namespace Nz
return from + interpolation * (to - from); 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<typename T> template<typename T>
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 #ifdef FP_FAST_FMAF
template<> 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); return std::fmaf(x, y, z);
} }
@ -302,7 +467,7 @@ namespace Nz
#ifdef FP_FAST_FMA #ifdef FP_FAST_FMA
template<> 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); return std::fma(x, y, z);
} }
@ -310,14 +475,21 @@ namespace Nz
#ifdef FP_FAST_FMAL #ifdef FP_FAST_FMAL
template<> 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); return std::fmal(x, y, z);
} }
#endif #endif
/*!
* \brief Normalizes the angle
* \return Normalized value between 0..2*(pi if radian or 180 if degrees)
*
* \param angle Angle to normalize
*/
template<typename T> template<typename T>
T NormalizeAngle(T angle) constexpr T NormalizeAngle(T angle)
{ {
#if NAZARA_MATH_ANGLE_RADIAN #if NAZARA_MATH_ANGLE_RADIAN
const T limit = T(M_PI); const T limit = T(M_PI);
@ -333,14 +505,31 @@ namespace Nz
return angle - limit; 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<typename T> template<typename T>
bool NumberEquals(T a, T b) constexpr bool NumberEquals(T a, T b)
{ {
return NumberEquals(a, b, std::numeric_limits<T>::epsilon()); return NumberEquals(a, b, std::numeric_limits<T>::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<typename T> template<typename T>
bool NumberEquals(T a, T b, T maxDifference) constexpr bool NumberEquals(T a, T b, T maxDifference)
{ {
if (b > a) if (b > a)
std::swap(a, b); std::swap(a, b);
@ -349,6 +538,17 @@ namespace Nz
return diff <= maxDifference; 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) inline String NumberToString(long long number, UInt8 radix)
{ {
#if NAZARA_MATH_SAFE #if NAZARA_MATH_SAFE
@ -389,12 +589,31 @@ namespace Nz
return str.Reverse(); 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<typename T> template<typename T>
T RadianToDegree(T radians) constexpr T RadianToDegree(T radians)
{ {
return radians * T(180.0/M_PI); 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) inline long long StringToNumber(String str, UInt8 radix, bool* ok)
{ {
#if NAZARA_MATH_SAFE #if NAZARA_MATH_SAFE
@ -444,6 +663,13 @@ namespace Nz
return (negative) ? -static_cast<long long>(total) : total; return (negative) ? -static_cast<long long>(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<typename T> template<typename T>
constexpr T ToDegrees(T angle) constexpr T ToDegrees(T angle)
{ {
@ -454,6 +680,13 @@ namespace Nz
#endif #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<typename T> template<typename T>
constexpr T ToRadians(T angle) constexpr T ToRadians(T angle)
{ {
@ -461,8 +694,8 @@ namespace Nz
return angle; return angle;
#else #else
return DegreeToRadian(angle); return DegreeToRadian(angle);
#endif
} }
#endif
} }
#include <Nazara/Core/DebugOff.hpp> #include <Nazara/Core/DebugOff.hpp>

View File

@ -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" // This file is part of the "Nazara Engine - Mathematics module"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
@ -13,42 +13,108 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::BoundingVolume<T>
* \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<T> object by default
*
* \remark extend is set to Extend_Null, aabb and obb are uninitialized
*/
template<typename T> template<typename T>
BoundingVolume<T>::BoundingVolume() : BoundingVolume<T>::BoundingVolume() :
extend(Extend_Null) extend(Extend_Null)
{ {
} }
/*!
* \brief Constructs a BoundingVolume<T> object from Extend
* \param Extend Extend of the volume part of enumeration Extend
*
* \remark Aabb and obb are uninitialized
*/
template<typename T> template<typename T>
BoundingVolume<T>::BoundingVolume(Extend Extend) BoundingVolume<T>::BoundingVolume(Extend Extend)
{ {
Set(Extend); Set(Extend);
} }
/*!
* \brief Constructs a BoundingVolume<T> 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<typename T> template<typename T>
BoundingVolume<T>::BoundingVolume(T X, T Y, T Z, T Width, T Height, T Depth) BoundingVolume<T>::BoundingVolume(T X, T Y, T Z, T Width, T Height, T Depth)
{ {
Set(X, Y, Z, Width, Height, Depth); Set(X, Y, Z, Width, Height, Depth);
} }
/*!
* \brief Constructs a BoundingVolume<T> object from a box
*
* \param box Box<T> object
*
* \remark Aabb is uninitialized
*/
template<typename T> template<typename T>
BoundingVolume<T>::BoundingVolume(const Box<T>& box) BoundingVolume<T>::BoundingVolume(const Box<T>& box)
{ {
Set(box); Set(box);
} }
/*!
* \brief Constructs a BoundingVolume<T> object from an oriented box
*
* \param orientedBox OrientedBox<T> object
*
* \remark Aabb is uninitialized
*/
template<typename T> template<typename T>
BoundingVolume<T>::BoundingVolume(const OrientedBox<T>& orientedBox) BoundingVolume<T>::BoundingVolume(const OrientedBox<T>& orientedBox)
{ {
Set(orientedBox); Set(orientedBox);
} }
/*!
* \brief Constructs a BoundingVolume<T> 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<typename T> template<typename T>
BoundingVolume<T>::BoundingVolume(const Vector3<T>& vec1, const Vector3<T>& vec2) BoundingVolume<T>::BoundingVolume(const Vector3<T>& vec1, const Vector3<T>& vec2)
{ {
Set(vec1, vec2); Set(vec1, vec2);
} }
/*!
* \brief Constructs a BoundingVolume<T> object from another type of BoundingVolume
*
* \param volume BoundingVolume of type U to convert to type T
*/
template<typename T> template<typename T>
template<typename U> template<typename U>
BoundingVolume<T>::BoundingVolume(const BoundingVolume<U>& volume) BoundingVolume<T>::BoundingVolume(const BoundingVolume<U>& volume)
@ -56,24 +122,46 @@ namespace Nz
Set(volume); Set(volume);
} }
/*!
* \brief Checks whether the volume is finite
* \return true if extend is Extend_Finite
*/
template<typename T> template<typename T>
bool BoundingVolume<T>::IsFinite() const bool BoundingVolume<T>::IsFinite() const
{ {
return extend == Extend_Finite; return extend == Extend_Finite;
} }
/*!
* \brief Checks whether the volume is infinite
* \return true if extend is Extend_Infinite
*/
template<typename T> template<typename T>
bool BoundingVolume<T>::IsInfinite() const bool BoundingVolume<T>::IsInfinite() const
{ {
return extend == Extend_Infinite; return extend == Extend_Infinite;
} }
/*!
* \brief Checks whether the volume is null
* \return true if extend is Extend_Null
*/
template<typename T> template<typename T>
bool BoundingVolume<T>::IsNull() const bool BoundingVolume<T>::IsNull() const
{ {
return extend == Extend_Null; 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<typename T> template<typename T>
BoundingVolume<T>& BoundingVolume<T>::MakeInfinite() BoundingVolume<T>& BoundingVolume<T>::MakeInfinite()
{ {
@ -82,6 +170,13 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Makes the bounding volume null
* \return A reference to this bounding volume with Extend_Null for extend
*
* \see Null
*/
template<typename T> template<typename T>
BoundingVolume<T>& BoundingVolume<T>::MakeNull() BoundingVolume<T>& BoundingVolume<T>::MakeNull()
{ {
@ -90,6 +185,15 @@ namespace Nz
return *this; 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<typename T> template<typename T>
BoundingVolume<T>& BoundingVolume<T>::Set(Extend Extend) BoundingVolume<T>& BoundingVolume<T>::Set(Extend Extend)
{ {
@ -98,6 +202,18 @@ namespace Nz
return *this; 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<typename T> template<typename T>
BoundingVolume<T>& BoundingVolume<T>::Set(T X, T Y, T Z, T Width, T Height, T Depth) BoundingVolume<T>& BoundingVolume<T>::Set(T X, T Y, T Z, T Width, T Height, T Depth)
{ {
@ -107,15 +223,29 @@ namespace Nz
return *this; 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<typename T> template<typename T>
BoundingVolume<T>& BoundingVolume<T>::Set(const BoundingVolume<T>& volume) BoundingVolume<T>& BoundingVolume<T>::Set(const BoundingVolume<T>& 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; extend = volume.extend;
return *this; return *this;
} }
/*!
* \brief Sets the components of the bounding volume from a box
* \return A reference to this bounding volume
*
* \param box Box<T> object
*/
template<typename T> template<typename T>
BoundingVolume<T>& BoundingVolume<T>::Set(const Box<T>& box) BoundingVolume<T>& BoundingVolume<T>::Set(const Box<T>& box)
{ {
@ -125,6 +255,13 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Sets the components of the bounding volume from an oriented box
* \return A reference to this bounding volume
*
* \param orientedBox OrientedBox<T> object
*/
template<typename T> template<typename T>
BoundingVolume<T>& BoundingVolume<T>::Set(const OrientedBox<T>& orientedBox) BoundingVolume<T>& BoundingVolume<T>::Set(const OrientedBox<T>& orientedBox)
{ {
@ -134,6 +271,14 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Sets a BoundingVolume<T> 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<typename T> template<typename T>
BoundingVolume<T>& BoundingVolume<T>::Set(const Vector3<T>& vec1, const Vector3<T>& vec2) BoundingVolume<T>& BoundingVolume<T>::Set(const Vector3<T>& vec1, const Vector3<T>& vec2)
{ {
@ -143,6 +288,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
template<typename U> template<typename U>
BoundingVolume<T>& BoundingVolume<T>::Set(const BoundingVolume<U>& volume) BoundingVolume<T>& BoundingVolume<T>::Set(const BoundingVolume<U>& volume)
@ -153,6 +305,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
String BoundingVolume<T>::ToString() const String BoundingVolume<T>::ToString() const
{ {
@ -173,6 +332,12 @@ namespace Nz
return "BoundingVolume(ERROR)"; return "BoundingVolume(ERROR)";
} }
/*!
* \brief Updates the obb and the aabb of the bounding volume
*
* \param transformMatrix Matrix4 which represents the transformation to apply
*/
template<typename T> template<typename T>
void BoundingVolume<T>::Update(const Matrix4<T>& transformMatrix) void BoundingVolume<T>::Update(const Matrix4<T>& transformMatrix)
{ {
@ -183,6 +348,12 @@ namespace Nz
aabb.ExtendTo(obb(i)); 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<typename T> template<typename T>
void BoundingVolume<T>::Update(const Vector3<T>& translation) void BoundingVolume<T>::Update(const Vector3<T>& translation)
{ {
@ -193,6 +364,13 @@ namespace Nz
aabb.ExtendTo(obb(i)); 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<typename T> template<typename T>
BoundingVolume<T> BoundingVolume<T>::operator*(T scalar) const BoundingVolume<T> BoundingVolume<T>::operator*(T scalar) const
{ {
@ -202,6 +380,13 @@ namespace Nz
return volume; 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<typename T> template<typename T>
BoundingVolume<T>& BoundingVolume<T>::operator*=(T scalar) BoundingVolume<T>& BoundingVolume<T>::operator*=(T scalar)
{ {
@ -210,6 +395,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
bool BoundingVolume<T>::operator==(const BoundingVolume& volume) const bool BoundingVolume<T>::operator==(const BoundingVolume& volume) const
{ {
@ -222,12 +414,26 @@ namespace Nz
return false; 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<typename T> template<typename T>
bool BoundingVolume<T>::operator!=(const BoundingVolume& volume) const bool BoundingVolume<T>::operator!=(const BoundingVolume& volume) const
{ {
return !operator==(volume); return !operator==(volume);
} }
/*!
* \brief Shorthand for the bounding volume (Extend_Infinite)
* \return A bounding volume with Extend_Infinite
*
* \see MakeInfinite
*/
template<typename T> template<typename T>
BoundingVolume<T> BoundingVolume<T>::Infinite() BoundingVolume<T> BoundingVolume<T>::Infinite()
{ {
@ -237,6 +443,21 @@ namespace Nz
return volume; 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<typename T> template<typename T>
BoundingVolume<T> BoundingVolume<T>::Lerp(const BoundingVolume& from, const BoundingVolume& to, T interpolation) BoundingVolume<T> BoundingVolume<T>::Lerp(const BoundingVolume& from, const BoundingVolume& to, T interpolation)
{ {
@ -275,13 +496,13 @@ namespace Nz
return from.obb * interpolation; 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) + ')'); NazaraError("Invalid extend type (From) (0x" + String::Number(from.extend, 16) + ')');
return Null(); return Null();
} }
case Extend_Infinite: 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: case Extend_Null:
{ {
@ -297,17 +518,24 @@ namespace Nz
return Null(); 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) + ')'); NazaraError("Invalid extend type (From) (0x" + String::Number(from.extend, 16) + ')');
return Null(); 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) + ')'); NazaraError("Invalid extend type (To) (0x" + String::Number(to.extend, 16) + ')');
return Null(); return Null();
} }
/*!
* \brief Shorthand for the bounding volume (Extend_Null)
* \return A bounding volume with Extend_Null
*
* \see MakeNull
*/
template<typename T> template<typename T>
BoundingVolume<T> BoundingVolume<T>::Null() BoundingVolume<T> BoundingVolume<T>::Null()
{ {
@ -316,13 +544,21 @@ namespace Nz
return volume; return volume;
} }
template<typename T>
std::ostream& operator<<(std::ostream& out, const BoundingVolume<T>& volume)
{
out << volume.ToString();
return out;
} }
/*!
* \brief Output operator
* \return The stream
*
* \param out The stream
* \param volume The bounding volume to output
*/
template<typename T>
std::ostream& operator<<(std::ostream& out, const Nz::BoundingVolume<T>& volume)
{
out << volume.ToString();
return out;
} }
#undef F #undef F

View File

@ -40,8 +40,8 @@ namespace Nz
Box& ExtendTo(const Vector3<T>& point); Box& ExtendTo(const Vector3<T>& point);
Sphere<T> GetBoundingSphere() const; Sphere<T> GetBoundingSphere() const;
Vector3<T> GetCorner(BoxCorner corner) const;
Vector3<T> GetCenter() const; Vector3<T> GetCenter() const;
Vector3<T> GetCorner(BoxCorner corner) const;
Vector3<T> GetLengths() const; Vector3<T> GetLengths() const;
Vector3<T> GetMaximum() const; Vector3<T> GetMaximum() const;
Vector3<T> GetMinimum() const; Vector3<T> GetMinimum() const;

View File

@ -12,41 +12,103 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::Box<T>
* \brief Math class that represents a three dimensional box
*/
/*!
* \brief Constructs a Box<T> 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<typename T> template<typename T>
Box<T>::Box(T Width, T Height, T Depth) Box<T>::Box(T Width, T Height, T Depth)
{ {
Set(Width, Height, Depth); Set(Width, Height, Depth);
} }
/*!
* \brief Constructs a Rect<T> 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<typename T> template<typename T>
Box<T>::Box(T X, T Y, T Z, T Width, T Height, T Depth) Box<T>::Box(T X, T Y, T Z, T Width, T Height, T Depth)
{ {
Set(X, Y, Z, Width, Height, Depth); Set(X, Y, Z, Width, Height, Depth);
} }
/*!
* \brief Constructs a Box<T> 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<typename T>
Box<T>::Box(const T vec[6])
{
Set(vec);
}
/*!
* \brief Constructs a Box<T> 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<typename T> template<typename T>
Box<T>::Box(const Rect<T>& rect) Box<T>::Box(const Rect<T>& rect)
{ {
Set(rect); Set(rect);
} }
/*!
* \brief Constructs a Box<T> 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<typename T> template<typename T>
Box<T>::Box(const Vector3<T>& lengths) Box<T>::Box(const Vector3<T>& lengths)
{ {
Set(lengths); Set(lengths);
} }
/*!
* \brief Constructs a Box<T> 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<typename T> template<typename T>
Box<T>::Box(const Vector3<T>& vec1, const Vector3<T>& vec2) Box<T>::Box(const Vector3<T>& vec1, const Vector3<T>& vec2)
{ {
Set(vec1, vec2); Set(vec1, vec2);
} }
template<typename T> /*!
Box<T>::Box(const T vec[6]) * \brief Constructs a Box<T> object from another type of Box
{ *
Set(vec); * \param box Box of type U to convert to type T
} */
template<typename T> template<typename T>
template<typename U> template<typename U>
@ -55,27 +117,67 @@ namespace Nz
Set(box); 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<typename T> template<typename T>
bool Box<T>::Contains(T X, T Y, T Z) const bool Box<T>::Contains(T X, T Y, T Z) const
{ {
return X >= x && X <= x+width && return X >= x && X <= x + width &&
Y >= y && Y <= y+height && Y >= y && Y <= y + height &&
Z >= z && Z <= z+depth; 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<typename T> template<typename T>
bool Box<T>::Contains(const Box<T>& box) const bool Box<T>::Contains(const Box<T>& box) const
{ {
return Contains(box.x, box.y, box.z) && 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<typename T> template<typename T>
bool Box<T>::Contains(const Vector3<T>& point) const bool Box<T>::Contains(const Vector3<T>& point) const
{ {
return Contains(point.x, point.y, point.z); 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<typename T> template<typename T>
Box<T>& Box<T>::ExtendTo(T X, T Y, T Z) Box<T>& Box<T>::ExtendTo(T X, T Y, T Z)
{ {
@ -94,6 +196,15 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Box<T>& Box<T>::ExtendTo(const Box& box) Box<T>& Box<T>::ExtendTo(const Box& box)
{ {
@ -112,12 +223,54 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Box<T>& Box<T>::ExtendTo(const Vector3<T>& point) Box<T>& Box<T>::ExtendTo(const Vector3<T>& point)
{ {
return ExtendTo(point.x, point.y, point.z); 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<typename T>
Sphere<T> Box<T>::GetBoundingSphere() const
{
return Sphere<T>(GetCenter(), GetRadius());
}
/*!
* \brief Gets a Vector3 for the center
* \return The position of the center of the box
*/
template<typename T>
Vector3<T> Box<T>::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<typename T> template<typename T>
Vector3<T> Box<T>::GetCorner(BoxCorner corner) const Vector3<T> Box<T>::GetCorner(BoxCorner corner) const
{ {
@ -152,17 +305,10 @@ namespace Nz
return Vector3<T>(); return Vector3<T>();
} }
template<typename T> /*!
Sphere<T> Box<T>::GetBoundingSphere() const * \brief Gets a Vector3 for the lengths
{ * \return The lengths of the box (width, height, depth)
return Sphere<T>(GetCenter(), GetRadius()); */
}
template<typename T>
Vector3<T> Box<T>::GetCenter() const
{
return GetPosition() + GetLengths()/F(2.0);
}
template<typename T> template<typename T>
Vector3<T> Box<T>::GetLengths() const Vector3<T> Box<T>::GetLengths() const
@ -170,19 +316,41 @@ namespace Nz
return Vector3<T>(width, height, depth); return Vector3<T>(width, height, depth);
} }
/*!
* \brief Gets a Vector3 for the maximum point
* \return The BoxCorner_NearRightTop of the box
*
* \see GetCorner
*/
template<typename T> template<typename T>
Vector3<T> Box<T>::GetMaximum() const Vector3<T> Box<T>::GetMaximum() const
{ {
return GetPosition() + GetLengths(); return GetPosition() + GetLengths();
} }
/*!
* \brief Gets a Vector3 for the minimum point
* \return The BoxCorner_FarLeftBottom of the box
*
* \see GetCorner, GetPosition
*/
template<typename T> template<typename T>
Vector3<T> Box<T>::GetMinimum() const Vector3<T> Box<T>::GetMinimum() const
{ {
///DOC: Alias de GetPosition()
return 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<typename T> template<typename T>
Vector3<T> Box<T>::GetNegativeVertex(const Vector3<T>& normal) const Vector3<T> Box<T>::GetNegativeVertex(const Vector3<T>& normal) const
{ {
@ -200,12 +368,28 @@ namespace Nz
return neg; return neg;
} }
/*!
* \brief Gets a Vector3 for the position
* \return The BoxCorner_FarLeftBottom of the box
*
* \see GetCorner, GetMinimum
*/
template<typename T> template<typename T>
Vector3<T> Box<T>::GetPosition() const Vector3<T> Box<T>::GetPosition() const
{ {
return Vector3<T>(x, y, z); return Vector3<T>(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<typename T> template<typename T>
Vector3<T> Box<T>::GetPositiveVertex(const Vector3<T>& normal) const Vector3<T> Box<T>::GetPositiveVertex(const Vector3<T>& normal) const
{ {
@ -223,27 +407,52 @@ namespace Nz
return pos; 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<typename T> template<typename T>
T Box<T>::GetRadius() const T Box<T>::GetRadius() const
{ {
return std::sqrt(GetSquaredRadius()); return std::sqrt(GetSquaredRadius());
} }
/*!
* \brief Gets the squared bounding sphere for the box
* \return A sphere containing the box
*
* \see GetBoundingSphere
*/
template<typename T> template<typename T>
Sphere<T> Box<T>::GetSquaredBoundingSphere() const Sphere<T> Box<T>::GetSquaredBoundingSphere() const
{ {
return Sphere<T>(GetCenter(), GetSquaredRadius()); return Sphere<T>(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<typename T> template<typename T>
T Box<T>::GetSquaredRadius() const T Box<T>::GetSquaredRadius() const
{ {
Vector3<T> size(GetLengths()); Vector3<T> 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(); 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<typename T> template<typename T>
bool Box<T>::Intersect(const Box& box, Box* intersection) const bool Box<T>::Intersect(const Box& box, Box* intersection) const
{ {
@ -275,12 +484,24 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Checks whether this box is valid
* \return true if the box has a strictly positive width, height and depth
*/
template<typename T> template<typename T>
bool Box<T>::IsValid() const bool Box<T>::IsValid() const
{ {
return width > F(0.0) && height > F(0.0) && depth > F(0.0); 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<typename T> template<typename T>
Box<T>& Box<T>::MakeZero() Box<T>& Box<T>::MakeZero()
{ {
@ -294,6 +515,17 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Box<T>& Box<T>::Set(T Width, T Height, T Depth) Box<T>& Box<T>::Set(T Width, T Height, T Depth)
{ {
@ -307,6 +539,17 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Constructs a Box<T> 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<typename T> template<typename T>
Box<T>& Box<T>::Set(T X, T Y, T Z, T Width, T Height, T Depth) Box<T>& Box<T>::Set(T X, T Y, T Z, T Width, T Height, T Depth)
{ {
@ -320,6 +563,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Box<T>& Box<T>::Set(const T box[6]) Box<T>& Box<T>::Set(const T box[6])
{ {
@ -333,6 +583,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Box<T>& Box<T>::Set(const Box& box) Box<T>& Box<T>::Set(const Box& box)
{ {
@ -341,6 +598,15 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Box<T>& Box<T>::Set(const Rect<T>& rect) Box<T>& Box<T>::Set(const Rect<T>& rect)
{ {
@ -354,25 +620,50 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Box<T>& Box<T>::Set(const Vector3<T>& lengths) Box<T>& Box<T>::Set(const Vector3<T>& lengths)
{ {
return Set(lengths.x, lengths.y, lengths.z); 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<typename T> template<typename T>
Box<T>& Box<T>::Set(const Vector3<T>& vec1, const Vector3<T>& vec2) Box<T>& Box<T>::Set(const Vector3<T>& vec1, const Vector3<T>& vec2)
{ {
x = std::min(vec1.x, vec2.x); x = std::min(vec1.x, vec2.x);
y = std::min(vec1.y, vec2.y); y = std::min(vec1.y, vec2.y);
z = std::min(vec1.z, vec2.z); z = std::min(vec1.z, vec2.z);
width = (vec2.x > vec1.x) ? vec2.x-vec1.x : vec1.x-vec2.x; 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; 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; depth = (vec2.z > vec1.z) ? vec2.z - vec1.z : vec1.z - vec2.z;
return *this; 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<typename T> template<typename T>
template<typename U> template<typename U>
Box<T>& Box<T>::Set(const Box<U>& box) Box<T>& Box<T>::Set(const Box<U>& box)
@ -387,6 +678,11 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Gives a string representation
* \return A string representation of the object: "Box(x, y, z, width, height, depth)"
*/
template<typename T> template<typename T>
String Box<T>::ToString() const String Box<T>::ToString() const
{ {
@ -395,19 +691,34 @@ namespace Nz
return ss << "Box(" << x << ", " << y << ", " << z << ", " << width << ", " << height << ", " << depth << ')'; 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<typename T> template<typename T>
Box<T>& Box<T>::Transform(const Matrix4<T>& matrix, bool applyTranslation) Box<T>& Box<T>::Transform(const Matrix4<T>& matrix, bool applyTranslation)
{ {
Vector3<T> center = matrix.Transform(GetCenter(), (applyTranslation) ? F(1.0) : F(0.0)); // Valeur multipliant la translation Vector3<T> center = matrix.Transform(GetCenter(), (applyTranslation) ? F(1.0) : F(0.0)); // Value multiplying the translation
Vector3<T> halfSize = GetLengths()/F(2.0); Vector3<T> 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, 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,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); 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); 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<typename T> template<typename T>
Box<T>& Box<T>::Translate(const Vector3<T>& translation) Box<T>& Box<T>::Translate(const Vector3<T>& translation)
{ {
@ -418,6 +729,15 @@ namespace Nz
return *this; 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<typename T> template<typename T>
T& Box<T>::operator[](unsigned int i) T& Box<T>::operator[](unsigned int i)
{ {
@ -435,6 +755,15 @@ namespace Nz
return *(&x+i); 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<typename T> template<typename T>
T Box<T>::operator[](unsigned int i) const T Box<T>::operator[](unsigned int i) const
{ {
@ -452,18 +781,39 @@ namespace Nz
return *(&x+i); 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<typename T> template<typename T>
Box<T> Box<T>::operator*(T scalar) const Box<T> Box<T>::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<typename T> template<typename T>
Box<T> Box<T>::operator*(const Vector3<T>& vec) const Box<T> Box<T>::operator*(const Vector3<T>& 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<typename T> template<typename T>
Box<T>& Box<T>::operator*=(T scalar) Box<T>& Box<T>::operator*=(T scalar)
{ {
@ -474,6 +824,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Box<T>& Box<T>::operator*=(const Vector3<T>& vec) Box<T>& Box<T>::operator*=(const Vector3<T>& vec)
{ {
@ -484,19 +841,47 @@ namespace Nz
return *this; 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<typename T> template<typename T>
bool Box<T>::operator==(const Box& box) const bool Box<T>::operator==(const Box& box) const
{ {
return NumberEquals(x, box.x) && NumberEquals(y, box.y) && NumberEquals(z, box.z) && 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<typename T> template<typename T>
bool Box<T>::operator!=(const Box& box) const bool Box<T>::operator!=(const Box& box) const
{ {
return !operator==(box); 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<typename T> template<typename T>
Box<T> Box<T>::Lerp(const Box& from, const Box& to, T interpolation) Box<T> Box<T>::Lerp(const Box& from, const Box& to, T interpolation)
{ {
@ -519,6 +904,13 @@ namespace Nz
return box; 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<typename T> template<typename T>
Box<T> Box<T>::Zero() Box<T> Box<T>::Zero()
{ {
@ -529,6 +921,14 @@ namespace Nz
} }
} }
/*!
* \brief Output operator
* \return The stream
*
* \param out The stream
* \param box The box to output
*/
template<typename T> template<typename T>
std::ostream& operator<<(std::ostream& out, const Nz::Box<T>& box) std::ostream& operator<<(std::ostream& out, const Nz::Box<T>& box)
{ {

View File

@ -28,15 +28,15 @@
#ifndef NAZARA_CONFIG_MATH_HPP #ifndef NAZARA_CONFIG_MATH_HPP
#define 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 #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 #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 #define NAZARA_MATH_SAFE 1
#endif // NAZARA_CONFIG_MATH_HPP #endif // NAZARA_CONFIG_MATH_HPP

View File

@ -28,14 +28,14 @@ namespace Nz
void MakeZero(); void MakeZero();
void Normalize(); EulerAngles& Normalize();
void Set(T P, T Y, T R); EulerAngles& Set(T P, T Y, T R);
void Set(const T angles[3]); EulerAngles& Set(const T angles[3]);
void Set(const EulerAngles<T>& angles); EulerAngles& Set(const EulerAngles<T>& angles);
//void Set(const Matrix3<T>& mat); //EulerAngles& Set(const Matrix3<T>& mat);
void Set(const Quaternion<T>& quat); EulerAngles& Set(const Quaternion<T>& quat);
template<typename U> void Set(const EulerAngles<U>& angles); template<typename U> EulerAngles& Set(const EulerAngles<U>& angles);
//Matrix3<T> ToRotationMatrix() const; //Matrix3<T> ToRotationMatrix() const;
Quaternion<T> ToQuaternion() const; Quaternion<T> ToQuaternion() const;

View File

@ -14,24 +14,58 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::Vector4<T>
* \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<T> object from its components
*
* \param P Pitch component = X axis
* \param Y Yaw component = Y axis
* \param R Roll component = Z axis
*/
template<typename T> template<typename T>
EulerAngles<T>::EulerAngles(T P, T Y, T R) EulerAngles<T>::EulerAngles(T P, T Y, T R)
{ {
Set(P, Y, R); Set(P, Y, R);
} }
/*!
* \brief Constructs a EulerAngles<T> 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<typename T> template<typename T>
EulerAngles<T>::EulerAngles(const T angles[3]) EulerAngles<T>::EulerAngles(const T angles[3])
{ {
Set(angles); Set(angles);
} }
/*!
* \brief Constructs a EulerAngles<T> object from a quaternion
*
* \param quat Quaternion representing a rotation of space
*/
template<typename T> template<typename T>
EulerAngles<T>::EulerAngles(const Quaternion<T>& quat) EulerAngles<T>::EulerAngles(const Quaternion<T>& quat)
{ {
Set(quat); Set(quat);
} }
/*!
* \brief Constructs a EulerAngles<T> object from another type of EulerAngles
*
* \param angles EulerAngles of type U to convert to type T
*/
template<typename T> template<typename T>
template<typename U> template<typename U>
EulerAngles<T>::EulerAngles(const EulerAngles<U>& angles) EulerAngles<T>::EulerAngles(const EulerAngles<U>& angles)
@ -39,57 +73,125 @@ namespace Nz
Set(angles); 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<typename T> template<typename T>
void EulerAngles<T>::MakeZero() void EulerAngles<T>::MakeZero()
{ {
Set(F(0.0), F(0.0), F(0.0)); 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<typename T> template<typename T>
void EulerAngles<T>::Normalize() EulerAngles<T>& EulerAngles<T>::Normalize()
{ {
pitch = NormalizeAngle(pitch); pitch = NormalizeAngle(pitch);
yaw = NormalizeAngle(yaw); yaw = NormalizeAngle(yaw);
roll = NormalizeAngle(roll); 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<typename T> template<typename T>
void EulerAngles<T>::Set(T P, T Y, T R) EulerAngles<T>& EulerAngles<T>::Set(T P, T Y, T R)
{ {
pitch = P; pitch = P;
yaw = Y; yaw = Y;
roll = R; 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<typename T> template<typename T>
void EulerAngles<T>::Set(const T angles[3]) EulerAngles<T>& EulerAngles<T>::Set(const T angles[3])
{ {
pitch = angles[0]; pitch = angles[0];
yaw = angles[1]; yaw = angles[1];
roll = angles[2]; 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<typename T> template<typename T>
void EulerAngles<T>::Set(const EulerAngles& angles) EulerAngles<T>& EulerAngles<T>::Set(const EulerAngles& angles)
{ {
std::memcpy(this, &angles, sizeof(EulerAngles)); 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<typename T> template<typename T>
void EulerAngles<T>::Set(const Quaternion<T>& quat) EulerAngles<T>& EulerAngles<T>::Set(const Quaternion<T>& 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<typename T> template<typename T>
template<typename U> template<typename U>
void EulerAngles<T>::Set(const EulerAngles<U>& angles) EulerAngles<T>& EulerAngles<T>::Set(const EulerAngles<U>& angles)
{ {
pitch = F(angles.pitch); pitch = F(angles.pitch);
yaw = F(angles.yaw); yaw = F(angles.yaw);
roll = F(angles.roll); 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<typename T> template<typename T>
Quaternion<T> EulerAngles<T>::ToQuaternion() const Quaternion<T> EulerAngles<T>::ToQuaternion() const
{ {
@ -102,11 +204,16 @@ namespace Nz
T s3 = std::sin(ToRadians(pitch) / F(2.0)); T s3 = std::sin(ToRadians(pitch) / F(2.0));
return Quaternion<T>(c1 * c2 * c3 - s1 * s2 * s3, return Quaternion<T>(c1 * c2 * c3 - s1 * s2 * s3,
s1 * s2 * c3 + c1 * c2 * s3, s1 * s2 * c3 + c1 * c2 * s3,
s1 * c2 * c3 + c1 * s2 * s3, s1 * c2 * c3 + c1 * s2 * s3,
c1 * s2 * c3 - s1 * c2 * s3); c1 * s2 * c3 - s1 * c2 * s3);
} }
/*!
* \brief Gives a string representation
* \return A string representation of the object: "EulerAngles(pitch, yaw, roll)"
*/
template<typename T> template<typename T>
String EulerAngles<T>::ToString() const String EulerAngles<T>::ToString() const
{ {
@ -115,22 +222,43 @@ namespace Nz
return ss << "EulerAngles(" << pitch << ", " << yaw << ", " << roll << ')'; 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<typename T> template<typename T>
EulerAngles<T> EulerAngles<T>::operator+(const EulerAngles& angles) const EulerAngles<T> EulerAngles<T>::operator+(const EulerAngles& angles) const
{ {
return EulerAngles(pitch + angles.pitch, return EulerAngles(pitch + angles.pitch,
yaw + angles.yaw, yaw + angles.yaw,
roll + angles.roll); 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<typename T> template<typename T>
EulerAngles<T> EulerAngles<T>::operator-(const EulerAngles& angles) const EulerAngles<T> EulerAngles<T>::operator-(const EulerAngles& angles) const
{ {
return EulerAngles(pitch - angles.pitch, return EulerAngles(pitch - angles.pitch,
yaw - angles.yaw, yaw - angles.yaw,
roll - angles.roll); 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<typename T> template<typename T>
EulerAngles<T>& EulerAngles<T>::operator+=(const EulerAngles& angles) EulerAngles<T>& EulerAngles<T>::operator+=(const EulerAngles& angles)
{ {
@ -141,6 +269,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
EulerAngles<T>& EulerAngles<T>::operator-=(const EulerAngles& angles) EulerAngles<T>& EulerAngles<T>::operator-=(const EulerAngles& angles)
{ {
@ -151,20 +286,41 @@ namespace Nz
return *this; 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<typename T> template<typename T>
bool EulerAngles<T>::operator==(const EulerAngles& angles) const bool EulerAngles<T>::operator==(const EulerAngles& angles) const
{ {
return NumberEquals(pitch, angles.pitch) && return NumberEquals(pitch, angles.pitch) &&
NumberEquals(yaw, angles.yaw) && NumberEquals(yaw, angles.yaw) &&
NumberEquals(roll, angles.roll); 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<typename T> template<typename T>
bool EulerAngles<T>::operator!=(const EulerAngles& angles) const bool EulerAngles<T>::operator!=(const EulerAngles& angles) const
{ {
return !operator==(angles); return !operator==(angles);
} }
/*!
* \brief Shorthand for the euler angle (0, 0, 0)
* \return A euler angle with components (0, 0, 0)
*
* \see MakeZero
*/
template<typename T> template<typename T>
EulerAngles<T> EulerAngles<T>::Zero() EulerAngles<T> EulerAngles<T>::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<typename T> template<typename T>
std::ostream& operator<<(std::ostream& out, const Nz::EulerAngles<T>& angles) std::ostream& operator<<(std::ostream& out, const Nz::EulerAngles<T>& angles)
{ {

View File

@ -15,6 +15,20 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::Frustum<T>
* \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<T> object from another type of Frustum
*
* \param frustum Frustum of type U to convert to type T
*/
template<typename T> template<typename T>
template<typename U> template<typename U>
Frustum<T>::Frustum(const Frustum<U>& frustum) Frustum<T>::Frustum(const Frustum<U>& frustum)
@ -22,6 +36,19 @@ namespace Nz
Set(frustum); 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<typename T> template<typename T>
Frustum<T>& Frustum<T>::Build(T angle, T ratio, T zNear, T zFar, const Vector3<T>& eye, const Vector3<T>& target, const Vector3<T>& up) Frustum<T>& Frustum<T>::Build(T angle, T ratio, T zNear, T zFar, const Vector3<T>& eye, const Vector3<T>& target, const Vector3<T>& up)
{ {
@ -45,18 +72,18 @@ namespace Nz
Vector3<T> nc = eye + f * zNear; Vector3<T> nc = eye + f * zNear;
Vector3<T> fc = eye + f * zFar; Vector3<T> fc = eye + f * zFar;
// Calcul du frustum // Computing the frustum
m_corners[BoxCorner_FarLeftBottom] = fc - u*farH - s*farW; m_corners[BoxCorner_FarLeftBottom] = fc - u * farH - s * farW;
m_corners[BoxCorner_FarLeftTop] = 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_FarRightTop] = fc + u * farH + s * farW;
m_corners[BoxCorner_FarRightBottom] = 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_NearLeftBottom] = nc - u * nearH - s * nearW;
m_corners[BoxCorner_NearLeftTop] = 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_NearRightTop] = nc + u * nearH + s * nearW;
m_corners[BoxCorner_NearRightBottom] = 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_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_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]); 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; 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<typename T> template<typename T>
bool Frustum<T>::Contains(const BoundingVolume<T>& volume) const bool Frustum<T>::Contains(const BoundingVolume<T>& volume) const
{ {
@ -102,11 +141,18 @@ namespace Nz
return false; 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<typename T> template<typename T>
bool Frustum<T>::Contains(const Box<T>& box) const bool Frustum<T>::Contains(const Box<T>& box) const
{ {
// http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/ // 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)) if (m_planes[i].Distance(box.GetPositiveVertex(m_planes[i].normal)) < F(0.0))
return false; return false;
@ -115,16 +161,30 @@ namespace Nz
return true; 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<typename T> template<typename T>
bool Frustum<T>::Contains(const OrientedBox<T>& orientedbox) const bool Frustum<T>::Contains(const OrientedBox<T>& orientedbox) const
{ {
return Contains(&orientedbox[0], 8); 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<typename T> template<typename T>
bool Frustum<T>::Contains(const Sphere<T>& sphere) const bool Frustum<T>::Contains(const Sphere<T>& 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) if (m_planes[i].Distance(sphere.GetPosition()) < -sphere.radius)
return false; return false;
@ -133,10 +193,17 @@ namespace Nz
return true; 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<typename T> template<typename T>
bool Frustum<T>::Contains(const Vector3<T>& point) const bool Frustum<T>::Contains(const Vector3<T>& 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)) if (m_planes[i].Distance(point) < F(0.0))
return false; return false;
@ -145,6 +212,14 @@ namespace Nz
return true; 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<typename T> template<typename T>
bool Frustum<T>::Contains(const Vector3<T>* points, unsigned int pointCount) const bool Frustum<T>::Contains(const Vector3<T>* points, unsigned int pointCount) const
{ {
@ -164,6 +239,15 @@ namespace Nz
return true; 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<typename T> template<typename T>
Frustum<T>& Frustum<T>::Extract(const Matrix4<T>& clipMatrix) Frustum<T>& Frustum<T>::Extract(const Matrix4<T>& clipMatrix)
{ {
@ -178,7 +262,7 @@ namespace Nz
plane[3] = clipMatrix[15] - clipMatrix[12]; plane[3] = clipMatrix[15] - clipMatrix[12];
// Normalize the result // 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[0] *= invLength;
plane[1] *= invLength; plane[1] *= invLength;
plane[2] *= invLength; plane[2] *= invLength;
@ -193,7 +277,7 @@ namespace Nz
plane[3] = clipMatrix[15] + clipMatrix[12]; plane[3] = clipMatrix[15] + clipMatrix[12];
// Normalize the result // 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[0] *= invLength;
plane[1] *= invLength; plane[1] *= invLength;
plane[2] *= invLength; plane[2] *= invLength;
@ -208,7 +292,7 @@ namespace Nz
plane[3] = clipMatrix[15] + clipMatrix[13]; plane[3] = clipMatrix[15] + clipMatrix[13];
// Normalize the result // 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[0] *= invLength;
plane[1] *= invLength; plane[1] *= invLength;
plane[2] *= invLength; plane[2] *= invLength;
@ -223,7 +307,7 @@ namespace Nz
plane[3] = clipMatrix[15] - clipMatrix[13]; plane[3] = clipMatrix[15] - clipMatrix[13];
// Normalize the result // 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[0] *= invLength;
plane[1] *= invLength; plane[1] *= invLength;
plane[2] *= invLength; plane[2] *= invLength;
@ -238,7 +322,7 @@ namespace Nz
plane[3] = clipMatrix[15] - clipMatrix[14]; plane[3] = clipMatrix[15] - clipMatrix[14];
// Normalize the result // 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[0] *= invLength;
plane[1] *= invLength; plane[1] *= invLength;
plane[2] *= invLength; plane[2] *= invLength;
@ -253,7 +337,7 @@ namespace Nz
plane[3] = clipMatrix[15] + clipMatrix[14]; plane[3] = clipMatrix[15] + clipMatrix[14];
// Normalize the result // 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[0] *= invLength;
plane[1] *= invLength; plane[1] *= invLength;
plane[2] *= invLength; plane[2] *= invLength;
@ -261,8 +345,8 @@ namespace Nz
m_planes[FrustumPlane_Near].Set(plane); m_planes[FrustumPlane_Near].Set(plane);
// Une fois les plans extraits, il faut extraire les points du frustum // Once planes have been extracted, we must extract points of the frustum
// Je me base sur cette page: http://www.gamedev.net/topic/393309-calculating-the-view-frustums-vertices/ // Based on: http://www.gamedev.net/topic/393309-calculating-the-view-frustums-vertices/
Matrix4<T> invClipMatrix; Matrix4<T> invClipMatrix;
if (clipMatrix.GetInverse(&invClipMatrix)) if (clipMatrix.GetInverse(&invClipMatrix))
@ -331,12 +415,31 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Frustum<T>& Frustum<T>::Extract(const Matrix4<T>& view, const Matrix4<T>& projection) Frustum<T>& Frustum<T>::Extract(const Matrix4<T>& view, const Matrix4<T>& projection)
{ {
return Extract(Matrix4<T>::Concatenate(view, projection)); return Extract(Matrix4<T>::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<typename T> template<typename T>
const Vector3<T>& Frustum<T>::GetCorner(BoxCorner corner) const const Vector3<T>& Frustum<T>::GetCorner(BoxCorner corner) const
{ {
@ -353,6 +456,15 @@ namespace Nz
return m_corners[corner]; 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<typename T> template<typename T>
const Plane<T>& Frustum<T>::GetPlane(FrustumPlane plane) const const Plane<T>& Frustum<T>::GetPlane(FrustumPlane plane) const
{ {
@ -369,6 +481,18 @@ namespace Nz
return m_planes[plane]; 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<typename T> template<typename T>
IntersectionSide Frustum<T>::Intersect(const BoundingVolume<T>& volume) const IntersectionSide Frustum<T>::Intersect(const BoundingVolume<T>& volume) const
{ {
@ -394,7 +518,7 @@ namespace Nz
} }
case Extend_Infinite: case Extend_Infinite:
return IntersectionSide_Intersecting; // On ne peut pas contenir l'infini return IntersectionSide_Intersecting; // We can not contain infinity
case Extend_Null: case Extend_Null:
return IntersectionSide_Outside; return IntersectionSide_Outside;
@ -404,13 +528,20 @@ namespace Nz
return IntersectionSide_Outside; 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<typename T> template<typename T>
IntersectionSide Frustum<T>::Intersect(const Box<T>& box) const IntersectionSide Frustum<T>::Intersect(const Box<T>& box) const
{ {
// http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/ // http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/
IntersectionSide side = IntersectionSide_Inside; 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)) if (m_planes[i].Distance(box.GetPositiveVertex(m_planes[i].normal)) < F(0.0))
return IntersectionSide_Outside; return IntersectionSide_Outside;
@ -421,19 +552,33 @@ namespace Nz
return side; 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<typename T> template<typename T>
IntersectionSide Frustum<T>::Intersect(const OrientedBox<T>& orientedbox) const IntersectionSide Frustum<T>::Intersect(const OrientedBox<T>& orientedbox) const
{ {
return Intersect(&orientedbox[0], 8); 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<typename T> template<typename T>
IntersectionSide Frustum<T>::Intersect(const Sphere<T>& sphere) const IntersectionSide Frustum<T>::Intersect(const Sphere<T>& sphere) const
{ {
// http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-points-and-spheres/ // http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-points-and-spheres/
IntersectionSide side = IntersectionSide_Inside; 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()); T distance = m_planes[i].Distance(sphere.GetPosition());
if (distance < -sphere.radius) if (distance < -sphere.radius)
@ -445,6 +590,14 @@ namespace Nz
return side; 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<typename T> template<typename T>
IntersectionSide Frustum<T>::Intersect(const Vector3<T>* points, unsigned int pointCount) const IntersectionSide Frustum<T>::Intersect(const Vector3<T>* points, unsigned int pointCount) const
{ {
@ -468,6 +621,13 @@ namespace Nz
return (c == 6) ? IntersectionSide_Inside : IntersectionSide_Intersecting; 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<typename T> template<typename T>
Frustum<T>& Frustum<T>::Set(const Frustum& frustum) Frustum<T>& Frustum<T>::Set(const Frustum& frustum)
{ {
@ -476,6 +636,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
template<typename U> template<typename U>
Frustum<T>& Frustum<T>::Set(const Frustum<U>& frustum) Frustum<T>& Frustum<T>::Set(const Frustum<U>& frustum)
@ -489,20 +656,33 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Gives a string representation
* \return A string representation of the object: "Frustum(Plane ...)"
*/
template<typename T> template<typename T>
String Frustum<T>::ToString() const String Frustum<T>::ToString() const
{ {
StringStream ss; StringStream ss;
return ss << "Frustum(Bottom: " << m_planes[FrustumPlane_Bottom].ToString() << "\n" return ss << "Frustum(Bottom: " << m_planes[FrustumPlane_Bottom].ToString() << "\n"
<< " Far: " << m_planes[FrustumPlane_Far].ToString() << "\n" << " Far: " << m_planes[FrustumPlane_Far].ToString() << "\n"
<< " Left: " << m_planes[FrustumPlane_Left].ToString() << "\n" << " Left: " << m_planes[FrustumPlane_Left].ToString() << "\n"
<< " Near: " << m_planes[FrustumPlane_Near].ToString() << "\n" << " Near: " << m_planes[FrustumPlane_Near].ToString() << "\n"
<< " Right: " << m_planes[FrustumPlane_Right].ToString() << "\n" << " Right: " << m_planes[FrustumPlane_Right].ToString() << "\n"
<< " Top: " << m_planes[FrustumPlane_Top].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<typename T> template<typename T>
std::ostream& operator<<(std::ostream& out, const Nz::Frustum<T>& frustum) std::ostream& operator<<(std::ostream& out, const Nz::Frustum<T>& frustum)
{ {

View File

@ -26,9 +26,9 @@ namespace Nz
public: public:
Matrix4() = default; Matrix4() = default;
Matrix4(T r11, T r12, T r13, T r14, Matrix4(T r11, T r12, T r13, T r14,
T r21, T r22, T r23, T r24, T r21, T r22, T r23, T r24,
T r31, T r32, T r33, T r34, T r31, T r32, T r33, T r34,
T r41, T r42, T r43, T r44); T r41, T r42, T r43, T r44);
//Matrix4(const Matrix3<T>& matrix); //Matrix4(const Matrix3<T>& matrix);
Matrix4(const T matrix[16]); Matrix4(const T matrix[16]);
template<typename U> explicit Matrix4(const Matrix4<U>& matrix); template<typename U> explicit Matrix4(const Matrix4<U>& matrix);
@ -77,9 +77,9 @@ namespace Nz
Matrix4& MakeZero(); Matrix4& MakeZero();
Matrix4& Set(T r11, T r12, T r13, T r14, Matrix4& Set(T r11, T r12, T r13, T r14,
T r21, T r22, T r23, T r24, T r21, T r22, T r23, T r24,
T r31, T r32, T r33, T r34, T r31, T r32, T r33, T r34,
T r41, T r42, T r43, T r44); T r41, T r42, T r43, T r44);
Matrix4& Set(const T matrix[16]); Matrix4& Set(const T matrix[16]);
//Matrix4(const Matrix3<T>& matrix); //Matrix4(const Matrix3<T>& matrix);
Matrix4& Set(const Matrix4& matrix); Matrix4& Set(const Matrix4& matrix);
@ -96,8 +96,8 @@ namespace Nz
Matrix4& Transpose(); Matrix4& Transpose();
operator T*(); operator T* ();
operator const T*() const; operator const T* () const;
T& operator()(unsigned int x, unsigned int y); T& operator()(unsigned int x, unsigned int y);
T operator()(unsigned int x, unsigned int y) const; T operator()(unsigned int x, unsigned int y) const;
@ -131,9 +131,9 @@ namespace Nz
static Matrix4 Zero(); static Matrix4 Zero();
T m11, m12, m13, m14, T m11, m12, m13, m14,
m21, m22, m23, m24, m21, m22, m23, m24,
m31, m32, m33, m34, m31, m32, m33, m34,
m41, m42, m43, m44; m41, m42, m43, m44;
}; };
typedef Matrix4<double> Matrix4d; typedef Matrix4<double> Matrix4d;

File diff suppressed because it is too large Load Diff

View File

@ -43,8 +43,8 @@ namespace Nz
void Update(const Matrix4<T>& transformMatrix); void Update(const Matrix4<T>& transformMatrix);
void Update(const Vector3<T>& transformMatrix); void Update(const Vector3<T>& transformMatrix);
operator Vector3<T>*(); operator Vector3<T>* ();
operator const Vector3<T>*() const; operator const Vector3<T>* () const;
Vector3<T>& operator()(unsigned int i); Vector3<T>& operator()(unsigned int i);
Vector3<T> operator()(unsigned int i) const; Vector3<T> operator()(unsigned int i) const;

View File

@ -13,24 +13,62 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::OrientedBox<T>
* \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<T> 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<typename T> template<typename T>
OrientedBox<T>::OrientedBox(T X, T Y, T Z, T Width, T Height, T Depth) OrientedBox<T>::OrientedBox(T X, T Y, T Z, T Width, T Height, T Depth)
{ {
Set(X, Y, Z, Width, Height, Depth); Set(X, Y, Z, Width, Height, Depth);
} }
/*!
* \brief Constructs a OrientedBox<T> object from a box
*
* \param box Box<T> object
*/
template<typename T> template<typename T>
OrientedBox<T>::OrientedBox(const Box<T>& box) OrientedBox<T>::OrientedBox(const Box<T>& box)
{ {
Set(box); Set(box);
} }
/*!
* \brief Constructs a OrientedBox<T> 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<typename T> template<typename T>
OrientedBox<T>::OrientedBox(const Vector3<T>& vec1, const Vector3<T>& vec2) OrientedBox<T>::OrientedBox(const Vector3<T>& vec1, const Vector3<T>& vec2)
{ {
Set(vec1, vec2); Set(vec1, vec2);
} }
/*!
* \brief Constructs a OrientedBox<T> object from another type of OrientedBox
*
* \param orientedBox OrientedBox of type U to convert to type T
*/
template<typename T> template<typename T>
template<typename U> template<typename U>
OrientedBox<T>::OrientedBox(const OrientedBox<U>& orientedBox) OrientedBox<T>::OrientedBox(const OrientedBox<U>& orientedBox)
@ -38,6 +76,15 @@ namespace Nz
Set(orientedBox); 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<typename T> template<typename T>
const Vector3<T>& OrientedBox<T>::GetCorner(BoxCorner corner) const const Vector3<T>& OrientedBox<T>::GetCorner(BoxCorner corner) const
{ {
@ -54,12 +101,24 @@ namespace Nz
return m_corners[corner]; 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<typename T> template<typename T>
bool OrientedBox<T>::IsValid() const bool OrientedBox<T>::IsValid() const
{ {
return localBox.IsValid(); 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<typename T> template<typename T>
OrientedBox<T>& OrientedBox<T>::MakeZero() OrientedBox<T>& OrientedBox<T>::MakeZero()
{ {
@ -68,6 +127,18 @@ namespace Nz
return *this; 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<typename T> template<typename T>
OrientedBox<T>& OrientedBox<T>::Set(T X, T Y, T Z, T Width, T Height, T Depth) OrientedBox<T>& OrientedBox<T>::Set(T X, T Y, T Z, T Width, T Height, T Depth)
{ {
@ -76,6 +147,13 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Sets the components of the oriented box from a box
* \return A reference to this oriented box
*
* \param box Box<T> object
*/
template<typename T> template<typename T>
OrientedBox<T>& OrientedBox<T>::Set(const Box<T>& box) OrientedBox<T>& OrientedBox<T>::Set(const Box<T>& box)
{ {
@ -84,6 +162,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
OrientedBox<T>& OrientedBox<T>::Set(const OrientedBox& orientedBox) OrientedBox<T>& OrientedBox<T>::Set(const OrientedBox& orientedBox)
{ {
@ -92,6 +177,14 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Sets a OrientedBox<T> 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<typename T> template<typename T>
OrientedBox<T>& OrientedBox<T>::Set(const Vector3<T>& vec1, const Vector3<T>& vec2) OrientedBox<T>& OrientedBox<T>::Set(const Vector3<T>& vec1, const Vector3<T>& vec2)
{ {
@ -100,6 +193,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
template<typename U> template<typename U>
OrientedBox<T>& OrientedBox<T>::Set(const OrientedBox<U>& orientedBox) OrientedBox<T>& OrientedBox<T>::Set(const OrientedBox<U>& orientedBox)
@ -112,21 +212,32 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Gives a string representation
* \return A string representation of the object: "OrientedBox(...)"
*/
template<typename T> template<typename T>
String OrientedBox<T>::ToString() const String OrientedBox<T>::ToString() const
{ {
StringStream ss; StringStream ss;
return ss << "OrientedBox(FLB: " << m_corners[BoxCorner_FarLeftBottom].ToString() << "\n" return ss << "OrientedBox(FLB: " << m_corners[BoxCorner_FarLeftBottom].ToString() << "\n"
<< " FLT: " << m_corners[BoxCorner_FarLeftTop].ToString() << "\n" << " FLT: " << m_corners[BoxCorner_FarLeftTop].ToString() << "\n"
<< " FRB: " << m_corners[BoxCorner_FarRightBottom].ToString() << "\n" << " FRB: " << m_corners[BoxCorner_FarRightBottom].ToString() << "\n"
<< " FRT: " << m_corners[BoxCorner_FarRightTop].ToString() << "\n" << " FRT: " << m_corners[BoxCorner_FarRightTop].ToString() << "\n"
<< " NLB: " << m_corners[BoxCorner_NearLeftBottom].ToString() << "\n" << " NLB: " << m_corners[BoxCorner_NearLeftBottom].ToString() << "\n"
<< " NLT: " << m_corners[BoxCorner_NearLeftTop].ToString() << "\n" << " NLT: " << m_corners[BoxCorner_NearLeftTop].ToString() << "\n"
<< " NRB: " << m_corners[BoxCorner_NearRightBottom].ToString() << "\n" << " NRB: " << m_corners[BoxCorner_NearRightBottom].ToString() << "\n"
<< " NRT: " << m_corners[BoxCorner_NearRightTop].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<typename T> template<typename T>
void OrientedBox<T>::Update(const Matrix4<T>& transformMatrix) void OrientedBox<T>::Update(const Matrix4<T>& transformMatrix)
{ {
@ -134,6 +245,12 @@ namespace Nz
m_corners[i] = transformMatrix.Transform(localBox.GetCorner(static_cast<BoxCorner>(i))); m_corners[i] = transformMatrix.Transform(localBox.GetCorner(static_cast<BoxCorner>(i)));
} }
/*!
* \brief Updates the corners of the box
*
* \param translation Vector3 which represents the translation to apply on the local box
*/
template<typename T> template<typename T>
void OrientedBox<T>::Update(const Vector3<T>& translation) void OrientedBox<T>::Update(const Vector3<T>& translation)
{ {
@ -141,18 +258,40 @@ namespace Nz
m_corners[i] = localBox.GetCorner(static_cast<BoxCorner>(i)) + translation; m_corners[i] = localBox.GetCorner(static_cast<BoxCorner>(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<typename T> template<typename T>
OrientedBox<T>::operator Vector3<T>*() OrientedBox<T>::operator Vector3<T>* ()
{ {
return &m_corners[0]; 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<typename T> template<typename T>
OrientedBox<T>::operator const Vector3<T>*() const OrientedBox<T>::operator const Vector3<T>* () const
{ {
return &m_corners[0]; 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<typename T> template<typename T>
Vector3<T>& OrientedBox<T>::operator()(unsigned int i) Vector3<T>& OrientedBox<T>::operator()(unsigned int i)
{ {
@ -170,6 +309,14 @@ namespace Nz
return m_corners[i]; 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<typename T> template<typename T>
Vector3<T> OrientedBox<T>::operator()(unsigned int i) const Vector3<T> OrientedBox<T>::operator()(unsigned int i) const
{ {
@ -187,6 +334,13 @@ namespace Nz
return m_corners[i]; 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<typename T> template<typename T>
OrientedBox<T> OrientedBox<T>::operator*(T scalar) const OrientedBox<T> OrientedBox<T>::operator*(T scalar) const
{ {
@ -196,6 +350,13 @@ namespace Nz
return box; 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<typename T> template<typename T>
OrientedBox<T>& OrientedBox<T>::operator*=(T scalar) OrientedBox<T>& OrientedBox<T>::operator*=(T scalar)
{ {
@ -204,18 +365,46 @@ namespace Nz
return *this; 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<typename T> template<typename T>
bool OrientedBox<T>::operator==(const OrientedBox& box) const bool OrientedBox<T>::operator==(const OrientedBox& box) const
{ {
return localBox == box.localBox; 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<typename T> template<typename T>
bool OrientedBox<T>::operator!=(const OrientedBox& box) const bool OrientedBox<T>::operator!=(const OrientedBox& box) const
{ {
return !operator==(box); 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<typename T> template<typename T>
OrientedBox<T> OrientedBox<T>::Lerp(const OrientedBox& from, const OrientedBox& to, T interpolation) OrientedBox<T> OrientedBox<T>::Lerp(const OrientedBox& from, const OrientedBox& to, T interpolation)
{ {
@ -225,6 +414,13 @@ namespace Nz
return orientedBox; 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<typename T> template<typename T>
OrientedBox<T> OrientedBox<T>::Zero() OrientedBox<T> OrientedBox<T>::Zero()
{ {
@ -235,6 +431,14 @@ namespace Nz
} }
} }
/*!
* \brief Output operator
* \return The stream
*
* \param out The stream
* \param orientedBox The orientedBox to output
*/
template<typename T> template<typename T>
std::ostream& operator<<(std::ostream& out, const Nz::OrientedBox<T>& orientedBox) std::ostream& operator<<(std::ostream& out, const Nz::OrientedBox<T>& orientedBox)
{ {

View File

@ -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" // This file is part of the "Nazara Engine - Mathematics module"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
@ -26,8 +26,12 @@ namespace Nz
Plane(const Plane& plane) = default; Plane(const Plane& plane) = default;
~Plane() = default; ~Plane() = default;
T Distance(const Vector3<T>& point) const;
T Distance(T x, T y, T z) const; T Distance(T x, T y, T z) const;
T Distance(const Vector3<T>& point) const;
Plane& MakeXY();
Plane& MakeXZ();
Plane& MakeYZ();
Plane& Set(T normalX, T normalY, T normalZ, T Distance); Plane& Set(T normalX, T normalY, T normalZ, T Distance);
Plane& Set(const T plane[4]); Plane& Set(const T plane[4]);

View File

@ -11,36 +11,88 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::Vector4<T>
* \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<T> 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<typename T> template<typename T>
Plane<T>::Plane(T normalX, T normalY, T normalZ, T D) Plane<T>::Plane(T normalX, T normalY, T normalZ, T D)
{ {
Set(normalX, normalY, normalZ, D); Set(normalX, normalY, normalZ, D);
} }
/*!
* \brief Constructs a Plane<T> 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<typename T> template<typename T>
Plane<T>::Plane(const T plane[4]) Plane<T>::Plane(const T plane[4])
{ {
Set(plane); Set(plane);
} }
/*!
* \brief Constructs a Plane<T> object from a normal and a distance
*
* \param Normal normal of the vector
* \param D Distance to origin
*/
template<typename T> template<typename T>
Plane<T>::Plane(const Vector3<T>& Normal, T D) Plane<T>::Plane(const Vector3<T>& Normal, T D)
{ {
Set(Normal, D); Set(Normal, D);
} }
/*!
* \brief Constructs a Plane<T> object from a normal and a point
*
* \param Normal Normal of the plane
* \param point Point which verifies the equation of the plane
*/
template<typename T> template<typename T>
Plane<T>::Plane(const Vector3<T>& Normal, const Vector3<T>& point) Plane<T>::Plane(const Vector3<T>& Normal, const Vector3<T>& point)
{ {
Set(Normal, point); Set(Normal, point);
} }
/*!
* \brief Constructs a Plane<T> 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<typename T> template<typename T>
Plane<T>::Plane(const Vector3<T>& point1, const Vector3<T>& point2, const Vector3<T>& point3) Plane<T>::Plane(const Vector3<T>& point1, const Vector3<T>& point2, const Vector3<T>& point3)
{ {
Set(point1, point2, point3); Set(point1, point2, point3);
} }
/*!
* \brief Constructs a Plane<T> object from another type of Plane
*
* \param plane Plane of type U to convert to type T
*/
template<typename T> template<typename T>
template<typename U> template<typename U>
Plane<T>::Plane(const Plane<U>& plane) Plane<T>::Plane(const Plane<U>& plane)
@ -48,11 +100,18 @@ namespace Nz
Set(plane); Set(plane);
} }
template<typename T> /*!
T Plane<T>::Distance(const Vector3<T>& point) const * \brief Returns the distance from the plane to the point
{ * \return Distance to the point
return normal.DotProduct(point) - distance; // ax + by + cd - d = 0. *
} * \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<typename T> template<typename T>
T Plane<T>::Distance(T x, T y, T z) const T Plane<T>::Distance(T x, T y, T z) const
@ -60,6 +119,72 @@ namespace Nz
return Distance(Vector3<T>(x, y, z)); return Distance(Vector3<T>(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<typename T>
T Plane<T>::Distance(const Vector3<T>& 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<typename T>
Plane<T>& Plane<T>::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<typename T>
Plane<T>& Plane<T>::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<typename T>
Plane<T>& Plane<T>::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<typename T> template<typename T>
Plane<T>& Plane<T>::Set(T normalX, T normalY, T normalZ, T D) Plane<T>& Plane<T>::Set(T normalX, T normalY, T normalZ, T D)
{ {
@ -69,6 +194,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Plane<T>& Plane<T>::Set(const T plane[4]) Plane<T>& Plane<T>::Set(const T plane[4])
{ {
@ -78,6 +210,13 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Sets the components of the plane from another plane
* \return A reference to this plane
*
* \param plane The other plane
*/
template<typename T> template<typename T>
Plane<T>& Plane<T>::Set(const Plane& plane) Plane<T>& Plane<T>::Set(const Plane& plane)
{ {
@ -86,6 +225,14 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Plane<T>& Plane<T>::Set(const Vector3<T>& Normal, T D) Plane<T>& Plane<T>::Set(const Vector3<T>& Normal, T D)
{ {
@ -95,6 +242,14 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Plane<T>& Plane<T>::Set(const Vector3<T>& Normal, const Vector3<T>& point) Plane<T>& Plane<T>::Set(const Vector3<T>& Normal, const Vector3<T>& point)
{ {
@ -104,6 +259,17 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Plane<T>& Plane<T>::Set(const Vector3<T>& point1, const Vector3<T>& point2, const Vector3<T>& point3) Plane<T>& Plane<T>::Set(const Vector3<T>& point1, const Vector3<T>& point2, const Vector3<T>& point3)
{ {
@ -117,6 +283,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
template<typename U> template<typename U>
Plane<T>& Plane<T>::Set(const Plane<U>& plane) Plane<T>& Plane<T>::Set(const Plane<U>& plane)
@ -127,6 +300,11 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Gives a string representation
* \return A string representation of the object: "Plane(Normal: Vector3(x, y, z); Distance: w)"
*/
template<typename T> template<typename T>
String Plane<T>::ToString() const String Plane<T>::ToString() const
{ {
@ -135,18 +313,50 @@ namespace Nz
return ss << "Plane(Normal: " << normal.ToString() << "; Distance: " << distance << ')'; 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<typename T> template<typename T>
bool Plane<T>::operator==(const Plane& plane) const bool Plane<T>::operator==(const Plane& plane) const
{ {
return (normal == plane.normal && NumberEquals(distance, plane.distance)) || (normal == -plane.normal && NumberEquals(distance, -plane.distance)); 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<typename T> template<typename T>
bool Plane<T>::operator!=(const Plane& plane) const bool Plane<T>::operator!=(const Plane& plane) const
{ {
return !operator==(plane); 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<typename T> template<typename T>
Plane<T> Plane<T>::Lerp(const Plane& from, const Plane& to, T interpolation) Plane<T> Plane<T>::Lerp(const Plane& from, const Plane& to, T interpolation)
{ {
@ -159,32 +369,70 @@ namespace Nz
#endif #endif
Plane plane; Plane plane;
plane.distance = Lerp(from.distance, to.distance, interpolation); plane.distance = Nz::Lerp(from.distance, to.distance, interpolation);
plane.normal = Vector3<T>::Lerp(from.normal, to.normal, interpolation); plane.normal = Vector3<T>::Lerp(from.normal, to.normal, interpolation);
plane.normal.Normalize(); plane.normal.Normalize();
return plane; return plane;
} }
/*!
* \brief Shorthand for the plane (0, 0, 1, 0)
* \return A plane with components (0, 0, 1, 0)
*
* \see MakeXY
*/
template<typename T> template<typename T>
Plane<T> Plane<T>::XY() Plane<T> Plane<T>::XY()
{ {
return Plane<T>(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<typename T> template<typename T>
Plane<T> Plane<T>::XZ() Plane<T> Plane<T>::XZ()
{ {
return Plane<T>(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<typename T> template<typename T>
Plane<T> Plane<T>::YZ() Plane<T> Plane<T>::YZ()
{ {
return Plane<T>(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<typename T> template<typename T>
std::ostream& operator<<(std::ostream& out, const Nz::Plane<T>& plane) std::ostream& operator<<(std::ostream& out, const Nz::Plane<T>& plane)
{ {

View File

@ -19,9 +19,9 @@ namespace Nz
public: public:
Quaternion() = default; Quaternion() = default;
Quaternion(T W, T X, T Y, T Z); Quaternion(T W, T X, T Y, T Z);
Quaternion(const T quat[4]);
Quaternion(T angle, const Vector3<T>& axis);
Quaternion(const EulerAngles<T>& angles); Quaternion(const EulerAngles<T>& angles);
Quaternion(T angle, const Vector3<T>& axis);
Quaternion(const T quat[4]);
//Quaternion(const Matrix3<T>& mat); //Quaternion(const Matrix3<T>& mat);
template<typename U> explicit Quaternion(const Quaternion<U>& quat); template<typename U> explicit Quaternion(const Quaternion<U>& quat);
Quaternion(const Quaternion& quat) = default; Quaternion(const Quaternion& quat) = default;
@ -47,9 +47,9 @@ namespace Nz
Quaternion& Normalize(T* length = nullptr); Quaternion& Normalize(T* length = nullptr);
Quaternion& Set(T W, T X, T Y, T Z); Quaternion& Set(T W, T X, T Y, T Z);
Quaternion& Set(const T quat[4]);
Quaternion& Set(T angle, const Vector3<T>& normalizedAxis);
Quaternion& Set(const EulerAngles<T>& angles); Quaternion& Set(const EulerAngles<T>& angles);
Quaternion& Set(T angle, const Vector3<T>& normalizedAxis);
Quaternion& Set(const T quat[4]);
//Quaternion& Set(const Matrix3<T>& mat); //Quaternion& Set(const Matrix3<T>& mat);
Quaternion& Set(const Quaternion& quat); Quaternion& Set(const Quaternion& quat);
template<typename U> Quaternion& Set(const Quaternion<U>& quat); template<typename U> Quaternion& Set(const Quaternion<U>& quat);
@ -60,7 +60,7 @@ namespace Nz
//Matrix3<T> ToRotationMatrix() const; //Matrix3<T> ToRotationMatrix() const;
String ToString() 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;
Quaternion operator*(const Quaternion& quat) const; Quaternion operator*(const Quaternion& quat) const;

View File

@ -15,29 +15,67 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::Quaternion<T>
* \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<T> object from its components
*
* \param W W component
* \param X X component
* \param Y Y component
* \param Z Z component
*/
template<typename T> template<typename T>
Quaternion<T>::Quaternion(T W, T X, T Y, T Z) Quaternion<T>::Quaternion(T W, T X, T Y, T Z)
{ {
Set(W, X, Y, Z); Set(W, X, Y, Z);
} }
/*!
* \brief Constructs a Quaternion<T> object from a EulerAngles
*
* \param angles Easier representation of rotation of space
*
* \see EulerAngles
*/
template<typename T> template<typename T>
Quaternion<T>::Quaternion(const T quat[4]) Quaternion<T>::Quaternion(const EulerAngles<T>& angles)
{ {
Set(quat); Set(angles);
} }
/*!
* \brief Constructs a Quaternion<T> 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<typename T> template<typename T>
Quaternion<T>::Quaternion(T angle, const Vector3<T>& axis) Quaternion<T>::Quaternion(T angle, const Vector3<T>& axis)
{ {
Set(angle, axis); Set(angle, axis);
} }
/*!
* \brief Constructs a Quaternion<T> 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<typename T> template<typename T>
Quaternion<T>::Quaternion(const EulerAngles<T>& angles) Quaternion<T>::Quaternion(const T quat[4])
{ {
Set(angles); Set(quat);
} }
/* /*
template<typename T> template<typename T>
Quaternion<T>::Quaternion(const Matrix3<T>& mat) Quaternion<T>::Quaternion(const Matrix3<T>& mat)
@ -45,6 +83,13 @@ namespace Nz
Set(mat); Set(mat);
} }
*/ */
/*!
* \brief Constructs a Quaternion<T> object from another type of Quaternion
*
* \param quat Quaternion of type U to convert to type T
*/
template<typename T> template<typename T>
template<typename U> template<typename U>
Quaternion<T>::Quaternion(const Quaternion<U>& quat) Quaternion<T>::Quaternion(const Quaternion<U>& quat)
@ -52,6 +97,11 @@ namespace Nz
Set(quat); Set(quat);
} }
/*!
* \brief Computes the w component of the quaternion to make it unit
* \return A reference to this quaternion
*/
template<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::ComputeW() Quaternion<T>& Quaternion<T>::ComputeW()
{ {
@ -65,6 +115,15 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::Conjugate() Quaternion<T>& Quaternion<T>::Conjugate()
{ {
@ -75,12 +134,28 @@ namespace Nz
return *this; 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<typename T> template<typename T>
T Quaternion<T>::DotProduct(const Quaternion& quat) const T Quaternion<T>::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<typename T> template<typename T>
Quaternion<T> Quaternion<T>::GetConjugate() const Quaternion<T> Quaternion<T>::GetConjugate() const
{ {
@ -90,6 +165,15 @@ namespace Nz
return quat; 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<typename T> template<typename T>
Quaternion<T> Quaternion<T>::GetInverse() const Quaternion<T> Quaternion<T>::GetInverse() const
{ {
@ -99,6 +183,17 @@ namespace Nz
return quat; 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<typename T> template<typename T>
Quaternion<T> Quaternion<T>::GetNormal(T* length) const Quaternion<T> Quaternion<T>::GetNormal(T* length) const
{ {
@ -108,6 +203,15 @@ namespace Nz
return quat; 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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::Inverse() Quaternion<T>& Quaternion<T>::Inverse()
{ {
@ -125,15 +229,34 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::MakeIdentity() Quaternion<T>& Quaternion<T>::MakeIdentity()
{ {
return Set(F(1.0), F(0.0), F(0.0), F(0.0)); 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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::MakeRotationBetween(const Vector3<T>& from, const Vector3<T>& to) Quaternion<T>& Quaternion<T>::MakeRotationBetween(const Vector3<T>& from, const Vector3<T>& to)
{ {
// TODO (Gawaboumga): Replace by http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors ?
T dot = from.DotProduct(to); T dot = from.DotProduct(to);
if (NumberEquals(dot, F(-1.0))) 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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::MakeZero() Quaternion<T>& Quaternion<T>::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(0.0));
} }
/*!
* \brief Calculates the magnitude (length) of the quaternion
* \return The magnitude
*
* \see SquaredMagnitude
*/
template<typename T> template<typename T>
T Quaternion<T>::Magnitude() const T Quaternion<T>::Magnitude() const
{ {
return std::sqrt(SquaredMagnitude()); 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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::Normalize(T* length) Quaternion<T>& Quaternion<T>::Normalize(T* length)
{ {
T norm = std::sqrt(SquaredMagnitude()); T norm = std::sqrt(SquaredMagnitude());
T invNorm = F(1.0) / norm; if (norm > F(0.0))
{
w *= invNorm; T invNorm = F(1.0) / norm;
x *= invNorm; w *= invNorm;
y *= invNorm; x *= invNorm;
z *= invNorm; y *= invNorm;
z *= invNorm;
}
if (length) if (length)
*length = norm; *length = norm;
@ -186,6 +336,16 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::Set(T W, T X, T Y, T Z) Quaternion<T>& Quaternion<T>::Set(T W, T X, T Y, T Z)
{ {
@ -197,17 +357,29 @@ namespace Nz
return *this; return *this;
} }
template<typename T> /*!
Quaternion<T>& Quaternion<T>::Set(const T quat[4]) * \brief Sets this quaternion from rotation specified by Euler angle
{ * \return A reference to this quaternion
w = quat[0]; *
x = quat[1]; * \param angles Easier representation of rotation of space
y = quat[2]; *
z = quat[3]; * \see EulerAngles
*/
return *this; template<typename T>
Quaternion<T>& Quaternion<T>::Set(const EulerAngles<T>& 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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::Set(T angle, const Vector3<T>& axis) Quaternion<T>& Quaternion<T>::Set(T angle, const Vector3<T>& axis)
{ {
@ -229,12 +401,46 @@ namespace Nz
return Normalize(); 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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::Set(const EulerAngles<T>& angles) Quaternion<T>& Quaternion<T>::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<typename T>
Quaternion<T>& Quaternion<T>::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<typename T> template<typename T>
template<typename U> template<typename U>
Quaternion<T>& Quaternion<T>::Set(const Quaternion<U>& quat) Quaternion<T>& Quaternion<T>::Set(const Quaternion<U>& quat)
@ -247,36 +453,48 @@ namespace Nz
return *this; return *this;
} }
template<typename T> /*!
Quaternion<T>& Quaternion<T>::Set(const Quaternion& quat) * \brief Calculates the squared magnitude (length) of the quaternion
{ * \return The squared magnitude
std::memcpy(this, &quat, sizeof(Quaternion)); *
* \see Magnitude
return *this; */
}
template<typename T> template<typename T>
T Quaternion<T>::SquaredMagnitude() const T Quaternion<T>::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<typename T> template<typename T>
EulerAngles<T> Quaternion<T>::ToEulerAngles() const EulerAngles<T> Quaternion<T>::ToEulerAngles() const
{ {
T test = x*y + z*w; T test = x * y + z * w;
if (test > F(0.499)) if (test > F(0.499))
// singularity at north pole // singularity at north pole
return EulerAngles<T>(FromDegrees(F(90.0)), FromRadians(F(2.0) * std::atan2(x, w)), F(0.0)); return EulerAngles<T>(FromDegrees(F(90.0)), FromRadians(F(2.0) * std::atan2(x, w)), F(0.0));
if (test < F(-0.499)) if (test < F(-0.499))
// singularity at south pole
return EulerAngles<T>(FromDegrees(F(-90.0)), FromRadians(F(-2.0) * std::atan2(x, w)), F(0.0)); return EulerAngles<T>(FromDegrees(F(-90.0)), FromRadians(F(-2.0) * std::atan2(x, w)), F(0.0));
return EulerAngles<T>(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)), return EulerAngles<T>(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::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))); 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<typename T> template<typename T>
String Quaternion<T>::ToString() const String Quaternion<T>::ToString() const
{ {
@ -285,11 +503,12 @@ namespace Nz
return ss << "Quaternion(" << w << " | " << x << ", " << y << ", " << z << ')'; return ss << "Quaternion(" << w << " | " << x << ", " << y << ", " << z << ')';
} }
template<typename T> /*!
Quaternion<T>& Quaternion<T>::operator=(const Quaternion& 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
return Set(quat); *
} * \param quat The other quaternion to add components with
*/
template<typename T> template<typename T>
Quaternion<T> Quaternion<T>::operator+(const Quaternion& quat) const Quaternion<T> Quaternion<T>::operator+(const Quaternion& quat) const
@ -303,18 +522,32 @@ namespace Nz
return result; 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<typename T> template<typename T>
Quaternion<T> Quaternion<T>::operator*(const Quaternion& quat) const Quaternion<T> Quaternion<T>::operator*(const Quaternion& quat) const
{ {
Quaternion result; Quaternion result;
result.w = w*quat.w - x*quat.x - y*quat.y - z*quat.z; 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.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.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.z = w * quat.z + z * quat.w + x * quat.y - y * quat.x;
return result; 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<typename T> template<typename T>
Vector3<T> Quaternion<T>::operator*(const Vector3<T>& vec) const Vector3<T> Quaternion<T>::operator*(const Vector3<T>& vec) const
{ {
@ -327,60 +560,123 @@ namespace Nz
return vec + uv + uuv; 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<typename T> template<typename T>
Quaternion<T> Quaternion<T>::operator*(T scale) const Quaternion<T> Quaternion<T>::operator*(T scale) const
{ {
return Quaternion(w * scale, return Quaternion(w * scale,
x * scale, x * scale,
y * scale, y * scale,
z * 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<typename T> template<typename T>
Quaternion<T> Quaternion<T>::operator/(const Quaternion& quat) const Quaternion<T> Quaternion<T>::operator/(const Quaternion& quat) const
{ {
return quat.GetConjugate() * (*this); 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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::operator+=(const Quaternion& quat) Quaternion<T>& Quaternion<T>::operator+=(const Quaternion& quat)
{ {
return operator=(operator+(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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::operator*=(const Quaternion& quat) Quaternion<T>& Quaternion<T>::operator*=(const Quaternion& quat)
{ {
return operator=(operator*(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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::operator*=(T scale) Quaternion<T>& Quaternion<T>::operator*=(T scale)
{ {
return operator=(operator*(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<typename T> template<typename T>
Quaternion<T>& Quaternion<T>::operator/=(const Quaternion& quat) Quaternion<T>& Quaternion<T>::operator/=(const Quaternion& quat)
{ {
return operator=(operator/(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<typename T> template<typename T>
bool Quaternion<T>::operator==(const Quaternion& quat) const bool Quaternion<T>::operator==(const Quaternion& quat) const
{ {
return NumberEquals(w, quat.w) && return NumberEquals(w, quat.w) &&
NumberEquals(x, quat.x) && NumberEquals(x, quat.x) &&
NumberEquals(y, quat.y) && NumberEquals(y, quat.y) &&
NumberEquals(z, quat.z); 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<typename T> template<typename T>
bool Quaternion<T>::operator!=(const Quaternion& quat) const bool Quaternion<T>::operator!=(const Quaternion& quat) const
{ {
return !operator==(quat); return !operator==(quat);
} }
/*!
* \brief Shorthand for the quaternion (1, 0, 0, 0)
* \return A quaternion with components (1, 0, 0, 0)
*
* \see MakeIdentity
*/
template<typename T> template<typename T>
Quaternion<T> Quaternion<T>::Identity() Quaternion<T> Quaternion<T>::Identity()
{ {
@ -390,6 +686,20 @@ namespace Nz
return quaternion; 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<typename T> template<typename T>
Quaternion<T> Quaternion<T>::Lerp(const Quaternion& from, const Quaternion& to, T interpolation) Quaternion<T> Quaternion<T>::Lerp(const Quaternion& from, const Quaternion& to, T interpolation)
{ {
@ -410,12 +720,32 @@ namespace Nz
return interpolated; 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<typename T> template<typename T>
Quaternion<T> Quaternion<T>::Normalize(const Quaternion& quat, T* length) Quaternion<T> Quaternion<T>::Normalize(const Quaternion& quat, T* length)
{ {
return quat.GetNormal(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<typename T> template<typename T>
Quaternion<T> Quaternion<T>::RotationBetween(const Vector3<T>& from, const Vector3<T>& to) Quaternion<T> Quaternion<T>::RotationBetween(const Vector3<T>& from, const Vector3<T>& to)
{ {
@ -425,6 +755,20 @@ namespace Nz
return quaternion; 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<typename T> template<typename T>
Quaternion<T> Quaternion<T>::Slerp(const Quaternion& from, const Quaternion& to, T interpolation) Quaternion<T> Quaternion<T>::Slerp(const Quaternion& from, const Quaternion& to, T interpolation)
{ {
@ -441,7 +785,7 @@ namespace Nz
T cosOmega = from.DotProduct(to); T cosOmega = from.DotProduct(to);
if (cosOmega < F(0.0)) if (cosOmega < F(0.0))
{ {
// On inverse tout // We invert everything
q.Set(-to.w, -to.x, -to.y, -to.z); q.Set(-to.w, -to.x, -to.y, -to.z);
cosOmega = -cosOmega; cosOmega = -cosOmega;
} }
@ -451,7 +795,7 @@ namespace Nz
T k0, k1; T k0, k1;
if (cosOmega > F(0.9999)) 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; k0 = F(1.0) - interpolation;
k1 = interpolation; k1 = interpolation;
} }
@ -460,7 +804,7 @@ namespace Nz
T sinOmega = std::sqrt(F(1.0) - cosOmega*cosOmega); T sinOmega = std::sqrt(F(1.0) - cosOmega*cosOmega);
T omega = std::atan2(sinOmega, cosOmega); T omega = std::atan2(sinOmega, cosOmega);
// Pour éviter deux divisions // To avoid two divisions
sinOmega = F(1.0)/sinOmega; sinOmega = F(1.0)/sinOmega;
k0 = std::sin((F(1.0) - interpolation) * omega) * 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); 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<typename T> template<typename T>
Quaternion<T> Quaternion<T>::Zero() Quaternion<T> Quaternion<T>::Zero()
{ {
@ -481,6 +832,14 @@ namespace Nz
} }
} }
/*!
* \brief Output operator
* \return The stream
*
* \param out The stream
* \param quat The quaternion to output
*/
template<typename T> template<typename T>
std::ostream& operator<<(std::ostream& out, const Nz::Quaternion<T>& quat) std::ostream& operator<<(std::ostream& out, const Nz::Quaternion<T>& quat)
{ {

View File

@ -24,9 +24,9 @@ namespace Nz
public: public:
Ray() = default; Ray() = default;
Ray(T X, T Y, T Z, T directionX, T directionY, T directionZ); Ray(T X, T Y, T Z, T directionX, T directionY, T directionZ);
Ray(const Vector3<T>& origin, const Vector3<T>& direction);
Ray(const T origin[3], const T direction[3]); Ray(const T origin[3], const T direction[3]);
Ray(const Plane<T>& planeOne, const Plane<T>& planeTwo); Ray(const Plane<T>& planeOne, const Plane<T>& planeTwo);
Ray(const Vector3<T>& origin, const Vector3<T>& direction);
template<typename U> explicit Ray(const Ray<U>& ray); template<typename U> explicit Ray(const Ray<U>& ray);
template<typename U> explicit Ray(const Vector3<U>& origin, const Vector3<U>& direction); template<typename U> explicit Ray(const Vector3<U>& origin, const Vector3<U>& direction);
Ray(const Ray<T>& ray) = default; Ray(const Ray<T>& ray) = default;
@ -42,16 +42,17 @@ namespace Nz
bool Intersect(const OrientedBox<T>& orientedBox, T* closestHit = nullptr, T* furthestHit = nullptr) const; bool Intersect(const OrientedBox<T>& orientedBox, T* closestHit = nullptr, T* furthestHit = nullptr) const;
bool Intersect(const Plane<T>& plane, T* hit = nullptr) const; bool Intersect(const Plane<T>& plane, T* hit = nullptr) const;
bool Intersect(const Sphere<T>& sphere, T* closestHit = nullptr, T* furthestHit = nullptr) const; bool Intersect(const Sphere<T>& sphere, T* closestHit = nullptr, T* furthestHit = nullptr) const;
bool Intersect(const Vector3<T>& firstPoint, const Vector3<T>& secondPoint, const Vector3<T>& thirdPoint, T* hit = nullptr) const;
Ray& MakeAxisX(); Ray& MakeAxisX();
Ray& MakeAxisY(); Ray& MakeAxisY();
Ray& MakeAxisZ(); Ray& MakeAxisZ();
Ray& Set(T X, T Y, T Z, T directionX, T directionY, T directionZ); Ray& Set(T X, T Y, T Z, T directionX, T directionY, T directionZ);
Ray& Set(const Vector3<T>& origin, const Vector3<T>& direction);
Ray& Set(const T origin[3], const T direction[3]); Ray& Set(const T origin[3], const T direction[3]);
Ray& Set(const Plane<T>& planeOne, const Plane<T>& planeTwo); Ray& Set(const Plane<T>& planeOne, const Plane<T>& planeTwo);
Ray& Set(const Ray& ray); Ray& Set(const Ray& ray);
Ray& Set(const Vector3<T>& origin, const Vector3<T>& direction);
template<typename U> Ray& Set(const Ray<U>& ray); template<typename U> Ray& Set(const Ray<U>& ray);
template<typename U> Ray& Set(const Vector3<U>& origin, const Vector3<U>& direction); template<typename U> Ray& Set(const Vector3<U>& origin, const Vector3<U>& direction);

View File

@ -10,29 +10,77 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::Ray<T>
* \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<T> 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<typename T> template<typename T>
Ray<T>::Ray(T X, T Y, T Z, T DirectionX, T DirectionY, T DirectionZ) Ray<T>::Ray(T X, T Y, T Z, T DirectionX, T DirectionY, T DirectionZ)
{ {
Set(X, Y, Z, DirectionX, DirectionY, DirectionZ); Set(X, Y, Z, DirectionX, DirectionY, DirectionZ);
} }
/*!
* \brief Constructs a Ray<T> 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<typename T>
Ray<T>::Ray(const Vector3<T>& Origin, const Vector3<T>& Direction)
{
Set(Origin, Direction);
}
/*!
* \brief Constructs a Ray<T> 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<typename T> template<typename T>
Ray<T>::Ray(const T Origin[3], const T Direction[3]) Ray<T>::Ray(const T Origin[3], const T Direction[3])
{ {
Set(Origin, Direction); Set(Origin, Direction);
} }
/*!
* \brief Constructs a Ray<T> 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<typename T> template<typename T>
Ray<T>::Ray(const Plane<T>& planeOne, const Plane<T>& planeTwo) Ray<T>::Ray(const Plane<T>& planeOne, const Plane<T>& planeTwo)
{ {
Set(planeOne, planeTwo); Set(planeOne, planeTwo);
} }
template<typename T> /*!
Ray<T>::Ray(const Vector3<T>& Origin, const Vector3<T>& Direction) * \brief Constructs a Ray<T> object from another type of Ray
{ *
Set(Origin, Direction); * \param ray Ray of type U to convert to type T
} */
template<typename T> template<typename T>
template<typename U> template<typename U>
@ -41,6 +89,13 @@ namespace Nz
Set(ray); Set(ray);
} }
/*!
* \brief Constructs a Ray<T> 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<typename T> template<typename T>
template<typename U> template<typename U>
Ray<T>::Ray(const Vector3<U>& Origin, const Vector3<U>& Direction) Ray<T>::Ray(const Vector3<U>& Origin, const Vector3<U>& Direction)
@ -48,6 +103,13 @@ namespace Nz
Set(Origin, Direction); 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<typename T> template<typename T>
T Ray<T>::ClosestPoint(const Vector3<T>& point) const T Ray<T>::ClosestPoint(const Vector3<T>& point) const
{ {
@ -55,15 +117,37 @@ namespace Nz
T vsq = direction.GetSquaredLength(); T vsq = direction.GetSquaredLength();
T proj = delta.DotProduct(direction); 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<typename T> template<typename T>
Vector3<T> Ray<T>::GetPoint(T lambda) const Vector3<T> Ray<T>::GetPoint(T lambda) const
{ {
return origin + lambda * direction; 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<typename T> template<typename T>
bool Ray<T>::Intersect(const BoundingVolume<T>& volume, T* closestHit, T* furthestHit) const bool Ray<T>::Intersect(const BoundingVolume<T>& volume, T* closestHit, T* furthestHit) const
{ {
@ -96,6 +180,17 @@ namespace Nz
return false; 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<typename T> template<typename T>
bool Ray<T>::Intersect(const Box<T>& box, T* closestHit, T* furthestHit) const bool Ray<T>::Intersect(const Box<T>& box, T* closestHit, T* furthestHit) const
{ {
@ -142,6 +237,18 @@ namespace Nz
return true; 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<typename T> template<typename T>
bool Ray<T>::Intersect(const Box<T>& box, const Matrix4<T>& transform, T* closestHit, T* furthestHit) const bool Ray<T>::Intersect(const Box<T>& box, const Matrix4<T>& transform, T* closestHit, T* furthestHit) const
{ {
@ -200,6 +307,17 @@ namespace Nz
return true; 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<typename T> template<typename T>
bool Ray<T>::Intersect(const OrientedBox<T>& orientedBox, T* closestHit, T* furthestHit) const bool Ray<T>::Intersect(const OrientedBox<T>& orientedBox, T* closestHit, T* furthestHit) const
{ {
@ -212,9 +330,9 @@ namespace Nz
// Construction de la matrice de transformation de l'OBB // Construction de la matrice de transformation de l'OBB
Matrix4<T> matrix(width.x, height.x, depth.x, corner.x, Matrix4<T> matrix(width.x, height.x, depth.x, corner.x,
width.y, height.y, depth.y, corner.y, width.y, height.y, depth.y, corner.y,
width.z, height.z, depth.z, corner.z, width.z, height.z, depth.z, corner.z,
F(0.0), F(0.0), F(0.0), F(1.0)); F(0.0), F(0.0), F(0.0), F(1.0));
matrix.InverseAffine(); matrix.InverseAffine();
@ -227,12 +345,22 @@ namespace Nz
return tmpRay.Intersect(tmpBox, closestHit, furthestHit); 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<typename T> template<typename T>
bool Ray<T>::Intersect(const Plane<T>& plane, T* hit) const bool Ray<T>::Intersect(const Plane<T>& plane, T* hit) const
{ {
T divisor = plane.normal.DotProduct(direction); T divisor = plane.normal.DotProduct(direction);
if (NumberEquals(divisor, F(0.0))) 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 T lambda = -(plane.normal.DotProduct(origin) - plane.distance) / divisor; // The plane is ax + by + cz = d
if (lambda < F(0.0)) if (lambda < F(0.0))
@ -244,6 +372,17 @@ namespace Nz
return true; 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<typename T> template<typename T>
bool Ray<T>::Intersect(const Sphere<T>& sphere, T* closestHit, T* furthestHit) const bool Ray<T>::Intersect(const Sphere<T>& sphere, T* closestHit, T* furthestHit) const
{ {
@ -253,8 +392,8 @@ namespace Nz
if (length < F(0.0)) if (length < F(0.0))
return false; // ray is perpendicular to the vector origin - center return false; // ray is perpendicular to the vector origin - center
T squaredDistance = sphereRay.GetSquaredLength() - length*length; T squaredDistance = sphereRay.GetSquaredLength() - length * length;
T squaredRadius = sphere.radius*sphere.radius; T squaredRadius = sphere.radius * sphere.radius;
if (squaredDistance > squaredRadius) if (squaredDistance > squaredRadius)
return false; // if the ray is further than the radius return false; // if the ray is further than the radius
@ -274,24 +413,102 @@ namespace Nz
return true; 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<typename T>
bool Ray<T>::Intersect(const Vector3<T>& firstPoint, const Vector3<T>& secondPoint, const Vector3<T>& thirdPoint, T* hit) const
{
// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
Vector3<T> firstEdge = secondPoint - firstPoint;
Vector3<T> secondEdge = thirdPoint - firstPoint;
Vector3<T> P = Vector3<T>::CrossProduct(direction, secondEdge);
const T divisor = firstEdge.DotProduct(P);
if (NumberEquals(divisor, F(0.0)))
return false; // Ray lies in plane of triangle
Vector3<T> 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<T> Q = Vector3<T>::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<typename T> template<typename T>
Ray<T>& Ray<T>::MakeAxisX() Ray<T>& Ray<T>::MakeAxisX()
{ {
return Set(Vector3<T>::Zero(), Vector3<T>::UnitX()); return Set(Vector3<T>::Zero(), Vector3<T>::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<typename T> template<typename T>
Ray<T>& Ray<T>::MakeAxisY() Ray<T>& Ray<T>::MakeAxisY()
{ {
return Set(Vector3<T>::Zero(), Vector3<T>::UnitY()); return Set(Vector3<T>::Zero(), Vector3<T>::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<typename T> template<typename T>
Ray<T>& Ray<T>::MakeAxisZ() Ray<T>& Ray<T>::MakeAxisZ()
{ {
return Set(Vector3<T>::Zero(), Vector3<T>::UnitZ()); return Set(Vector3<T>::Zero(), Vector3<T>::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<typename T> template<typename T>
Ray<T>& Ray<T>::Set(T X, T Y, T Z, T directionX, T directionY, T directionZ) Ray<T>& Ray<T>::Set(T X, T Y, T Z, T directionX, T directionY, T directionZ)
{ {
@ -301,6 +518,31 @@ namespace Nz
return *this; 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<typename T>
Ray<T>& Ray<T>::Set(const Vector3<T>& Origin, const Vector3<T>& 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<typename T> template<typename T>
Ray<T>& Ray<T>::Set(const T Origin[3], const T Direction[3]) Ray<T>& Ray<T>::Set(const T Origin[3], const T Direction[3])
{ {
@ -310,6 +552,17 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Ray<T>& Ray<T>::Set(const Plane<T>& planeOne, const Plane<T>& planeTwo) Ray<T>& Ray<T>::Set(const Plane<T>& planeOne, const Plane<T>& planeTwo)
{ {
@ -321,7 +574,7 @@ namespace Nz
#if NAZARA_MATH_SAFE #if NAZARA_MATH_SAFE
if (NumberEquals(det, F(0.0))) if (NumberEquals(det, F(0.0)))
{ {
String error("Planes are parallel."); String error("Planes are parallel");
NazaraError(error); NazaraError(error);
throw std::domain_error(error); throw std::domain_error(error);
@ -338,6 +591,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Ray<T>& Ray<T>::Set(const Ray& ray) Ray<T>& Ray<T>::Set(const Ray& ray)
{ {
@ -346,14 +606,12 @@ namespace Nz
return *this; return *this;
} }
template<typename T> /*!
Ray<T>& Ray<T>::Set(const Vector3<T>& Origin, const Vector3<T>& Direction) * \brief Sets the components of the ray from another type of Ray
{ * \return A reference to this ray
direction = Direction; *
origin = Origin; * \param ray Ray of type U to convert its components
*/
return *this;
}
template<typename T> template<typename T>
template<typename U> template<typename U>
@ -365,6 +623,14 @@ namespace Nz
return *this; 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<typename T> template<typename T>
template<typename U> template<typename U>
Ray<T>& Ray<T>::Set(const Vector3<U>& Origin, const Vector3<U>& Direction) Ray<T>& Ray<T>::Set(const Vector3<U>& Origin, const Vector3<U>& Direction)
@ -375,6 +641,11 @@ namespace Nz
return *this; 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<typename T> template<typename T>
String Ray<T>::ToString() const String Ray<T>::ToString() const
{ {
@ -383,24 +654,54 @@ namespace Nz
return ss << "Ray(origin: " << origin.ToString() << ", direction: " << direction.ToString() << ")"; 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<typename T> template<typename T>
Vector3<T> Ray<T>::operator*(T lambda) const Vector3<T> Ray<T>::operator*(T lambda) const
{ {
return GetPoint(lambda); 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<typename T> template<typename T>
bool Ray<T>::operator==(const Ray& ray) const bool Ray<T>::operator==(const Ray& ray) const
{ {
return direction == ray.direction && origin == ray.origin; 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<typename T> template<typename T>
bool Ray<T>::operator!=(const Ray& ray) const bool Ray<T>::operator!=(const Ray& ray) const
{ {
return !operator==(ray); 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<typename T> template<typename T>
Ray<T> Ray<T>::AxisX() Ray<T> Ray<T>::AxisX()
{ {
@ -410,6 +711,13 @@ namespace Nz
return axis; 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<typename T> template<typename T>
Ray<T> Ray<T>::AxisY() Ray<T> Ray<T>::AxisY()
{ {
@ -419,6 +727,13 @@ namespace Nz
return axis; 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<typename T> template<typename T>
Ray<T> Ray<T>::AxisZ() Ray<T> Ray<T>::AxisZ()
{ {
@ -428,13 +743,34 @@ namespace Nz
return axis; 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<typename T> template<typename T>
Ray<T> Ray<T>::Lerp(const Ray& from, const Ray& to, T interpolation) Ray<T> Ray<T>::Lerp(const Ray& from, const Ray& to, T interpolation)
{ {
return Ray<T>(from.origin.Lerp(to.origin, interpolation), from.direction.Lerp(to.direction, interpolation)); return Ray<T>(Nz::Vector3<T>::Lerp(from.origin, to.origin, interpolation), Nz::Vector3<T>::Lerp(from.direction, to.direction, interpolation));
} }
} }
/*!
* \brief Output operator
* \return The stream
*
* \param out The stream
* \param ray The ray to output
*/
template<typename T> template<typename T>
std::ostream& operator<<(std::ostream& out, const Nz::Ray<T>& ray) std::ostream& operator<<(std::ostream& out, const Nz::Ray<T>& ray)
{ {

View File

@ -28,12 +28,12 @@ namespace Nz
~Rect() = default; ~Rect() = default;
bool Contains(T X, T Y) const; bool Contains(T X, T Y) const;
bool Contains(const Vector2<T>& point) const;
bool Contains(const Rect& rect) const; bool Contains(const Rect& rect) const;
bool Contains(const Vector2<T>& point) const;
Rect& ExtendTo(T X, T Y); Rect& ExtendTo(T X, T Y);
Rect& ExtendTo(const Vector2<T>& point);
Rect& ExtendTo(const Rect& rect); Rect& ExtendTo(const Rect& rect);
Rect& ExtendTo(const Vector2<T>& point);
Vector2<T> GetCenter() const; Vector2<T> GetCenter() const;
Vector2<T> GetCorner(RectCorner corner) const; Vector2<T> GetCorner(RectCorner corner) const;

View File

@ -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" // This file is part of the "Nazara Engine - Mathematics module"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
@ -12,36 +12,89 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::Rect<T>
* \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<T> 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<typename T> template<typename T>
Rect<T>::Rect(T Width, T Height) Rect<T>::Rect(T Width, T Height)
{ {
Set(Width, Height); Set(Width, Height);
} }
/*!
* \brief Constructs a Rect<T> 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<typename T> template<typename T>
Rect<T>::Rect(T X, T Y, T Width, T Height) Rect<T>::Rect(T X, T Y, T Width, T Height)
{ {
Set(X, Y, Width, Height); Set(X, Y, Width, Height);
} }
/*!
* \brief Constructs a Rect<T> 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<typename T> template<typename T>
Rect<T>::Rect(const T vec[4]) Rect<T>::Rect(const T vec[4])
{ {
Set(vec); Set(vec);
} }
/*!
* \brief Constructs a Rect<T> object from a vector representing width and height
*
* \param lengths (Width, Height) of the rectangle
*
* \remark X and Y will be (0, 0)
*/
template<typename T> template<typename T>
Rect<T>::Rect(const Vector2<T>& lengths) Rect<T>::Rect(const Vector2<T>& lengths)
{ {
Set(lengths); Set(lengths);
} }
/*!
* \brief Constructs a Rect<T> 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<typename T> template<typename T>
Rect<T>::Rect(const Vector2<T>& vec1, const Vector2<T>& vec2) Rect<T>::Rect(const Vector2<T>& vec1, const Vector2<T>& vec2)
{ {
Set(vec1, vec2); Set(vec1, vec2);
} }
/*!
* \brief Constructs a Rect<T> object from another type of Rect
*
* \param rect Rect of type U to convert to type T
*/
template<typename T> template<typename T>
template<typename U> template<typename U>
Rect<T>::Rect(const Rect<U>& rect) Rect<T>::Rect(const Rect<U>& rect)
@ -49,25 +102,63 @@ namespace Nz
Set(rect); 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<typename T> template<typename T>
bool Rect<T>::Contains(T X, T Y) const bool Rect<T>::Contains(T X, T Y) const
{ {
return X >= x && X <= x+width && return X >= x && X <= (x + width) &&
Y >= y && Y <= y+height; 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<typename T>
bool Rect<T>::Contains(const Rect<T>& 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<typename T> template<typename T>
bool Rect<T>::Contains(const Vector2<T>& point) const bool Rect<T>::Contains(const Vector2<T>& point) const
{ {
return Contains(point.x, point.y); return Contains(point.x, point.y);
} }
template<typename T> /*!
bool Rect<T>::Contains(const Rect<T>& rect) const * \brief Extends the rectangle to contain the point in the boundary
{ * \return A reference to this rectangle extended
return Contains(rect.x, rect.y) && *
Contains(rect.x + rect.width, rect.y + rect.height); * \param X X position of the point
} * \param Y Y position of the point
*
* \see ExtendTo
*/
template<typename T> template<typename T>
Rect<T>& Rect<T>::ExtendTo(T X, T Y) Rect<T>& Rect<T>::ExtendTo(T X, T Y)
@ -84,11 +175,14 @@ namespace Nz
return *this; return *this;
} }
template<typename T> /*!
Rect<T>& Rect<T>::ExtendTo(const Vector2<T>& point) * \brief Extends the rectangle to contain the rectangle
{ * \return A reference to this rectangle extended
return ExtendTo(point.x, point.y); *
} * \param rect Other rectangle to contain
*
* \see ExtendTo
*/
template<typename T> template<typename T>
Rect<T>& Rect<T>::ExtendTo(const Rect& rect) Rect<T>& Rect<T>::ExtendTo(const Rect& rect)
@ -105,12 +199,41 @@ namespace Nz
return *this; 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<typename T>
Rect<T>& Rect<T>::ExtendTo(const Vector2<T>& point)
{
return ExtendTo(point.x, point.y);
}
/*!
* \brief Gets a Vector2 for the center
* \return The position of the center of the rectangle
*/
template<typename T> template<typename T>
Vector2<T> Rect<T>::GetCenter() const Vector2<T> Rect<T>::GetCenter() const
{ {
return GetPosition() + GetLengths() / F(2.0); 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<typename T> template<typename T>
Vector2<T> Rect<T>::GetCorner(RectCorner corner) const Vector2<T> Rect<T>::GetCorner(RectCorner corner) const
{ {
@ -133,25 +256,52 @@ namespace Nz
return Vector2<T>(); return Vector2<T>();
} }
/*!
* \brief Gets a Vector2 for the lengths
* \return The lengths of the rectangle (width, height)
*/
template<typename T> template<typename T>
Vector2<T> Rect<T>::GetLengths() const Vector2<T> Rect<T>::GetLengths() const
{ {
return Vector2<T>(width, height); return Vector2<T>(width, height);
} }
/*!
* \brief Gets a Vector2 for the maximum point
* \return The RectCorner_RightBottom of the rectangle
*
* \see GetCorner
*/
template<typename T> template<typename T>
Vector2<T> Rect<T>::GetMaximum() const Vector2<T> Rect<T>::GetMaximum() const
{ {
return GetPosition() + GetLengths(); return GetPosition() + GetLengths();
} }
/*!
* \brief Gets a Vector2 for the minimum point
* \return The RectCorner_LeftTop of the rectangle
*
* \see GetCorner, GetPosition
*/
template<typename T> template<typename T>
Vector2<T> Rect<T>::GetMinimum() const Vector2<T> Rect<T>::GetMinimum() const
{ {
///DOC: Alias de GetPosition()
return 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<typename T> template<typename T>
Vector2<T> Rect<T>::GetNegativeVertex(const Vector2<T>& normal) const Vector2<T> Rect<T>::GetNegativeVertex(const Vector2<T>& normal) const
{ {
@ -166,12 +316,28 @@ namespace Nz
return neg; return neg;
} }
/*!
* \brief Gets a Vector2 for the position
* \return The RectCorner_LeftTop of the rectangle
*
* \see GetCorner, GetMinimum
*/
template<typename T> template<typename T>
Vector2<T> Rect<T>::GetPosition() const Vector2<T> Rect<T>::GetPosition() const
{ {
return Vector2<T>(x, y); return Vector2<T>(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<typename T> template<typename T>
Vector2<T> Rect<T>::GetPositiveVertex(const Vector2<T>& normal) const Vector2<T> Rect<T>::GetPositiveVertex(const Vector2<T>& normal) const
{ {
@ -186,6 +352,14 @@ namespace Nz
return pos; 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<typename T> template<typename T>
bool Rect<T>::Intersect(const Rect& rect, Rect* intersection) const bool Rect<T>::Intersect(const Rect& rect, Rect* intersection) const
{ {
@ -210,12 +384,24 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Checks whether this rectangle is valid
* \return true if the rectangle has a strictly positive width and height
*/
template<typename T> template<typename T>
bool Rect<T>::IsValid() const bool Rect<T>::IsValid() const
{ {
return width > F(0.0) && height > F(0.0); 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<typename T> template<typename T>
Rect<T>& Rect<T>::MakeZero() Rect<T>& Rect<T>::MakeZero()
{ {
@ -227,6 +413,16 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Rect<T>& Rect<T>::Set(T Width, T Height) Rect<T>& Rect<T>::Set(T Width, T Height)
{ {
@ -238,6 +434,16 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Rect<T>& Rect<T>::Set(T X, T Y, T Width, T Height) Rect<T>& Rect<T>::Set(T X, T Y, T Width, T Height)
{ {
@ -249,6 +455,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Rect<T>& Rect<T>::Set(const T rect[4]) Rect<T>& Rect<T>::Set(const T rect[4])
{ {
@ -260,6 +473,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Rect<T>& Rect<T>::Set(const Rect<T>& rect) Rect<T>& Rect<T>::Set(const Rect<T>& rect)
{ {
@ -268,23 +488,48 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Rect<T>& Rect<T>::Set(const Vector2<T>& lengths) Rect<T>& Rect<T>::Set(const Vector2<T>& lengths)
{ {
return Set(lengths.x, lengths.y); return Set(lengths.x, lengths.y);
} }
/*!
* \brief Sets a Rect<T> 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<typename T> template<typename T>
Rect<T>& Rect<T>::Set(const Vector2<T>& vec1, const Vector2<T>& vec2) Rect<T>& Rect<T>::Set(const Vector2<T>& vec1, const Vector2<T>& vec2)
{ {
x = std::min(vec1.x, vec2.x); x = std::min(vec1.x, vec2.x);
y = std::min(vec1.y, vec2.y); y = std::min(vec1.y, vec2.y);
width = (vec2.x > vec1.x) ? vec2.x-vec1.x : vec1.x-vec2.x; 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; height = (vec2.y > vec1.y) ? vec2.y - vec1.y : vec1.y - vec2.y;
return *this; 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<typename T> template<typename T>
template<typename U> template<typename U>
Rect<T>& Rect<T>::Set(const Rect<U>& rect) Rect<T>& Rect<T>::Set(const Rect<U>& rect)
@ -297,6 +542,11 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Gives a string representation
* \return A string representation of the object: "Rect(x, y, width, height)"
*/
template<typename T> template<typename T>
String Rect<T>::ToString() const String Rect<T>::ToString() const
{ {
@ -305,6 +555,13 @@ namespace Nz
return ss << "Rect(" << x << ", " << y << ", " << width << ", " << height << ')'; 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<typename T> template<typename T>
Rect<T>& Rect<T>::Translate(const Vector2<T>& translation) Rect<T>& Rect<T>::Translate(const Vector2<T>& translation)
{ {
@ -314,6 +571,15 @@ namespace Nz
return *this; 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<typename T> template<typename T>
T& Rect<T>::operator[](unsigned int i) T& Rect<T>::operator[](unsigned int i)
{ {
@ -331,6 +597,15 @@ namespace Nz
return *(&x+i); 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<typename T> template<typename T>
T Rect<T>::operator[](unsigned int i) const T Rect<T>::operator[](unsigned int i) const
{ {
@ -348,30 +623,65 @@ namespace Nz
return *(&x+i); 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<typename T> template<typename T>
Rect<T> Rect<T>::operator*(T scalar) const Rect<T> Rect<T>::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<typename T> template<typename T>
Rect<T> Rect<T>::operator*(const Vector2<T>& vec) const Rect<T> Rect<T>::operator*(const Vector2<T>& vec) const
{ {
return Rect(x, y, width*vec.x, height*vec.y); 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<typename T> template<typename T>
Rect<T> Rect<T>::operator/(T scalar) const Rect<T> Rect<T>::operator/(T scalar) const
{ {
return Rect(x, y, width/scalar, height/scalar); 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<typename T> template<typename T>
Rect<T> Rect<T>::operator/(const Vector2<T>& vec) const Rect<T> Rect<T>::operator/(const Vector2<T>& vec) const
{ {
return Rect(x, y, width/vec.x, height/vec.y); 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<typename T> template<typename T>
Rect<T>& Rect<T>::operator*=(T scalar) Rect<T>& Rect<T>::operator*=(T scalar)
{ {
@ -381,6 +691,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Rect<T>& Rect<T>::operator*=(const Vector2<T>& vec) Rect<T>& Rect<T>::operator*=(const Vector2<T>& vec)
{ {
@ -390,6 +707,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Rect<T>& Rect<T>::operator/=(T scalar) Rect<T>& Rect<T>::operator/=(T scalar)
{ {
@ -399,6 +723,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Rect<T>& Rect<T>::operator/=(const Vector2<T>& vec) Rect<T>& Rect<T>::operator/=(const Vector2<T>& vec)
{ {
@ -408,19 +739,47 @@ namespace Nz
return *this; 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<typename T> template<typename T>
bool Rect<T>::operator==(const Rect& rect) const bool Rect<T>::operator==(const Rect& rect) const
{ {
return NumberEquals(x, rect.x) && NumberEquals(y, rect.y) && 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<typename T> template<typename T>
bool Rect<T>::operator!=(const Rect& rect) const bool Rect<T>::operator!=(const Rect& rect) const
{ {
return !operator==(rect); 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<typename T> template<typename T>
Rect<T> Rect<T>::Lerp(const Rect& from, const Rect& to, T interpolation) Rect<T> Rect<T>::Lerp(const Rect& from, const Rect& to, T interpolation)
{ {
@ -433,14 +792,21 @@ namespace Nz
#endif #endif
Rect rect; Rect rect;
rect.x = Lerp(from.x, to.x, interpolation); rect.x = Nz::Lerp(from.x, to.x, interpolation);
rect.y = Lerp(from.y, to.y, interpolation); rect.y = Nz::Lerp(from.y, to.y, interpolation);
rect.width = Lerp(from.width, to.width, interpolation); rect.width = Nz::Lerp(from.width, to.width, interpolation);
rect.height = Lerp(from.height, to.height, interpolation); rect.height = Nz::Lerp(from.height, to.height, interpolation);
return rect; 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<typename T> template<typename T>
Rect<T> Rect<T>::Zero() Rect<T> Rect<T>::Zero()
{ {
@ -451,6 +817,14 @@ namespace Nz
} }
} }
/*!
* \brief Output operator
* \return The stream
*
* \param out The stream
* \param rect The rectangle to output
*/
template<typename T> template<typename T>
std::ostream& operator<<(std::ostream& out, const Nz::Rect<T>& rect) std::ostream& operator<<(std::ostream& out, const Nz::Rect<T>& rect)
{ {

View File

@ -46,6 +46,7 @@ namespace Nz
bool IsValid() const; bool IsValid() const;
Sphere& MakeUnit();
Sphere& MakeZero(); Sphere& MakeZero();
Sphere& Set(T X, T Y, T Z, T Radius); Sphere& Set(T X, T Y, T Z, T Radius);
@ -71,6 +72,7 @@ namespace Nz
bool operator!=(const Sphere& sphere) const; bool operator!=(const Sphere& sphere) const;
static Sphere Lerp(const Sphere& from, const Sphere& to, T interpolation); static Sphere Lerp(const Sphere& from, const Sphere& to, T interpolation);
static Sphere Unit();
static Sphere Zero(); static Sphere Zero();
T x, y, z, radius; T x, y, z, radius;

View File

@ -13,6 +13,20 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::Sphere<T>
* \brief Math class that represents a sphere "S2" in a three dimensional euclidean space
*/
/*!
* \brief Constructs a Sphere<T> 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<typename T> template<typename T>
Sphere<T>::Sphere(T X, T Y, T Z, T Radius) Sphere<T>::Sphere(T X, T Y, T Z, T Radius)
{ {
@ -25,18 +39,38 @@ namespace Nz
Set(rect); Set(rect);
} }
*/ */
/*!
* \brief Constructs a Sphere<T> object from its position and radius
*
* \param center Center of the sphere
* \param Radius Half of the diameter
*/
template<typename T> template<typename T>
Sphere<T>::Sphere(const Vector3<T>& center, T Radius) Sphere<T>::Sphere(const Vector3<T>& center, T Radius)
{ {
Set(center, Radius); Set(center, Radius);
} }
/*!
* \brief Constructs a Sphere<T> 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<typename T> template<typename T>
Sphere<T>::Sphere(const T sphere[4]) Sphere<T>::Sphere(const T sphere[4])
{ {
Set(sphere); Set(sphere);
} }
/*!
* \brief Constructs a Sphere<T> object from another type of Sphere
*
* \param sphere Sphere of type U to convert to type T
*/
template<typename T> template<typename T>
template<typename U> template<typename U>
Sphere<T>::Sphere(const Sphere<U>& sphere) Sphere<T>::Sphere(const Sphere<U>& sphere)
@ -44,12 +78,32 @@ namespace Nz
Set(sphere); 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<typename T> template<typename T>
bool Sphere<T>::Contains(T X, T Y, T Z) const bool Sphere<T>::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<typename T> template<typename T>
bool Sphere<T>::Contains(const Box<T>& box) const bool Sphere<T>::Contains(const Box<T>& box) const
{ {
@ -61,12 +115,31 @@ namespace Nz
return false; 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<typename T> template<typename T>
bool Sphere<T>::Contains(const Vector3<T>& point) const bool Sphere<T>::Contains(const Vector3<T>& point) const
{ {
return Contains(point.x, point.y, point.z); 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<typename T> template<typename T>
T Sphere<T>::Distance(T X, T Y, T Z) const T Sphere<T>::Distance(T X, T Y, T Z) const
{ {
@ -74,12 +147,32 @@ namespace Nz
return distance.GetLength(); 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<typename T> template<typename T>
T Sphere<T>::Distance(const Vector3<T>& point) const T Sphere<T>::Distance(const Vector3<T>& point) const
{ {
return Distance(point.x, point.y, point.z); 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<typename T> template<typename T>
Sphere<T>& Sphere<T>::ExtendTo(T X, T Y, T Z) Sphere<T>& Sphere<T>::ExtendTo(T X, T Y, T Z)
{ {
@ -90,12 +183,30 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Sphere<T>& Sphere<T>::ExtendTo(const Vector3<T>& point) Sphere<T>& Sphere<T>::ExtendTo(const Vector3<T>& point)
{ {
return ExtendTo(point.x, point.y, point.z); 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<typename T> template<typename T>
Vector3<T> Sphere<T>::GetNegativeVertex(const Vector3<T>& normal) const Vector3<T> Sphere<T>::GetNegativeVertex(const Vector3<T>& normal) const
{ {
@ -105,12 +216,26 @@ namespace Nz
return neg; return neg;
} }
/*!
* \brief Gets a Vector3 of the position
* \return The position of the center of the sphere
*/
template<typename T> template<typename T>
Vector3<T> Sphere<T>::GetPosition() const Vector3<T> Sphere<T>::GetPosition() const
{ {
return Vector3<T>(x, y, z); return Vector3<T>(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<typename T> template<typename T>
Vector3<T> Sphere<T>::GetPositiveVertex(const Vector3<T>& normal) const Vector3<T> Sphere<T>::GetPositiveVertex(const Vector3<T>& normal) const
{ {
@ -120,6 +245,13 @@ namespace Nz
return pos; return pos;
} }
/*!
* \brief Checks whether or not this sphere intersects a box
* \return true if the box intersects
*
* \param box Box to check
*/
template<typename T> template<typename T>
bool Sphere<T>::Intersect(const Box<T>& box) const bool Sphere<T>::Intersect(const Box<T>& box) const
{ {
@ -128,51 +260,88 @@ namespace Nz
if (x < box.x) if (x < box.x)
{ {
T diff = x - box.x; T diff = x - box.x;
squaredDistance += diff*diff; squaredDistance += diff * diff;
} }
else if (x > box.x + box.width) else if (x > box.x + box.width)
{ {
T diff = x - (box.x + box.width); T diff = x - (box.x + box.width);
squaredDistance += diff*diff; squaredDistance += diff * diff;
} }
if (y < box.y) if (y < box.y)
{ {
T diff = y - box.y; T diff = y - box.y;
squaredDistance += diff*diff; squaredDistance += diff * diff;
} }
else if (y > box.y + box.height) else if (y > box.y + box.height)
{ {
T diff = y - (box.y + box.height); T diff = y - (box.y + box.height);
squaredDistance += diff*diff; squaredDistance += diff * diff;
} }
if (z < box.z) if (z < box.z)
{ {
T diff = z - box.z; T diff = z - box.z;
squaredDistance += diff*diff; squaredDistance += diff * diff;
} }
else if (z > box.z + box.depth) else if (z > box.z + box.depth)
{ {
T diff = z - (box.z + box.depth); T diff = z - (box.z + box.depth);
squaredDistance += diff*diff; squaredDistance += diff * diff;
} }
return squaredDistance <= radius * radius; 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<typename T> template<typename T>
bool Sphere<T>::Intersect(const Sphere& sphere) const bool Sphere<T>::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<typename T> template<typename T>
bool Sphere<T>::IsValid() const bool Sphere<T>::IsValid() const
{ {
return radius > F(0.0); 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<typename T>
Sphere<T>& Sphere<T>::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<typename T> template<typename T>
Sphere<T>& Sphere<T>::MakeZero() Sphere<T>& Sphere<T>::MakeZero()
{ {
@ -184,6 +353,16 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Sphere<T>& Sphere<T>::Set(T X, T Y, T Z, T Radius) Sphere<T>& Sphere<T>::Set(T X, T Y, T Z, T Radius)
{ {
@ -195,6 +374,14 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Sphere<T>& Sphere<T>::Set(const Vector3<T>& center, T Radius) Sphere<T>& Sphere<T>::Set(const Vector3<T>& center, T Radius)
{ {
@ -217,6 +404,14 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Sphere<T>& Sphere<T>::Set(const Sphere& sphere) Sphere<T>& Sphere<T>::Set(const Sphere& sphere)
{ {
@ -225,6 +420,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Sphere<T>& Sphere<T>::Set(const T sphere[4]) Sphere<T>& Sphere<T>::Set(const T sphere[4])
{ {
@ -236,6 +438,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
template<typename U> template<typename U>
Sphere<T>& Sphere<T>::Set(const Sphere<U>& sphere) Sphere<T>& Sphere<T>::Set(const Sphere<U>& sphere)
@ -248,19 +457,44 @@ namespace Nz
return *this; 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<typename T> template<typename T>
T Sphere<T>::SquaredDistance(T X, T Y, T Z) const T Sphere<T>::SquaredDistance(T X, T Y, T Z) const
{ {
Vector3<T> distance(X-x, Y-y, Z-z); Vector3<T> distance(X - x, Y - y, Z - z);
return distance.GetSquaredLength(); 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<typename T> template<typename T>
T Sphere<T>::SquaredDistance(const Vector3<T>& point) const T Sphere<T>::SquaredDistance(const Vector3<T>& point) const
{ {
return SquaredDistance(point.x, point.y, point.z); 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<typename T> template<typename T>
String Sphere<T>::ToString() const String Sphere<T>::ToString() const
{ {
@ -269,6 +503,15 @@ namespace Nz
return ss << "Sphere(" << x << ", " << y << ", " << z << "; " << radius << ')'; 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<typename T> template<typename T>
T& Sphere<T>::operator[](unsigned int i) T& Sphere<T>::operator[](unsigned int i)
{ {
@ -286,6 +529,15 @@ namespace Nz
return *(&x+i); 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<typename T> template<typename T>
T Sphere<T>::operator[](unsigned int i) const T Sphere<T>::operator[](unsigned int i) const
{ {
@ -303,31 +555,89 @@ namespace Nz
return *(&x+i); 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<typename T> template<typename T>
Sphere<T> Sphere<T>::operator*(T scalar) const Sphere<T> Sphere<T>::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<typename T> template<typename T>
Sphere<T>& Sphere<T>::operator*=(T scalar) Sphere<T>& Sphere<T>::operator*=(T scalar)
{ {
radius *= 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<typename T> template<typename T>
bool Sphere<T>::operator==(const Sphere& sphere) const bool Sphere<T>::operator==(const Sphere& sphere) const
{ {
return NumberEquals(x, sphere.x) && NumberEquals(y, sphere.y) && NumberEquals(z, sphere.z) && 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<typename T> template<typename T>
bool Sphere<T>::operator!=(const Sphere& sphere) const bool Sphere<T>::operator!=(const Sphere& sphere) const
{ {
return !operator==(sphere); 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<typename T>
Sphere<T> Sphere<T>::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<typename T> template<typename T>
Sphere<T> Sphere<T>::Lerp(const Sphere& from, const Sphere& to, T interpolation) Sphere<T> Sphere<T>::Lerp(const Sphere& from, const Sphere& to, T interpolation)
{ {
@ -340,14 +650,21 @@ namespace Nz
#endif #endif
Sphere sphere; Sphere sphere;
sphere.x = Lerp(from.x, to.x, interpolation); sphere.x = Nz::Lerp(from.x, to.x, interpolation);
sphere.y = Lerp(from.y, to.y, interpolation); sphere.y = Nz::Lerp(from.y, to.y, interpolation);
sphere.z = Lerp(from.z, to.z, interpolation); sphere.z = Nz::Lerp(from.z, to.z, interpolation);
sphere.radius = Lerp(from.radius, to.radius, interpolation); sphere.radius = Nz::Lerp(from.radius, to.radius, interpolation);
return sphere; 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<typename T> template<typename T>
Sphere<T> Sphere<T>::Zero() Sphere<T> Sphere<T>::Zero()
{ {
@ -358,6 +675,14 @@ namespace Nz
} }
} }
/*!
* \brief Output operator
* \return The stream
*
* \param out The stream
* \param sphere The sphere to output
*/
template<typename T> template<typename T>
std::ostream& operator<<(std::ostream& out, const Nz::Sphere<T>& sphere) std::ostream& operator<<(std::ostream& out, const Nz::Sphere<T>& sphere)
{ {

View File

@ -62,8 +62,8 @@ namespace Nz
String ToString() const; String ToString() const;
operator T*(); operator T* ();
operator const T*() const; operator const T* () const;
const Vector2& operator+() const; const Vector2& operator+() 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;
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 Lerp(const Vector2& from, const Vector2& to, T interpolation);
static Vector2 Normalize(const Vector2& vec);
static Vector2 Unit(); static Vector2 Unit();
static Vector2 UnitX(); static Vector2 UnitX();
static Vector2 UnitY(); static Vector2 UnitY();

View File

@ -13,24 +13,54 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::Vector2<T>
* \brief Math class that represents an element of the two dimensional vector space
*/
/*!
* \brief Constructs a Vector2<T> object from its coordinates
*
* \param X X component
* \param Y Y component
*/
template<typename T> template<typename T>
Vector2<T>::Vector2(T X, T Y) Vector2<T>::Vector2(T X, T Y)
{ {
Set(X, Y); Set(X, Y);
} }
/*!
* \brief Constructs explicitely a Vector2<T> object from its "scale"
*
* \param scale X component = Y component
*/
template<typename T> template<typename T>
Vector2<T>::Vector2(T scale) Vector2<T>::Vector2(T scale)
{ {
Set(scale); Set(scale);
} }
/*!
* \brief Constructs a Vector2<T> object from an array of two elements
*
* \param vec[2] vec[0] is X component and vec[1] is Y component
*/
template<typename T> template<typename T>
Vector2<T>::Vector2(const T vec[2]) Vector2<T>::Vector2(const T vec[2])
{ {
Set(vec); Set(vec);
} }
/*!
* \brief Constructs a Vector2<T> object from another type of Vector2
*
* \param vec Vector of type U to convert to type T
*/
template<typename T> template<typename T>
template<typename U> template<typename U>
Vector2<T>::Vector2(const Vector2<U>& vec) Vector2<T>::Vector2(const Vector2<U>& vec)
@ -38,60 +68,140 @@ namespace Nz
Set(vec); Set(vec);
} }
/*!
* \brief Constructs a Vector2<T> object from a Vector3
*
* \param vec Vector3 where only the first two components are taken
*/
template<typename T> template<typename T>
Vector2<T>::Vector2(const Vector3<T>& vec) Vector2<T>::Vector2(const Vector3<T>& vec)
{ {
Set(vec); Set(vec);
} }
/*!
* \brief Constructs a Vector2<T> object from a Vector4
*
* \param vec Vector4 where only the first two components are taken
*/
template<typename T> template<typename T>
Vector2<T>::Vector2(const Vector4<T>& vec) Vector2<T>::Vector2(const Vector4<T>& vec)
{ {
Set(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<typename T> template<typename T>
T Vector2<T>::AbsDotProduct(const Vector2& vec) const T Vector2<T>::AbsDotProduct(const Vector2& vec) const
{ {
return std::abs(x * vec.x) + std::abs(y * vec.y); 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<typename T> template<typename T>
T Vector2<T>::AngleBetween(const Vector2& vec) const T Vector2<T>::AngleBetween(const Vector2& vec) const
{ {
return FromRadians(std::atan2(vec.y, vec.x) - std::atan2(y, x)); 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<typename T> template<typename T>
T Vector2<T>::Distance(const Vector2& vec) const T Vector2<T>::Distance(const Vector2& vec) const
{ {
return std::sqrt(SquaredDistance(vec)); 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<typename T> template<typename T>
float Vector2<T>::Distancef(const Vector2& vec) const float Vector2<T>::Distancef(const Vector2& vec) const
{ {
return std::sqrt(static_cast<float>(SquaredDistance(vec))); return std::sqrt(static_cast<float>(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<typename T> template<typename T>
T Vector2<T>::DotProduct(const Vector2& vec) const T Vector2<T>::DotProduct(const Vector2& vec) const
{ {
return x*vec.x + y*vec.y; return x*vec.x + y*vec.y;
} }
/*!
* \brief Calculates the length (magnitude) of the vector
* \return The length of the vector
*
* \see GetSquaredLength
*/
template<typename T> template<typename T>
T Vector2<T>::GetLength() const T Vector2<T>::GetLength() const
{ {
return std::sqrt(GetSquaredLength()); return static_cast<T>(std::sqrt(GetSquaredLength()));
} }
/*!
* \brief Calculates the length (magnitude) of the vector
* \return The length in float of the vector
*/
template<typename T> template<typename T>
float Vector2<T>::GetLengthf() const float Vector2<T>::GetLengthf() const
{ {
return std::sqrt(static_cast<float>(GetSquaredLength())); return std::sqrt(static_cast<float>(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<typename T> template<typename T>
Vector2<T> Vector2<T>::GetNormal(T* length) const Vector2<T> Vector2<T>::GetNormal(T* length) const
{ {
@ -101,36 +211,80 @@ namespace Nz
return vec; return vec;
} }
/*!
* \brief Calculates the squared length (magnitude) of the vector
* \return The squared length of the vector
*
* \see GetLength
*/
template<typename T> template<typename T>
T Vector2<T>::GetSquaredLength() const T Vector2<T>::GetSquaredLength() const
{ {
return x*x + y*y; return x*x + y*y;
} }
/*!
* \brief Makes the vector (1, 1)
* \return A reference to this vector with components (1, 1)
*
* \see Unit
*/
template<typename T> template<typename T>
Vector2<T>& Vector2<T>::MakeUnit() Vector2<T>& Vector2<T>::MakeUnit()
{ {
return Set(F(1.0), F(1.0)); 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::MakeUnitX() Vector2<T>& Vector2<T>::MakeUnitX()
{ {
return Set(F(1.0), F(0.0)); 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::MakeUnitY() Vector2<T>& Vector2<T>::MakeUnitY()
{ {
return Set(F(0.0), F(1.0)); 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::MakeZero() Vector2<T>& Vector2<T>::MakeZero()
{ {
return Set(F(0.0), F(0.0)); 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::Maximize(const Vector2& vec) Vector2<T>& Vector2<T>::Maximize(const Vector2& vec)
{ {
@ -143,6 +297,15 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::Minimize(const Vector2& vec) Vector2<T>& Vector2<T>::Minimize(const Vector2& vec)
{ {
@ -155,6 +318,17 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::Normalize(T* length) Vector2<T>& Vector2<T>::Normalize(T* length)
{ {
@ -172,6 +346,14 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Sets the components of the vector
* \return A reference to this vector
*
* \param X X component
* \param Y Y component
*/
template<typename T> template<typename T>
Vector2<T>& Vector2<T>::Set(T X, T Y) Vector2<T>& Vector2<T>::Set(T X, T Y)
{ {
@ -181,6 +363,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::Set(T scale) Vector2<T>& Vector2<T>::Set(T scale)
{ {
@ -190,6 +379,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::Set(const T vec[2]) Vector2<T>& Vector2<T>::Set(const T vec[2])
{ {
@ -198,6 +394,13 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Sets the components of the vector from another vector
* \return A reference to this vector
*
* \param vec The other vector
*/
template<typename T> template<typename T>
Vector2<T>& Vector2<T>::Set(const Vector2& vec) Vector2<T>& Vector2<T>::Set(const Vector2& vec)
{ {
@ -206,6 +409,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
template<typename U> template<typename U>
Vector2<T>& Vector2<T>::Set(const Vector2<U>& vec) Vector2<T>& Vector2<T>::Set(const Vector2<U>& vec)
@ -216,6 +426,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::Set(const Vector3<T>& vec) Vector2<T>& Vector2<T>::Set(const Vector3<T>& vec)
{ {
@ -225,6 +442,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::Set(const Vector4<T>& vec) Vector2<T>& Vector2<T>::Set(const Vector4<T>& vec)
{ {
@ -234,12 +458,26 @@ namespace Nz
return *this; 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<typename T> template<typename T>
T Vector2<T>::SquaredDistance(const Vector2& vec) const T Vector2<T>::SquaredDistance(const Vector2& vec) const
{ {
return (*this - vec).GetSquaredLength(); return (*this - vec).GetSquaredLength();
} }
/*!
* \brief Gives a string representation
* \return A string representation of the object: "Vector2(x, y)"
*/
template<typename T> template<typename T>
String Vector2<T>::ToString() const String Vector2<T>::ToString() const
{ {
@ -248,54 +486,116 @@ namespace Nz
return ss << "Vector2(" << x << ", " << y << ')'; 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<typename T> template<typename T>
Vector2<T>::operator T*() Vector2<T>::operator T* ()
{ {
return &x; 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<typename T> template<typename T>
Vector2<T>::operator const T*() const Vector2<T>::operator const T* () const
{ {
return &x; return &x;
} }
/*!
* \brief Helps to represent the sign of the vector
* \return A constant reference to this vector
*/
template<typename T> template<typename T>
const Vector2<T>& Vector2<T>::operator+() const const Vector2<T>& Vector2<T>::operator+() const
{ {
return *this; return *this;
} }
/*!
* \brief Negates the components of the vector
* \return A constant reference to this vector with negate components
*/
template<typename T> template<typename T>
Vector2<T> Vector2<T>::operator-() const Vector2<T> Vector2<T>::operator-() const
{ {
return Vector2(-x, -y); 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<typename T> template<typename T>
Vector2<T> Vector2<T>::operator+(const Vector2& vec) const Vector2<T> Vector2<T>::operator+(const Vector2& vec) const
{ {
return Vector2(x + vec.x, y + vec.y); 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<typename T> template<typename T>
Vector2<T> Vector2<T>::operator-(const Vector2& vec) const Vector2<T> Vector2<T>::operator-(const Vector2& vec) const
{ {
return Vector2(x - vec.x, y - vec.y); 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<typename T> template<typename T>
Vector2<T> Vector2<T>::operator*(const Vector2& vec) const Vector2<T> Vector2<T>::operator*(const Vector2& vec) const
{ {
return Vector2(x * vec.x, y * vec.y); 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<typename T> template<typename T>
Vector2<T> Vector2<T>::operator*(T scale) const Vector2<T> Vector2<T>::operator*(T scale) const
{ {
return Vector2(x * scale, y * scale); 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<typename T> template<typename T>
Vector2<T> Vector2<T>::operator/(const Vector2& vec) const Vector2<T> Vector2<T>::operator/(const Vector2& vec) const
{ {
@ -312,6 +612,16 @@ namespace Nz
return Vector2(x / vec.x, y / vec.y); 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<typename T> template<typename T>
Vector2<T> Vector2<T>::operator/(T scale) const Vector2<T> Vector2<T>::operator/(T scale) const
{ {
@ -328,6 +638,13 @@ namespace Nz
return Vector2(x / scale, y / scale); 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::operator+=(const Vector2& vec) Vector2<T>& Vector2<T>::operator+=(const Vector2& vec)
{ {
@ -337,6 +654,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::operator-=(const Vector2& vec) Vector2<T>& Vector2<T>::operator-=(const Vector2& vec)
{ {
@ -346,6 +670,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::operator*=(const Vector2& vec) Vector2<T>& Vector2<T>::operator*=(const Vector2& vec)
{ {
@ -355,6 +686,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::operator*=(T scale) Vector2<T>& Vector2<T>::operator*=(T scale)
{ {
@ -364,6 +702,16 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::operator/=(const Vector2& vec) Vector2<T>& Vector2<T>::operator/=(const Vector2& vec)
{ {
@ -383,6 +731,16 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector2<T>& Vector2<T>::operator/=(T scale) Vector2<T>& Vector2<T>::operator/=(T scale)
{ {
@ -402,19 +760,40 @@ namespace Nz
return *this; 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<typename T> template<typename T>
bool Vector2<T>::operator==(const Vector2& vec) const bool Vector2<T>::operator==(const Vector2& vec) const
{ {
return NumberEquals(x, vec.x) && 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<typename T> template<typename T>
bool Vector2<T>::operator!=(const Vector2& vec) const bool Vector2<T>::operator!=(const Vector2& vec) const
{ {
return !operator==(vec); 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<typename T> template<typename T>
bool Vector2<T>::operator<(const Vector2& vec) const bool Vector2<T>::operator<(const Vector2& vec) const
{ {
@ -424,6 +803,13 @@ namespace Nz
return x < vec.x; 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<typename T> template<typename T>
bool Vector2<T>::operator<=(const Vector2& vec) const bool Vector2<T>::operator<=(const Vector2& vec) const
{ {
@ -433,24 +819,95 @@ namespace Nz
return x < vec.x; 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<typename T> template<typename T>
bool Vector2<T>::operator>(const Vector2& vec) const bool Vector2<T>::operator>(const Vector2& vec) const
{ {
return !operator<=(vec); 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<typename T> template<typename T>
bool Vector2<T>::operator>=(const Vector2& vec) const bool Vector2<T>::operator>=(const Vector2& vec) const
{ {
return !operator<(vec); 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<typename T>
T Vector2<T>::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<typename T> template<typename T>
Vector2<T> Vector2<T>::Lerp(const Vector2& from, const Vector2& to, T interpolation) Vector2<T> Vector2<T>::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<typename T>
Vector2<T> Vector2<T>::Normalize(const Vector2& vec)
{
return vec.GetNormal();
}
/*!
* \brief Shorthand for the vector (1, 1)
* \return A vector with components (1, 1)
*
* \see MakeUnit
*/
template<typename T> template<typename T>
Vector2<T> Vector2<T>::Unit() Vector2<T> Vector2<T>::Unit()
{ {
@ -460,6 +917,13 @@ namespace Nz
return vector; return vector;
} }
/*!
* \brief Shorthand for the vector (1, 0)
* \return A vector with components (1, 0)
*
* \see MakeUnitX
*/
template<typename T> template<typename T>
Vector2<T> Vector2<T>::UnitX() Vector2<T> Vector2<T>::UnitX()
{ {
@ -469,6 +933,13 @@ namespace Nz
return vector; return vector;
} }
/*!
* \brief Shorthand for the vector (0, 1)
* \return A vector with components (0, 1)
*
* \see MakeUnitY
*/
template<typename T> template<typename T>
Vector2<T> Vector2<T>::UnitY() Vector2<T> Vector2<T>::UnitY()
{ {
@ -478,6 +949,13 @@ namespace Nz
return vector; return vector;
} }
/*!
* \brief Shorthand for the vector (0, 0)
* \return A vector with components (0, 0)
*
* \see MakeZero
*/
template<typename T> template<typename T>
Vector2<T> Vector2<T>::Zero() Vector2<T> Vector2<T>::Zero()
{ {
@ -488,18 +966,43 @@ namespace Nz
} }
} }
/*!
* \brief Output operator
* \return The stream
*
* \param out The stream
* \param vec The vector to output
*/
template<typename T> template<typename T>
std::ostream& operator<<(std::ostream& out, const Nz::Vector2<T>& vec) std::ostream& operator<<(std::ostream& out, const Nz::Vector2<T>& vec)
{ {
return out << vec.ToString(); 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<typename T> template<typename T>
Nz::Vector2<T> operator*(T scale, const Nz::Vector2<T>& vec) Nz::Vector2<T> operator*(T scale, const Nz::Vector2<T>& vec)
{ {
return Nz::Vector2<T>(scale * vec.x, scale * vec.y); return Nz::Vector2<T>(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<typename T> template<typename T>
Nz::Vector2<T> operator/(T scale, const Nz::Vector2<T>& vec) Nz::Vector2<T> operator/(T scale, const Nz::Vector2<T>& vec)
{ {
@ -513,7 +1016,7 @@ Nz::Vector2<T> operator/(T scale, const Nz::Vector2<T>& vec)
} }
#endif #endif
return Nz::Vector2<T>(scale/vec.x, scale/vec.y); return Nz::Vector2<T>(scale / vec.x, scale / vec.y);
} }
#undef F #undef F

View File

@ -73,8 +73,8 @@ namespace Nz
String ToString() const; String ToString() const;
operator T*(); operator T* ();
operator const T*() const; operator const T* () const;
const Vector3& operator+() const; const Vector3& operator+() const;
Vector3 operator-() const; Vector3 operator-() const;

File diff suppressed because it is too large Load Diff

View File

@ -60,8 +60,8 @@ namespace Nz
String ToString() const; String ToString() const;
operator T*(); operator T* ();
operator const T*() const; operator const T* () const;
const Vector4& operator+() const; const Vector4& operator+() 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;
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 UnitX();
static Vector4 UnitY(); static Vector4 UnitY();
static Vector4 UnitZ(); static Vector4 UnitZ();

View File

@ -14,54 +14,125 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::Vector4<T>
* \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<T> object from its coordinates
*
* \param X X component
* \param Y Y component
* \param Z Z component
* \param W W component
*/
template<typename T> template<typename T>
Vector4<T>::Vector4(T X, T Y, T Z, T W) Vector4<T>::Vector4(T X, T Y, T Z, T W)
{ {
Set(X, Y, Z, W); Set(X, Y, Z, W);
} }
/*!
* \brief Constructs a Vector4<T> object from two components and a Vector2<T>
*
* \param X X component
* \param Y Y component
* \param vec vec.X = Z component and vec.y = W component
*/
template<typename T> template<typename T>
Vector4<T>::Vector4(T X, T Y, const Vector2<T>& vec) Vector4<T>::Vector4(T X, T Y, const Vector2<T>& vec)
{ {
Set(X, Y, vec); Set(X, Y, vec);
} }
/*!
* \brief Constructs a Vector4<T> object from one component, a Vector2<T> and one component
*
* \param X X component
* \param vec vec.X = Y component and vec.y = Z component
* \param W W component
*/
template<typename T> template<typename T>
Vector4<T>::Vector4(T X, const Vector2<T>& vec, T W) Vector4<T>::Vector4(T X, const Vector2<T>& vec, T W)
{ {
Set(X, vec, W); Set(X, vec, W);
} }
/*!
* \brief Constructs a Vector4<T> object from one component and a Vector3<T>
*
* \param X X component
* \param vec vec.X = Y component, vec.y = Z component and vec.z = W component
*/
template<typename T> template<typename T>
Vector4<T>::Vector4(T X, const Vector3<T>& vec) Vector4<T>::Vector4(T X, const Vector3<T>& vec)
{ {
Set(X, vec); Set(X, vec);
} }
/*!
* \brief Constructs explicitely a Vector4<T> object from its "scale"
*
* \param scale X component = Y component = Z component = W component
*/
template<typename T> template<typename T>
Vector4<T>::Vector4(T scale) Vector4<T>::Vector4(T scale)
{ {
Set(scale); Set(scale);
} }
/*!
* \brief Constructs a Vector4<T> 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<typename T> template<typename T>
Vector4<T>::Vector4(const T vec[4]) Vector4<T>::Vector4(const T vec[4])
{ {
Set(vec); Set(vec);
} }
/*!
* \brief Constructs a Vector4<T> object from a Vector2<T> and two components
*
* \param vec vec.X = X component and vec.y = Y component
* \param Z Z component
* \param W W component
*/
template<typename T> template<typename T>
Vector4<T>::Vector4(const Vector2<T>& vec, T Z, T W) Vector4<T>::Vector4(const Vector2<T>& vec, T Z, T W)
{ {
Set(vec, Z, W); Set(vec, Z, W);
} }
/*!
* \brief Constructs a Vector4<T> object from one component and a Vector3<T>
*
* \param vec vec.X = X component, vec.y = Y component and vec.z = Z component
* \param W W component
*/
template<typename T> template<typename T>
Vector4<T>::Vector4(const Vector3<T>& vec, T W) Vector4<T>::Vector4(const Vector3<T>& vec, T W)
{ {
Set(vec, W); Set(vec, W);
} }
/*!
* \brief Constructs a Vector4<T> object from another type of Vector4
*
* \param vec Vector of type U to convert to type T
*/
template<typename T> template<typename T>
template<typename U> template<typename U>
Vector4<T>::Vector4(const Vector4<U>& vec) Vector4<T>::Vector4(const Vector4<U>& vec)
@ -69,18 +140,45 @@ namespace Nz
Set(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<typename T> template<typename T>
T Vector4<T>::AbsDotProduct(const Vector4& vec) const T Vector4<T>::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); 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<typename T> template<typename T>
T Vector4<T>::DotProduct(const Vector4& vec) const T Vector4<T>::DotProduct(const Vector4& vec) const
{ {
return x*vec.x + y*vec.y + z*vec.z + w*vec.w; 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<typename T> template<typename T>
Vector4<T> Vector4<T>::GetNormal(T* length) const Vector4<T> Vector4<T>::GetNormal(T* length) const
{ {
@ -90,30 +188,67 @@ namespace Nz
return vec; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::MakeUnitX() Vector4<T>& Vector4<T>::MakeUnitX()
{ {
return Set(F(1.0), F(0.0), F(0.0), F(1.0)); 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::MakeUnitY() Vector4<T>& Vector4<T>::MakeUnitY()
{ {
return Set(F(0.0), F(1.0), F(0.0), F(1.0)); 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::MakeUnitZ() Vector4<T>& Vector4<T>::MakeUnitZ()
{ {
return Set(F(0.0), F(0.0), F(1.0), F(1.0)); 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::MakeZero() Vector4<T>& Vector4<T>::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<typename T> template<typename T>
Vector4<T>& Vector4<T>::Maximize(const Vector4& vec) Vector4<T>& Vector4<T>::Maximize(const Vector4& vec)
{ {
@ -132,6 +267,15 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::Minimize(const Vector4& vec) Vector4<T>& Vector4<T>::Minimize(const Vector4& vec)
{ {
@ -150,11 +294,20 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::Normalize(T* length) Vector4<T>& Vector4<T>::Normalize(T* length)
{ {
T invLength = F(1.0)/w; 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; y *= invLength;
z *= invLength; z *= invLength;
@ -166,6 +319,16 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::Set(T X, T Y, T Z, T W) Vector4<T>& Vector4<T>::Set(T X, T Y, T Z, T W)
{ {
@ -177,6 +340,15 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::Set(T X, T Y, const Vector2<T>& vec) Vector4<T>& Vector4<T>::Set(T X, T Y, const Vector2<T>& vec)
{ {
@ -188,6 +360,15 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::Set(T X, const Vector2<T>& vec, T W) Vector4<T>& Vector4<T>::Set(T X, const Vector2<T>& vec, T W)
{ {
@ -199,6 +380,14 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::Set(T X, const Vector3<T>& vec) Vector4<T>& Vector4<T>::Set(T X, const Vector3<T>& vec)
{ {
@ -210,6 +399,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::Set(T scale) Vector4<T>& Vector4<T>::Set(T scale)
{ {
@ -221,6 +417,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::Set(const T vec[4]) Vector4<T>& Vector4<T>::Set(const T vec[4])
{ {
@ -229,6 +432,14 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::Set(const Vector2<T>& vec, T Z, T W) Vector4<T>& Vector4<T>::Set(const Vector2<T>& vec, T Z, T W)
{ {
@ -240,6 +451,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::Set(const Vector3<T>& vec, T W) Vector4<T>& Vector4<T>::Set(const Vector3<T>& vec, T W)
{ {
@ -251,6 +469,13 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Sets the components of the vector from another vector
* \return A reference to this vector
*
* \param vec The other vector
*/
template<typename T> template<typename T>
Vector4<T>& Vector4<T>::Set(const Vector4& vec) Vector4<T>& Vector4<T>::Set(const Vector4& vec)
{ {
@ -259,6 +484,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
template<typename U> template<typename U>
Vector4<T>& Vector4<T>::Set(const Vector4<U>& vec) Vector4<T>& Vector4<T>::Set(const Vector4<U>& vec)
@ -271,6 +503,11 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Gives a string representation
* \return A string representation of the object: "Vector4(x, y, z, w)"
*/
template<typename T> template<typename T>
String Vector4<T>::ToString() const String Vector4<T>::ToString() const
{ {
@ -279,54 +516,116 @@ namespace Nz
return ss << "Vector4(" << x << ", " << y << ", " << z << ", " << w << ')'; 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<typename T> template<typename T>
Vector4<T>::operator T*() Vector4<T>::operator T* ()
{ {
return &x; 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<typename T> template<typename T>
Vector4<T>::operator const T*() const Vector4<T>::operator const T* () const
{ {
return &x; return &x;
} }
/*!
* \brief Helps to represent the sign of the vector
* \return A constant reference to this vector
*/
template<typename T> template<typename T>
const Vector4<T>& Vector4<T>::operator+() const const Vector4<T>& Vector4<T>::operator+() const
{ {
return *this; return *this;
} }
/*!
* \brief Negates the components of the vector
* \return A constant reference to this vector with negate components
*/
template<typename T> template<typename T>
Vector4<T> Vector4<T>::operator-() const Vector4<T> Vector4<T>::operator-() const
{ {
return Vector4(-x, -y, -z, -w); 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<typename T> template<typename T>
Vector4<T> Vector4<T>::operator+(const Vector4& vec) const Vector4<T> Vector4<T>::operator+(const Vector4& vec) const
{ {
return Vector4(x + vec.x, y + vec.y, z + vec.z, w + vec.w); 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<typename T> template<typename T>
Vector4<T> Vector4<T>::operator-(const Vector4& vec) const Vector4<T> Vector4<T>::operator-(const Vector4& vec) const
{ {
return Vector4(x - vec.x, y - vec.y, z - vec.z, w - vec.w); 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<typename T> template<typename T>
Vector4<T> Vector4<T>::operator*(const Vector4& vec) const Vector4<T> Vector4<T>::operator*(const Vector4& vec) const
{ {
return Vector4(x * vec.x, y * vec.y, z * vec.z, w * vec.w); 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<typename T> template<typename T>
Vector4<T> Vector4<T>::operator*(T scale) const Vector4<T> Vector4<T>::operator*(T scale) const
{ {
return Vector4(x * scale, y * scale, z * scale, w * scale); 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<typename T> template<typename T>
Vector4<T> Vector4<T>::operator/(const Vector4& vec) const Vector4<T> Vector4<T>::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); 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<typename T> template<typename T>
Vector4<T> Vector4<T>::operator/(T scale) const Vector4<T> Vector4<T>::operator/(T scale) const
{ {
@ -359,6 +668,13 @@ namespace Nz
return Vector4(x / scale, y / scale, z / scale, w / scale); 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::operator+=(const Vector4& vec) Vector4<T>& Vector4<T>::operator+=(const Vector4& vec)
{ {
@ -370,6 +686,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::operator-=(const Vector4& vec) Vector4<T>& Vector4<T>::operator-=(const Vector4& vec)
{ {
@ -381,6 +704,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::operator*=(const Vector4& vec) Vector4<T>& Vector4<T>::operator*=(const Vector4& vec)
{ {
@ -392,6 +722,13 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::operator*=(T scale) Vector4<T>& Vector4<T>::operator*=(T scale)
{ {
@ -403,6 +740,16 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::operator/=(const Vector4& vec) Vector4<T>& Vector4<T>::operator/=(const Vector4& vec)
{ {
@ -424,6 +771,16 @@ namespace Nz
return *this; 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<typename T> template<typename T>
Vector4<T>& Vector4<T>::operator/=(T scale) Vector4<T>& Vector4<T>::operator/=(T scale)
{ {
@ -445,21 +802,42 @@ namespace Nz
return *this; 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<typename T> template<typename T>
bool Vector4<T>::operator==(const Vector4& vec) const bool Vector4<T>::operator==(const Vector4& vec) const
{ {
return NumberEquals(x, vec.x) && return NumberEquals(x, vec.x) &&
NumberEquals(y, vec.y) && NumberEquals(y, vec.y) &&
NumberEquals(z, vec.z) && NumberEquals(z, vec.z) &&
NumberEquals(w, vec.w); 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<typename T> template<typename T>
bool Vector4<T>::operator!=(const Vector4& vec) const bool Vector4<T>::operator!=(const Vector4& vec) const
{ {
return !operator==(vec); 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<typename T> template<typename T>
bool Vector4<T>::operator<(const Vector4& vec) const bool Vector4<T>::operator<(const Vector4& vec) const
{ {
@ -479,6 +857,13 @@ namespace Nz
return x < vec.x; 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<typename T> template<typename T>
bool Vector4<T>::operator<=(const Vector4& vec) const bool Vector4<T>::operator<=(const Vector4& vec) const
{ {
@ -498,18 +883,79 @@ namespace Nz
return x < vec.x; 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<typename T> template<typename T>
bool Vector4<T>::operator>(const Vector4& vec) const bool Vector4<T>::operator>(const Vector4& vec) const
{ {
return !operator<=(vec); 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<typename T> template<typename T>
bool Vector4<T>::operator>=(const Vector4& vec) const bool Vector4<T>::operator>=(const Vector4& vec) const
{ {
return !operator<(vec); 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<typename T>
Vector4<T> Vector4<T>::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<typename T>
Vector4<T> Vector4<T>::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<typename T> template<typename T>
Vector4<T> Vector4<T>::UnitX() Vector4<T> Vector4<T>::UnitX()
{ {
@ -519,6 +965,13 @@ namespace Nz
return vector; return vector;
} }
/*!
* \brief Shorthand for the vector (0, 1, 0, 1)
* \return A vector with components (0, 1, 0, 1)
*
* \see MakeUnitY
*/
template<typename T> template<typename T>
Vector4<T> Vector4<T>::UnitY() Vector4<T> Vector4<T>::UnitY()
{ {
@ -528,6 +981,13 @@ namespace Nz
return vector; return vector;
} }
/*!
* \brief Shorthand for the vector (0, 0, 1, 1)
* \return A vector with components (0, 0, 1, 1)
*
* \see MakeUnitZ
*/
template<typename T> template<typename T>
Vector4<T> Vector4<T>::UnitZ() Vector4<T> Vector4<T>::UnitZ()
{ {
@ -537,6 +997,13 @@ namespace Nz
return vector; return vector;
} }
/*!
* \brief Shorthand for the vector (0, 0, 0, 1)
* \return A vector with components (0, 0, 0, 1)
*
* \see MakeZero
*/
template<typename T> template<typename T>
Vector4<T> Vector4<T>::Zero() Vector4<T> Vector4<T>::Zero()
{ {
@ -547,18 +1014,44 @@ namespace Nz
} }
} }
/*!
* \brief Output operator
* \return The stream
*
* \param out The stream
* \param vec The vector to output
*/
template<typename T> template<typename T>
std::ostream& operator<<(std::ostream& out, const Nz::Vector4<T>& vec) std::ostream& operator<<(std::ostream& out, const Nz::Vector4<T>& vec)
{ {
return out << vec.ToString(); 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<typename T> template<typename T>
Nz::Vector4<T> operator*(T scale, const Nz::Vector4<T>& vec) Nz::Vector4<T> operator*(T scale, const Nz::Vector4<T>& vec)
{ {
return Nz::Vector4<T>(scale * vec.x, scale * vec.y, scale * vec.z, scale * vec.w); return Nz::Vector4<T>(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<typename T> template<typename T>
Nz::Vector4<T> operator/(T scale, const Nz::Vector4<T>& vec) Nz::Vector4<T> operator/(T scale, const Nz::Vector4<T>& vec)
{ {

View File

@ -225,7 +225,7 @@ namespace Nz
public: public:
NullGeom(); NullGeom();
void ComputeInertialMatrix(Vector3f* inertia, Vector3f* center) const; void ComputeInertialMatrix(Vector3f* inertia, Vector3f* center) const override;
GeomType GetType() const override; GeomType GetType() const override;

View File

@ -43,12 +43,12 @@ namespace Nz
void Detach(AttachmentPoint attachmentPoint, UInt8 index); void Detach(AttachmentPoint attachmentPoint, UInt8 index);
unsigned int GetHeight() const override; unsigned int GetHeight() const override;
RenderTargetParameters GetParameters() const; RenderTargetParameters GetParameters() const override;
Vector2ui GetSize() const; Vector2ui GetSize() const;
unsigned int GetWidth() const override; unsigned int GetWidth() const override;
bool IsComplete() const; bool IsComplete() const;
bool IsRenderable() const; bool IsRenderable() const override;
inline bool IsValid() const; inline bool IsValid() const;
bool Lock() const; bool Lock() const;

View File

@ -46,11 +46,11 @@ namespace Nz
void EnableVerticalSync(bool enabled); void EnableVerticalSync(bool enabled);
unsigned int GetHeight() const; unsigned int GetHeight() const override;
RenderTargetParameters GetParameters() const; RenderTargetParameters GetParameters() const override;
unsigned int GetWidth() const; unsigned int GetWidth() const override;
bool IsRenderable() const; bool IsRenderable() const override;
bool IsValid() const; bool IsValid() const;
void SetFramerateLimit(unsigned int limit); void SetFramerateLimit(unsigned int limit);

View File

@ -24,7 +24,7 @@ namespace Nz
SimpleTextDrawer(SimpleTextDrawer&& drawer); SimpleTextDrawer(SimpleTextDrawer&& drawer);
virtual ~SimpleTextDrawer(); virtual ~SimpleTextDrawer();
const Rectui& GetBounds() const; const Rectui& GetBounds() const override;
unsigned int GetCharacterSize() const; unsigned int GetCharacterSize() const;
const Color& GetColor() const; const Color& GetColor() const;
Font* GetFont() const; Font* GetFont() const;

View File

@ -180,7 +180,7 @@ namespace Nz
return true; 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 // Si la musique a été demandée en mono, nous devons la convertir à la volée lors de la lecture
if (m_mixToMono) if (m_mixToMono)

View File

@ -70,9 +70,8 @@ namespace Nz
bool DirectoryImpl::Create(const String& dirPath) bool DirectoryImpl::Create(const String& dirPath)
{ {
mode_t permissions; // TODO: check permissions 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;
return mkdir(dirPath.GetConstBuffer(), permissions) != -1;;
} }
bool DirectoryImpl::Exists(const String& dirPath) bool DirectoryImpl::Exists(const String& dirPath)

View File

@ -9,6 +9,8 @@
#if defined(NAZARA_PLATFORM_WINDOWS) #if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Network/Win32/SocketImpl.hpp> #include <Nazara/Network/Win32/SocketImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Network/Posix/SocketImpl.hpp>
#else #else
#error Missing implementation: Socket #error Missing implementation: Socket
#endif #endif
@ -105,4 +107,4 @@ namespace Nz
m_handle = handle; m_handle = handle;
OnOpened(); OnOpened();
} }
} }

View File

@ -12,6 +12,8 @@
#if defined(NAZARA_PLATFORM_WINDOWS) #if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Network/Win32/IpAddressImpl.hpp> #include <Nazara/Network/Win32/IpAddressImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Network/Posix/IpAddressImpl.hpp>
#else #else
#error Missing implementation: Network #error Missing implementation: Network
#endif #endif

View File

@ -12,6 +12,8 @@
#if defined(NAZARA_PLATFORM_WINDOWS) #if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Network/Win32/SocketImpl.hpp> #include <Nazara/Network/Win32/SocketImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Network/Posix/SocketImpl.hpp>
#else #else
#error Missing implementation: Network #error Missing implementation: Network
#endif #endif

View File

@ -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 <Nazara/Network/Posix/IpAddressImpl.hpp>
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Network/Posix/SocketImpl.hpp>
#include <cstring>
#include <Nazara/Network/Debug.hpp>
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<char, NI_MAXHOST> hostnameBuffer;
std::array<char, NI_MAXSERV> 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<sockaddr_in*>(info->ai_addr);
return FromSockAddr(ipv4);
}
case AF_INET6:
{
sockaddr_in6* ipv6 = reinterpret_cast<sockaddr_in6*>(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<const sockaddr_in*>(address));
case AF_INET6:
return FromSockAddr(reinterpret_cast<const sockaddr_in6*>(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<sockaddr*>(socketAddress.data()), socketAddressLen, hostname, service, NI_NUMERICSERV) != 0)
{
if (error)
*error = TranslateEAIErrorToResolveError(errno);
return false;
}
if (error)
*error = ResolveError_NoError;
return true;
}
std::vector<HostnameInfo> IpAddressImpl::ResolveHostname(NetProtocol procol, const String& hostname, const String& service, ResolveError* error)
{
std::vector<HostnameInfo> 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<sockaddr_in*>(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<sockaddr_in6*>(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;
}
}

View File

@ -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 <Nazara/Network/IpAddress.hpp>
#include <netdb.h>
#include <netinet/in.h>
namespace Nz
{
class IpAddressImpl
{
public:
using SockAddrBuffer = std::array<UInt8, sizeof(sockaddr_in6)>;
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<HostnameInfo> 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);
};
}

View File

@ -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 <Nazara/Network/Posix/SocketImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Log.hpp>
#include <Nazara/Network/Posix/IpAddressImpl.hpp>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstring>
#include <Nazara/Network/Debug.hpp>
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<sockaddr*>(&nameBuffer), &bufferLength);
if (newClient != InvalidHandle)
{
if (address)
*address = IpAddressImpl::FromSockAddr(reinterpret_cast<const sockaddr*>(&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<const sockaddr*>(&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<const sockaddr*>(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<long>(msTimeout / 1000ULL);
tv.tv_usec = static_cast<long>((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<const sockaddr*>(&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<sockaddr*>(nameBuffer.data()), &bufferLength) == SOCKET_ERROR)
{
if (error)
*error = TranslateErrnoToResolveError(GetLastErrorCode());
return IpAddress();
}
if (error)
*error = SocketError_NoError;
return IpAddressImpl::FromSockAddr(reinterpret_cast<sockaddr*>(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<sockaddr*>(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<sockaddr*>(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<char*>(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<sockaddr*>(&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<const sockaddr*>(&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<const char*>(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<const char*>(buffer), length, 0, reinterpret_cast<const sockaddr*>(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<const char*>(&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;
}

View File

@ -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 <Nazara/Network/SocketHandle.hpp>
#include <Nazara/Network/Enums.hpp>
#include <Nazara/Network/IpAddress.hpp>
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;
};
}

View File

@ -10,6 +10,8 @@
#if defined(NAZARA_PLATFORM_WINDOWS) #if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Network/Win32/SocketImpl.hpp> #include <Nazara/Network/Win32/SocketImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Network/Posix/SocketImpl.hpp>
#else #else
#error Missing implementation: Socket #error Missing implementation: Socket
#endif #endif

View File

@ -11,6 +11,8 @@
#if defined(NAZARA_PLATFORM_WINDOWS) #if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Network/Win32/SocketImpl.hpp> #include <Nazara/Network/Win32/SocketImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Network/Posix/SocketImpl.hpp>
#else #else
#error Missing implementation: Socket #error Missing implementation: Socket
#endif #endif
@ -60,4 +62,4 @@ namespace Nz
m_boundAddress = IpAddress::Invalid; m_boundAddress = IpAddress::Invalid;
} }
} }

View File

@ -7,6 +7,8 @@
#if defined(NAZARA_PLATFORM_WINDOWS) #if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Network/Win32/SocketImpl.hpp> #include <Nazara/Network/Win32/SocketImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Network/Posix/SocketImpl.hpp>
#else #else
#error Missing implementation: Socket #error Missing implementation: Socket
#endif #endif

View File

@ -136,7 +136,7 @@ namespace Nz
OpenEWMHConnection(sharedConnection); OpenEWMHConnection(sharedConnection);
} }
NazaraNotice("Initialized: Utility module"); NazaraNotice("Initialized: Display module");
return true; return true;
} }

View File

@ -17,7 +17,7 @@ namespace Nz
{ {
class String; class String;
class X11 class NAZARA_UTILITY_API X11
{ {
public: public:
X11() = delete; X11() = delete;

View File

@ -1,7 +1,7 @@
#include <Nazara/Math/Algorithm.hpp> #include <Nazara/Math/Algorithm.hpp>
#include <Catch/catch.hpp> #include <Catch/catch.hpp>
TEST_CASE("Approach", "[MATH][ALGORITHM]" ) TEST_CASE("Approach", "[MATH][ALGORITHM]")
{ {
SECTION("Approach 8 with 5 by 2") 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") 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") 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") SECTION("Nearest power of two of 16 = 16")
{ {
REQUIRE(Nz::GetNearestPowerOfTwo(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") 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") 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") 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") 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") 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") 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") 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") SECTION("235 in string")
{ {

View File

@ -99,5 +99,20 @@ SCENARIO("BoundingVolume", "[MATH][BOUNDINGVOLUME]")
REQUIRE(firstCenterAndUnit.aabb != secondCenterAndUnit.aabb); 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);
}
}
} }
} }

View File

@ -64,6 +64,18 @@ SCENARIO("Box", "[MATH][BOX]")
REQUIRE(tmp == firstCenterAndUnit); 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") GIVEN("Two wrong box (negative width, height and depth")

View File

@ -15,8 +15,8 @@ SCENARIO("EulerAngles", "[MATH][EULERANGLES]")
WHEN("We do some operations") WHEN("We do some operations")
{ {
Nz::EulerAnglesf euler90(90.f, 90.f, 90.f); Nz::EulerAnglesf euler90(Nz::FromDegrees(90.f), Nz::FromDegrees(90.f), Nz::FromDegrees(90.f));
Nz::EulerAnglesf euler270(270.f, 270.f, 270.f); Nz::EulerAnglesf euler270(Nz::FromDegrees(270.f), Nz::FromDegrees(270.f), Nz::FromDegrees(270.f));
Nz::EulerAnglesf euler360 = euler90 + euler270; Nz::EulerAnglesf euler360 = euler90 + euler270;
euler360.Normalize(); 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") GIVEN("Euler angles with rotation 45 on each axis")
{ {
WHEN("We convert to quaternion") WHEN("We convert to quaternion")

View File

@ -78,5 +78,18 @@ SCENARIO("Frustum", "[MATH][FRUSTUM]")
CHECK(frustum.Contains(&tmp, 1)); 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);
}
}
} }
} }

View File

@ -37,19 +37,29 @@ SCENARIO("Matrix4", "[MATH][Matrix4]")
REQUIRE(firstIdentity.Inverse() == secondIdentity.InverseAffine()); 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") GIVEN("Two different matrix")
{ {
Nz::Matrix4f matrix1(1.0f, 0.0f, 0.0f, 0.0f, Nz::Matrix4f matrix1(1.0f, 0.0f, 0.0f, 0.0f,
7.0f, 2.0f, 0.0f, 0.0f, 7.0f, 2.0f, 0.0f, 0.0f,
1.0f, 5.0f, 3.0f, 0.0f, 1.0f, 5.0f, 3.0f, 0.0f,
8.0f, 9.0f, 2.0f, 4.0f); 8.0f, 9.0f, 2.0f, 4.0f);
Nz::Matrix4f matrix2(1.0f, 1.0f, 2.0f, -1.0f, Nz::Matrix4f matrix2(1.0f, 1.0f, 2.0f, -1.0f,
-2.0f, -1.0f, -2.0f, 2.0f, -2.0f, -1.0f, -2.0f, 2.0f,
4.0f, 2.0f, 5.0f, -4.0f, 4.0f, 2.0f, 5.0f, -4.0f,
5.0f, -3.0f, -7.0f, -6.0f); 5.0f, -3.0f, -7.0f, -6.0f);
WHEN("We ask for determinant") 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()); 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, 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, -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, 1.f);
REQUIRE(transformedMatrix == rotation45X); REQUIRE(transformedMatrix == rotation45X);
transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(Nz::FromDegrees(45.f), 0.f, 0.f).ToQuaternion()); 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()); 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, 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, 0.f, 1.f, 0.f, 0.f,
std::sqrt(2.f) / 2.f, 0.f, std::sqrt(2.f) / 2.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, 0.f, 0.f, 1.f);
REQUIRE(transformedMatrix == rotation45Y); REQUIRE(transformedMatrix == rotation45Y);
transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(0.f, Nz::FromDegrees(45.f), 0.f).ToQuaternion()); 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()); 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, 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, -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, 1.f, 0.f,
0.f, 0.f, 0.f, 1.f); 0.f, 0.f, 0.f, 1.f);
REQUIRE(transformedMatrix == rotation45Z); REQUIRE(transformedMatrix == rotation45Z);
transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(Nz::EulerAnglesf(0.f, 0.f, Nz::FromDegrees(45.f)).ToQuaternion())); transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(Nz::EulerAnglesf(0.f, 0.f, Nz::FromDegrees(45.f)).ToQuaternion()));

View File

@ -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);
}
}
} }
} }

View File

@ -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)); 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)") GIVEN("The plane XZ, distance 1 with 3 points (0, 1, 0), (1, 1, 1), (-1, 1, 0)")

View File

@ -32,6 +32,22 @@ SCENARIO("Quaternion", "[MATH][QUATERNION]")
REQUIRE((firstQuaternion * Nz::Vector3f::UnitZ()) == -Nz::Vector3f::UnitZ()); 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") GIVEN("The four unit quaternions")
@ -154,5 +170,18 @@ SCENARIO("Quaternion", "[MATH][QUATERNION]")
REQUIRE(quaternionC.z == Approx(unitZ225.z)); 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);
}*/
}
} }
} }

View File

@ -86,10 +86,37 @@ SCENARIO("Ray", "[MATH][RAY]")
Nz::BoundingVolumef nullVolume(Nz::Extend_Null); Nz::BoundingVolumef nullVolume(Nz::Extend_Null);
CHECK(!ray.Intersect(nullVolume)); CHECK(!ray.Intersect(nullVolume));
float tmpClosest = -1.f;
float tmpFurthest = -1.f;
Nz::BoundingVolumef infiniteVolume(Nz::Extend_Infinite); 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<float>::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))));
}
} }
} }
} }

View File

@ -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);
}
}
} }
} }

View File

@ -59,5 +59,45 @@ SCENARIO("Sphere", "[MATH][SPHERE]")
REQUIRE(centerUnitBox.GetSquaredBoundingSphere() == Nz::Spheref(Nz::Vector3f::Zero(), 0.75f)); 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);
}
}
} }
} }

View File

@ -15,6 +15,7 @@ SCENARIO("Vector2", "[MATH][VECTOR2]")
THEN("They are the same") THEN("They are the same")
{ {
REQUIRE(firstUnit == secondUnit); REQUIRE(firstUnit == secondUnit);
REQUIRE(firstUnit <= secondUnit);
} }
} }
@ -22,11 +23,13 @@ SCENARIO("Vector2", "[MATH][VECTOR2]")
{ {
Nz::Vector2f tmp(-1.f, 1.f); 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.AbsDotProduct(tmp) == Approx(2.f));
REQUIRE(firstUnit.DotProduct(tmp) == Approx(0.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))); 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));
}
}
} }
} }

View File

@ -26,7 +26,8 @@ SCENARIO("Vector3", "[MATH][VECTOR3]")
{ {
REQUIRE(firstUnit.AbsDotProduct(tmp) == Approx(2.f)); REQUIRE(firstUnit.AbsDotProduct(tmp) == Approx(2.f));
REQUIRE(firstUnit.DotProduct(tmp) == Approx(0.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))); 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));
}
}
} }
} }

View File

@ -39,5 +39,15 @@ SCENARIO("Vector4", "[MATH][VECTOR4]")
REQUIRE(tmp.Normalize() == Nz::Vector4f(Nz::Vector3f::Unit() * (1.f / 3.f), 1.f)); 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));
}
}
} }
} }