Browse Source

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.
pull/278/head
Vladimír Vondruš 13 years ago
parent
commit
d9bc507e00
  1. 63
      src/Physics/AbstractObjectShape.cpp
  2. 119
      src/Physics/AbstractObjectShape.h
  3. 4
      src/Physics/CMakeLists.txt
  4. 41
      src/Physics/ObjectShape.cpp
  5. 127
      src/Physics/ObjectShape.h
  6. 10
      src/Physics/ObjectShapeGroup.cpp
  7. 8
      src/Physics/ObjectShapeGroup.h
  8. 10
      src/Physics/Physics.h
  9. 72
      src/Physics/Test/ObjectShapeTest.cpp

63
src/Physics/AbstractObjectShape.cpp

@ -0,0 +1,63 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>
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 <Utility/Debug.h>
#include "Physics/ObjectShapeGroup.h"
#include "Physics/Implementation/CollisionDispatch.h"
namespace Magnum { namespace Physics {
template<UnsignedInt dimensions> AbstractObjectShape<dimensions>::AbstractObjectShape(SceneGraph::AbstractObject<dimensions>* object, ObjectShapeGroup<dimensions>* group): SceneGraph::AbstractGroupedFeature<dimensions, AbstractObjectShape<dimensions>>(object, group) {
this->setCachedTransformations(SceneGraph::AbstractFeature<dimensions>::CachedTransformation::Absolute);
}
template<UnsignedInt dimensions> ObjectShapeGroup<dimensions>* AbstractObjectShape<dimensions>::group() {
return static_cast<ObjectShapeGroup<dimensions>*>(SceneGraph::AbstractGroupedFeature<dimensions, AbstractObjectShape<dimensions>>::group());
}
template<UnsignedInt dimensions> const ObjectShapeGroup<dimensions>* AbstractObjectShape<dimensions>::group() const {
return static_cast<const ObjectShapeGroup<dimensions>*>(SceneGraph::AbstractGroupedFeature<dimensions, AbstractObjectShape<dimensions>>::group());
}
template<UnsignedInt dimensions> auto AbstractObjectShape<dimensions>::type() const -> Type {
return abstractTransformedShape()->type();
}
template<UnsignedInt dimensions> bool AbstractObjectShape<dimensions>::collides(const AbstractObjectShape<dimensions>* other) const {
return Implementation::collides(abstractTransformedShape(), other->abstractTransformedShape());
}
template<UnsignedInt dimensions> void AbstractObjectShape<dimensions>::markDirty() {
group()->setDirty();
}
#ifndef DOXYGEN_GENERATING_OUTPUT
template class MAGNUM_PHYSICS_EXPORT AbstractObjectShape<2>;
template class MAGNUM_PHYSICS_EXPORT AbstractObjectShape<3>;
#endif
}}

