// Copyright (C) 2012 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 #include #include #include #include #define F(a) static_cast(a) template NzAxisAlignedBox::NzAxisAlignedBox() : extend(nzExtend_Null) { } template NzAxisAlignedBox::NzAxisAlignedBox(nzExtend Extend) { Set(Extend); } template NzAxisAlignedBox::NzAxisAlignedBox(T X, T Y, T Z, T Width, T Height, T Depth) { Set(X, Y, Z, Width, Height, Depth); } template NzAxisAlignedBox::NzAxisAlignedBox(const NzCube& Cube) { Set(Cube); } template NzAxisAlignedBox::NzAxisAlignedBox(const NzVector3& vec1, const NzVector3& vec2) { Set(vec1, vec2); } template template NzAxisAlignedBox::NzAxisAlignedBox(const NzAxisAlignedBox& box) { Set(box); } template bool NzAxisAlignedBox::Contains(T x, T y, T z) const { switch (extend) { case nzExtend_Finite: return cube.Contains(x, y, z); case nzExtend_Infinite: return true; case nzExtend_Null: return false; } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(extend, 16) + ')'); return false; } template bool NzAxisAlignedBox::Contains(const NzAxisAlignedBox& box) const { if (extend == nzExtend_Null || box.extend == nzExtend_Null) return false; else if (extend == nzExtend_Infinite || box.extend == nzExtend_Infinite) return true; return cube.Contains(box.cube); } template bool NzAxisAlignedBox::Contains(const NzVector3& vector) const { switch (extend) { case nzExtend_Finite: return cube.Contains(vector); case nzExtend_Infinite: return true; case nzExtend_Null: return false; } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(extend, 16) + ')'); return false; } template NzAxisAlignedBox& NzAxisAlignedBox::ExtendTo(T X, T Y, T Z) { switch (extend) { case nzExtend_Finite: cube.ExtendTo(X, Y, Z); return *this; case nzExtend_Infinite: return *this; // Rien à faire case nzExtend_Null: return Set(cube.Set(X, Y, Z, F(0.0), F(0.0), F(0.0)));; } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(extend, 16) + ')'); return *this; } template NzAxisAlignedBox& NzAxisAlignedBox::ExtendTo(const NzAxisAlignedBox& box) { switch (extend) { case nzExtend_Finite: switch (box.extend) { case nzExtend_Finite: cube.ExtendTo(box.cube); return *this; case nzExtend_Infinite: return MakeInfinite(); case nzExtend_Null: return *this; } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(box.extend, 16) + ')'); return *this; case nzExtend_Infinite: return *this; // Rien à faire case nzExtend_Null: return Set(box); } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(extend, 16) + ')'); return *this; } template NzAxisAlignedBox& NzAxisAlignedBox::ExtendTo(const NzVector3& vector) { return ExtendTo(vector.x, vector.y, vector.z); } template NzVector3 NzAxisAlignedBox::GetCorner(nzCorner corner) const { switch (extend) { case nzExtend_Finite: return cube.GetCorner(corner); case nzExtend_Infinite: // Il est possible de renvoyer un vecteur avec des flottants infinis dont le signe dépend du coin // Bien que ça soit plus juste mathématiquement, je ne vois pas l'intérêt... NazaraError("Infinite AABB has no corner"); return NzVector3(); case nzExtend_Null: return NzVector3::Zero(); } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(extend, 16) + ')'); return NzVector3(); } template NzCube NzAxisAlignedBox::GetCube() const { return cube; } template nzExtend NzAxisAlignedBox::GetExtend() const { return extend; } template NzVector3 NzAxisAlignedBox::GetNegativeVertex(const NzVector3& normal) const { switch (extend) { case nzExtend_Finite: return cube.GetNegativeVertex(normal); case nzExtend_Infinite: // Il est possible de renvoyer un vecteur avec des flottants infinis dont le signe dépend de la normale // Bien que ça soit plus juste mathématiquement, je ne vois pas l'intérêt... NazaraError("Infinite AABB has no negative vertex"); return NzVector3(); case nzExtend_Null: return NzVector3::Zero(); } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(extend, 16) + ')'); return NzVector3(); } template NzVector3 NzAxisAlignedBox::GetPosition() const { switch (extend) { case nzExtend_Finite: return cube.GetPosition(); case nzExtend_Infinite: // Il est possible de renvoyer un vecteur avec des flottants infinis // Bien que ça soit plus juste mathématiquement, je ne vois pas l'intérêt... NazaraError("Infinite AABB has no position"); return NzVector3(); case nzExtend_Null: return NzVector3::Zero(); } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(extend, 16) + ')'); return NzVector3(); } template NzVector3 NzAxisAlignedBox::GetPositiveVertex(const NzVector3& normal) const { switch (extend) { case nzExtend_Finite: return cube.GetPositiveVertex(normal); case nzExtend_Infinite: // Il est possible de renvoyer un vecteur avec des flottants infinis dont le signe dépend de la normale // Bien que ça soit plus juste mathématiquement, je ne vois pas l'intérêt... NazaraError("Infinite AABB has no corner"); return NzVector3(); case nzExtend_Null: return NzVector3::Zero(); } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(extend, 16) + ')'); return NzVector3(); } template NzVector3 NzAxisAlignedBox::GetSize() const { switch (extend) { case nzExtend_Finite: return cube.GetSize(); case nzExtend_Infinite: // Il est possible de renvoyer un vecteur avec des flottants infinis // Bien que ça soit plus juste mathématiquement, je ne vois pas l'intérêt... NazaraError("Infinite AABB has no size"); return NzVector3(); case nzExtend_Null: return NzVector3::Zero(); } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(extend, 16) + ')'); return NzVector3(); } template bool NzAxisAlignedBox::Intersect(const NzAxisAlignedBox& box, NzAxisAlignedBox* intersection) const { switch (extend) { case nzExtend_Finite: { switch (box.extend) { case nzExtend_Finite: { if (cube.Intersect(box.cube, &intersection->cube)) { intersection->extend = nzExtend_Finite; return true; } else return false; } case nzExtend_Infinite: intersection->Set(*this); return true; case nzExtend_Null: return false; } NazaraError("Invalid extend type (0x" + NzString::Number(box.extend, 16) + ')'); return false; } case nzExtend_Infinite: if (!box.IsNull()) // Si l'AABB n'est pas nulle, c'est qu'elle est finie ou infinie { // Et dans ce cas, il y a toujous intersection équivalente à la seconde AABB intersection->Set(box); return true; } else return false; case nzExtend_Null: return false; // N'a jamais de collision avec quoi que ce soit } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(extend, 16) + ')'); return false; } template bool NzAxisAlignedBox::IsFinite() const { return extend == nzExtend_Finite; } template bool NzAxisAlignedBox::IsInfinite() const { return extend == nzExtend_Infinite; } template bool NzAxisAlignedBox::IsNull() const { return extend == nzExtend_Null; } template NzAxisAlignedBox& NzAxisAlignedBox::MakeInfinite() { extend = nzExtend_Infinite; return *this; } template NzAxisAlignedBox& NzAxisAlignedBox::MakeNull() { extend = nzExtend_Infinite; return *this; } template NzAxisAlignedBox& NzAxisAlignedBox::Set(nzExtend Extend) { extend = Extend; return *this; } template NzAxisAlignedBox& NzAxisAlignedBox::Set(T X, T Y, T Z, T Width, T Height, T Depth) { cube.Set(X, Y, Z, Width, Height, Depth); extend = nzExtend_Finite; return *this; } template NzAxisAlignedBox& NzAxisAlignedBox::Set(const NzAxisAlignedBox& box) { std::memcpy(this, &box, sizeof(NzAxisAlignedBox)); return *this; } template NzAxisAlignedBox& NzAxisAlignedBox::Set(const NzCube& Cube) { cube.Set(Cube); extend = nzExtend_Finite; return *this; } template NzAxisAlignedBox& NzAxisAlignedBox::Set(const NzVector3& vec1, const NzVector3& vec2) { cube.Set(vec1, vec2); extend = nzExtend_Finite; return *this; } template template NzAxisAlignedBox& NzAxisAlignedBox::Set(const NzAxisAlignedBox& box) { cube.Set(box); extend = nzExtend_Finite; return *this; } template NzString NzAxisAlignedBox::ToString() const { switch (extend) { case nzExtend_Finite: return "NzAxisAlignedBox(min=" + cube.GetPosition().ToString() + ", max=" + (cube.GetPosition()+cube.GetSize()).ToString() + ')'; case nzExtend_Infinite: return "NzAxisAlignedBox(Infinite)"; case nzExtend_Null: return "NzAxisAlignedBox(Null)"; } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(extend, 16) + ')'); return "NzAxisAlignedBox(ERROR)"; } template NzAxisAlignedBox& NzAxisAlignedBox::Transform(const NzMatrix4& matrix, bool applyTranslation) { if (extend != nzExtend_Finite) return *this; // Toute transformation d'une AABox autre que finie résultera en la même AABox NzVector3 center = matrix.Transform(cube.GetCenter(), (applyTranslation) ? F(1.0) : F(0.0)); // Valeur multipliant la translation NzVector3 halfSize = cube.GetSize() * F(0.5); halfSize.Set(std::fabs(matrix(0,0))*halfSize.x + std::fabs(matrix(1,0))*halfSize.y + std::fabs(matrix(2,0))*halfSize.z, std::fabs(matrix(0,1))*halfSize.x + std::fabs(matrix(1,1))*halfSize.y + std::fabs(matrix(2,1))*halfSize.z, std::fabs(matrix(0,2))*halfSize.x + std::fabs(matrix(1,2))*halfSize.y + std::fabs(matrix(2,2))*halfSize.z); cube.Set(center - halfSize, center + halfSize); return *this; } template NzAxisAlignedBox NzAxisAlignedBox::operator*(T scalar) const { NzAxisAlignedBox box(*this); box *= scalar; return box; } template NzAxisAlignedBox& NzAxisAlignedBox::operator*=(T scalar) { switch (extend) { case nzExtend_Finite: cube *= scalar; return *this; case nzExtend_Infinite: // L'infini multiplié par quoi que ce soit d'autre que zéro reste l'infini // (On ne se préoccupe pas de l'infini de signe négatif, car ça finirait par être équivalent) if (NzNumberEquals(scalar, F(0.0))) MakeNull(); return *this; case nzExtend_Null: return *this; // } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (0x" + NzString::Number(extend, 16) + ')'); return NzVector3(); } template bool NzAxisAlignedBox::operator==(const NzAxisAlignedBox& box) const { if (extend == box.extend) return cube == box.cube; else return false; } template bool NzAxisAlignedBox::operator!=(const NzAxisAlignedBox& box) const { return !operator==(box); } template NzAxisAlignedBox NzAxisAlignedBox::Infinite() { NzAxisAlignedBox box; box.MakeInfinite(); return box; } template NzAxisAlignedBox NzAxisAlignedBox::Lerp(const NzAxisAlignedBox& from, const NzAxisAlignedBox& to, T interpolation) { #ifdef NAZARA_DEBUG if (interpolation < 0.f || interpolation > 1.f) { NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')'); return Null(); } #endif if (NzNumberEquals(interpolation, 0.f)) return from; if (NzNumberEquals(interpolation, 1.f)) return to; switch (to.extend) { case nzExtend_Finite: { switch (from.extend) { case nzExtend_Finite: return NzCube::Lerp(from.cube, to.cube, interpolation); case nzExtend_Infinite: return Infinite(); case nzExtend_Null: return from.cube * interpolation; } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (From AABB) (0x" + NzString::Number(from.extend, 16) + ')'); return Null(); } case nzExtend_Infinite: return Infinite(); // Un petit peu d'infini est infini quand même ;) case nzExtend_Null: { switch (from.extend) { case nzExtend_Finite: return from.cube * (F(1.0) - interpolation); case nzExtend_Infinite: return Infinite(); case nzExtend_Null: return Null(); } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (From AABB) (0x" + NzString::Number(from.extend, 16) + ')'); return Null(); } } // Si nous arrivons ici c'est que l'extend est invalide NazaraError("Invalid extend type (To AABB) (0x" + NzString::Number(from.extend, 16) + ')'); return Null(); } template NzAxisAlignedBox NzAxisAlignedBox::Null() { NzAxisAlignedBox box; box.MakeNull(); return box; } template std::ostream& operator<<(std::ostream& out, const NzAxisAlignedBox& box) { out << box.ToString(); return out; } #undef F #include