diff --git a/examples/DeferredShading/main.cpp b/examples/DeferredShading/main.cpp index 6b098f0a8..da74d1f93 100644 --- a/examples/DeferredShading/main.cpp +++ b/examples/DeferredShading/main.cpp @@ -715,7 +715,7 @@ int main() builder.BindVertexBuffer(0, *cubeMeshGfx->GetVertexBuffer(0)); builder.BindPipeline(*skyboxPipeline); - builder.DrawIndexed(static_cast(cubeMeshGfx->GetIndexCount(0))); + builder.DrawIndexed(Nz::SafeCast(cubeMeshGfx->GetIndexCount(0))); }); forwardPass.SetExecutionCallback([&] { diff --git a/include/Nazara/Core/Algorithm.hpp b/include/Nazara/Core/Algorithm.hpp index b52ddba95..30e1749da 100644 --- a/include/Nazara/Core/Algorithm.hpp +++ b/include/Nazara/Core/Algorithm.hpp @@ -36,6 +36,16 @@ namespace Nz template void HashCombine(std::size_t& seed, const T& v); template bool IsPowerOfTwo(T value); template T ReverseBits(T integer); +#ifdef NAZARA_DEBUG + template && std::is_integral_v, int> = 0> To SafeCast(From value); + template && std::is_floating_point_v, int> = 0> To SafeCast(From value); + template && std::is_floating_point_v, int> = 0> To SafeCast(From value); + template && std::is_integral_v, int> = 0> To SafeCast(From value); + template&& std::is_integral_v, int> = 0> To SafeCast(From value); + template&& std::is_enum_v, int> = 0> To SafeCast(From value); +#else + template To SafeCast(From value); +#endif template constexpr auto UnderlyingCast(T value) -> std::underlying_type_t; template diff --git a/include/Nazara/Core/Algorithm.inl b/include/Nazara/Core/Algorithm.inl index 9b4e347fe..7cf5b2a68 100644 --- a/include/Nazara/Core/Algorithm.inl +++ b/include/Nazara/Core/Algorithm.inl @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -291,6 +292,75 @@ namespace Nz return reversed; } +#ifdef NAZARA_DEBUG + template && std::is_integral_v, int>> + To SafeCast(From value) + { + // Type capable of storing the biggest value between the two types + using MaxValueType = std::conditional_t<(sizeof(From) > sizeof(To) || (sizeof(From) == sizeof(To) && std::is_signed_v)), From, To>; + // Type capable of storing the smallest value between the two types + using MinValueType = std::conditional_t<(sizeof(From) > sizeof(To) || (sizeof(From) == sizeof(To) && std::is_signed_v)), From, To>; + + if constexpr (!std::is_signed_v) + assert(value >= 0); + + assert(static_cast(value) <= static_cast(std::numeric_limits::max())); + assert(static_cast(value) >= static_cast(std::numeric_limits::lowest())); + + return static_cast(value); + } + + template && std::is_floating_point_v, int>> + To SafeCast(From value) + { + // Type capable of storing the biggest value between the two types + using MaxValueType = std::conditional_t<(sizeof(From) > sizeof(To)), From, To>; + // Type capable of storing the smallest value between the two types + using MinValueType = std::conditional_t<(sizeof(From) > sizeof(To)), From, To>; + + assert(static_cast(value) <= static_cast(std::numeric_limits::max())); + assert(static_cast(value) >= static_cast(std::numeric_limits::lowest())); + + return static_cast(value); + } + + template && std::is_floating_point_v, int>> + To SafeCast(From value) + { + assert(floor(value) == value); + + assert(value <= static_cast(std::numeric_limits::max())); + assert(value >= static_cast(std::numeric_limits::lowest())); + + return static_cast(value); + } + + template && std::is_integral_v, int>> + To SafeCast(From value) + { + return static_cast(value); + } + + template && std::is_integral_v, int>> + To SafeCast(From value) + { + return static_cast(SafeCast>(value)); + } + + template && std::is_enum_v, int>> + To SafeCast(From value) + { + return SafeCast(static_cast>(value)); + } + +#else + template + To SafeCast(From value) + { + return static_cast(value); + } +#endif + template constexpr auto UnderlyingCast(T value) -> std::underlying_type_t { diff --git a/include/Nazara/Graphics/RenderElement.inl b/include/Nazara/Graphics/RenderElement.inl index df057213d..a51ae4d70 100644 --- a/include/Nazara/Graphics/RenderElement.inl +++ b/include/Nazara/Graphics/RenderElement.inl @@ -3,12 +3,14 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include +#include namespace Nz { inline RenderElement::RenderElement(BasicRenderElement elementType) : - RenderElement(static_cast(elementType)) + RenderElement(SafeCast(elementType)) { } @@ -22,3 +24,5 @@ namespace Nz return m_elementType; } } + +#include diff --git a/src/Nazara/Physics2D/Collider2D.cpp b/src/Nazara/Physics2D/Collider2D.cpp index 9e73a685c..5c39cdcc0 100644 --- a/src/Nazara/Physics2D/Collider2D.cpp +++ b/src/Nazara/Physics2D/Collider2D.cpp @@ -71,7 +71,7 @@ namespace Nz std::array vertices; Vector2f origin = FromChipmunk(pos); - float r = static_cast(radius); + float r = SafeCast(radius); RadianAnglef angleBetweenVertices = 2.f * Pi / vertices.size(); for (std::size_t i = 0; i < vertices.size(); ++i) @@ -91,7 +91,7 @@ namespace Nz { const auto& callback = *static_cast(userdata); - static std::pair sincos = Nz::DegreeAnglef(90.f).GetSinCos(); + static std::pair sincos = DegreeAnglef(90.f).GetSinCos(); Vector2f from = FromChipmunk(a); Vector2f to = FromChipmunk(b); @@ -100,7 +100,7 @@ namespace Nz Vector2f thicknessNormal(sincos.second * normal.x - sincos.first * normal.y, sincos.first * normal.x + sincos.second * normal.y); - float thickness = static_cast(radius); + float thickness = SafeCast(radius); std::array vertices; vertices[0] = from + thickness * thicknessNormal; @@ -166,14 +166,14 @@ namespace Nz { } - Nz::Vector2f BoxCollider2D::ComputeCenterOfMass() const + Vector2f BoxCollider2D::ComputeCenterOfMass() const { return m_rect.GetCenter(); } float BoxCollider2D::ComputeMomentOfInertia(float mass) const { - return static_cast(cpMomentForBox2(mass, cpBBNew(m_rect.x, m_rect.y, m_rect.x + m_rect.width, m_rect.y + m_rect.height))); + return SafeCast(cpMomentForBox2(mass, cpBBNew(m_rect.x, m_rect.y, m_rect.x + m_rect.width, m_rect.y + m_rect.height))); } ColliderType2D BoxCollider2D::GetType() const @@ -195,14 +195,14 @@ namespace Nz { } - Nz::Vector2f CircleCollider2D::ComputeCenterOfMass() const + Vector2f CircleCollider2D::ComputeCenterOfMass() const { return m_offset; } float CircleCollider2D::ComputeMomentOfInertia(float mass) const { - return static_cast(cpMomentForCircle(mass, 0.f, m_radius, cpv(m_offset.x, m_offset.y))); + return SafeCast(cpMomentForCircle(mass, 0.f, m_radius, cpv(m_offset.x, m_offset.y))); } ColliderType2D CircleCollider2D::GetType() const @@ -224,9 +224,9 @@ namespace Nz { } - Nz::Vector2f CompoundCollider2D::ComputeCenterOfMass() const + Vector2f CompoundCollider2D::ComputeCenterOfMass() const { - Nz::Vector2f centerOfMass = Nz::Vector2f::Zero(); + Vector2f centerOfMass = Vector2f::Zero(); for (const auto& geom : m_geoms) centerOfMass += geom->ComputeCenterOfMass(); @@ -285,20 +285,20 @@ namespace Nz m_vertices[i].Set(*vertices++); } - Nz::Vector2f ConvexCollider2D::ComputeCenterOfMass() const + Vector2f ConvexCollider2D::ComputeCenterOfMass() const { static_assert(sizeof(cpVect) == sizeof(Vector2d), "Chipmunk vector is not equivalent to Vector2d"); cpVect center = cpCentroidForPoly(int(m_vertices.size()), reinterpret_cast(m_vertices.data())); - return Nz::Vector2f(float(center.x), float(center.y)); + return Vector2f(float(center.x), float(center.y)); } float ConvexCollider2D::ComputeMomentOfInertia(float mass) const { static_assert(sizeof(cpVect) == sizeof(Vector2d), "Chipmunk vector is not equivalent to Vector2d"); - return static_cast(cpMomentForPoly(mass, int(m_vertices.size()), reinterpret_cast(m_vertices.data()), cpv(0.0, 0.0), m_radius)); + return SafeCast(cpMomentForPoly(mass, int(m_vertices.size()), reinterpret_cast(m_vertices.data()), cpv(0.0, 0.0), m_radius)); } ColliderType2D ConvexCollider2D::GetType() const @@ -319,9 +319,9 @@ namespace Nz return ColliderType2D::Null; } - Nz::Vector2f NullCollider2D::ComputeCenterOfMass() const + Vector2f NullCollider2D::ComputeCenterOfMass() const { - return Nz::Vector2f::Zero(); + return Vector2f::Zero(); } float NullCollider2D::ComputeMomentOfInertia(float mass) const @@ -336,14 +336,14 @@ namespace Nz /******************************** SegmentCollider2D *********************************/ - Nz::Vector2f SegmentCollider2D::ComputeCenterOfMass() const + Vector2f SegmentCollider2D::ComputeCenterOfMass() const { return (m_first + m_second) / 2.f; } float SegmentCollider2D::ComputeMomentOfInertia(float mass) const { - return static_cast(cpMomentForSegment(mass, cpv(m_first.x, m_first.y), cpv(m_second.x, m_second.y), m_thickness)); + return SafeCast(cpMomentForSegment(mass, cpv(m_first.x, m_first.y), cpv(m_second.x, m_second.y), m_thickness)); } ColliderType2D SegmentCollider2D::GetType() const diff --git a/src/Nazara/Physics3D/Collider3D.cpp b/src/Nazara/Physics3D/Collider3D.cpp index d4b36ba99..a20b236cc 100644 --- a/src/Nazara/Physics3D/Collider3D.cpp +++ b/src/Nazara/Physics3D/Collider3D.cpp @@ -145,38 +145,38 @@ namespace Nz std::shared_ptr Collider3D::GenerateMesh() const { - std::vector colliderVertices; - std::vector colliderIndices; + std::vector colliderVertices; + std::vector colliderIndices; // Generate a line list - ForEachPolygon([&](const Nz::Vector3f* vertices, std::size_t vertexCount) + ForEachPolygon([&](const Vector3f* vertices, std::size_t vertexCount) { - Nz::UInt16 firstIndex = colliderVertices.size(); + UInt16 firstIndex = SafeCast(colliderVertices.size()); for (std::size_t i = 0; i < vertexCount; ++i) colliderVertices.push_back(vertices[i]); for (std::size_t i = 1; i < vertexCount; ++i) { - colliderIndices.push_back(firstIndex + i - 1); - colliderIndices.push_back(firstIndex + i); + colliderIndices.push_back(SafeCast(firstIndex + i - 1)); + colliderIndices.push_back(SafeCast(firstIndex + i)); } if (vertexCount > 2) { - colliderIndices.push_back(firstIndex + vertexCount - 1); - colliderIndices.push_back(firstIndex); + colliderIndices.push_back(SafeCast(firstIndex + vertexCount - 1)); + colliderIndices.push_back(SafeCast(firstIndex)); } }); - std::shared_ptr colliderVB = std::make_shared(Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ), colliderVertices.size(), Nz::DataStorage::Software, 0); + std::shared_ptr colliderVB = std::make_shared(VertexDeclaration::Get(VertexLayout::XYZ), colliderVertices.size(), DataStorage::Software, 0); colliderVB->Fill(colliderVertices.data(), 0, colliderVertices.size()); - std::shared_ptr colliderIB = std::make_shared(false, colliderIndices.size(), Nz::DataStorage::Software, 0); + std::shared_ptr colliderIB = std::make_shared(false, colliderIndices.size(), DataStorage::Software, 0); colliderIB->Fill(colliderIndices.data(), 0, colliderIndices.size()); - std::shared_ptr colliderSubMesh = std::make_shared(std::move(colliderVB), std::move(colliderIB)); + std::shared_ptr colliderSubMesh = std::make_shared(std::move(colliderVB), std::move(colliderIB)); colliderSubMesh->GenerateAABB(); - colliderSubMesh->SetPrimitiveMode(Nz::PrimitiveMode::LineList); + colliderSubMesh->SetPrimitiveMode(PrimitiveMode::LineList); return colliderSubMesh; }