diff --git a/include/Nazara/Core/HashDigest.hpp b/include/Nazara/Core/HashDigest.hpp index 8083f2999..9e6459d04 100644 --- a/include/Nazara/Core/HashDigest.hpp +++ b/include/Nazara/Core/HashDigest.hpp @@ -28,7 +28,7 @@ class NAZARA_API NzHashDigest NzString ToHex() const; - nzUInt8 operator[](unsigned short pos) const; + nzUInt8 operator[](unsigned int pos) const; NzHashDigest& operator=(const NzHashDigest& rhs); NzHashDigest& operator=(NzHashDigest&& rhs) noexcept; @@ -45,7 +45,7 @@ class NAZARA_API NzHashDigest private: NzString m_hashName; nzUInt8* m_digest; - unsigned short m_digestLength; + unsigned int m_digestLength; }; #endif // NAZARA_HASHDIGEST_HPP diff --git a/include/Nazara/Math.hpp b/include/Nazara/Math.hpp index e69eab49c..e70158c4a 100644 --- a/include/Nazara/Math.hpp +++ b/include/Nazara/Math.hpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/Math/EulerAngles.inl b/include/Nazara/Math/EulerAngles.inl index 36527087a..a085d99cf 100644 --- a/include/Nazara/Math/EulerAngles.inl +++ b/include/Nazara/Math/EulerAngles.inl @@ -83,9 +83,9 @@ template template void NzEulerAngles::Set(const NzEulerAngles& angles) { - pitch = static_cast(angles.pitch); - yaw = static_cast(angles.yaw); - roll = static_cast(angles.roll); + pitch = F(angles.pitch); + yaw = F(angles.yaw); + roll = F(angles.roll); } template diff --git a/include/Nazara/Math/Plane.hpp b/include/Nazara/Math/Plane.hpp index 2b95141ee..b816ae195 100644 --- a/include/Nazara/Math/Plane.hpp +++ b/include/Nazara/Math/Plane.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014 Jérôme Leclercq +// Copyright (C) 2014 Jérôme Leclercq // This file is part of the "Nazara Engine - Mathematics module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -38,6 +38,9 @@ class NzPlane NzString ToString() const; static NzPlane Lerp(const NzPlane& from, const NzPlane& to, T interpolation); + static NzPlane XY(); + static NzPlane XZ(); + static NzPlane YZ(); NzVector3 normal; T distance; diff --git a/include/Nazara/Math/Plane.inl b/include/Nazara/Math/Plane.inl index 640e9ea2f..4e7c81029 100644 --- a/include/Nazara/Math/Plane.inl +++ b/include/Nazara/Math/Plane.inl @@ -152,6 +152,24 @@ NzPlane NzPlane::Lerp(const NzPlane& from, const NzPlane& to, T interpolat return plane; } +template +NzPlane NzPlane::XY() +{ + return NzPlane(F(0.0), F(0.0), F(1.0), F(0.0)); +} + +template +NzPlane NzPlane::XZ() +{ + return NzPlane(F(0.0), F(1.0), F(0.0), F(0.0)); +} + +template +NzPlane NzPlane::YZ() +{ + return NzPlane(F(1.0), F(0.0), F(0.0), F(0.0)); +} + template std::ostream& operator<<(std::ostream& out, const NzPlane& plane) { diff --git a/include/Nazara/Math/Ray.hpp b/include/Nazara/Math/Ray.hpp new file mode 100644 index 000000000..d342dcc26 --- /dev/null +++ b/include/Nazara/Math/Ray.hpp @@ -0,0 +1,69 @@ +// Copyright (C) 2014 Rémi Bèges - Jérôme Leclercq +// This file is part of the "Nazara Engine - Mathematics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_RAY_HPP +#define NAZARA_RAY_HPP + +#include +#include +#include +#include +#include +#include +#include + +template class NzRay +{ + public: + NzRay() = default; + NzRay(T X, T Y, T Z, T directionX, T directionY, T directionZ); + NzRay(const T origin[3], const T direction[3]); + NzRay(const NzVector3& origin, const NzVector3& direction); + NzRay(const NzPlane& planeOne, const NzPlane& planeTwo); + template explicit NzRay(const NzVector3& origin, const NzVector3& direction); + template explicit NzRay(const NzRay& ray); + NzRay(const NzRay& ray) = default; + ~NzRay() = default; + + NzVector3 GetClosestPoint(const NzVector3& point) const; + NzVector3 GetPoint(T lambda) const; + + bool Intersect(const NzBox& box, NzVector3 * hitPoint = nullptr, NzVector3 * hitSecondPoint = nullptr) const; + bool Intersect(const NzOrientedBox& orientedBox, NzVector3 * hitPoint = nullptr, NzVector3 * hitSecondPoint = nullptr) const; + bool Intersect(const NzPlane& plane, NzVector3 * hitPoint = nullptr) const; + bool Intersect(const NzSphere& sphere, NzVector3 * hitPoint = nullptr, NzVector3 * hitSecondPoint = nullptr) const; + + NzVector3 operator*(T lambda) const; + + NzRay& Set(T X, T Y, T Z, T directionX, T directionY, T directionZ); + NzRay& Set(const T origin[3], const T direction[3]); + NzRay& Set(const NzVector3& origin, const NzVector3& direction); + NzRay& Set(const NzPlane& planeOne, const NzPlane& planeTwo); + template NzRay& Set(const NzVector3& origin, const NzVector3& direction); + template NzRay& Set(const NzRay& ray); + NzRay& Set(const NzRay& ray); + + NzRay& SetDirection(const NzVector3& direction); + NzRay& SetOrigin(const NzVector3& origin); + + NzString ToString() const; + + static NzRay Lerp(const NzRay& from, const NzRay& to, T interpolation); + static NzRay UnitX(); + static NzRay UnitY(); + static NzRay UnitZ(); + + NzVector3 direction, origin; +}; + +template std::ostream& operator<<(std::ostream& out, const NzRay& vec); + +typedef NzRay NzRayd; +typedef NzRay NzRayf; + +#include + +#endif // NAZARA_RAY_HPP diff --git a/include/Nazara/Math/Ray.inl b/include/Nazara/Math/Ray.inl new file mode 100644 index 000000000..1b423f900 --- /dev/null +++ b/include/Nazara/Math/Ray.inl @@ -0,0 +1,328 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Mathematics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +#define F(a) static_cast(a) + +template +NzRay::NzRay(T X, T Y, T Z, T DirectionX, T DirectionY, T DirectionZ) +{ + Set(X, Y, Z, DirectionX, DirectionY, DirectionZ); +} + +template +NzRay::NzRay(const T Origin[3], const T Direction[3]) +{ + Set(Origin, Direction); +} + +template +NzRay::NzRay(const NzVector3& Origin, const NzVector3& Direction) +{ + Set(Origin, Direction); +} + +template +NzRay::NzRay(const NzPlane& planeOne, const NzPlane& planeTwo) +{ + Set(planeOne, planeTwo); +} + +template +template +NzRay::NzRay(const NzVector3& Origin, const NzVector3& Direction) +{ + Set(Origin, Direction); +} + +template +template +NzRay::NzRay(const NzRay& ray) +{ + Set(ray); +} + +template +NzVector3 NzRay::GetClosestPoint(const NzVector3& point) const +{ + NzVector3 delta = point - origin; + T vsq = direction.GetSquaredLength(); + T proj = delta.DotProduct(direction); + + return GetPoint(proj/vsq); +} + +template +NzVector3 NzRay::GetPoint(T lambda) const +{ + return NzVector3(origin + direction * lambda); +} + +template +bool NzRay::Intersect(const NzBox& box, NzVector3 * hitPoint, NzVector3 * hitSecondPoint) const +{ + // Slab method + + #if NAZARA_MATH_SAFE + if (NzNumberEquals(direction.x, F(0.0)) || NzNumberEquals(direction.y, F(0.0)) || NzNumberEquals(direction.z, F(0.0))) + { + NazaraWarning("Division by zero !"); // The algorithm is still correct. + } + #endif + + T tx1 = (box.x - origin.x) / direction.x; + T tx2 = (box.x + box.width - origin.x) / direction.x; + + T tmin = std::min(tx1, tx2); + T tmax = std::max(tx1, tx2); + + T ty1 = (box.y - origin.y) / direction.y; + T ty2 = (box.y + box.height - origin.y) / direction.y; + + tmin = std::max(tmin, std::min(ty1, ty2)); + tmax = std::min(tmax, std::max(ty1, ty2)); + + T tz1 = (box.z - origin.z) / direction.z; + T tz2 = (box.z + box.depth - origin.z) / direction.z; + + tmin = std::max(tmin, std::min(tz1, tz2)); + tmax = std::min(tmax, std::max(tz1, tz2)); + + if (hitPoint) + hitPoint->Set(GetPoint(tmin)); + if (hitSecondPoint) + hitSecondPoint->Set(GetPoint(tmax)); + + return tmax >= std::max(F(0.0), tmin) && tmin < INFINITY; +} + +template +bool NzRay::Intersect(const NzOrientedBox& orientedBox, NzVector3 * hitPoint, NzVector3 * hitSecondPoint) const +{ + NzVector3 width = (orientedBox.GetCorner(nzCorner_NearLeftBottom) - orientedBox.GetCorner(nzCorner_FarLeftBottom)).Normalize(); + NzVector3 height = (orientedBox.GetCorner(nzCorner_FarLeftTop) - orientedBox.GetCorner(nzCorner_FarLeftBottom)).Normalize(); + NzVector3 depth = (orientedBox.GetCorner(nzCorner_FarRightBottom) - orientedBox.GetCorner(nzCorner_FarLeftBottom)).Normalize(); + + // Construction of the inverse of the matrix who did the rotation -> orthogonal matrix. + NzMatrix4 transformation(width.x, height.x, depth.x, F(0.0), + width.y, height.y, depth.y, F(0.0), + width.z, height.z, depth.z, F(0.0), + F(0.0), F(0.0), F(0.0), F(1.0)); + + // Reduction to aabb problem + NzVector3 newOrigin = transformation.Transform(origin); + NzVector3 newDirection = transformation.Transform(direction); + + NzVector3 tmp, tmp2; + if (NzRay(newOrigin, newDirection).Intersect(NzBox(orientedBox.GetCorner(nzCorner_NearRightTop), orientedBox.GetCorner(nzCorner_FarLeftBottom)), &tmp, &tmp2)) + { + if (hitPoint) + { + transformation.Transpose(); + hitPoint->Set(transformation.Transform(tmp)); + if (hitSecondPoint) + hitSecondPoint->Set(transformation.Transform(tmp2)); + } + + return true; + } + + return false; +} + +template +bool NzRay::Intersect(const NzPlane& plane, NzVector3 * hitPoint) const +{ + T divisor = plane.normal.DotProduct(direction); + + if (NzNumberEquals(divisor, F(0.0))) + return false; // perpendicular + + if (!hitPoint) + return true; + + T lambda = - (plane.normal.DotProduct(origin) - plane.distance) / divisor; // The plane is ax+by+cz=d + hitPoint->Set(GetPoint(lambda)); + + return true; +} + +template +bool NzRay::Intersect(const NzSphere& sphere, NzVector3 * hitPoint, NzVector3 * hitSecondPoint) const +{ + NzVector3 distanceCenterOrigin = sphere.GetPosition() - origin; + T length = distanceCenterOrigin.DotProduct(direction); + + if (length < F(0.0)) + return false; // ray is perpendicular to the vector origin - center + + T squaredDistance = distanceCenterOrigin.GetSquaredLength() - length * length; + + T squaredRadius = sphere.GetRadius() * sphere.GetRadius(); + + if (squaredDistance > squaredRadius) + return false; // if the ray is further than the radius + + if (!hitPoint) + return true; + + T deltaLambda = std::sqrt(squaredRadius - squaredDistance); + + if (hitPoint) + hitPoint->Set(GetPoint(length - deltaLambda)); + if (hitSecondPoint) + hitSecondPoint->Set(GetPoint(length + deltaLambda)); + + return true; +} + +template +NzVector3 NzRay::operator*(T lambda) const +{ + return GetPoint(lambda); +} + +template +NzRay& NzRay::Set(T X, T Y, T Z, T directionX, T directionY, T directionZ) +{ + direction = NzVector3(directionX, directionY, directionZ); + origin = NzVector3(X, Y, Z); + + return *this; +} + +template +NzRay& NzRay::Set(const T Origin[3], const T Direction[3]) +{ + direction = NzVector3(Direction); + origin = NzVector3(Origin); + + return *this; +} + +template +NzRay& NzRay::Set(const NzVector3& Origin, const NzVector3& Direction) +{ + direction = Direction; + origin = Origin; + + return *this; +} + +template +NzRay& NzRay::Set(const NzPlane& planeOne, const NzPlane& planeTwo) +{ + T termOne = planeOne.normal.GetLength(); + T termTwo = planeOne.normal.DotProduct(planeTwo.normal); + T termFour = planeTwo.normal.GetLength(); + T det = termOne * termFour - termTwo * termTwo; + + #if NAZARA_MATH_SAFE + if (NzNumberEquals(det, F(0.0))) + { + + NzString error("Planes are parallel."); + + NazaraError(error); + throw std::domain_error(error); + } + #endif + + T invdet = F(1.0) / det; + T fc0 = (termFour * -planeOne.distance + termTwo * planeTwo.distance) * invdet; + T fc1 = (termOne * -planeTwo.distance + termTwo * planeOne.distance) * invdet; + + direction = planeOne.normal.CrossProduct(planeTwo.normal); + origin = planeOne.normal * fc0 + planeTwo.normal * fc1; + + return *this; +} + +template +template +NzRay& NzRay::Set(const NzVector3& Origin, const NzVector3& Direction) +{ + direction = NzVector3(Direction); + origin = NzVector3(Origin); + + return *this; +} + +template +template +NzRay& NzRay::Set(const NzRay& ray) +{ + direction = NzVector3(ray.direction); + origin = NzVector3(ray.origin); + + return *this; +} + +template +NzRay& NzRay::Set(const NzRay& ray) +{ + std::memcpy(this, &ray, sizeof(NzRay)); + + return *this; +} + +template +NzRay& NzRay::SetDirection(const NzVector3& Direction) +{ + direction = Direction; + + return *this; +} + +template +NzRay& NzRay::SetOrigin(const NzVector3& Origin) +{ + origin = Origin; + + return *this; +} + +template +NzString NzRay::ToString() const +{ + NzStringStream ss; + + return ss << "Ray(origin: " << origin.ToString() << ", direction: " << direction.ToString() << ")"; +} + +template +NzRay NzRay::Lerp(const NzRay& from, const NzRay& to, T interpolation) +{ + return NzRay(from.origin.Lerp(to.origin, interpolation), from.direction.Lerp(to.direction, interpolation)); +} + +template +NzRay NzRay::UnitX() +{ + return NzRay(NzVector3::Zero(), NzVector3::UnitX()); +} + +template +NzRay NzRay::UnitY() +{ + return NzRay(NzVector3::Zero(), NzVector3::UnitY()); +} + +template +NzRay NzRay::UnitZ() +{ + return NzRay(NzVector3::Zero(), NzVector3::UnitZ()); +} + +template +std::ostream& operator<<(std::ostream& out, const NzRay& ray) +{ + return out << ray.ToString(); +} + +#undef F + +#include diff --git a/include/Nazara/Math/Sphere.inl b/include/Nazara/Math/Sphere.inl index 9c56fac16..b9a97eb43 100644 --- a/include/Nazara/Math/Sphere.inl +++ b/include/Nazara/Math/Sphere.inl @@ -117,6 +117,7 @@ NzVector3 NzSphere::GetPositiveVertex(const NzVector3& normal) const return pos; } + template bool NzSphere::Intersect(const NzBox& box) const { diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index 2086524ba..45f2caa5c 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -23,6 +23,8 @@ class NzVector2 T AbsDotProduct(const NzVector2& vec) const; + T AngleBetween(const NzVector2& vec, bool toDegree = true) const; + T Distance(const NzVector2& vec) const; float Distancef(const NzVector2& vec) const; diff --git a/include/Nazara/Math/Vector2.inl b/include/Nazara/Math/Vector2.inl index bf19c4af7..b480bffd3 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -54,6 +54,15 @@ inline unsigned int NzVector2::AbsDotProduct(const NzVector2 +T NzVector2::AngleBetween(const NzVector2& vec, bool toDegree) const +{ + if (toDegree) + return NzRadianToDegree(std::atan2(vec.y, vec.x) - std::atan2(y, x)); + else + return std::atan2(vec.y, vec.x) - std::atan2(y, x); +} + template T NzVector2::Distance(const NzVector2& vec) const { diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index 67b2cd388..8be7f40b5 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -24,6 +24,8 @@ template class NzVector3 T AbsDotProduct(const NzVector3& vec) const; + T AngleBetween(const NzVector3& vec, bool toDegree = true) const; + NzVector3 CrossProduct(const NzVector3& vec) const; T Distance(const NzVector3& vec) const; diff --git a/include/Nazara/Math/Vector3.inl b/include/Nazara/Math/Vector3.inl index 0d0b08335..aa1661bae 100644 --- a/include/Nazara/Math/Vector3.inl +++ b/include/Nazara/Math/Vector3.inl @@ -60,6 +60,30 @@ inline unsigned int NzVector3::AbsDotProduct(const NzVector3 +T NzVector3::AngleBetween(const NzVector3& vec, bool toDegree) const +{ + T alpha = DotProduct(vec); + T divisor = (GetLength() * vec.GetLength()); + + #if NAZARA_MATH_SAFE + if (NzNumberEquals(divisor, F(0.0))) + { + NzString error("Division by zero"); + + NazaraError(error); + throw std::domain_error(error); + } + #endif + + alpha /= divisor; + + if (toDegree) + return NzRadianToDegree(std::acos(NzClamp(alpha, F(-1.0), F(1.0)))); + else + return std::acos(NzClamp(alpha, F(-1.0), F(1.0))); +} + template NzVector3 NzVector3::CrossProduct(const NzVector3& vec) const { diff --git a/src/Nazara/Core/HashDigest.cpp b/src/Nazara/Core/HashDigest.cpp index 74b80100a..27aa22db3 100644 --- a/src/Nazara/Core/HashDigest.cpp +++ b/src/Nazara/Core/HashDigest.cpp @@ -89,7 +89,7 @@ NzString NzHashDigest::ToHex() const return NzString(new NzString::SharedString(1, length, length, hexOutput)); } -nzUInt8 NzHashDigest::operator[](unsigned short pos) const +nzUInt8 NzHashDigest::operator[](unsigned int pos) const { #if NAZARA_CORE_SAFE if (pos >= m_digestLength) diff --git a/src/Nazara/Physics/Geom.cpp b/src/Nazara/Physics/Geom.cpp index 0eb463ab9..a7e348f07 100644 --- a/src/Nazara/Physics/Geom.cpp +++ b/src/Nazara/Physics/Geom.cpp @@ -17,6 +17,9 @@ namespace case nzPrimitiveType_Box: return new NzBoxGeom(physWorld, primitive.box.lengths, primitive.matrix); + case nzPrimitiveType_Cone: + return new NzConeGeom(physWorld, primitive.cone.length, primitive.cone.radius, primitive.matrix); + case nzPrimitiveType_Plane: return new NzBoxGeom(physWorld, NzVector3f(primitive.plane.size.x, 0.01f, primitive.plane.size.y), primitive.matrix); ///TODO: PlaneGeom?