From c089fce239afdb58d74932734b5147455e395e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 4 May 2013 16:27:31 +0200 Subject: [PATCH] Physics shape rework #5: renaming. ObjectShape* is now Shape*, ShapeGroup is now Composition. --- src/DebugTools/ShapeRenderer.cpp | 44 +-- src/DebugTools/ShapeRenderer.h | 4 +- ...tractObjectShape.cpp => AbstractShape.cpp} | 24 +- ...{AbstractObjectShape.h => AbstractShape.h} | 34 +- src/Physics/CMakeLists.txt | 14 +- src/Physics/Composition.cpp | 167 ++++++++++ src/Physics/Composition.h | 298 ++++++++++++++++++ src/Physics/ObjectShapeGroup.cpp | 58 ---- src/Physics/ObjectShapeGroup.h | 113 ------- src/Physics/Physics.h | 28 +- src/Physics/{ObjectShape.cpp => Shape.cpp} | 24 +- src/Physics/{ObjectShape.h => Shape.h} | 70 ++-- src/Physics/ShapeGroup.cpp | 139 +------- src/Physics/ShapeGroup.h | 285 +++-------------- src/Physics/Test/CMakeLists.txt | 4 +- ...ShapeGroupTest.cpp => CompositionTest.cpp} | 64 ++-- src/Physics/Test/ShapeImplementationTest.cpp | 4 +- .../{ObjectShapeTest.cpp => ShapeTest.cpp} | 44 +-- src/Physics/shapeImplementation.cpp | 4 +- src/Physics/shapeImplementation.h | 8 +- 20 files changed, 715 insertions(+), 715 deletions(-) rename src/Physics/{AbstractObjectShape.cpp => AbstractShape.cpp} (56%) rename src/Physics/{AbstractObjectShape.h => AbstractShape.h} (72%) create mode 100644 src/Physics/Composition.cpp create mode 100644 src/Physics/Composition.h delete mode 100644 src/Physics/ObjectShapeGroup.cpp delete mode 100644 src/Physics/ObjectShapeGroup.h rename src/Physics/{ObjectShape.cpp => Shape.cpp} (50%) rename src/Physics/{ObjectShape.h => Shape.h} (50%) rename src/Physics/Test/{ShapeGroupTest.cpp => CompositionTest.cpp} (65%) rename src/Physics/Test/{ObjectShapeTest.cpp => ShapeTest.cpp} (77%) diff --git a/src/DebugTools/ShapeRenderer.cpp b/src/DebugTools/ShapeRenderer.cpp index fe02f6a56..c205d5d7a 100644 --- a/src/DebugTools/ShapeRenderer.cpp +++ b/src/DebugTools/ShapeRenderer.cpp @@ -25,8 +25,8 @@ #include "ShapeRenderer.h" #include "ResourceManager.h" -#include "Physics/ObjectShape.h" -#include "Physics/ShapeGroup.h" +#include "Physics/Composition.h" +#include "Physics/Shape.h" #include "SceneGraph/AbstractCamera.h" #include "Implementation/AxisAlignedBoxRenderer.h" @@ -41,25 +41,25 @@ namespace Implementation { template<> void createDebugMesh(ShapeRenderer<2>* renderer, const Physics::Implementation::AbstractShape<2>* shape) { switch(shape->type()) { - case Physics::AbstractObjectShape2D::Type::AxisAlignedBox: + case Physics::AbstractShape2D::Type::AxisAlignedBox: renderer->renderers.push_back(new Implementation::AxisAlignedBoxRenderer<2>(shape)); break; - case Physics::AbstractObjectShape2D::Type::Box: + case Physics::AbstractShape2D::Type::Box: renderer->renderers.push_back(new Implementation::BoxRenderer<2>(shape)); break; - case Physics::AbstractObjectShape2D::Type::LineSegment: + case Physics::AbstractShape2D::Type::LineSegment: renderer->renderers.push_back(new Implementation::LineSegmentRenderer<2>(shape)); break; - case Physics::AbstractObjectShape2D::Type::Point: + case Physics::AbstractShape2D::Type::Point: renderer->renderers.push_back(new Implementation::PointRenderer<2>(shape)); break; - case Physics::AbstractObjectShape2D::Type::ShapeGroup: { - const Physics::ShapeGroup2D& group = - static_cast*>(shape)->shape; - for(std::size_t i = 0; i != group.size(); ++i) - createDebugMesh(renderer, Physics::Implementation::getAbstractShape(group, i)); + case Physics::AbstractShape2D::Type::Composition: { + const Physics::Composition2D& composition = + static_cast*>(shape)->shape; + for(std::size_t i = 0; i != composition.size(); ++i) + createDebugMesh(renderer, Physics::Implementation::getAbstractShape(composition, i)); } break; - case Physics::AbstractObjectShape2D::Type::Sphere: + case Physics::AbstractShape2D::Type::Sphere: renderer->renderers.push_back(new Implementation::SphereRenderer<2>(shape)); break; default: @@ -69,23 +69,23 @@ template<> void createDebugMesh(ShapeRenderer<2>* renderer, const Physics::Imple template<> void createDebugMesh(ShapeRenderer<3>* renderer, const Physics::Implementation::AbstractShape<3>* shape) { switch(shape->type()) { - case Physics::AbstractObjectShape3D::Type::AxisAlignedBox: + case Physics::AbstractShape3D::Type::AxisAlignedBox: renderer->renderers.push_back(new Implementation::AxisAlignedBoxRenderer<3>(shape)); break; - case Physics::AbstractObjectShape3D::Type::Box: + case Physics::AbstractShape3D::Type::Box: renderer->renderers.push_back(new Implementation::BoxRenderer<3>(shape)); break; - case Physics::AbstractObjectShape3D::Type::LineSegment: + case Physics::AbstractShape3D::Type::LineSegment: renderer->renderers.push_back(new Implementation::LineSegmentRenderer<3>(shape)); break; - case Physics::AbstractObjectShape3D::Type::Point: + case Physics::AbstractShape3D::Type::Point: renderer->renderers.push_back(new Implementation::PointRenderer<3>(shape)); break; - case Physics::AbstractObjectShape3D::Type::ShapeGroup: { - const Physics::ShapeGroup3D& group = - static_cast*>(shape)->shape; - for(std::size_t i = 0; i != group.size(); ++i) - createDebugMesh(renderer, Physics::Implementation::getAbstractShape(group, i)); + case Physics::AbstractShape3D::Type::Composition: { + const Physics::Composition3D& composition = + static_cast*>(shape)->shape; + for(std::size_t i = 0; i != composition.size(); ++i) + createDebugMesh(renderer, Physics::Implementation::getAbstractShape(composition, i)); } break; default: Warning() << "DebugTools::ShapeRenderer3D::createShapeRenderer(): type" << shape->type() << "not implemented"; @@ -94,7 +94,7 @@ template<> void createDebugMesh(ShapeRenderer<3>* renderer, const Physics::Imple } -template ShapeRenderer::ShapeRenderer(Physics::AbstractObjectShape* shape, ResourceKey options, SceneGraph::DrawableGroup* drawables): SceneGraph::Drawable(shape->object(), drawables), options(ResourceManager::instance()->get(options)) { +template ShapeRenderer::ShapeRenderer(Physics::AbstractShape* shape, ResourceKey options, SceneGraph::DrawableGroup* drawables): SceneGraph::Drawable(shape->object(), drawables), options(ResourceManager::instance()->get(options)) { Implementation::createDebugMesh(this, Physics::Implementation::getAbstractShape(shape)); } diff --git a/src/DebugTools/ShapeRenderer.h b/src/DebugTools/ShapeRenderer.h index 378babba9..17561b609 100644 --- a/src/DebugTools/ShapeRenderer.h +++ b/src/DebugTools/ShapeRenderer.h @@ -144,7 +144,7 @@ template class MAGNUM_DEBUGTOOLS_EXPORT ShapeRenderer: p public: /** * @brief Constructor - * @param shape Object for which to create debug renderer + * @param shape Shape for which to create debug renderer * @param options Options resource key. See * @ref ShapeRenderer-usage "class documentation" for more * information. @@ -154,7 +154,7 @@ template class MAGNUM_DEBUGTOOLS_EXPORT ShapeRenderer: p * @p shape must be available for the whole lifetime of the renderer * and if it is group, it must not change its internal structure. */ - explicit ShapeRenderer(Physics::AbstractObjectShape* shape, ResourceKey options = ResourceKey(), SceneGraph::DrawableGroup* drawables = nullptr); + explicit ShapeRenderer(Physics::AbstractShape* shape, ResourceKey options = ResourceKey(), SceneGraph::DrawableGroup* drawables = nullptr); ~ShapeRenderer(); diff --git a/src/Physics/AbstractObjectShape.cpp b/src/Physics/AbstractShape.cpp similarity index 56% rename from src/Physics/AbstractObjectShape.cpp rename to src/Physics/AbstractShape.cpp index e60486efe..0070ca5da 100644 --- a/src/Physics/AbstractObjectShape.cpp +++ b/src/Physics/AbstractShape.cpp @@ -22,42 +22,42 @@ DEALINGS IN THE SOFTWARE. */ -#include "AbstractObjectShape.h" +#include "AbstractShape.h" #include -#include "Physics/ObjectShapeGroup.h" +#include "Physics/ShapeGroup.h" #include "Physics/Implementation/CollisionDispatch.h" namespace Magnum { namespace Physics { -template AbstractObjectShape::AbstractObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group): SceneGraph::AbstractGroupedFeature>(object, group) { +template AbstractShape::AbstractShape(SceneGraph::AbstractObject* object, ShapeGroup* group): SceneGraph::AbstractGroupedFeature>(object, group) { this->setCachedTransformations(SceneGraph::AbstractFeature::CachedTransformation::Absolute); } -template ObjectShapeGroup* AbstractObjectShape::group() { - return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); +template ShapeGroup* AbstractShape::group() { + return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); } -template const ObjectShapeGroup* AbstractObjectShape::group() const { - return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); +template const ShapeGroup* AbstractShape::group() const { + return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); } -template auto AbstractObjectShape::type() const -> Type { +template auto AbstractShape::type() const -> Type { return abstractTransformedShape()->type(); } -template bool AbstractObjectShape::collides(const AbstractObjectShape* other) const { +template bool AbstractShape::collides(const AbstractShape* other) const { return Implementation::collides(abstractTransformedShape(), other->abstractTransformedShape()); } -template void AbstractObjectShape::markDirty() { +template void AbstractShape::markDirty() { group()->setDirty(); } #ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_PHYSICS_EXPORT AbstractObjectShape<2>; -template class MAGNUM_PHYSICS_EXPORT AbstractObjectShape<3>; +template class MAGNUM_PHYSICS_EXPORT AbstractShape<2>; +template class MAGNUM_PHYSICS_EXPORT AbstractShape<3>; #endif }} diff --git a/src/Physics/AbstractObjectShape.h b/src/Physics/AbstractShape.h similarity index 72% rename from src/Physics/AbstractObjectShape.h rename to src/Physics/AbstractShape.h index 90b5baf6e..6d1ada5ab 100644 --- a/src/Physics/AbstractObjectShape.h +++ b/src/Physics/AbstractShape.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_AbstractObjectShape_h -#define Magnum_Physics_AbstractObjectShape_h +#ifndef Magnum_Physics_AbstractShape_h +#define Magnum_Physics_AbstractShape_h /* This file is part of Magnum. @@ -25,7 +25,7 @@ */ /** @file - * @brief Class Magnum::Physics::AbstractObjectShape, typedef Magnum::Physics::AbstractObjectShape2D, Magnum::Physics::AbstractObjectShape3D + * @brief Class Magnum::Physics::AbstractShape, typedef Magnum::Physics::AbstractShape2D, Magnum::Physics::AbstractShape3D */ #include "Magnum.h" @@ -37,19 +37,19 @@ namespace Magnum { namespace Physics { namespace Implementation { - template inline const AbstractShape* getAbstractShape(const AbstractObjectShape* objectShape) { - return objectShape->abstractTransformedShape(); + template inline const AbstractShape* getAbstractShape(const Physics::AbstractShape* shape) { + return shape->abstractTransformedShape(); } } /** @brief Base class for object shapes -This class is not directly instantiable, see ObjectShape instead. -@see AbstractObjectShape2D, AbstractObjectShape3D +This class is not directly instantiable, see Shape instead. +@see AbstractShape2D, AbstractShape3D */ -template class MAGNUM_PHYSICS_EXPORT AbstractObjectShape: public SceneGraph::AbstractGroupedFeature> { - friend const Implementation::AbstractShape* Implementation::getAbstractShape<>(const AbstractObjectShape* objectShape); +template class MAGNUM_PHYSICS_EXPORT AbstractShape: public SceneGraph::AbstractGroupedFeature> { + friend const Implementation::AbstractShape* Implementation::getAbstractShape<>(const AbstractShape*); public: enum: UnsignedInt { @@ -66,7 +66,7 @@ template class MAGNUM_PHYSICS_EXPORT AbstractObjectShape Capsule, /**< Capsule */ AxisAlignedBox, /**< @ref AxisAlignedBox "Axis aligned box" */ Box, /**< Box */ - ShapeGroup, /**< @ref ShapeGroup "Shape group" */ + Composition, /**< @ref Composition "Shape group" */ Plane /**< Plane (3D only) */ }; #else @@ -78,15 +78,15 @@ template class MAGNUM_PHYSICS_EXPORT AbstractObjectShape * @param object Object holding this feature * @param group Group this shape belongs to */ - explicit AbstractObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group = nullptr); + explicit AbstractShape(SceneGraph::AbstractObject* object, ShapeGroup* group = nullptr); /** - * @brief Object shape group containing this shape + * @brief Shape group containing this shape * * If the shape doesn't belong to any group, returns `nullptr`. */ - ObjectShapeGroup* group(); - const ObjectShapeGroup* group() const; /**< @overload */ + ShapeGroup* group(); + const ShapeGroup* group() const; /**< @overload */ /** * @brief Shape type @@ -98,7 +98,7 @@ template class MAGNUM_PHYSICS_EXPORT AbstractObjectShape * * Default implementation returns false. */ - bool collides(const AbstractObjectShape* other) const; + bool collides(const AbstractShape* other) const; protected: /** Marks also the group as dirty */ @@ -109,10 +109,10 @@ template class MAGNUM_PHYSICS_EXPORT AbstractObjectShape }; /** @brief Base class for two-dimensional object shapes */ -typedef AbstractObjectShape<2> AbstractObjectShape2D; +typedef AbstractShape<2> AbstractShape2D; /** @brief Base class for three-dimensional object shapes */ -typedef AbstractObjectShape<3> AbstractObjectShape3D; +typedef AbstractShape<3> AbstractShape3D; }} diff --git a/src/Physics/CMakeLists.txt b/src/Physics/CMakeLists.txt index c12fe8a1a..87b16c9b1 100644 --- a/src/Physics/CMakeLists.txt +++ b/src/Physics/CMakeLists.txt @@ -23,15 +23,15 @@ # set(MagnumPhysics_SRCS - AbstractObjectShape.cpp + AbstractShape.cpp AxisAlignedBox.cpp Box.cpp Capsule.cpp + Composition.cpp Line.cpp Plane.cpp Point.cpp - ObjectShape.cpp - ObjectShapeGroup.cpp + Shape.cpp ShapeGroup.cpp Sphere.cpp @@ -40,18 +40,18 @@ set(MagnumPhysics_SRCS Implementation/CollisionDispatch.cpp) set(MagnumPhysics_HEADERS - AbstractObjectShape.h + AbstractShape.h AxisAlignedBox.h Box.h Capsule.h + Composition.h Line.h LineSegment.h - ObjectShape.h - ObjectShapeGroup.h + Shape.h + ShapeGroup.h Physics.h Plane.h Point.h - ShapeGroup.h Sphere.h magnumPhysicsVisibility.h diff --git a/src/Physics/Composition.cpp b/src/Physics/Composition.cpp new file mode 100644 index 000000000..aab3ed112 --- /dev/null +++ b/src/Physics/Composition.cpp @@ -0,0 +1,167 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Composition.h" + +#include +#include + +#include "Physics/Implementation/CollisionDispatch.h" + +namespace Magnum { namespace Physics { + +/* +Hierarchy implementation notes: + +The hierarchy is stored in flat array to provide easy access for the user and +to save some allocations. Each node has zero, one or two subnodes. Value of +`Node::rightNode` describes which child nodes exist: + + * 0 - no child subnodes + * 1 - only left subnode exists + * 2 - only right subnode exists + * >2 - both child nodes exist + +If left node exists, it is right next to current one. If right node exists, it +is at position `Node::rightNode-1` relative to current one (this applies also +when `rightNode` is equal to 2, right node is right next to current one, +because there are no left nodes). + +The node also specifies which shapes belong to it. Root node owns whole shape +array and `Node::rightShape` marks first shape belonging to the right child +node, relatively to begin. This recurses into child nodes, thus left child node +has shapes from parent's begin to parent's `rightShape`. + +Shapes are merged together by concatenating its node and shape list and adding +new node at the beginning with properly set `rightNode` and `rightShape`. +Because these values are relative to parent, they don't need to be modified +when concatenating. +*/ + +template Composition::Composition(const Composition& other): _shapeCount(other._shapeCount), _nodeCount(other._nodeCount) { + copyShapes(0, other); + copyNodes(0, other); +} + +template Composition::Composition(Composition&& other): _shapeCount(other._shapeCount), _nodeCount(other._nodeCount), _shapes(other._shapes), _nodes(other._nodes) { + other._shapes = nullptr; + other._shapeCount = 0; + + other._nodes = nullptr; + other._nodeCount = 0; +} + +template Composition::~Composition() { + for(std::size_t i = 0; i != _shapeCount; ++i) + delete _shapes[i]; + + delete[] _shapes; + delete[] _nodes; +} + +template Composition& Composition::operator=(const Composition& other) { + for(std::size_t i = 0; i != _shapeCount; ++i) + delete _shapes[i]; + + if(_shapeCount != other._shapeCount) { + delete[] _shapes; + _shapeCount = other._shapeCount; + _shapes = new Implementation::AbstractShape*[_shapeCount]; + } + + if(_nodeCount != other._nodeCount) { + delete[] _nodes; + _nodeCount = other._nodeCount; + _nodes = new Node[_nodeCount]; + } + + copyShapes(0, other); + copyNodes(0, other); + return *this; +} + +template Composition& Composition::operator=(Composition&& other) { + std::swap(other._shapeCount, _shapeCount); + std::swap(other._nodeCount, _nodeCount); + std::swap(other._shapes, _shapes); + std::swap(other._nodes, _nodes); + return *this; +} + +template void Composition::copyShapes(const std::size_t offset, Composition&& other) { + std::move(other._shapes, other._shapes+other._shapeCount, _shapes+offset); + delete[] other._shapes; + other._shapes = nullptr; + other._shapeCount = 0; +} + +template void Composition::copyShapes(const std::size_t offset, const Composition& other) { + for(std::size_t i = 0; i != other._shapeCount; ++i) + _shapes[i+offset] = other._shapes[i]->clone(); +} + +template void Composition::copyNodes(std::size_t offset, const Composition& other) { + std::copy(other._nodes, other._nodes+other._nodeCount, _nodes+offset); +} + +template Composition Composition::transformed(const typename DimensionTraits::MatrixType& matrix) const { + Composition out(*this); + for(std::size_t i = 0; i != _shapeCount; ++i) + _shapes[i]->transform(matrix, out._shapes[i]); + return out; +} + +template bool Composition::collides(const Implementation::AbstractShape* const a, const std::size_t node, const std::size_t shapeBegin, const std::size_t shapeEnd) const { + /* Empty group */ + if(shapeBegin == shapeEnd) return false; + + CORRADE_INTERNAL_ASSERT(node < _nodeCount && shapeBegin < shapeEnd); + + /* Collision on the left child. If the node is leaf one (no left child + exists), do it directly, recurse instead. */ + const bool collidesLeft = (_nodes[node].rightNode == 0 || _nodes[node].rightNode == 2) ? + Implementation::collides(a, _shapes[shapeBegin]) : + collides(a, node+1, shapeBegin, shapeBegin+_nodes[node].rightShape); + + /* NOT operation */ + if(_nodes[node].operation == CompositionOperation::Not) + return !collidesLeft; + + /* Short-circuit evaluation for AND/OR */ + if((_nodes[node].operation == CompositionOperation::Or) == collidesLeft) + return collidesLeft; + + /* Now the collision result depends only on the right child. Similar to + collision on the left child. */ + return (_nodes[node].rightNode < 2) ? + Implementation::collides(a, _shapes[shapeBegin+_nodes[node].rightShape]) : + collides(a, node+_nodes[node].rightNode-1, shapeBegin+_nodes[node].rightShape, shapeEnd); +} + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_PHYSICS_EXPORT Composition<2>; +template class MAGNUM_PHYSICS_EXPORT Composition<3>; +#endif + +}} diff --git a/src/Physics/Composition.h b/src/Physics/Composition.h new file mode 100644 index 000000000..9a6cf879a --- /dev/null +++ b/src/Physics/Composition.h @@ -0,0 +1,298 @@ +#ifndef Magnum_Physics_Composition_h +#define Magnum_Physics_Composition_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Physics::Composition, enum Magnum::Physics::CompositionOperation + */ + +#include +#include +#include + +#include "DimensionTraits.h" +#include "Physics/Physics.h" +#include "Physics/magnumPhysicsVisibility.h" +#include "Physics/shapeImplementation.h" + +namespace Magnum { namespace Physics { + +namespace Implementation { + template struct ShapeHelper; + + template inline AbstractShape* getAbstractShape(Composition& group, std::size_t i) { + return group._shapes[i]; + } + template inline const AbstractShape* getAbstractShape(const Composition& group, std::size_t i) { + return group._shapes[i]; + } +} + +/** @brief Shape operation */ +enum class CompositionOperation: UnsignedByte { + Not, /**< Boolean NOT */ + And, /**< Boolean AND */ + Or /**< Boolean OR */ +}; + +/** +@brief Composition of shapes + +Result of logical operations on shapes. +See @ref collision-detection for brief introduction. +*/ +template class MAGNUM_PHYSICS_EXPORT Composition { + friend Implementation::AbstractShape* Implementation::getAbstractShape<>(Composition&, std::size_t); + friend const Implementation::AbstractShape* Implementation::getAbstractShape<>(const Composition&, std::size_t); + friend struct Implementation::ShapeHelper>; + + public: + enum: UnsignedInt { + Dimensions = dimensions /**< Dimension count */ + }; + + /** @brief Shape type */ + #ifdef DOXYGEN_GENERATING_OUTPUT + enum class Type { + Point, /**< Point */ + Line, /**< Line */ + LineSegment, /**< @ref LineSegment "Line segment" */ + Sphere, /**< Sphere */ + Capsule, /**< Capsule */ + AxisAlignedBox, /**< @ref AxisAlignedBox "Axis aligned box" */ + Box, /**< Box */ + Plane /**< Plane (3D only) */ + }; + #else + typedef typename Implementation::ShapeDimensionTraits::Type Type; + #endif + + /** + * @brief Default constructor + * + * Creates empty hierarchy. + */ + inline explicit Composition(): _shapeCount(0), _nodeCount(0), _shapes(nullptr), _nodes(nullptr) {} + + /** + * @brief Unary operation constructor + * @param operation Unary operation + * @param a Operand + */ + template explicit Composition(CompositionOperation operation, T&& a); + + /** + * @brief Binary operation constructor + * @param operation Binary operation + * @param a Left operand + * @param b Right operand + */ + template explicit Composition(CompositionOperation operation, T&& a, U&& b); + + /** @brief Copy constructor */ + Composition(const Composition& other); + + /** @brief Move constructor */ + Composition(Composition&& other); + + ~Composition(); + + /** @brief Assigment operator */ + Composition& operator=(const Composition& other); + + /** @brief Move assignment operator */ + Composition& operator=(Composition&& other); + + /** @brief Transformed shape */ + Composition transformed(const typename DimensionTraits::MatrixType& matrix) const; + + /** @brief Count of shapes in the hierarchy */ + inline std::size_t size() const { return _shapeCount; } + + /** @brief Type of shape at given position */ + inline Type type(std::size_t i) const { return _shapes[i]->type(); } + + /** @brief Shape at given position */ + template const T& get(std::size_t i) const; + + /** @brief Collision with another shape */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template inline bool operator%(const T& other) const { + #else + template inline auto operator%(const T& other) const -> typename std::enable_if::type()), typename Implementation::ShapeDimensionTraits::Type>::value, bool>::type { + #endif + Implementation::Shape a(other); + return collides(&a); + } + + private: + struct Node { + std::size_t rightNode, rightShape; + CompositionOperation operation; + }; + + inline bool collides(const Implementation::AbstractShape* a) const { + return collides(a, 0, 0, _shapeCount); + } + + bool collides(const Implementation::AbstractShape* a, std::size_t node, std::size_t shapeBegin, std::size_t shapeEnd) const; + + template inline constexpr static std::size_t shapeCount(const T&) { + return 1; + } + inline constexpr static std::size_t shapeCount(const Composition& hierarchy) { + return hierarchy._shapeCount; + } + template inline constexpr static std::size_t nodeCount(const T&) { + return 0; + } + inline constexpr static std::size_t nodeCount(const Composition& hierarchy) { + return hierarchy._nodeCount; + } + + template inline void copyShapes(std::size_t offset, const T& shape) { + _shapes[offset] = new Implementation::Shape(shape); + } + void copyShapes(std::size_t offset, Composition&& other); + void copyShapes(std::size_t offset, const Composition& other); + + template inline void copyNodes(std::size_t, const T&) {} + void copyNodes(std::size_t offset, const Composition& other); + + std::size_t _shapeCount, _nodeCount; + Implementation::AbstractShape** _shapes; + Node* _nodes; +}; + +/** @brief Two-dimensional shape hierarchy */ +typedef Composition<2> Composition2D; + +/** @brief Three-dimensional shape hierarchy */ +typedef Composition<3> Composition3D; + +#ifdef DOXYGEN_GENERATING_OUTPUT +/** @debugoperator{Magnum::Physics::Composition} */ +template Debug operator<<(Debug debug, typename Composition::Type value); +#endif + +/** @relates Composition +@brief Collision of shape with Composition +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline bool operator%(const T& a, const Composition& b) { +#else +template inline auto operator%(const T& a, const Composition& b) -> typename std::enable_if::type()), typename Implementation::ShapeDimensionTraits::Type>::value, bool>::type { +#endif + return b % a; +} + +#ifdef DOXYGEN_GENERATING_OUTPUT +/** @relates Composition +@brief Logical NOT of shape +*/ +template inline Composition operator!(T a); + +/** @relates Composition +@brief Logical AND of two shapes + +[Short-circuit evaluation](http://en.wikipedia.org/wiki/Short-circuit_evaluation) +is used here, so this operation can be used for providing simplified shape +version, because collision with @p b is computed only if @p a collides. +See @ref collision-detection-shape-simplification for an example. +*/ +template inline Composition operator&&(T a, T b); + +/** @relates Composition +@brief Logical OR of two shapes + +[Short-circuit evaluation](http://en.wikipedia.org/wiki/Short-circuit_evaluation) +is used, so if collision with @p a is detected, collision with @p b is not +computed. +*/ +template inline Composition operator||(T a, T b); +#endif + +#ifndef DOXYGEN_GENERATING_OUTPUT +#define enableIfIsShapeType typename std::enable_if< \ + std::is_same::type()), typename Implementation::ShapeDimensionTraits::Type>::value, \ + Composition>::type +#define enableIfAreShapeType typename std::enable_if< \ + std::is_same::type()), typename Implementation::ShapeDimensionTraits::Type>::value && \ + std::is_same::type()), typename Implementation::ShapeDimensionTraits::Type>::value, \ + Composition>::type +template inline auto operator!(T&& a) -> enableIfIsShapeType { + return Composition(CompositionOperation::Not, std::forward(a)); +} +template inline auto operator&&(T&& a, U&& b) -> enableIfAreShapeType { + return Composition(CompositionOperation::And, std::forward(a), std::forward(b)); +} +template inline auto operator||(T&& a, U&& b) -> enableIfAreShapeType { + return Composition(CompositionOperation::Or, std::forward(a), std::forward(b)); +} +#undef enableIfIsShapeType +#undef enableIfAreShapeType +#endif + +template template Composition::Composition(CompositionOperation operation, T&& a): _shapeCount(shapeCount(a)), _nodeCount(nodeCount(a)+1), _shapes(new Implementation::AbstractShape*[_shapeCount]), _nodes(new Node[_nodeCount]) { + CORRADE_ASSERT(operation == CompositionOperation::Not, + "Physics::Composition::Composition(): unary operation expected", ); + _nodes[0].operation = operation; + + /* 0 = no children, 1 = left child only */ + _nodes[0].rightNode = (nodeCount(a) == 0 ? 0 : 1); + _nodes[0].rightShape = shapeCount(a); + copyNodes(1, a); + copyShapes(0, std::forward(a)); +} + +template template Composition::Composition(CompositionOperation operation, T&& a, U&& b): _shapeCount(shapeCount(a) + shapeCount(b)), _nodeCount(nodeCount(a) + nodeCount(b) + 1), _shapes(new Implementation::AbstractShape*[_shapeCount]), _nodes(new Node[_nodeCount]) { + CORRADE_ASSERT(operation != CompositionOperation::Not, + "Physics::Composition::Composition(): binary operation expected", ); + _nodes[0].operation = operation; + + /* 0 = no children, 1 = left child only, 2 = right child only, >2 = both */ + if(nodeCount(a) == 0 && nodeCount(b) == 0) + _nodes[0].rightNode = 0; + else if(nodeCount(b) == 0) + _nodes[0].rightNode = 1; + else _nodes[0].rightNode = nodeCount(a) + 2; + + _nodes[0].rightShape = shapeCount(a); + copyNodes(1, a); + copyNodes(nodeCount(a) + 1, b); + copyShapes(shapeCount(a), std::forward(b)); + copyShapes(0, std::forward(a)); +} + +template template inline const T& Composition::get(std::size_t i) const { + CORRADE_ASSERT(_shapes[i]->type() == Implementation::TypeOf::type(), + "Physics::Composition::get(): given shape is not of type" << Implementation::TypeOf::type() << + "but" << _shapes[i]->type(), *static_cast(nullptr)); + return static_cast*>(_shapes[i])->shape; +} + +}} + +#endif diff --git a/src/Physics/ObjectShapeGroup.cpp b/src/Physics/ObjectShapeGroup.cpp deleted file mode 100644 index b9e842cd3..000000000 --- a/src/Physics/ObjectShapeGroup.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include "ObjectShapeGroup.h" - -#include "Physics/AbstractObjectShape.h" - -namespace Magnum { namespace Physics { - -template void ObjectShapeGroup::setClean() { - /* Clean all objects */ - if(!this->isEmpty()) { - std::vector*> objects(this->size()); - for(std::size_t i = 0; i != this->size(); ++i) - objects[i] = (*this)[i]->object(); - - objects[0]->setClean(objects); - } - - dirty = false; -} - -template AbstractObjectShape* ObjectShapeGroup::firstCollision(const AbstractObjectShape* shape) { - setClean(); - for(std::size_t i = 0; i != this->size(); ++i) - if((*this)[i] != shape && (*this)[i]->collides(shape)) - return (*this)[i]; - - return nullptr; -} - -#ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup<2>; -template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup<3>; -#endif - -}} diff --git a/src/Physics/ObjectShapeGroup.h b/src/Physics/ObjectShapeGroup.h deleted file mode 100644 index 0c7c35a31..000000000 --- a/src/Physics/ObjectShapeGroup.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef Magnum_Physics_ObjectShapeGroup_h -#define Magnum_Physics_ObjectShapeGroup_h -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -/** @file - * @brief Class Magnum::Physics::ObjectShapeGroup, typedef Magnum::Physics::ObjectShapeGroup2D, Magnum::Physics::ObjectShapeGroup3D - */ - -#include - -#include "Physics/Physics.h" -#include "SceneGraph/FeatureGroup.h" - -#include "magnumPhysicsVisibility.h" - -namespace Magnum { namespace Physics { - -/** -@brief Group of object shapes - -See ObjectShape for more information. -@see @ref scenegraph, ObjectShapeGroup2D, ObjectShapeGroup3D -*/ -template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: public SceneGraph::FeatureGroup> { - friend class AbstractObjectShape; - - public: - /** - * @brief Constructor - * - * Marks the group as dirty. - */ - inline explicit ObjectShapeGroup(): dirty(true) {} - - /** - * @brief Whether the group is dirty - * @return True if any object in the group is dirty, false otherwise. - */ - inline bool isDirty() const { return dirty; } - - /** - * @brief Set the group as dirty - * - * If some body in the group changes its transformation, it sets dirty - * status also on the group to indicate that the body and maybe also - * group state needs to be cleaned before computing collisions. - * - * @see setClean() - */ - inline void setDirty() { dirty = true; } - - /** - * @brief Set the group and all bodies as clean - * - * This function is called before computing any collisions to ensure - * all objects are cleaned. - */ - void setClean(); - - /** - * @brief First collision of given shape with other shapes in the group - * - * Returns first shape colliding with given one. If there aren't any - * collisions, returns `nullptr`. Calls setClean() before the - * operation. - */ - AbstractObjectShape* firstCollision(const AbstractObjectShape* shape); - - private: - bool dirty; -}; - -/** -@brief Group of two-dimensional shaped objects - -See ObjectShape for more information. -@see ObjectShapeGroup3D -*/ -typedef ObjectShapeGroup<2> ObjectShapeGroup2D; - -/** -@brief Group of three-dimensional shaped objects - -See ObjectShape for more information. -@see ObjectShapeGroup2D -*/ -typedef ObjectShapeGroup<3> ObjectShapeGroup3D; - -}} - -#endif diff --git a/src/Physics/Physics.h b/src/Physics/Physics.h index 7396273db..f0f9a7dfc 100644 --- a/src/Physics/Physics.h +++ b/src/Physics/Physics.h @@ -34,9 +34,9 @@ namespace Magnum { namespace Physics { /** @todoc remove when doxygen is sane again */ #ifndef DOXYGEN_GENERATING_OUTPUT -template class AbstractObjectShape; -typedef AbstractObjectShape<2> AbstractObjectShape2D; -typedef AbstractObjectShape<3> AbstractObjectShape3D; +template class AbstractShape; +typedef AbstractShape<2> AbstractShape2D; +typedef AbstractShape<3> AbstractShape3D; template class AxisAlignedBox; typedef AxisAlignedBox<2> AxisAlignedBox2D; @@ -50,6 +50,10 @@ template class Capsule; typedef Capsule<2> Capsule2D; typedef Capsule<3> Capsule3D; +template class Composition; +typedef Composition<2> Composition2D; +typedef Composition<3> Composition3D; + template class Line; typedef Line<2> Line2D; typedef Line<3> Line3D; @@ -58,17 +62,7 @@ template class LineSegment; typedef LineSegment<2> LineSegment2D; typedef LineSegment<3> LineSegment3D; -template class ObjectShape; - -template class ObjectShapeGroup; -typedef ObjectShapeGroup<2> ObjectShapeGroup2D; -typedef ObjectShapeGroup<3> ObjectShapeGroup3D; - -class Plane; - -template class Point; -typedef Point<2> Point2D; -typedef Point<3> Point3D; +template class Shape; template class ShapeGroup; typedef ShapeGroup<2> ShapeGroup2D; @@ -79,6 +73,12 @@ typedef Sphere<2> Sphere2D; typedef Sphere<3> Sphere3D; #endif +class Plane; + +template class Point; +typedef Point<2> Point2D; +typedef Point<3> Point3D; + }} #endif diff --git a/src/Physics/ObjectShape.cpp b/src/Physics/Shape.cpp similarity index 50% rename from src/Physics/ObjectShape.cpp rename to src/Physics/Shape.cpp index c8925842c..47a74e8e2 100644 --- a/src/Physics/ObjectShape.cpp +++ b/src/Physics/Shape.cpp @@ -22,27 +22,27 @@ DEALINGS IN THE SOFTWARE. */ -#include "ObjectShape.h" +#include "Shape.h" -#include "Physics/ShapeGroup.h" +#include "Physics/Composition.h" namespace Magnum { namespace Physics { namespace Implementation { -template void ObjectShapeHelper>::set(ObjectShape>& objectShape, const ShapeGroup& shape) { - objectShape._transformedShape.shape = objectShape._shape.shape = shape; +template void ShapeHelper>::set(Physics::Shape>& shape, const Composition& composition) { + shape._transformedShape.shape = shape._shape.shape = composition; } -template void ObjectShapeHelper>::set(ObjectShape>& objectShape, ShapeGroup&& shape) { - objectShape._transformedShape.shape = objectShape._shape.shape = std::move(shape); +template void ShapeHelper>::set(Physics::Shape>& shape, Composition&& composition) { + shape._transformedShape.shape = shape._shape.shape = std::move(composition); } -template void ObjectShapeHelper>::transform(ObjectShape>& objectShape, const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { - CORRADE_INTERNAL_ASSERT(objectShape._shape.shape.size() == objectShape._transformedShape.shape.size()); - for(std::size_t i = 0; i != objectShape.shape().size(); ++i) - objectShape._shape.shape._shapes[i]->transform(absoluteTransformationMatrix, objectShape._transformedShape.shape._shapes[i]); +template void ShapeHelper>::transform(Physics::Shape>& shape, const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { + CORRADE_INTERNAL_ASSERT(shape._shape.shape.size() == shape._transformedShape.shape.size()); + for(std::size_t i = 0; i != shape.shape().size(); ++i) + shape._shape.shape._shapes[i]->transform(absoluteTransformationMatrix, shape._transformedShape.shape._shapes[i]); } -template struct MAGNUM_PHYSICS_EXPORT ObjectShapeHelper>; -template struct MAGNUM_PHYSICS_EXPORT ObjectShapeHelper>; +template struct MAGNUM_PHYSICS_EXPORT ShapeHelper>; +template struct MAGNUM_PHYSICS_EXPORT ShapeHelper>; }}} diff --git a/src/Physics/ObjectShape.h b/src/Physics/Shape.h similarity index 50% rename from src/Physics/ObjectShape.h rename to src/Physics/Shape.h index f421e7d42..75127b2dd 100644 --- a/src/Physics/ObjectShape.h +++ b/src/Physics/Shape.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_ObjectShape_h -#define Magnum_Physics_ObjectShape_h +#ifndef Magnum_Physics_Shape_h +#define Magnum_Physics_Shape_h /* This file is part of Magnum. @@ -25,10 +25,10 @@ */ /** @file - * @brief Class Magnum::Physics::ObjectShape + * @brief Class Magnum::Physics::Shape */ -#include "Physics/AbstractObjectShape.h" +#include "Physics/AbstractShape.h" #include "Physics/Physics.h" #include "magnumPhysicsVisibility.h" @@ -36,33 +36,33 @@ namespace Magnum { namespace Physics { namespace Implementation { - template struct ObjectShapeHelper; + template struct ShapeHelper; } /** @brief Object shape -Adds shape for collision detection to object. Each %ObjectShape is part of -some ObjectShapeGroup, which essentially maintains a set of objects which can +Adds shape for collision detection to object. Each %Shape is part of +some ShapeGroup, which essentially maintains a set of objects which can collide with each other. -@section ObjectShape-usage Usage +@section Shape-usage Usage Add the feature to the object and some shape group (you can also use -ObjectShapeGroup::add() and ObjectShapeGroup::remove() later) and configure the +ShapeGroup::add() and ShapeGroup::remove() later) and configure the shape. @code -Physics::ObjectShapeGroup3D shapes; +Physics::ShapeGroup3D shapes; Object3D* object; -auto shape = new Physics::ObjectShape(object, {{}, 0.75f}, &shapes); +auto shape = new Physics::Shape(object, {{}, 0.75f}, &shapes); @endcode -@see @ref scenegraph, ObjectShapeGroup2D, ObjectShapeGroup3D, +@see @ref scenegraph, ShapeGroup2D, ShapeGroup3D, DebugTools::ShapeRenderer */ -template class MAGNUM_PHYSICS_EXPORT ObjectShape: public AbstractObjectShape { - friend struct Implementation::ObjectShapeHelper; +template class MAGNUM_PHYSICS_EXPORT Shape: public AbstractShape { + friend struct Implementation::ShapeHelper; public: /** @@ -71,17 +71,17 @@ template class MAGNUM_PHYSICS_EXPORT ObjectShape: public AbstractObject * @param shape Shape * @param group Group this shape belongs to */ - template explicit ObjectShape(SceneGraph::AbstractObject* object, const T& shape, ObjectShapeGroup* group = nullptr): AbstractObjectShape(object, group) { - Implementation::ObjectShapeHelper::set(*this, shape); + template explicit Shape(SceneGraph::AbstractObject* object, const T& shape, ShapeGroup* group = nullptr): AbstractShape(object, group) { + Implementation::ShapeHelper::set(*this, shape); } /** @overload */ - template explicit ObjectShape(SceneGraph::AbstractObject* object, T&& shape, ObjectShapeGroup* group = nullptr): AbstractObjectShape(object, group) { - Implementation::ObjectShapeHelper::set(*this, std::move(shape)); + template explicit Shape(SceneGraph::AbstractObject* object, T&& shape, ShapeGroup* group = nullptr): AbstractShape(object, group) { + Implementation::ShapeHelper::set(*this, std::move(shape)); } /** @overload */ - template explicit ObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group = nullptr): AbstractObjectShape(object, group) {} + template explicit Shape(SceneGraph::AbstractObject* object, ShapeGroup* group = nullptr): AbstractShape(object, group) {} /** @brief Shape */ inline const T& shape() const { return _shape.shape; } @@ -92,7 +92,7 @@ template class MAGNUM_PHYSICS_EXPORT ObjectShape: public AbstractObject * * Marks the feature as dirty. */ - ObjectShape* setShape(const T& shape); + Shape* setShape(const T& shape); /** * @brief Transformed shape @@ -116,41 +116,41 @@ template class MAGNUM_PHYSICS_EXPORT ObjectShape: public AbstractObject Implementation::Shape _shape, _transformedShape; }; -template inline ObjectShape* ObjectShape::setShape(const T& shape) { - Implementation::ObjectShapeHelper::set(*this, shape); +template inline Shape* Shape::setShape(const T& shape) { + Implementation::ShapeHelper::set(*this, shape); this->object()->setDirty(); return this; } -template inline const T& ObjectShape::transformedShape() { +template inline const T& Shape::transformedShape() { this->object()->setClean(); return _transformedShape.shape; } -template void ObjectShape::markDirty() { +template void Shape::markDirty() { if(this->group()) this->group()->setDirty(); } -template void ObjectShape::clean(const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { - Implementation::ObjectShapeHelper::transform(*this, absoluteTransformationMatrix); +template void Shape::clean(const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { + Implementation::ShapeHelper::transform(*this, absoluteTransformationMatrix); } namespace Implementation { - template struct ObjectShapeHelper { - inline static void set(ObjectShape& objectShape, const T& shape) { - objectShape._shape.shape = shape; + template struct ShapeHelper { + inline static void set(Physics::Shape& shape, const T& s) { + shape._shape.shape = s; } - inline static void transform(ObjectShape& objectShape, const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { - objectShape._transformedShape.shape = objectShape._shape.shape.transformed(absoluteTransformationMatrix); + inline static void transform(Physics::Shape& shape, const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { + shape._transformedShape.shape = shape._shape.shape.transformed(absoluteTransformationMatrix); } }; - template struct MAGNUM_PHYSICS_EXPORT ObjectShapeHelper> { - static void set(ObjectShape>& objectShape, const ShapeGroup& shape); - static void set(ObjectShape>& objectShape, ShapeGroup&& shape); + template struct MAGNUM_PHYSICS_EXPORT ShapeHelper> { + static void set(Physics::Shape>& shape, const Composition& composition); + static void set(Physics::Shape>& shape, Composition&& composition); - static void transform(ObjectShape>& objectShape, const typename DimensionTraits::MatrixType& absoluteTransformationMatrix); + static void transform(Physics::Shape>& shape, const typename DimensionTraits::MatrixType& absoluteTransformationMatrix); }; } diff --git a/src/Physics/ShapeGroup.cpp b/src/Physics/ShapeGroup.cpp index ca939a9d6..0e9707be5 100644 --- a/src/Physics/ShapeGroup.cpp +++ b/src/Physics/ShapeGroup.cpp @@ -24,139 +24,30 @@ #include "ShapeGroup.h" -#include -#include - -#include "Physics/Implementation/CollisionDispatch.h" +#include "Physics/AbstractShape.h" namespace Magnum { namespace Physics { -/* -Hierarchy implementation notes: - -The hierarchy is stored in flat array to provide easy access for the user and -to save some allocations. Each node has zero, one or two subnodes. Value of -`Node::rightNode` describes which child nodes exist: - - * 0 - no child subnodes - * 1 - only left subnode exists - * 2 - only right subnode exists - * >2 - both child nodes exist - -If left node exists, it is right next to current one. If right node exists, it -is at position `Node::rightNode-1` relative to current one (this applies also -when `rightNode` is equal to 2, right node is right next to current one, -because there are no left nodes). - -The node also specifies which shapes belong to it. Root node owns whole shape -array and `Node::rightShape` marks first shape belonging to the right child -node, relatively to begin. This recurses into child nodes, thus left child node -has shapes from parent's begin to parent's `rightShape`. - -Shapes are merged together by concatenating its node and shape list and adding -new node at the beginning with properly set `rightNode` and `rightShape`. -Because these values are relative to parent, they don't need to be modified -when concatenating. -*/ - -template ShapeGroup::ShapeGroup(const ShapeGroup& other): _shapeCount(other._shapeCount), _nodeCount(other._nodeCount) { - copyShapes(0, other); - copyNodes(0, other); -} - -template ShapeGroup::ShapeGroup(ShapeGroup&& other): _shapeCount(other._shapeCount), _nodeCount(other._nodeCount), _shapes(other._shapes), _nodes(other._nodes) { - other._shapes = nullptr; - other._shapeCount = 0; - - other._nodes = nullptr; - other._nodeCount = 0; -} - -template ShapeGroup::~ShapeGroup() { - for(std::size_t i = 0; i != _shapeCount; ++i) - delete _shapes[i]; - - delete[] _shapes; - delete[] _nodes; -} - -template ShapeGroup& ShapeGroup::operator=(const ShapeGroup& other) { - for(std::size_t i = 0; i != _shapeCount; ++i) - delete _shapes[i]; +template void ShapeGroup::setClean() { + /* Clean all objects */ + if(!this->isEmpty()) { + std::vector*> objects(this->size()); + for(std::size_t i = 0; i != this->size(); ++i) + objects[i] = (*this)[i]->object(); - if(_shapeCount != other._shapeCount) { - delete[] _shapes; - _shapeCount = other._shapeCount; - _shapes = new Implementation::AbstractShape*[_shapeCount]; + objects[0]->setClean(objects); } - if(_nodeCount != other._nodeCount) { - delete[] _nodes; - _nodeCount = other._nodeCount; - _nodes = new Node[_nodeCount]; - } - - copyShapes(0, other); - copyNodes(0, other); - return *this; -} - -template ShapeGroup& ShapeGroup::operator=(ShapeGroup&& other) { - std::swap(other._shapeCount, _shapeCount); - std::swap(other._nodeCount, _nodeCount); - std::swap(other._shapes, _shapes); - std::swap(other._nodes, _nodes); - return *this; -} - -template void ShapeGroup::copyShapes(const std::size_t offset, ShapeGroup&& other) { - std::move(other._shapes, other._shapes+other._shapeCount, _shapes+offset); - delete[] other._shapes; - other._shapes = nullptr; - other._shapeCount = 0; -} - -template void ShapeGroup::copyShapes(const std::size_t offset, const ShapeGroup& other) { - for(std::size_t i = 0; i != other._shapeCount; ++i) - _shapes[i+offset] = other._shapes[i]->clone(); + dirty = false; } -template void ShapeGroup::copyNodes(std::size_t offset, const ShapeGroup& other) { - std::copy(other._nodes, other._nodes+other._nodeCount, _nodes+offset); -} - -template ShapeGroup ShapeGroup::transformed(const typename DimensionTraits::MatrixType& matrix) const { - ShapeGroup out(*this); - for(std::size_t i = 0; i != _shapeCount; ++i) - _shapes[i]->transform(matrix, out._shapes[i]); - return out; -} - -template bool ShapeGroup::collides(const Implementation::AbstractShape* const a, const std::size_t node, const std::size_t shapeBegin, const std::size_t shapeEnd) const { - /* Empty group */ - if(shapeBegin == shapeEnd) return false; - - CORRADE_INTERNAL_ASSERT(node < _nodeCount && shapeBegin < shapeEnd); - - /* Collision on the left child. If the node is leaf one (no left child - exists), do it directly, recurse instead. */ - const bool collidesLeft = (_nodes[node].rightNode == 0 || _nodes[node].rightNode == 2) ? - Implementation::collides(a, _shapes[shapeBegin]) : - collides(a, node+1, shapeBegin, shapeBegin+_nodes[node].rightShape); - - /* NOT operation */ - if(_nodes[node].operation == ShapeOperation::Not) - return !collidesLeft; - - /* Short-circuit evaluation for AND/OR */ - if((_nodes[node].operation == ShapeOperation::Or) == collidesLeft) - return collidesLeft; +template AbstractShape* ShapeGroup::firstCollision(const AbstractShape* shape) { + setClean(); + for(std::size_t i = 0; i != this->size(); ++i) + if((*this)[i] != shape && (*this)[i]->collides(shape)) + return (*this)[i]; - /* Now the collision result depends only on the right child. Similar to - collision on the left child. */ - return (_nodes[node].rightNode < 2) ? - Implementation::collides(a, _shapes[shapeBegin+_nodes[node].rightShape]) : - collides(a, node+_nodes[node].rightNode-1, shapeBegin+_nodes[node].rightShape, shapeEnd); + return nullptr; } #ifndef DOXYGEN_GENERATING_OUTPUT diff --git a/src/Physics/ShapeGroup.h b/src/Physics/ShapeGroup.h index 51b5f55b2..93d230c54 100644 --- a/src/Physics/ShapeGroup.h +++ b/src/Physics/ShapeGroup.h @@ -25,273 +25,88 @@ */ /** @file - * @brief Class Magnum::Physics::ShapeGroup, enum Magnum::Physics::ShapeOperation + * @brief Class Magnum::Physics::ShapeGroup, typedef Magnum::Physics::ShapeGroup2D, Magnum::Physics::ShapeGroup3D */ -#include -#include -#include +#include -#include "DimensionTraits.h" #include "Physics/Physics.h" -#include "Physics/magnumPhysicsVisibility.h" -#include "Physics/shapeImplementation.h" +#include "SceneGraph/FeatureGroup.h" -namespace Magnum { namespace Physics { - -namespace Implementation { - template struct ObjectShapeHelper; +#include "magnumPhysicsVisibility.h" - template inline AbstractShape* getAbstractShape(ShapeGroup& group, std::size_t i) { - return group._shapes[i]; - } - template inline const AbstractShape* getAbstractShape(const ShapeGroup& group, std::size_t i) { - return group._shapes[i]; - } -} - -/** @brief Shape operation */ -enum class ShapeOperation: UnsignedByte { - Not, /**< Boolean NOT */ - And, /**< Boolean AND */ - Or /**< Boolean OR */ -}; +namespace Magnum { namespace Physics { /** -@brief Shape group +@brief Group of shapes -Result of logical operations on shapes. -See @ref collision-detection for brief introduction. +See Shape for more information. +@see @ref scenegraph, ShapeGroup2D, ShapeGroup3D */ -template class MAGNUM_PHYSICS_EXPORT ShapeGroup { - friend Implementation::AbstractShape* Implementation::getAbstractShape<>(ShapeGroup&, std::size_t); - friend const Implementation::AbstractShape* Implementation::getAbstractShape<>(const ShapeGroup&, std::size_t); - friend struct Implementation::ObjectShapeHelper>; +template class MAGNUM_PHYSICS_EXPORT ShapeGroup: public SceneGraph::FeatureGroup> { + friend class AbstractShape; public: - enum: UnsignedInt { - Dimensions = dimensions /**< Dimension count */ - }; - - /** @brief Shape type */ - #ifdef DOXYGEN_GENERATING_OUTPUT - enum class Type { - Point, /**< Point */ - Line, /**< Line */ - LineSegment, /**< @ref LineSegment "Line segment" */ - Sphere, /**< Sphere */ - Capsule, /**< Capsule */ - AxisAlignedBox, /**< @ref AxisAlignedBox "Axis aligned box" */ - Box, /**< Box */ - Plane /**< Plane (3D only) */ - }; - #else - typedef typename Implementation::ShapeDimensionTraits::Type Type; - #endif - /** - * @brief Default constructor + * @brief Constructor * - * Creates empty hierarchy. + * Marks the group as dirty. */ - inline explicit ShapeGroup(): _shapeCount(0), _nodeCount(0), _shapes(nullptr), _nodes(nullptr) {} + inline explicit ShapeGroup(): dirty(true) {} /** - * @brief Unary operation constructor - * @param operation Unary operation - * @param a Operand + * @brief Whether the group is dirty + * @return True if any object in the group is dirty, false otherwise. */ - template explicit ShapeGroup(ShapeOperation operation, T&& a); + inline bool isDirty() const { return dirty; } /** - * @brief Binary operation constructor - * @param operation Binary operation - * @param a Left operand - * @param b Right operand + * @brief Set the group as dirty + * + * If some body in the group changes its transformation, it sets dirty + * status also on the group to indicate that the body and maybe also + * group state needs to be cleaned before computing collisions. + * + * @see setClean() */ - template explicit ShapeGroup(ShapeOperation operation, T&& a, U&& b); - - /** @brief Copy constructor */ - ShapeGroup(const ShapeGroup& other); - - /** @brief Move constructor */ - ShapeGroup(ShapeGroup&& other); - - ~ShapeGroup(); - - /** @brief Assigment operator */ - ShapeGroup& operator=(const ShapeGroup& other); - - /** @brief Move assignment operator */ - ShapeGroup& operator=(ShapeGroup&& other); + inline void setDirty() { dirty = true; } - /** @brief Transformed shape */ - ShapeGroup transformed(const typename DimensionTraits::MatrixType& matrix) const; - - /** @brief Count of shapes in the hierarchy */ - inline std::size_t size() const { return _shapeCount; } - - /** @brief Type of shape at given position */ - inline Type type(std::size_t i) const { return _shapes[i]->type(); } - - /** @brief Shape at given position */ - template const T& get(std::size_t i) const; + /** + * @brief Set the group and all bodies as clean + * + * This function is called before computing any collisions to ensure + * all objects are cleaned. + */ + void setClean(); - /** @brief Collision with another shape */ - #ifdef DOXYGEN_GENERATING_OUTPUT - template inline bool operator%(const T& other) const { - #else - template inline auto operator%(const T& other) const -> typename std::enable_if::type()), typename Implementation::ShapeDimensionTraits::Type>::value, bool>::type { - #endif - Implementation::Shape a(other); - return collides(&a); - } + /** + * @brief First collision of given shape with other shapes in the group + * + * Returns first shape colliding with given one. If there aren't any + * collisions, returns `nullptr`. Calls setClean() before the + * operation. + */ + AbstractShape* firstCollision(const AbstractShape* shape); private: - struct Node { - std::size_t rightNode, rightShape; - ShapeOperation operation; - }; - - inline bool collides(const Implementation::AbstractShape* a) const { - return collides(a, 0, 0, _shapeCount); - } - - bool collides(const Implementation::AbstractShape* a, std::size_t node, std::size_t shapeBegin, std::size_t shapeEnd) const; - - template inline constexpr static std::size_t shapeCount(const T&) { - return 1; - } - inline constexpr static std::size_t shapeCount(const ShapeGroup& hierarchy) { - return hierarchy._shapeCount; - } - template inline constexpr static std::size_t nodeCount(const T&) { - return 0; - } - inline constexpr static std::size_t nodeCount(const ShapeGroup& hierarchy) { - return hierarchy._nodeCount; - } - - template inline void copyShapes(std::size_t offset, const T& shape) { - _shapes[offset] = new Implementation::Shape(shape); - } - void copyShapes(std::size_t offset, ShapeGroup&& other); - void copyShapes(std::size_t offset, const ShapeGroup& other); - - template inline void copyNodes(std::size_t, const T&) {} - void copyNodes(std::size_t offset, const ShapeGroup& other); - - std::size_t _shapeCount, _nodeCount; - Implementation::AbstractShape** _shapes; - Node* _nodes; + bool dirty; }; -/** @brief Two-dimensional shape hierarchy */ -typedef ShapeGroup<2> ShapeGroup2D; - -/** @brief Three-dimensional shape hierarchy */ -typedef ShapeGroup<3> ShapeGroup3D; - -#ifdef DOXYGEN_GENERATING_OUTPUT -/** @debugoperator{Magnum::Physics::ShapeGroup} */ -template Debug operator<<(Debug debug, typename ShapeGroup::Type value); -#endif - -/** @relates ShapeGroup -@brief Collision of shape with ShapeGroup -*/ -#ifdef DOXYGEN_GENERATING_OUTPUT -template inline bool operator%(const T& a, const ShapeGroup& b) { -#else -template inline auto operator%(const T& a, const ShapeGroup& b) -> typename std::enable_if::type()), typename Implementation::ShapeDimensionTraits::Type>::value, bool>::type { -#endif - return b % a; -} - -#ifdef DOXYGEN_GENERATING_OUTPUT -/** @relates ShapeGroup -@brief Logical NOT of shape -*/ -template inline ShapeGroup operator!(T a); - -/** @relates ShapeGroup -@brief Logical AND of two shapes +/** +@brief Group of two-dimensional shaped objects -[Short-circuit evaluation](http://en.wikipedia.org/wiki/Short-circuit_evaluation) -is used here, so this operation can be used for providing simplified shape -version, because collision with @p b is computed only if @p a collides. -See @ref collision-detection-shape-simplification for an example. +See Shape for more information. +@see ShapeGroup3D */ -template inline ShapeGroup operator&&(T a, T b); +typedef ShapeGroup<2> ShapeGroup2D; -/** @relates ShapeGroup -@brief Logical OR of two shapes +/** +@brief Group of three-dimensional shaped objects -[Short-circuit evaluation](http://en.wikipedia.org/wiki/Short-circuit_evaluation) -is used, so if collision with @p a is detected, collision with @p b is not -computed. +See Shape for more information. +@see ShapeGroup2D */ -template inline ShapeGroup operator||(T a, T b); -#endif - -#ifndef DOXYGEN_GENERATING_OUTPUT -#define enableIfIsShapeType typename std::enable_if< \ - std::is_same::type()), typename Implementation::ShapeDimensionTraits::Type>::value, \ - ShapeGroup>::type -#define enableIfAreShapeType typename std::enable_if< \ - std::is_same::type()), typename Implementation::ShapeDimensionTraits::Type>::value && \ - std::is_same::type()), typename Implementation::ShapeDimensionTraits::Type>::value, \ - ShapeGroup>::type -template inline auto operator!(T&& a) -> enableIfIsShapeType { - return ShapeGroup(ShapeOperation::Not, std::forward(a)); -} -template inline auto operator&&(T&& a, U&& b) -> enableIfAreShapeType { - return ShapeGroup(ShapeOperation::And, std::forward(a), std::forward(b)); -} -template inline auto operator||(T&& a, U&& b) -> enableIfAreShapeType { - return ShapeGroup(ShapeOperation::Or, std::forward(a), std::forward(b)); -} -#undef enableIfIsShapeType -#undef enableIfAreShapeType -#endif - -template template ShapeGroup::ShapeGroup(ShapeOperation operation, T&& a): _shapeCount(shapeCount(a)), _nodeCount(nodeCount(a)+1), _shapes(new Implementation::AbstractShape*[_shapeCount]), _nodes(new Node[_nodeCount]) { - CORRADE_ASSERT(operation == ShapeOperation::Not, - "Physics::ShapeGroup::ShapeGroup(): unary operation expected", ); - _nodes[0].operation = operation; - - /* 0 = no children, 1 = left child only */ - _nodes[0].rightNode = (nodeCount(a) == 0 ? 0 : 1); - _nodes[0].rightShape = shapeCount(a); - copyNodes(1, a); - copyShapes(0, std::forward(a)); -} - -template template ShapeGroup::ShapeGroup(ShapeOperation operation, T&& a, U&& b): _shapeCount(shapeCount(a) + shapeCount(b)), _nodeCount(nodeCount(a) + nodeCount(b) + 1), _shapes(new Implementation::AbstractShape*[_shapeCount]), _nodes(new Node[_nodeCount]) { - CORRADE_ASSERT(operation != ShapeOperation::Not, - "Physics::ShapeGroup::ShapeGroup(): binary operation expected", ); - _nodes[0].operation = operation; - - /* 0 = no children, 1 = left child only, 2 = right child only, >2 = both */ - if(nodeCount(a) == 0 && nodeCount(b) == 0) - _nodes[0].rightNode = 0; - else if(nodeCount(b) == 0) - _nodes[0].rightNode = 1; - else _nodes[0].rightNode = nodeCount(a) + 2; - - _nodes[0].rightShape = shapeCount(a); - copyNodes(1, a); - copyNodes(nodeCount(a) + 1, b); - copyShapes(shapeCount(a), std::forward(b)); - copyShapes(0, std::forward(a)); -} - -template template inline const T& ShapeGroup::get(std::size_t i) const { - CORRADE_ASSERT(_shapes[i]->type() == Implementation::TypeOf::type(), - "Physics::ShapeGroup::get(): given shape is not of type" << Implementation::TypeOf::type() << - "but" << _shapes[i]->type(), *static_cast(nullptr)); - return static_cast*>(_shapes[i])->shape; -} +typedef ShapeGroup<3> ShapeGroup3D; }} diff --git a/src/Physics/Test/CMakeLists.txt b/src/Physics/Test/CMakeLists.txt index 659b3761c..47c7812e6 100644 --- a/src/Physics/Test/CMakeLists.txt +++ b/src/Physics/Test/CMakeLists.txt @@ -29,7 +29,7 @@ corrade_add_test(PhysicsCapsuleTest CapsuleTest.cpp LIBRARIES MagnumPhysics) corrade_add_test(PhysicsLineTest LineTest.cpp LIBRARIES MagnumPhysics) corrade_add_test(PhysicsPlaneTest PlaneTest.cpp LIBRARIES MagnumPhysics) corrade_add_test(PhysicsPointTest PointTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test(PhysicsShapeGroupTest ShapeGroupTest.cpp LIBRARIES MagnumPhysics) +corrade_add_test(PhysicsCompositionTest CompositionTest.cpp LIBRARIES MagnumPhysics) corrade_add_test(PhysicsSphereTest SphereTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test(PhysicsObjectShapeTest ObjectShapeTest.cpp LIBRARIES MagnumPhysics) +corrade_add_test(PhysicsShapeTest ShapeTest.cpp LIBRARIES MagnumPhysics) diff --git a/src/Physics/Test/ShapeGroupTest.cpp b/src/Physics/Test/CompositionTest.cpp similarity index 65% rename from src/Physics/Test/ShapeGroupTest.cpp rename to src/Physics/Test/CompositionTest.cpp index b0ac44194..c7b9c5419 100644 --- a/src/Physics/Test/ShapeGroupTest.cpp +++ b/src/Physics/Test/CompositionTest.cpp @@ -27,16 +27,16 @@ #include "Math/Matrix4.h" #include "Physics/Point.h" #include "Physics/AxisAlignedBox.h" -#include "Physics/ShapeGroup.h" +#include "Physics/Composition.h" #include "Physics/Sphere.h" #include "ShapeTestBase.h" namespace Magnum { namespace Physics { namespace Test { -class ShapeGroupTest: public Corrade::TestSuite::Tester { +class CompositionTest: public Corrade::TestSuite::Tester { public: - ShapeGroupTest(); + CompositionTest(); void negated(); void anded(); @@ -46,31 +46,31 @@ class ShapeGroupTest: public Corrade::TestSuite::Tester { void empty(); }; -ShapeGroupTest::ShapeGroupTest() { - addTests({&ShapeGroupTest::negated, - &ShapeGroupTest::anded, - &ShapeGroupTest::ored, - &ShapeGroupTest::multipleUnary, - &ShapeGroupTest::hierarchy, - &ShapeGroupTest::empty}); +CompositionTest::CompositionTest() { + addTests({&CompositionTest::negated, + &CompositionTest::anded, + &CompositionTest::ored, + &CompositionTest::multipleUnary, + &CompositionTest::hierarchy, + &CompositionTest::empty}); } -void ShapeGroupTest::negated() { - const Physics::ShapeGroup2D a = !Physics::Point2D(Vector2::xAxis(0.5f)); +void CompositionTest::negated() { + const Physics::Composition2D a = !Physics::Point2D(Vector2::xAxis(0.5f)); CORRADE_COMPARE(a.size(), 1); - CORRADE_COMPARE(a.type(0), ShapeGroup2D::Type::Point); + CORRADE_COMPARE(a.type(0), Composition2D::Type::Point); CORRADE_COMPARE(a.get(0).position(), Vector2::xAxis(0.5f)); VERIFY_NOT_COLLIDES(a, Physics::Sphere2D({}, 1.0f)); } -void ShapeGroupTest::anded() { - const Physics::ShapeGroup2D a = Physics::Sphere2D({}, 1.0f) && Physics::Point2D(Vector2::xAxis(0.5f)); +void CompositionTest::anded() { + const Physics::Composition2D a = Physics::Sphere2D({}, 1.0f) && Physics::Point2D(Vector2::xAxis(0.5f)); CORRADE_COMPARE(a.size(), 2); - CORRADE_COMPARE(a.type(0), ShapeGroup2D::Type::Sphere); - CORRADE_COMPARE(a.type(1), ShapeGroup2D::Type::Point); + CORRADE_COMPARE(a.type(0), Composition2D::Type::Sphere); + CORRADE_COMPARE(a.type(1), Composition2D::Type::Point); CORRADE_COMPARE(a.get(0).position(), Vector2()); CORRADE_COMPARE(a.get(0).radius(), 1.0f); CORRADE_COMPARE(a.get(1).position(), Vector2::xAxis(0.5f)); @@ -79,12 +79,12 @@ void ShapeGroupTest::anded() { VERIFY_COLLIDES(a, Physics::Sphere2D(Vector2::xAxis(0.5f), 0.25f)); } -void ShapeGroupTest::ored() { - const Physics::ShapeGroup2D a = Physics::Sphere2D({}, 1.0f) || Physics::Point2D(Vector2::xAxis(1.5f)); +void CompositionTest::ored() { + const Physics::Composition2D a = Physics::Sphere2D({}, 1.0f) || Physics::Point2D(Vector2::xAxis(1.5f)); CORRADE_COMPARE(a.size(), 2); - CORRADE_COMPARE(a.type(0), ShapeGroup2D::Type::Sphere); - CORRADE_COMPARE(a.type(1), ShapeGroup2D::Type::Point); + CORRADE_COMPARE(a.type(0), Composition2D::Type::Sphere); + CORRADE_COMPARE(a.type(1), Composition2D::Type::Point); CORRADE_COMPARE(a.get(0).position(), Vector2()); CORRADE_COMPARE(a.get(0).radius(), 1.0f); CORRADE_COMPARE(a.get(1).position(), Vector2::xAxis(1.5f)); @@ -93,32 +93,32 @@ void ShapeGroupTest::ored() { VERIFY_COLLIDES(a, Physics::Sphere2D(Vector2::xAxis(1.5f), 0.25f)); } -void ShapeGroupTest::multipleUnary() { - const Physics::ShapeGroup2D a = !!!!Physics::Point2D(Vector2::xAxis(0.5f)); +void CompositionTest::multipleUnary() { + const Physics::Composition2D a = !!!!Physics::Point2D(Vector2::xAxis(0.5f)); CORRADE_COMPARE(a.size(), 1); - CORRADE_COMPARE(a.type(0), ShapeGroup2D::Type::Point); + CORRADE_COMPARE(a.type(0), Composition2D::Type::Point); CORRADE_COMPARE(a.get(0).position(), Vector2::xAxis(0.5f)); VERIFY_COLLIDES(a, Physics::Sphere2D({}, 1.0f)); } -void ShapeGroupTest::hierarchy() { - const Physics::ShapeGroup3D a = Physics::Sphere3D({}, 1.0f) && +void CompositionTest::hierarchy() { + const Physics::Composition3D a = Physics::Sphere3D({}, 1.0f) && (Physics::Point3D(Vector3::xAxis(1.5f)) || !Physics::AxisAlignedBox3D({}, Vector3(0.5f))); CORRADE_COMPARE(a.size(), 3); - CORRADE_COMPARE(a.type(0), ShapeGroup3D::Type::Sphere); - CORRADE_COMPARE(a.type(1), ShapeGroup3D::Type::Point); - CORRADE_COMPARE(a.type(2), ShapeGroup3D::Type::AxisAlignedBox); + CORRADE_COMPARE(a.type(0), Composition3D::Type::Sphere); + CORRADE_COMPARE(a.type(1), Composition3D::Type::Point); + CORRADE_COMPARE(a.type(2), Composition3D::Type::AxisAlignedBox); CORRADE_COMPARE(a.get(1).position(), Vector3::xAxis(1.5f)); VERIFY_COLLIDES(a, Physics::Sphere3D(Vector3::xAxis(1.5f), 0.6f)); VERIFY_NOT_COLLIDES(a, Physics::Point3D(Vector3(0.25f))); } -void ShapeGroupTest::empty() { - const Physics::ShapeGroup2D a; +void CompositionTest::empty() { + const Physics::Composition2D a; CORRADE_COMPARE(a.size(), 0); @@ -127,4 +127,4 @@ void ShapeGroupTest::empty() { }}} -CORRADE_TEST_MAIN(Magnum::Physics::Test::ShapeGroupTest) +CORRADE_TEST_MAIN(Magnum::Physics::Test::CompositionTest) diff --git a/src/Physics/Test/ShapeImplementationTest.cpp b/src/Physics/Test/ShapeImplementationTest.cpp index 1e7e690ec..57371a19c 100644 --- a/src/Physics/Test/ShapeImplementationTest.cpp +++ b/src/Physics/Test/ShapeImplementationTest.cpp @@ -42,8 +42,8 @@ ShapeImplementationTest::ShapeImplementationTest() { void ShapeImplementationTest::debug() { std::ostringstream o; - Debug(&o) << Implementation::ShapeDimensionTraits<2>::Type::ShapeGroup; - CORRADE_COMPARE(o.str(), "Physics::Shape2D::Type::ShapeGroup\n"); + Debug(&o) << Implementation::ShapeDimensionTraits<2>::Type::Composition; + CORRADE_COMPARE(o.str(), "Physics::Shape2D::Type::Composition\n"); o.str({}); Debug(&o) << Implementation::ShapeDimensionTraits<3>::Type::Plane; diff --git a/src/Physics/Test/ObjectShapeTest.cpp b/src/Physics/Test/ShapeTest.cpp similarity index 77% rename from src/Physics/Test/ObjectShapeTest.cpp rename to src/Physics/Test/ShapeTest.cpp index a48f6ea94..369606bab 100644 --- a/src/Physics/Test/ObjectShapeTest.cpp +++ b/src/Physics/Test/ShapeTest.cpp @@ -24,10 +24,10 @@ #include -#include "Physics/ObjectShapeGroup.h" -#include "Physics/ObjectShape.h" -#include "Physics/Point.h" #include "Physics/ShapeGroup.h" +#include "Physics/Shape.h" +#include "Physics/Point.h" +#include "Physics/Composition.h" #include "Physics/Sphere.h" #include "SceneGraph/MatrixTransformation2D.h" #include "SceneGraph/MatrixTransformation3D.h" @@ -35,9 +35,9 @@ namespace Magnum { namespace Physics { namespace Test { -class ObjectShapeTest: public Corrade::TestSuite::Tester { +class ShapeTest: public Corrade::TestSuite::Tester { public: - ObjectShapeTest(); + ShapeTest(); void clean(); void firstCollision(); @@ -49,22 +49,22 @@ typedef SceneGraph::Object> Object2D; typedef SceneGraph::Scene> Scene3D; typedef SceneGraph::Object> Object3D; -ObjectShapeTest::ObjectShapeTest() { - addTests({&ObjectShapeTest::clean, - &ObjectShapeTest::firstCollision, - &ObjectShapeTest::shapeGroup}); +ShapeTest::ShapeTest() { + addTests({&ShapeTest::clean, + &ShapeTest::firstCollision, + &ShapeTest::shapeGroup}); } -void ObjectShapeTest::clean() { +void ShapeTest::clean() { Scene3D scene; - ObjectShapeGroup3D shapes; + ShapeGroup3D shapes; Object3D a(&scene); - auto shape = new Physics::ObjectShape(&a, {{1.0f, -2.0f, 3.0f}}, &shapes); + auto shape = new Physics::Shape(&a, {{1.0f, -2.0f, 3.0f}}, &shapes); a.scale(Vector3(-2.0f)); Object3D b(&scene); - new Physics::ObjectShape(&b, &shapes); + new Physics::Shape(&b, &shapes); /* Everything is dirty at the beginning */ CORRADE_VERIFY(shapes.isDirty()); @@ -95,18 +95,18 @@ void ObjectShapeTest::clean() { CORRADE_VERIFY(b.isDirty()); } -void ObjectShapeTest::firstCollision() { +void ShapeTest::firstCollision() { Scene3D scene; - ObjectShapeGroup3D shapes; + ShapeGroup3D shapes; Object3D a(&scene); - auto aShape = new ObjectShape(&a, {{1.0f, -2.0f, 3.0f}, 1.5f}, &shapes); + auto aShape = new Shape(&a, {{1.0f, -2.0f, 3.0f}, 1.5f}, &shapes); Object3D b(&scene); - auto bShape = new ObjectShape(&b, {{3.0f, -2.0f, 3.0f}}, &shapes); + auto bShape = new Shape(&b, {{3.0f, -2.0f, 3.0f}}, &shapes); Object3D c(&scene); - new ObjectShape(&c, &shapes); + new Shape(&c, &shapes); /* No collisions initially */ CORRADE_VERIFY(!shapes.firstCollision(aShape)); @@ -123,13 +123,13 @@ void ObjectShapeTest::firstCollision() { CORRADE_VERIFY(!shapes.isDirty()); } -void ObjectShapeTest::shapeGroup() { +void ShapeTest::shapeGroup() { Scene2D scene; - ObjectShapeGroup2D shapes; + ShapeGroup2D shapes; /* Verify construction */ Object2D a(&scene); - auto shape = new ObjectShape(&a, Physics::Sphere2D({}, 0.5f) || Physics::Point2D({0.25f, -1.0f})); + auto shape = new Shape(&a, Physics::Sphere2D({}, 0.5f) || Physics::Point2D({0.25f, -1.0f})); CORRADE_COMPARE(shape->transformedShape().size(), 2); /* Verify the original shape is updated */ @@ -141,4 +141,4 @@ void ObjectShapeTest::shapeGroup() { }}} -CORRADE_TEST_MAIN(Magnum::Physics::Test::ObjectShapeTest) +CORRADE_TEST_MAIN(Magnum::Physics::Test::ShapeTest) diff --git a/src/Physics/shapeImplementation.cpp b/src/Physics/shapeImplementation.cpp index 1d777a2a2..40a199ea0 100644 --- a/src/Physics/shapeImplementation.cpp +++ b/src/Physics/shapeImplementation.cpp @@ -38,7 +38,7 @@ Debug operator<<(Debug debug, ShapeDimensionTraits<2>::Type value) { _val(Capsule) _val(AxisAlignedBox) _val(Box) - _val(ShapeGroup) + _val(Composition) #undef _val } @@ -56,7 +56,7 @@ Debug operator<<(Debug debug, ShapeDimensionTraits<3>::Type value) { _val(AxisAlignedBox) _val(Box) _val(Plane) - _val(ShapeGroup) + _val(Composition) #undef _val } diff --git a/src/Physics/shapeImplementation.h b/src/Physics/shapeImplementation.h index 320649c42..dde2a6e33 100644 --- a/src/Physics/shapeImplementation.h +++ b/src/Physics/shapeImplementation.h @@ -47,7 +47,7 @@ template<> struct ShapeDimensionTraits<2> { Capsule = 7, AxisAlignedBox = 11, Box = 13, - ShapeGroup = 17 + Composition = 17 }; }; @@ -61,7 +61,7 @@ template<> struct ShapeDimensionTraits<3> { AxisAlignedBox = 11, Box = 13, Plane = 17, - ShapeGroup = 19 + Composition = 19 }; }; @@ -112,9 +112,9 @@ template<> struct TypeOf { return ShapeDimensionTraits<3>::Type::Plane; } }; -template struct TypeOf> { +template struct TypeOf> { inline constexpr static typename ShapeDimensionTraits::Type type() { - return ShapeDimensionTraits::Type::ShapeGroup; + return ShapeDimensionTraits::Type::Composition; } };