diff --git a/src/Physics/AbstractObjectShape.cpp b/src/Physics/AbstractObjectShape.cpp new file mode 100644 index 000000000..e60486efe --- /dev/null +++ b/src/Physics/AbstractObjectShape.cpp @@ -0,0 +1,63 @@ +/* + 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 "AbstractObjectShape.h" + +#include + +#include "Physics/ObjectShapeGroup.h" +#include "Physics/Implementation/CollisionDispatch.h" + +namespace Magnum { namespace Physics { + +template AbstractObjectShape::AbstractObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group): SceneGraph::AbstractGroupedFeature>(object, group) { + this->setCachedTransformations(SceneGraph::AbstractFeature::CachedTransformation::Absolute); +} + +template ObjectShapeGroup* AbstractObjectShape::group() { + return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); +} + +template const ObjectShapeGroup* AbstractObjectShape::group() const { + return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); +} + +template auto AbstractObjectShape::type() const -> Type { + return abstractTransformedShape()->type(); +} + +template bool AbstractObjectShape::collides(const AbstractObjectShape* other) const { + return Implementation::collides(abstractTransformedShape(), other->abstractTransformedShape()); +} + +template void AbstractObjectShape::markDirty() { + group()->setDirty(); +} + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_PHYSICS_EXPORT AbstractObjectShape<2>; +template class MAGNUM_PHYSICS_EXPORT AbstractObjectShape<3>; +#endif + +}} diff --git a/src/Physics/AbstractObjectShape.h b/src/Physics/AbstractObjectShape.h new file mode 100644 index 000000000..90b5baf6e --- /dev/null +++ b/src/Physics/AbstractObjectShape.h @@ -0,0 +1,119 @@ +#ifndef Magnum_Physics_AbstractObjectShape_h +#define Magnum_Physics_AbstractObjectShape_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::AbstractObjectShape, typedef Magnum::Physics::AbstractObjectShape2D, Magnum::Physics::AbstractObjectShape3D + */ + +#include "Magnum.h" +#include "DimensionTraits.h" +#include "Physics/magnumPhysicsVisibility.h" +#include "Physics/shapeImplementation.h" +#include "SceneGraph/AbstractGroupedFeature.h" + +namespace Magnum { namespace Physics { + +namespace Implementation { + template inline const AbstractShape* getAbstractShape(const AbstractObjectShape* objectShape) { + return objectShape->abstractTransformedShape(); + } +} + +/** +@brief Base class for object shapes + +This class is not directly instantiable, see ObjectShape instead. +@see AbstractObjectShape2D, AbstractObjectShape3D +*/ +template class MAGNUM_PHYSICS_EXPORT AbstractObjectShape: public SceneGraph::AbstractGroupedFeature> { + friend const Implementation::AbstractShape* Implementation::getAbstractShape<>(const AbstractObjectShape* objectShape); + + 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 */ + ShapeGroup, /**< @ref ShapeGroup "Shape group" */ + Plane /**< Plane (3D only) */ + }; + #else + typedef typename Implementation::ShapeDimensionTraits::Type Type; + #endif + + /** + * @brief Constructor + * @param object Object holding this feature + * @param group Group this shape belongs to + */ + explicit AbstractObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group = nullptr); + + /** + * @brief Object shape group containing this shape + * + * If the shape doesn't belong to any group, returns `nullptr`. + */ + ObjectShapeGroup* group(); + const ObjectShapeGroup* group() const; /**< @overload */ + + /** + * @brief Shape type + */ + Type type() const; + + /** + * @brief Detect collision with other shape + * + * Default implementation returns false. + */ + bool collides(const AbstractObjectShape* other) const; + + protected: + /** Marks also the group as dirty */ + void markDirty() override; + + private: + virtual const Implementation::AbstractShape MAGNUM_PHYSICS_LOCAL * abstractTransformedShape() const = 0; +}; + +/** @brief Base class for two-dimensional object shapes */ +typedef AbstractObjectShape<2> AbstractObjectShape2D; + +/** @brief Base class for three-dimensional object shapes */ +typedef AbstractObjectShape<3> AbstractObjectShape3D; + +}} + +#endif diff --git a/src/Physics/CMakeLists.txt b/src/Physics/CMakeLists.txt index c36e10df6..c12fe8a1a 100644 --- a/src/Physics/CMakeLists.txt +++ b/src/Physics/CMakeLists.txt @@ -23,7 +23,7 @@ # set(MagnumPhysics_SRCS - AbstractShape.cpp + AbstractObjectShape.cpp AxisAlignedBox.cpp Box.cpp Capsule.cpp @@ -40,7 +40,7 @@ set(MagnumPhysics_SRCS Implementation/CollisionDispatch.cpp) set(MagnumPhysics_HEADERS - AbstractShape.h + AbstractObjectShape.h AxisAlignedBox.h Box.h Capsule.h diff --git a/src/Physics/ObjectShape.cpp b/src/Physics/ObjectShape.cpp index a5eb93791..c8925842c 100644 --- a/src/Physics/ObjectShape.cpp +++ b/src/Physics/ObjectShape.cpp @@ -24,40 +24,25 @@ #include "ObjectShape.h" -#include +#include "Physics/ShapeGroup.h" -#include "AbstractShape.h" -#include "ObjectShapeGroup.h" +namespace Magnum { namespace Physics { namespace Implementation { -namespace Magnum { namespace Physics { - -template ObjectShape::ObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group): SceneGraph::AbstractGroupedFeature>(object, group), _shape(nullptr) { - this->setCachedTransformations(SceneGraph::AbstractFeature::CachedTransformation::Absolute); -} - -template ObjectShape::~ObjectShape() { - delete _shape; -} - -template ObjectShapeGroup* ObjectShape::group() { - return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); -} - -template const ObjectShapeGroup* ObjectShape::group() const { - return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); +template void ObjectShapeHelper>::set(ObjectShape>& objectShape, const ShapeGroup& shape) { + objectShape._transformedShape.shape = objectShape._shape.shape = shape; } -template void ObjectShape::markDirty() { - group()->setDirty(); +template void ObjectShapeHelper>::set(ObjectShape>& objectShape, ShapeGroup&& shape) { + objectShape._transformedShape.shape = objectShape._shape.shape = std::move(shape); } -template void ObjectShape::clean(const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { - if(_shape) _shape->applyTransformationMatrix(absoluteTransformationMatrix); +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]); } -#ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_PHYSICS_EXPORT ObjectShape<2>; -template class MAGNUM_PHYSICS_EXPORT ObjectShape<3>; -#endif +template struct MAGNUM_PHYSICS_EXPORT ObjectShapeHelper>; +template struct MAGNUM_PHYSICS_EXPORT ObjectShapeHelper>; -}} +}}} diff --git a/src/Physics/ObjectShape.h b/src/Physics/ObjectShape.h index b940c23e1..f421e7d42 100644 --- a/src/Physics/ObjectShape.h +++ b/src/Physics/ObjectShape.h @@ -25,16 +25,20 @@ */ /** @file - * @brief Class Magnum::Physics::ObjectShape, typedef Magnum::Physics::ObjectShape2D, Magnum::Physics::ObjectShape3D + * @brief Class Magnum::Physics::ObjectShape */ -#include "SceneGraph/AbstractGroupedFeature.h" +#include "Physics/AbstractObjectShape.h" #include "Physics/Physics.h" #include "magnumPhysicsVisibility.h" namespace Magnum { namespace Physics { +namespace Implementation { + template struct ObjectShapeHelper; +} + /** @brief Object shape @@ -45,95 +49,110 @@ collide with each other. @section ObjectShape-usage Usage Add the feature to the object and some shape group (you can also use -ObjectShapeGroup::add() and ObjectShapeGroup::remove() later) and then set -desired object shape using setShape(). +ObjectShapeGroup::add() and ObjectShapeGroup::remove() later) and configure the +shape. @code Physics::ObjectShapeGroup3D shapes; Object3D* object; -auto shape = new Physics::ObjectShape3D(object, &shapes); -shape->setShape(Physics::Sphere3D({}, 0.75f) || Physics::AxisAlignedBox3D({}, {3.0f, 1.5f, 2.0f})); +auto shape = new Physics::ObjectShape(object, {{}, 0.75f}, &shapes); @endcode -@see @ref scenegraph, ObjectShape2D, ObjectShape3D, ObjectShapeGroup2D, - ObjectShapeGroup3D, DebugTools::ShapeRenderer +@see @ref scenegraph, ObjectShapeGroup2D, ObjectShapeGroup3D, + DebugTools::ShapeRenderer */ -template class MAGNUM_PHYSICS_EXPORT ObjectShape: public SceneGraph::AbstractGroupedFeature> { +template class MAGNUM_PHYSICS_EXPORT ObjectShape: public AbstractObjectShape { + friend struct Implementation::ObjectShapeHelper; + public: /** * @brief Constructor * @param object Object holding this feature + * @param shape Shape * @param group Group this shape belongs to - * - * Creates empty object shape. - * @see setShape() */ - explicit ObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group = nullptr); + template explicit ObjectShape(SceneGraph::AbstractObject* object, const T& shape, ObjectShapeGroup* group = nullptr): AbstractObjectShape(object, group) { + Implementation::ObjectShapeHelper::set(*this, shape); + } - /** - * @brief Destructor - * - * Deletes associated shape. - */ - ~ObjectShape(); + /** @overload */ + template explicit ObjectShape(SceneGraph::AbstractObject* object, T&& shape, ObjectShapeGroup* group = nullptr): AbstractObjectShape(object, group) { + Implementation::ObjectShapeHelper::set(*this, std::move(shape)); + } - /** @brief Shape */ - inline AbstractShape* shape() { return _shape; } - inline const AbstractShape* shape() const { return _shape; } /**< @overload */ + /** @overload */ + template explicit ObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group = nullptr): AbstractObjectShape(object, group) {} - /** - * @brief Set shape - * @return Pointer to self (for method chaining) - */ - inline ObjectShape* setShape(AbstractShape* shape) { - _shape = shape; - this->object()->setDirty(); - return this; - } + /** @brief Shape */ + inline const T& shape() const { return _shape.shape; } /** * @brief Set shape * @return Pointer to self (for method chaining) * - * Convenience overload for setShape(AbstractShape*), allowing you to - * use e.g. ShapeGroup operators: - * @code - * Physics::ObjectShape3D* shape; - * shape->setShape(Physics::Sphere3D({}, 0.75f) || Physics::AxisAlignedBox3D({}, {3.0f, 1.5f, 2.0f})); - * @endcode + * Marks the feature as dirty. */ - #ifdef DOXYGEN_GENERATING_OUTPUT - template inline ObjectShape* setShape(T&& shape) { - #else - template inline typename std::enable_if, T>::value, ObjectShape*>::type setShape(T&& shape) { - #endif - return setShape(new T(std::move(shape))); - } + ObjectShape* setShape(const T& shape); /** - * @brief Object shape group containing this shape + * @brief Transformed shape * - * If the shape doesn't belong to any group, returns `nullptr`. + * Cleans the feature before returning the shape. */ - ObjectShapeGroup* group(); - const ObjectShapeGroup* group() const; /**< @overload */ + const T& transformedShape(); protected: /** Marks also the group as dirty */ void markDirty() override; /** Applies transformation to associated shape. */ - void clean(const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) override; + void clean(const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) override; private: - AbstractShape* _shape; + const Implementation::AbstractShape* abstractTransformedShape() const override { + return &_transformedShape; + } + + Implementation::Shape _shape, _transformedShape; }; -/** @brief Two-dimensional object shape */ -typedef ObjectShape<2> ObjectShape2D; +template inline ObjectShape* ObjectShape::setShape(const T& shape) { + Implementation::ObjectShapeHelper::set(*this, shape); + this->object()->setDirty(); + return this; +} + +template inline const T& ObjectShape::transformedShape() { + this->object()->setClean(); + return _transformedShape.shape; +} + +template void ObjectShape::markDirty() { + if(this->group()) this->group()->setDirty(); +} + +template void ObjectShape::clean(const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { + Implementation::ObjectShapeHelper::transform(*this, absoluteTransformationMatrix); +} + +namespace Implementation { + template struct ObjectShapeHelper { + inline static void set(ObjectShape& objectShape, const T& shape) { + objectShape._shape.shape = shape; + } + + inline static void transform(ObjectShape& objectShape, const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { + objectShape._transformedShape.shape = objectShape._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); -/** @brief Three-dimensional object shape */ -typedef ObjectShape<3> ObjectShape3D; + static void transform(ObjectShape>& objectShape, const typename DimensionTraits::MatrixType& absoluteTransformationMatrix); + }; +} }} diff --git a/src/Physics/ObjectShapeGroup.cpp b/src/Physics/ObjectShapeGroup.cpp index 994f71a02..b9e842cd3 100644 --- a/src/Physics/ObjectShapeGroup.cpp +++ b/src/Physics/ObjectShapeGroup.cpp @@ -24,8 +24,7 @@ #include "ObjectShapeGroup.h" -#include "Physics/AbstractShape.h" -#include "Physics/ObjectShape.h" +#include "Physics/AbstractObjectShape.h" namespace Magnum { namespace Physics { @@ -42,13 +41,10 @@ template void ObjectShapeGroup::setClean() { dirty = false; } -template ObjectShape* ObjectShapeGroup::firstCollision(const ObjectShape* shape) { - /* Nothing to test with, done */ - if(!shape->shape()) return nullptr; - +template AbstractObjectShape* ObjectShapeGroup::firstCollision(const AbstractObjectShape* shape) { setClean(); for(std::size_t i = 0; i != this->size(); ++i) - if((*this)[i] != shape && (*this)[i]->shape() && (*this)[i]->shape()->collides(shape->shape())) + if((*this)[i] != shape && (*this)[i]->collides(shape)) return (*this)[i]; return nullptr; diff --git a/src/Physics/ObjectShapeGroup.h b/src/Physics/ObjectShapeGroup.h index 9d674b0be..0c7c35a31 100644 --- a/src/Physics/ObjectShapeGroup.h +++ b/src/Physics/ObjectShapeGroup.h @@ -30,7 +30,7 @@ #include -#include "Physics/ObjectShape.h" +#include "Physics/Physics.h" #include "SceneGraph/FeatureGroup.h" #include "magnumPhysicsVisibility.h" @@ -43,8 +43,8 @@ namespace Magnum { namespace Physics { See ObjectShape for more information. @see @ref scenegraph, ObjectShapeGroup2D, ObjectShapeGroup3D */ -template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: public SceneGraph::FeatureGroup> { - friend class ObjectShape; +template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: public SceneGraph::FeatureGroup> { + friend class AbstractObjectShape; public: /** @@ -86,7 +86,7 @@ template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: p * collisions, returns `nullptr`. Calls setClean() before the * operation. */ - ObjectShape* firstCollision(const ObjectShape* shape); + AbstractObjectShape* firstCollision(const AbstractObjectShape* shape); private: bool dirty; diff --git a/src/Physics/Physics.h b/src/Physics/Physics.h index d0a297bc5..7396273db 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 AbstractShape; -typedef AbstractShape<2> AbstractShape2D; -typedef AbstractShape<3> AbstractShape3D; +template class AbstractObjectShape; +typedef AbstractObjectShape<2> AbstractObjectShape2D; +typedef AbstractObjectShape<3> AbstractObjectShape3D; template class AxisAlignedBox; typedef AxisAlignedBox<2> AxisAlignedBox2D; @@ -58,9 +58,7 @@ template class LineSegment; typedef LineSegment<2> LineSegment2D; typedef LineSegment<3> LineSegment3D; -template class ObjectShape; -typedef ObjectShape<2> ObjectShape2D; -typedef ObjectShape<3> ObjectShape3D; +template class ObjectShape; template class ObjectShapeGroup; typedef ObjectShapeGroup<2> ObjectShapeGroup2D; diff --git a/src/Physics/Test/ObjectShapeTest.cpp b/src/Physics/Test/ObjectShapeTest.cpp index 056c680f1..a48f6ea94 100644 --- a/src/Physics/Test/ObjectShapeTest.cpp +++ b/src/Physics/Test/ObjectShapeTest.cpp @@ -27,7 +27,9 @@ #include "Physics/ObjectShapeGroup.h" #include "Physics/ObjectShape.h" #include "Physics/Point.h" +#include "Physics/ShapeGroup.h" #include "Physics/Sphere.h" +#include "SceneGraph/MatrixTransformation2D.h" #include "SceneGraph/MatrixTransformation3D.h" #include "SceneGraph/Scene.h" @@ -39,90 +41,102 @@ class ObjectShapeTest: public Corrade::TestSuite::Tester { void clean(); void firstCollision(); + void shapeGroup(); }; +typedef SceneGraph::Scene> Scene2D; +typedef SceneGraph::Object> Object2D; typedef SceneGraph::Scene> Scene3D; typedef SceneGraph::Object> Object3D; ObjectShapeTest::ObjectShapeTest() { addTests({&ObjectShapeTest::clean, - &ObjectShapeTest::firstCollision}); + &ObjectShapeTest::firstCollision, + &ObjectShapeTest::shapeGroup}); } void ObjectShapeTest::clean() { Scene3D scene; - ObjectShapeGroup3D group; + ObjectShapeGroup3D shapes; Object3D a(&scene); - ObjectShape3D* shape = new ObjectShape3D(&a, &group); - shape->setShape(Physics::Point3D({1.0f, -2.0f, 3.0f})); + auto shape = new Physics::ObjectShape(&a, {{1.0f, -2.0f, 3.0f}}, &shapes); a.scale(Vector3(-2.0f)); Object3D b(&scene); - new ObjectShape3D(&b, &group); + new Physics::ObjectShape(&b, &shapes); /* Everything is dirty at the beginning */ - CORRADE_VERIFY(group.isDirty()); + CORRADE_VERIFY(shapes.isDirty()); CORRADE_VERIFY(a.isDirty()); CORRADE_VERIFY(b.isDirty()); /* Cleaning object will not clean anything other */ a.setClean(); - CORRADE_VERIFY(group.isDirty()); + CORRADE_VERIFY(shapes.isDirty()); CORRADE_VERIFY(!a.isDirty()); CORRADE_VERIFY(b.isDirty()); /* Verify that the feature was actually cleaned */ - CORRADE_COMPARE(static_cast(shape->shape())->transformedPosition(), + CORRADE_COMPARE(shape->transformedShape().position(), Vector3(-2.0f, 4.0f, -6.0f)); /* Setting group clean will clean whole group */ a.setDirty(); - group.setClean(); - CORRADE_VERIFY(!group.isDirty()); + shapes.setClean(); + CORRADE_VERIFY(!shapes.isDirty()); CORRADE_VERIFY(!a.isDirty()); CORRADE_VERIFY(!b.isDirty()); /* Setting object dirty will set also the group, but not other objects */ b.setDirty(); - CORRADE_VERIFY(group.isDirty()); + CORRADE_VERIFY(shapes.isDirty()); CORRADE_VERIFY(!a.isDirty()); CORRADE_VERIFY(b.isDirty()); } void ObjectShapeTest::firstCollision() { Scene3D scene; - ObjectShapeGroup3D group; + ObjectShapeGroup3D shapes; Object3D a(&scene); - ObjectShape3D* aShape = new ObjectShape3D(&a, &group); - aShape->setShape(Physics::Sphere3D({1.0f, -2.0f, 3.0f}, 1.5f)); + auto aShape = new ObjectShape(&a, {{1.0f, -2.0f, 3.0f}, 1.5f}, &shapes); Object3D b(&scene); - ObjectShape3D* bShape = new ObjectShape3D(&b, &group); - bShape->setShape(Physics::Point3D({3.0f, -2.0f, 3.0f})); + auto bShape = new ObjectShape(&b, {{3.0f, -2.0f, 3.0f}}, &shapes); Object3D c(&scene); - ObjectShape3D* cShape = new ObjectShape3D(&c, &group); - - /* No-op if the object has no shape */ - CORRADE_VERIFY(group.isDirty()); - CORRADE_VERIFY(!group.firstCollision(cShape)); - CORRADE_VERIFY(group.isDirty()); + new ObjectShape(&c, &shapes); /* No collisions initially */ - CORRADE_VERIFY(!group.firstCollision(aShape)); - CORRADE_VERIFY(!group.firstCollision(bShape)); - CORRADE_VERIFY(!group.isDirty()); + CORRADE_VERIFY(!shapes.firstCollision(aShape)); + CORRADE_VERIFY(!shapes.firstCollision(bShape)); + CORRADE_VERIFY(!shapes.isDirty()); /* Move point into sphere */ b.translate(Vector3::xAxis(-1.0f)); /* Collision */ - CORRADE_VERIFY(group.isDirty()); - CORRADE_VERIFY(group.firstCollision(aShape) == bShape); - CORRADE_VERIFY(group.firstCollision(bShape) == aShape); - CORRADE_VERIFY(!group.isDirty()); + CORRADE_VERIFY(shapes.isDirty()); + CORRADE_VERIFY(shapes.firstCollision(aShape) == bShape); + CORRADE_VERIFY(shapes.firstCollision(bShape) == aShape); + CORRADE_VERIFY(!shapes.isDirty()); +} + +void ObjectShapeTest::shapeGroup() { + Scene2D scene; + ObjectShapeGroup2D shapes; + + /* Verify construction */ + Object2D a(&scene); + auto shape = new ObjectShape(&a, Physics::Sphere2D({}, 0.5f) || Physics::Point2D({0.25f, -1.0f})); + CORRADE_COMPARE(shape->transformedShape().size(), 2); + + /* Verify the original shape is updated */ + const auto& point = shape->transformedShape().get(1); + a.translate(Vector2::xAxis(5.0f)); + a.setClean(); + CORRADE_COMPARE(point.position(), Vector2(5.25f, -1.0f)); } }}}