119
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š <mosra@centrum.cz>
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<UnsignedInt dimensions> inline const AbstractShape<dimensions>* getAbstractShape(const AbstractObjectShape<dimensions>* objectShape) {
return objectShape->abstractTransformedShape();
}
}
/**
@brief Base class for object shapes
This class is not directly instantiable, see ObjectShape instead.
@see AbstractObjectShape2D, AbstractObjectShape3D
*/
template<UnsignedInt dimensions> class MAGNUM_PHYSICS_EXPORT AbstractObjectShape: public SceneGraph::AbstractGroupedFeature<dimensions, AbstractObjectShape<dimensions>> {
friend const Implementation::AbstractShape<dimensions>* Implementation::getAbstractShape<>(const AbstractObjectShape<dimensions>* 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<dimensions>::Type Type;
#endif
/**
* @brief Constructor
* @param object Object holding this feature
* @param group Group this shape belongs to
*/
explicit AbstractObjectShape(SceneGraph::AbstractObject<dimensions>* object, ObjectShapeGroup<dimensions>* group = nullptr);
/**
* @brief Object shape group containing this shape
*
* If the shape doesn't belong to any group, returns `nullptr`.
*/
ObjectShapeGroup<dimensions>* group();
const ObjectShapeGroup<dimensions>* group() const; /**< @overload */
/**
* @brief Shape type
*/
Type type() const;
/**
* @brief Detect collision with other shape
*
* Default implementation returns false.
*/
bool collides(const AbstractObjectShape<dimensions>* other) const;
protected:
/** Marks also the group as dirty */
void markDirty() override;
private:
virtual const Implementation::AbstractShape<dimensions> 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

4
src/Physics/CMakeLists.txt

@ -23,7 +23,7 @@
# #
set(MagnumPhysics_SRCS set(MagnumPhysics_SRCS
AbstractShape.cpp AbstractObjectShape.cpp
AxisAlignedBox.cpp AxisAlignedBox.cpp
Box.cpp Box.cpp
Capsule.cpp Capsule.cpp
@ -40,7 +40,7 @@ set(MagnumPhysics_SRCS
Implementation/CollisionDispatch.cpp) Implementation/CollisionDispatch.cpp)
set(MagnumPhysics_HEADERS set(MagnumPhysics_HEADERS
AbstractShape.h AbstractObjectShape.h
AxisAlignedBox.h AxisAlignedBox.h
Box.h Box.h
Capsule.h Capsule.h

41
src/Physics/ObjectShape.cpp

@ -24,40 +24,25 @@
#include "ObjectShape.h" #include "ObjectShape.h"
#include <algorithm> #include "Physics/ShapeGroup.h"
#include "AbstractShape.h" namespace Magnum { namespace Physics { namespace Implementation {
#include "ObjectShapeGroup.h"
namespace Magnum { namespace Physics { template<UnsignedInt dimensions> void ObjectShapeHelper<ShapeGroup<dimensions>>::set(ObjectShape<ShapeGroup<dimensions>>& objectShape, const ShapeGroup<dimensions>& shape) {
objectShape._transformedShape.shape = objectShape._shape.shape = shape;
template<UnsignedInt dimensions> ObjectShape<dimensions>::ObjectShape(SceneGraph::AbstractObject<dimensions>* object, ObjectShapeGroup<dimensions>* group): SceneGraph::AbstractGroupedFeature<dimensions, ObjectShape<dimensions>>(object, group), _shape(nullptr) {
this->setCachedTransformations(SceneGraph::AbstractFeature<dimensions>::CachedTransformation::Absolute);
}
template<UnsignedInt dimensions> ObjectShape<dimensions>::~ObjectShape() {
delete _shape;
}
template<UnsignedInt dimensions> ObjectShapeGroup<dimensions>* ObjectShape<dimensions>::group() {
return static_cast<ObjectShapeGroup<dimensions>*>(SceneGraph::AbstractGroupedFeature<dimensions, ObjectShape<dimensions>>::group());
}
template<UnsignedInt dimensions> const ObjectShapeGroup<dimensions>* ObjectShape<dimensions>::group() const {
return static_cast<const ObjectShapeGroup<dimensions>*>(SceneGraph::AbstractGroupedFeature<dimensions, ObjectShape<dimensions>>::group());
} }
template<UnsignedInt dimensions> void ObjectShape<dimensions>::markDirty() { template<UnsignedInt dimensions> void ObjectShapeHelper<ShapeGroup<dimensions>>::set(ObjectShape<ShapeGroup<dimensions>>& objectShape, ShapeGroup<dimensions>&& shape) {
group()->setDirty(); objectShape._transformedShape.shape = objectShape._shape.shape = std::move(shape);
} }
template<UnsignedInt dimensions> void ObjectShape<dimensions>::clean(const typename DimensionTraits<dimensions>::MatrixType& absoluteTransformationMatrix) { template<UnsignedInt dimensions> void ObjectShapeHelper<ShapeGroup<dimensions>>::transform(ObjectShape<ShapeGroup<dimensions>>& objectShape, const typename DimensionTraits<dimensions>::MatrixType& absoluteTransformationMatrix) {
if(_shape) _shape->applyTransformationMatrix(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 struct MAGNUM_PHYSICS_EXPORT ObjectShapeHelper<ShapeGroup<2>>;
template class MAGNUM_PHYSICS_EXPORT ObjectShape<2>; template struct MAGNUM_PHYSICS_EXPORT ObjectShapeHelper<ShapeGroup<3>>;
template class MAGNUM_PHYSICS_EXPORT ObjectShape<3>;
#endif
}} }}}

127
src/Physics/ObjectShape.h

@ -25,16 +25,20 @@
*/ */
/** @file /** @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 "Physics/Physics.h"
#include "magnumPhysicsVisibility.h" #include "magnumPhysicsVisibility.h"
namespace Magnum { namespace Physics { namespace Magnum { namespace Physics {
namespace Implementation {
template<class> struct ObjectShapeHelper;
}
/** /**
@brief Object shape @brief Object shape
@ -45,95 +49,110 @@ collide with each other.
@section ObjectShape-usage Usage @section ObjectShape-usage Usage
Add the feature to the object and some shape group (you can also use Add the feature to the object and some shape group (you can also use
ObjectShapeGroup::add() and ObjectShapeGroup::remove() later) and then set ObjectShapeGroup::add() and ObjectShapeGroup::remove() later) and configure the
desired object shape using setShape(). shape.
@code @code
Physics::ObjectShapeGroup3D shapes; Physics::ObjectShapeGroup3D shapes;
Object3D* object; Object3D* object;
auto shape = new Physics::ObjectShape3D(object, &shapes); auto shape = new Physics::ObjectShape<Physics::Sphere3D>(object, {{}, 0.75f}, &shapes);
shape->setShape(Physics::Sphere3D({}, 0.75f) || Physics::AxisAlignedBox3D({}, {3.0f, 1.5f, 2.0f}));
@endcode @endcode
@see @ref scenegraph, ObjectShape2D, ObjectShape3D, ObjectShapeGroup2D, @see @ref scenegraph, ObjectShapeGroup2D, ObjectShapeGroup3D,
ObjectShapeGroup3D, DebugTools::ShapeRenderer DebugTools::ShapeRenderer
*/ */
template<UnsignedInt dimensions> class MAGNUM_PHYSICS_EXPORT ObjectShape: public SceneGraph::AbstractGroupedFeature<dimensions, ObjectShape<dimensions>> { template<class T> class MAGNUM_PHYSICS_EXPORT ObjectShape: public AbstractObjectShape<T::Dimensions> {
friend struct Implementation::ObjectShapeHelper<T>;
public: public:
/** /**
* @brief Constructor * @brief Constructor
* @param object Object holding this feature * @param object Object holding this feature
* @param shape Shape
* @param group Group this shape belongs to * @param group Group this shape belongs to
*
* Creates empty object shape.
* @see setShape()
*/ */
explicit ObjectShape(SceneGraph::AbstractObject<dimensions>* object, ObjectShapeGroup<dimensions>* group = nullptr); template<class ...U> explicit ObjectShape(SceneGraph::AbstractObject<T::Dimensions>* object, const T& shape, ObjectShapeGroup<T::Dimensions>* group = nullptr): AbstractObjectShape<T::Dimensions>(object, group) {
Implementation::ObjectShapeHelper<T>::set(*this, shape);
}
/** /** @overload */
* @brief Destructor template<class ...U> explicit ObjectShape(SceneGraph::AbstractObject<T::Dimensions>* object, T&& shape, ObjectShapeGroup<T::Dimensions>* group = nullptr): AbstractObjectShape<T::Dimensions>(object, group) {
* Implementation::ObjectShapeHelper<T>::set(*this, std::move(shape));
* Deletes associated shape. }
*/
~ObjectShape();
/** @brief Shape */ /** @overload */
inline AbstractShape<dimensions>* shape() { return _shape; } template<class ...U> explicit ObjectShape(SceneGraph::AbstractObject<T::Dimensions>* object, ObjectShapeGroup<T::Dimensions>* group = nullptr): AbstractObjectShape<T::Dimensions>(object, group) {}
inline const AbstractShape<dimensions>* shape() const { return _shape; } /**< @overload */
/** /** @brief Shape */
* @brief Set shape inline const T& shape() const { return _shape.shape; }
* @return Pointer to self (for method chaining)
*/
inline ObjectShape<dimensions>* setShape(AbstractShape<dimensions>* shape) {
_shape = shape;
this->object()->setDirty();
return this;
}
/** /**
* @brief Set shape * @brief Set shape
* @return Pointer to self (for method chaining) * @return Pointer to self (for method chaining)
* *
* Convenience overload for setShape(AbstractShape*), allowing you to * Marks the feature as dirty.
* use e.g. ShapeGroup operators:
* @code
* Physics::ObjectShape3D* shape;
* shape->setShape(Physics::Sphere3D({}, 0.75f) || Physics::AxisAlignedBox3D({}, {3.0f, 1.5f, 2.0f}));
* @endcode
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT ObjectShape<T>* setShape(const T& shape);
template<class T> inline ObjectShape<dimensions>* setShape(T&& shape) {
#else
template<class T> inline typename std::enable_if<std::is_base_of<Physics::AbstractShape<dimensions>, T>::value, ObjectShape<dimensions>*>::type setShape(T&& shape) {
#endif
return setShape(new T(std::move(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<dimensions>* group(); const T& transformedShape();
const ObjectShapeGroup<dimensions>* group() const; /**< @overload */
protected: protected:
/** Marks also the group as dirty */ /** Marks also the group as dirty */
void markDirty() override; void markDirty() override;
/** Applies transformation to associated shape. */ /** Applies transformation to associated shape. */
void clean(const typename DimensionTraits<dimensions>::MatrixType& absoluteTransformationMatrix) override; void clean(const typename DimensionTraits<T::Dimensions>::MatrixType& absoluteTransformationMatrix) override;
private: private:
AbstractShape<dimensions>* _shape; const Implementation::AbstractShape<T::Dimensions>* abstractTransformedShape() const override {
return &_transformedShape;
}
Implementation::Shape<T> _shape, _transformedShape;
}; };
/** @brief Two-dimensional object shape */ template<class T> inline ObjectShape<T>* ObjectShape<T>::setShape(const T& shape) {
typedef ObjectShape<2> ObjectShape2D; Implementation::ObjectShapeHelper<T>::set(*this, shape);
this->object()->setDirty();
return this;
}
template<class T> inline const T& ObjectShape<T>::transformedShape() {
this->object()->setClean();
return _transformedShape.shape;
}
template<class T> void ObjectShape<T>::markDirty() {
if(this->group()) this->group()->setDirty();
}
template<class T> void ObjectShape<T>::clean(const typename DimensionTraits<T::Dimensions>::MatrixType& absoluteTransformationMatrix) {
Implementation::ObjectShapeHelper<T>::transform(*this, absoluteTransformationMatrix);
}
namespace Implementation {
template<class T> struct ObjectShapeHelper {
inline static void set(ObjectShape<T>& objectShape, const T& shape) {
objectShape._shape.shape = shape;
}
inline static void transform(ObjectShape<T>& objectShape, const typename DimensionTraits<T::Dimensions>::MatrixType& absoluteTransformationMatrix) {
objectShape._transformedShape.shape = objectShape._shape.shape.transformed(absoluteTransformationMatrix);
}
};
template<UnsignedInt dimensions> struct MAGNUM_PHYSICS_EXPORT ObjectShapeHelper<ShapeGroup<dimensions>> {
static void set(ObjectShape<ShapeGroup<dimensions>>& objectShape, const ShapeGroup<dimensions>& shape);
static void set(ObjectShape<ShapeGroup<dimensions>>& objectShape, ShapeGroup<dimensions>&& shape);
/** @brief Three-dimensional object shape */ static void transform(ObjectShape<ShapeGroup<dimensions>>& objectShape, const typename DimensionTraits<dimensions>::MatrixType& absoluteTransformationMatrix);
typedef ObjectShape<3> ObjectShape3D; };
}
}} }}

10
src/Physics/ObjectShapeGroup.cpp

@ -24,8 +24,7 @@
#include "ObjectShapeGroup.h" #include "ObjectShapeGroup.h"
#include "Physics/AbstractShape.h" #include "Physics/AbstractObjectShape.h"
#include "Physics/ObjectShape.h"
namespace Magnum { namespace Physics { namespace Magnum { namespace Physics {
@ -42,13 +41,10 @@ template<UnsignedInt dimensions> void ObjectShapeGroup<dimensions>::setClean() {
dirty = false; dirty = false;
} }
template<UnsignedInt dimensions> ObjectShape<dimensions>* ObjectShapeGroup<dimensions>::firstCollision(const ObjectShape<dimensions>* shape) { template<UnsignedInt dimensions> AbstractObjectShape<dimensions>* ObjectShapeGroup<dimensions>::firstCollision(const AbstractObjectShape<dimensions>* shape) {
/* Nothing to test with, done */
if(!shape->shape()) return nullptr;
setClean(); setClean();
for(std::size_t i = 0; i != this->size(); ++i) 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 (*this)[i];
return nullptr; return nullptr;

8
src/Physics/ObjectShapeGroup.h

@ -30,7 +30,7 @@
#include <vector> #include <vector>
#include "Physics/ObjectShape.h" #include "Physics/Physics.h"
#include "SceneGraph/FeatureGroup.h" #include "SceneGraph/FeatureGroup.h"
#include "magnumPhysicsVisibility.h" #include "magnumPhysicsVisibility.h"
@ -43,8 +43,8 @@ namespace Magnum { namespace Physics {
See ObjectShape for more information. See ObjectShape for more information.
@see @ref scenegraph, ObjectShapeGroup2D, ObjectShapeGroup3D @see @ref scenegraph, ObjectShapeGroup2D, ObjectShapeGroup3D
*/ */
template<UnsignedInt dimensions> class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: public SceneGraph::FeatureGroup<dimensions, ObjectShape<dimensions>> { template<UnsignedInt dimensions> class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: public SceneGraph::FeatureGroup<dimensions, AbstractObjectShape<dimensions>> {
friend class ObjectShape<dimensions>; friend class AbstractObjectShape<dimensions>;
public: public:
/** /**
@ -86,7 +86,7 @@ template<UnsignedInt dimensions> class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: p
* collisions, returns `nullptr`. Calls setClean() before the * collisions, returns `nullptr`. Calls setClean() before the
* operation. * operation.
*/ */
ObjectShape<dimensions>* firstCollision(const ObjectShape<dimensions>* shape); AbstractObjectShape<dimensions>* firstCollision(const AbstractObjectShape<dimensions>* shape);
private: private:
bool dirty; bool dirty;

10
src/Physics/Physics.h

@ -34,9 +34,9 @@ namespace Magnum { namespace Physics {
/** @todoc remove when doxygen is sane again */ /** @todoc remove when doxygen is sane again */
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
template<UnsignedInt> class AbstractShape; template<UnsignedInt> class AbstractObjectShape;
typedef AbstractShape<2> AbstractShape2D; typedef AbstractObjectShape<2> AbstractObjectShape2D;
typedef AbstractShape<3> AbstractShape3D; typedef AbstractObjectShape<3> AbstractObjectShape3D;
template<UnsignedInt> class AxisAlignedBox; template<UnsignedInt> class AxisAlignedBox;
typedef AxisAlignedBox<2> AxisAlignedBox2D; typedef AxisAlignedBox<2> AxisAlignedBox2D;
@ -58,9 +58,7 @@ template<UnsignedInt> class LineSegment;
typedef LineSegment<2> LineSegment2D; typedef LineSegment<2> LineSegment2D;
typedef LineSegment<3> LineSegment3D; typedef LineSegment<3> LineSegment3D;
template<UnsignedInt> class ObjectShape; template<class> class ObjectShape;
typedef ObjectShape<2> ObjectShape2D;
typedef ObjectShape<3> ObjectShape3D;
template<UnsignedInt> class ObjectShapeGroup; template<UnsignedInt> class ObjectShapeGroup;
typedef ObjectShapeGroup<2> ObjectShapeGroup2D; typedef ObjectShapeGroup<2> ObjectShapeGroup2D;

72
src/Physics/Test/ObjectShapeTest.cpp

@ -27,7 +27,9 @@
#include "Physics/ObjectShapeGroup.h" #include "Physics/ObjectShapeGroup.h"
#include "Physics/ObjectShape.h" #include "Physics/ObjectShape.h"
#include "Physics/Point.h" #include "Physics/Point.h"
#include "Physics/ShapeGroup.h"
#include "Physics/Sphere.h" #include "Physics/Sphere.h"
#include "SceneGraph/MatrixTransformation2D.h"
#include "SceneGraph/MatrixTransformation3D.h" #include "SceneGraph/MatrixTransformation3D.h"
#include "SceneGraph/Scene.h" #include "SceneGraph/Scene.h"
@ -39,90 +41,102 @@ class ObjectShapeTest: public Corrade::TestSuite::Tester {
void clean(); void clean();
void firstCollision(); void firstCollision();
void shapeGroup();
}; };
typedef SceneGraph::Scene<SceneGraph::MatrixTransformation2D<>> Scene2D;
typedef SceneGraph::Object<SceneGraph::MatrixTransformation2D<>> Object2D;
typedef SceneGraph::Scene<SceneGraph::MatrixTransformation3D<>> Scene3D; typedef SceneGraph::Scene<SceneGraph::MatrixTransformation3D<>> Scene3D;
typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D<>> Object3D; typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D<>> Object3D;
ObjectShapeTest::ObjectShapeTest() { ObjectShapeTest::ObjectShapeTest() {
addTests({&ObjectShapeTest::clean, addTests({&ObjectShapeTest::clean,
&ObjectShapeTest::firstCollision}); &ObjectShapeTest::firstCollision,
&ObjectShapeTest::shapeGroup});
} }
void ObjectShapeTest::clean() { void ObjectShapeTest::clean() {
Scene3D scene; Scene3D scene;
ObjectShapeGroup3D group; ObjectShapeGroup3D shapes;
Object3D a(&scene); Object3D a(&scene);
ObjectShape3D* shape = new ObjectShape3D(&a, &group); auto shape = new Physics::ObjectShape<Physics::Point3D>(&a, {{1.0f, -2.0f, 3.0f}}, &shapes);
shape->setShape(Physics::Point3D({1.0f, -2.0f, 3.0f}));
a.scale(Vector3(-2.0f)); a.scale(Vector3(-2.0f));
Object3D b(&scene); Object3D b(&scene);
new ObjectShape3D(&b, &group); new Physics::ObjectShape<Physics::Point3D>(&b, &shapes);
/* Everything is dirty at the beginning */ /* Everything is dirty at the beginning */
CORRADE_VERIFY(group.isDirty()); CORRADE_VERIFY(shapes.isDirty());
CORRADE_VERIFY(a.isDirty()); CORRADE_VERIFY(a.isDirty());
CORRADE_VERIFY(b.isDirty()); CORRADE_VERIFY(b.isDirty());
/* Cleaning object will not clean anything other */ /* Cleaning object will not clean anything other */
a.setClean(); a.setClean();
CORRADE_VERIFY(group.isDirty()); CORRADE_VERIFY(shapes.isDirty());
CORRADE_VERIFY(!a.isDirty()); CORRADE_VERIFY(!a.isDirty());
CORRADE_VERIFY(b.isDirty()); CORRADE_VERIFY(b.isDirty());
/* Verify that the feature was actually cleaned */ /* Verify that the feature was actually cleaned */
CORRADE_COMPARE(static_cast<const Physics::Point3D*>(shape->shape())->transformedPosition(), CORRADE_COMPARE(shape->transformedShape().position(),
Vector3(-2.0f, 4.0f, -6.0f)); Vector3(-2.0f, 4.0f, -6.0f));
/* Setting group clean will clean whole group */ /* Setting group clean will clean whole group */
a.setDirty(); a.setDirty();
group.setClean(); shapes.setClean();
CORRADE_VERIFY(!group.isDirty()); CORRADE_VERIFY(!shapes.isDirty());
CORRADE_VERIFY(!a.isDirty()); CORRADE_VERIFY(!a.isDirty());
CORRADE_VERIFY(!b.isDirty()); CORRADE_VERIFY(!b.isDirty());
/* Setting object dirty will set also the group, but not other objects */ /* Setting object dirty will set also the group, but not other objects */
b.setDirty(); b.setDirty();
CORRADE_VERIFY(group.isDirty()); CORRADE_VERIFY(shapes.isDirty());
CORRADE_VERIFY(!a.isDirty()); CORRADE_VERIFY(!a.isDirty());
CORRADE_VERIFY(b.isDirty()); CORRADE_VERIFY(b.isDirty());
} }
void ObjectShapeTest::firstCollision() { void ObjectShapeTest::firstCollision() {
Scene3D scene; Scene3D scene;
ObjectShapeGroup3D group; ObjectShapeGroup3D shapes;
Object3D a(&scene); Object3D a(&scene);
ObjectShape3D* aShape = new ObjectShape3D(&a, &group); auto aShape = new ObjectShape<Physics::Sphere3D>(&a, {{1.0f, -2.0f, 3.0f}, 1.5f}, &shapes);
aShape->setShape(Physics::Sphere3D({1.0f, -2.0f, 3.0f}, 1.5f));
Object3D b(&scene); Object3D b(&scene);
ObjectShape3D* bShape = new ObjectShape3D(&b, &group); auto bShape = new ObjectShape<Physics::Point3D>(&b, {{3.0f, -2.0f, 3.0f}}, &shapes);
bShape->setShape(Physics::Point3D({3.0f, -2.0f, 3.0f}));
Object3D c(&scene); Object3D c(&scene);
ObjectShape3D* cShape = new ObjectShape3D(&c, &group); new ObjectShape<Physics::ShapeGroup3D>(&c, &shapes);
/* No-op if the object has no shape */
CORRADE_VERIFY(group.isDirty());
CORRADE_VERIFY(!group.firstCollision(cShape));
CORRADE_VERIFY(group.isDirty());
/* No collisions initially */ /* No collisions initially */
CORRADE_VERIFY(!group.firstCollision(aShape)); CORRADE_VERIFY(!shapes.firstCollision(aShape));
CORRADE_VERIFY(!group.firstCollision(bShape)); CORRADE_VERIFY(!shapes.firstCollision(bShape));
CORRADE_VERIFY(!group.isDirty()); CORRADE_VERIFY(!shapes.isDirty());
/* Move point into sphere */ /* Move point into sphere */
b.translate(Vector3::xAxis(-1.0f)); b.translate(Vector3::xAxis(-1.0f));
/* Collision */ /* Collision */
CORRADE_VERIFY(group.isDirty()); CORRADE_VERIFY(shapes.isDirty());
CORRADE_VERIFY(group.firstCollision(aShape) == bShape); CORRADE_VERIFY(shapes.firstCollision(aShape) == bShape);
CORRADE_VERIFY(group.firstCollision(bShape) == aShape); CORRADE_VERIFY(shapes.firstCollision(bShape) == aShape);
CORRADE_VERIFY(!group.isDirty()); CORRADE_VERIFY(!shapes.isDirty());
}
void ObjectShapeTest::shapeGroup() {
Scene2D scene;
ObjectShapeGroup2D shapes;
/* Verify construction */
Object2D a(&scene);
auto shape = new ObjectShape<Physics::ShapeGroup2D>(&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<Physics::Point2D>(1);
a.translate(Vector2::xAxis(5.0f));
a.setClean();
CORRADE_COMPARE(point.position(), Vector2(5.25f, -1.0f));
} }
}}} }}}

Loading…
Cancel
Save