// 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 #include #include #include #define F(a) static_cast(a) template NzBox::NzBox(T Width, T Height, T Depth) { Set(Width, Height, Depth); } template NzBox::NzBox(T X, T Y, T Z, T Width, T Height, T Depth) { Set(X, Y, Z, Width, Height, Depth); } template NzBox::NzBox(const NzRect& rect) { Set(rect); } template NzBox::NzBox(const NzVector3& lengths) { Set(lengths); } template NzBox::NzBox(const NzVector3& vec1, const NzVector3& vec2) { Set(vec1, vec2); } template NzBox::NzBox(const T vec[6]) { Set(vec); } template template NzBox::NzBox(const NzBox& box) { Set(box); } template bool NzBox::Contains(T X, T Y, T Z) const { return X >= x && X < x+width && Y >= y && Y < y+height && Z >= z && Z < z+depth; } template bool NzBox::Contains(const NzBox& box) const { return Contains(box.x, box.y, box.z) && Contains(box.x + box.width, box.y + box.height, box.z + box.depth); } template bool NzBox::Contains(const NzVector3& point) const { return Contains(point.x, point.y, point.z); } template NzBox& NzBox::ExtendTo(T X, T Y, T Z) { width = std::max(x + width, X); height = std::max(y + height, Y); depth = std::max(z + depth, Z); x = std::min(x, X); y = std::min(y, Y); z = std::min(z, Z); width -= x; height -= y; depth -= z; return *this; } template NzBox& NzBox::ExtendTo(const NzBox& box) { width = std::max(x + width, box.x + box.width); height = std::max(y + height, box.y + box.height); depth = std::max(z + depth, box.z + box.depth); x = std::min(x, box.x); y = std::min(y, box.y); z = std::min(z, box.z); width -= x; height -= y; depth -= z; return *this; } template NzBox& NzBox::ExtendTo(const NzVector3& point) { return ExtendTo(point.x, point.y, point.z); } template NzVector3 NzBox::GetCorner(nzCorner corner) const { switch (corner) { case nzCorner_FarLeftBottom: return NzVector3(x, y, z); case nzCorner_FarLeftTop: return NzVector3(x, y + height, z); case nzCorner_FarRightBottom: return NzVector3(x + width, y, z); case nzCorner_FarRightTop: return NzVector3(x + width, y + height, z); case nzCorner_NearLeftBottom: return NzVector3(x, y, z + depth); case nzCorner_NearLeftTop: return NzVector3(x, y + height, z + depth); case nzCorner_NearRightBottom: return NzVector3(x + width, y, z + depth); case nzCorner_NearRightTop: return NzVector3(x + width, y + height, z + depth); } NazaraError("Corner not handled (0x" + NzString::Number(corner, 16) + ')'); return NzVector3(); } template NzSphere NzBox::GetBoundingSphere() const { return NzSphere(GetCenter(), GetRadius()); } template NzVector3 NzBox::GetCenter() const { return GetPosition() + GetLengths()/F(2.0); } template NzVector3 NzBox::GetLengths() const { return NzVector3(width, height, depth); } template NzVector3 NzBox::GetMaximum() const { return GetPosition() + GetLengths(); } template NzVector3 NzBox::GetMinimum() const { ///DOC: Alias de GetPosition() return GetPosition(); } template NzVector3 NzBox::GetNegativeVertex(const NzVector3& normal) const { NzVector3 neg(GetPosition()); if (normal.x < F(0.0)) neg.x += width; if (normal.y < F(0.0)) neg.y += height; if (normal.z < F(0.0)) neg.z += depth; return neg; } template NzVector3 NzBox::GetPosition() const { return NzVector3(x, y, z); } template NzVector3 NzBox::GetPositiveVertex(const NzVector3& normal) const { NzVector3 pos(GetPosition()); if (normal.x > F(0.0)) pos.x += width; if (normal.y > F(0.0)) pos.y += height; if (normal.z > F(0.0)) pos.z += depth; return pos; } template T NzBox::GetRadius() const { return std::sqrt(GetSquaredRadius()); } template NzSphere NzBox::GetSquaredBoundingSphere() const { return NzSphere(GetCenter(), GetSquaredRadius()); } template T NzBox::GetSquaredRadius() const { NzVector3 size(GetLengths()); size /= F(2.0); // La taille étant relative à la position (minimum) de la boite et non pas à son centre return size.GetSquaredLength(); } template bool NzBox::Intersect(const NzBox& box, NzBox* intersection) const { T left = std::max(x, box.x); T right = std::min(x + width, box.x + box.width); T top = std::max(y, box.y); T bottom = std::min(y + height, box.y + box.height); T up = std::max(z, box.z); T down = std::min(z + depth, box.z + box.depth); if (left < right && top < bottom && up < down) { if (intersection) { intersection->x = left; intersection->y = top; intersection->z = up; intersection->width = right - left; intersection->height = bottom - top; intersection->depth = down - up; } return true; } else return false; } template bool NzBox::IsValid() const { return width > F(0.0) && height > F(0.0) && depth > F(0.0); } template NzBox& NzBox::MakeZero() { x = F(0.0); y = F(0.0); z = F(0.0); width = F(0.0); height = F(0.0); depth = F(0.0); return *this; } template NzBox& NzBox::Set(T Width, T Height, T Depth) { x = F(0.0); y = F(0.0); z = F(0.0); width = Width; height = Height; depth = Depth; return *this; } template NzBox& NzBox::Set(T X, T Y, T Z, T Width, T Height, T Depth) { x = X; y = Y; z = Z; width = Width; height = Height; depth = Depth; return *this; } template NzBox& NzBox::Set(const T box[6]) { x = box[0]; y = box[1]; z = box[2]; width = box[3]; height = box[4]; depth = box[5]; return *this; } template NzBox& NzBox::Set(const NzBox& box) { std::memcpy(this, &box, sizeof(NzBox)); return *this; } template NzBox& NzBox::Set(const NzRect& rect) { x = rect.x; y = rect.y; z = F(0.0); width = rect.width; height = rect.height; depth = F(1.0); return *this; } template NzBox& NzBox::Set(const NzVector3& lengths) { return Set(lengths.x, lengths.y, lengths.z); } template NzBox& NzBox::Set(const NzVector3& vec1, const NzVector3& vec2) { x = std::min(vec1.x, vec2.x); y = std::min(vec1.y, vec2.y); z = std::min(vec1.z, vec2.z); width = (vec2.x > vec1.x) ? vec2.x-vec1.x : vec1.x-vec2.x; height = (vec2.y > vec1.y) ? vec2.y-vec1.y : vec1.y-vec2.y; depth = (vec2.z > vec1.z) ? vec2.z-vec1.z : vec1.z-vec2.z; return *this; } template template NzBox& NzBox::Set(const NzBox& box) { x = F(box.x); y = F(box.y); z = F(box.z); width = F(box.width); height = F(box.height); depth = F(box.depth); return *this; } template NzString NzBox::ToString() const { NzStringStream ss; return ss << "Box(" << x << ", " << y << ", " << z << ", " << width << ", " << height << ", " << depth << ')'; } template NzBox& NzBox::Transform(const NzMatrix4& matrix, bool applyTranslation) { NzVector3 center = matrix.Transform(GetCenter(), (applyTranslation) ? F(1.0) : F(0.0)); // Valeur multipliant la translation NzVector3 halfSize = GetLengths()/F(2.0); 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); return Set(center - halfSize, center + halfSize); } template NzBox& NzBox::Translate(const NzVector3& translation) { x += translation.x; y += translation.y; z += translation.z; return *this; } template T& NzBox::operator[](unsigned int i) { #if NAZARA_MATH_SAFE if (i >= 6) { NzStringStream ss; ss << "Index out of range: (" << i << " >= 6)"; NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif return *(&x+i); } template T NzBox::operator[](unsigned int i) const { #if NAZARA_MATH_SAFE if (i >= 6) { NzStringStream ss; ss << "Index out of range: (" << i << " >= 6)"; NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif return *(&x+i); } template NzBox NzBox::operator*(T scalar) const { return NzBox(x, y, z, width*scalar, height*scalar, depth*scalar); } template NzBox NzBox::operator*(const NzVector3& vec) const { return NzBox(x, y, z, width*vec.x, height*vec.y, depth*vec.z); } template NzBox& NzBox::operator*=(T scalar) { width *= scalar; height *= scalar; depth *= scalar; return *this; } template NzBox& NzBox::operator*=(const NzVector3& vec) { width *= vec.x; height *= vec.y; depth *= vec.z; return *this; } template bool NzBox::operator==(const NzBox& box) const { return NzNumberEquals(x, box.x) && NzNumberEquals(y, box.y) && NzNumberEquals(z, box.z) && NzNumberEquals(width, box.width) && NzNumberEquals(height, box.height) && NzNumberEquals(depth, box.depth); } template bool NzBox::operator!=(const NzBox& box) const { return !operator==(box); } template NzBox NzBox::Lerp(const NzBox& from, const NzBox& to, T interpolation) { #ifdef NAZARA_DEBUG if (interpolation < F(0.0) || interpolation > F(1.0)) { NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')'); return Zero(); } #endif NzBox box; box.x = NzLerp(from.x, to.x, interpolation); box.y = NzLerp(from.y, to.y, interpolation); box.z = NzLerp(from.z, to.z, interpolation); box.width = NzLerp(from.width, to.width, interpolation); box.height = NzLerp(from.height, to.height, interpolation); box.depth = NzLerp(from.depth, to.depth, interpolation); return box; } template NzBox NzBox::Zero() { NzBox box; box.MakeZero(); return box; } template std::ostream& operator<<(std::ostream& out, const NzBox& box) { return out << box.ToString(); } #undef F #include