From d9bc507e00d1f73ec051d4288aae3cae953351b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 25 Apr 2013 16:58:56 +0200 Subject: [PATCH] Physics shape rework #4: new ObjectShape implementation. The feature is now templated on shape type, which makes it actually useful, as it is possible to conveniently query shape parameters from it. It has now non-templated base and ObjectShapeGroup operates only with it. --- src/Physics/AbstractObjectShape.cpp | 63 +++++++++++++ src/Physics/AbstractObjectShape.h | 119 +++++++++++++++++++++++++ src/Physics/CMakeLists.txt | 4 +- src/Physics/ObjectShape.cpp | 41 +++------ src/Physics/ObjectShape.h | 127 +++++++++++++++------------ src/Physics/ObjectShapeGroup.cpp | 10 +-- src/Physics/ObjectShapeGroup.h | 8 +- src/Physics/Physics.h | 10 +-- src/Physics/Test/ObjectShapeTest.cpp | 72 +++++++++------ 9 files changed, 324 insertions(+), 130 deletions(-) create mode 100644 src/Physics/AbstractObjectShape.cpp create mode 100644 src/Physics/AbstractObjectShape.h 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)); } }}}