Browse Source

SceneGraph: using std::reference_wrapper instead of pointers.

Currently all the functions taking vectors of objects (e.g. setClean(),
transformations() and transformationMatrices()) were taking pointers,
which lead to additional (and often forgotten) nullptr checks. The
internals are now much more clean, as the parts where we are dealing
with pointers are reduced to bare minimum.

Also renamed private Object::setClean() function to
Object::setCleanInternal() to avoid overload clash with the public one.

The old way is now an nullptr-checked alias to the new one, is marked
as deprecated and will be removed in some future release.
pull/51/head
Vladimír Vondruš 12 years ago
parent
commit
aa49008358
  1. 5
      src/Magnum/SceneGraph/AbstractCamera.hpp
  2. 27
      src/Magnum/SceneGraph/AbstractObject.h
  3. 40
      src/Magnum/SceneGraph/Object.h
  4. 166
      src/Magnum/SceneGraph/Object.hpp
  5. 31
      src/Magnum/SceneGraph/Test/ObjectTest.cpp
  6. 5
      src/Magnum/Shapes/ShapeGroup.cpp

5
src/Magnum/SceneGraph/AbstractCamera.hpp

@ -93,9 +93,10 @@ template<UnsignedInt dimensions, class T> void AbstractCamera<dimensions, T>::dr
AbstractFeature<dimensions, T>::object().setClean(); AbstractFeature<dimensions, T>::object().setClean();
/* Compute transformations of all objects in the group relative to the camera */ /* Compute transformations of all objects in the group relative to the camera */
std::vector<AbstractObject<dimensions, T>*> objects(group.size()); std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>> objects;
objects.reserve(group.size());
for(std::size_t i = 0; i != group.size(); ++i) for(std::size_t i = 0; i != group.size(); ++i)
objects[i] = &group[i].object(); objects.push_back(group[i].object());
std::vector<typename DimensionTraits<dimensions, T>::MatrixType> transformations = std::vector<typename DimensionTraits<dimensions, T>::MatrixType> transformations =
scene->transformationMatrices(objects, _cameraMatrix); scene->transformationMatrices(objects, _cameraMatrix);

27
src/Magnum/SceneGraph/AbstractObject.h

@ -29,6 +29,7 @@
* @brief Class @ref Magnum::SceneGraph::AbstractObject, alias @ref Magnum::SceneGraph::AbstractBasicObject2D, @ref Magnum::SceneGraph::AbstractBasicObject3D, typedef @ref Magnum::SceneGraph::AbstractObject2D, @ref Magnum::SceneGraph::AbstractObject3D * @brief Class @ref Magnum::SceneGraph::AbstractObject, alias @ref Magnum::SceneGraph::AbstractBasicObject2D, @ref Magnum::SceneGraph::AbstractBasicObject3D, typedef @ref Magnum::SceneGraph::AbstractObject2D, @ref Magnum::SceneGraph::AbstractObject3D
*/ */
#include <functional>
#include <vector> #include <vector>
#include <Corrade/Containers/LinkedList.h> #include <Corrade/Containers/LinkedList.h>
@ -154,10 +155,18 @@ template<UnsignedInt dimensions, class T> class AbstractObject
* @ref Object type, use typesafe @ref Object::transformationMatrices() * @ref Object type, use typesafe @ref Object::transformationMatrices()
* when possible. * when possible.
*/ */
std::vector<MatrixType> transformationMatrices(const std::vector<AbstractObject<dimensions, T>*>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const { std::vector<MatrixType> transformationMatrices(const std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const {
return doTransformationMatrices(objects, initialTransformationMatrix); return doTransformationMatrices(objects, initialTransformationMatrix);
} }
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief transformationMatrices(const std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>>&, const MatrixType&)
* @deprecated Use @ref Magnum::SceneGraph::AbstractObject::transformationMatrices(const std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>>&, const MatrixType&) "transformationMatrices(const std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>>&, const MatrixType&)" instead.
*/
CORRADE_DEPRECATED("use transformationMatrices(const std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>>&, const MatrixType&) instead") std::vector<MatrixType> transformationMatrices(const std::vector<AbstractObject<dimensions, T>*>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const;
#endif
/*@}*/ /*@}*/
/** /**
@ -174,11 +183,19 @@ template<UnsignedInt dimensions, class T> class AbstractObject
* @ref Object type, use typesafe @ref Object::setClean() when * @ref Object type, use typesafe @ref Object::setClean() when
* possible. * possible.
*/ */
static void setClean(const std::vector<AbstractObject<dimensions, T>*>& objects) { static void setClean(const std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>>& objects) {
if(objects.empty()) return; if(objects.empty()) return;
objects.front()->doSetClean(objects); objects.front().get().doSetClean(objects);
} }
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief setClean(const std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>>&)
* @deprecated Use @ref Magnum::SceneGraph::AbstractObject::setClean(const std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>>&) "setClean(const std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>>&)" instead.
*/
static CORRADE_DEPRECATED("use setClean(const std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>>&) instead") void setClean(const std::vector<AbstractObject<dimensions, T>*>& objects);
#endif
/** /**
* @brief Whether absolute transformation is dirty * @brief Whether absolute transformation is dirty
* *
@ -223,12 +240,12 @@ template<UnsignedInt dimensions, class T> class AbstractObject
virtual MatrixType doTransformationMatrix() const = 0; virtual MatrixType doTransformationMatrix() const = 0;
virtual MatrixType doAbsoluteTransformationMatrix() const = 0; virtual MatrixType doAbsoluteTransformationMatrix() const = 0;
virtual std::vector<MatrixType> doTransformationMatrices(const std::vector<AbstractObject<dimensions, T>*>& objects, const MatrixType& initialTransformationMatrix) const = 0; virtual std::vector<MatrixType> doTransformationMatrices(const std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>>& objects, const MatrixType& initialTransformationMatrix) const = 0;
virtual bool doIsDirty() const = 0; virtual bool doIsDirty() const = 0;
virtual void doSetDirty() = 0; virtual void doSetDirty() = 0;
virtual void doSetClean() = 0; virtual void doSetClean() = 0;
virtual void doSetClean(const std::vector<AbstractObject<dimensions, T>*>& objects) = 0; virtual void doSetClean(const std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>>& objects) = 0;
}; };
#ifndef CORRADE_GCC46_COMPATIBILITY #ifndef CORRADE_GCC46_COMPATIBILITY

40
src/Magnum/SceneGraph/Object.h

@ -247,7 +247,15 @@ template<class Transformation> class Object: public AbstractObject<Transformatio
* if specified. * if specified.
* @see @ref transformations() * @see @ref transformations()
*/ */
std::vector<MatrixType> transformationMatrices(const std::vector<Object<Transformation>*>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const; std::vector<MatrixType> transformationMatrices(const std::vector<std::reference_wrapper<Object<Transformation>>>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const;
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief transformationMatrices(const std::vector<std::reference_wrapper<Object<Transformation>>>&, const MatrixType&)
* @deprecated Use @ref Magnum::SceneGraph::Object::transformationMatrices(const std::vector<std::reference_wrapper<Object<Transformation>>>&, const MatrixType&) "transformationMatrices(const std::vector<std::reference_wrapper<Object<Transformation>>>&, const MatrixType&)" instead.
*/
CORRADE_DEPRECATED("use transformationMatrices(const std::vector<std::reference_wrapper<Object<Transformation>>>&, const MatrixType&) instead") std::vector<MatrixType> transformationMatrices(const std::vector<Object<Transformation>*>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const;
#endif
/** /**
* @brief Transformations of given group of objects relative to this object * @brief Transformations of given group of objects relative to this object
@ -258,7 +266,15 @@ template<class Transformation> class Object: public AbstractObject<Transformatio
*/ */
/* `objects` passed by copy intentionally (to allow move from /* `objects` passed by copy intentionally (to allow move from
transformationMatrices() and avoid copy in the function itself) */ transformationMatrices() and avoid copy in the function itself) */
std::vector<typename Transformation::DataType> transformations(std::vector<Object<Transformation>*> objects, const typename Transformation::DataType& initialTransformation = typename Transformation::DataType()) const; std::vector<typename Transformation::DataType> transformations(std::vector<std::reference_wrapper<Object<Transformation>>> objects, const typename Transformation::DataType& initialTransformation = typename Transformation::DataType()) const;
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief transformations(std::vector<std::reference_wrapper<Object<Transformation>>>, const typename Transformation::DataType&)
* @deprecated Use @ref Magnum::SceneGraph::Object::transformations(std::vector<std::reference_wrapper<Object<Transformation>>>, const typename Transformation::DataType&) "transformations(std::vector<std::reference_wrapper<Object<Transformation>>>, const typename Transformation::DataType&)" instead.
*/
CORRADE_DEPRECATED("use transformations(std::vector<std::reference_wrapper<Object<Transformation>>>, const typename Transformation::DataType&) instead") std::vector<typename Transformation::DataType> transformations(std::vector<Object<Transformation>*> objects, const typename Transformation::DataType& initialTransformation = typename Transformation::DataType()) const;
#endif
/*@}*/ /*@}*/
@ -275,7 +291,15 @@ template<class Transformation> class Object: public AbstractObject<Transformatio
* @see @ref setClean() * @see @ref setClean()
*/ */
/* `objects` passed by copy intentionally (to avoid copy internally) */ /* `objects` passed by copy intentionally (to avoid copy internally) */
static void setClean(std::vector<Object<Transformation>*> objects); static void setClean(std::vector<std::reference_wrapper<Object<Transformation>>> objects);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief setClean(std::vector<std::reference_wrapper<Object<Transformation>>>)
* @deprecated Use @ref Magnum::SceneGraph::Object::setClean(std::vector<std::reference_wrapper<Object<Transformation>>> "setClean(std::vector<std::reference_wrapper<Object<Transformation>>>" instead.
*/
CORRADE_DEPRECATED("use setClean(std::vector<std::reference_wrapper<Object<Transformation>>>) instead") static void setClean(std::vector<Object<Transformation>*> objects);
#endif
/** @copydoc AbstractObject::isDirty() */ /** @copydoc AbstractObject::isDirty() */
bool isDirty() const { return !!(flags & Flag::Dirty); } bool isDirty() const { return !!(flags & Flag::Dirty); }
@ -291,7 +315,7 @@ template<class Transformation> class Object: public AbstractObject<Transformatio
* calls @ref setClean() on every parent which is not already clean. If * calls @ref setClean() on every parent which is not already clean. If
* the object is already clean, the function does nothing. * the object is already clean, the function does nothing.
* *
* See also @ref setClean(std::vector<Object<Transformation>*>), * See also @ref setClean(std::vector<std::reference_wrapper<Object<Transformation>>>),
* which cleans given set of objects more efficiently than when calling * which cleans given set of objects more efficiently than when calling
* @ref setClean() on each object individually. * @ref setClean() on each object individually.
* @see @ref scenegraph-caching, @ref setDirty(), @ref isDirty() * @see @ref scenegraph-caching, @ref setDirty(), @ref isDirty()
@ -317,16 +341,16 @@ template<class Transformation> class Object: public AbstractObject<Transformatio
return absoluteTransformationMatrix(); return absoluteTransformationMatrix();
} }
std::vector<MatrixType> doTransformationMatrices(const std::vector<AbstractObject<Transformation::Dimensions, typename Transformation::Type>*>& objects, const MatrixType& initialTransformationMatrix) const override final; std::vector<MatrixType> doTransformationMatrices(const std::vector<std::reference_wrapper<AbstractObject<Transformation::Dimensions, typename Transformation::Type>>>& objects, const MatrixType& initialTransformationMatrix) const override final;
typename Transformation::DataType MAGNUM_SCENEGRAPH_LOCAL computeJointTransformation(const std::vector<Object<Transformation>*>& jointObjects, std::vector<typename Transformation::DataType>& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const; typename Transformation::DataType MAGNUM_SCENEGRAPH_LOCAL computeJointTransformation(const std::vector<std::reference_wrapper<Object<Transformation>>>& jointObjects, std::vector<typename Transformation::DataType>& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const;
bool MAGNUM_SCENEGRAPH_LOCAL doIsDirty() const override final { return isDirty(); } bool MAGNUM_SCENEGRAPH_LOCAL doIsDirty() const override final { return isDirty(); }
void MAGNUM_SCENEGRAPH_LOCAL doSetDirty() override final { setDirty(); } void MAGNUM_SCENEGRAPH_LOCAL doSetDirty() override final { setDirty(); }
void MAGNUM_SCENEGRAPH_LOCAL doSetClean() override final { setClean(); } void MAGNUM_SCENEGRAPH_LOCAL doSetClean() override final { setClean(); }
void doSetClean(const std::vector<AbstractObject<Transformation::Dimensions, typename Transformation::Type>*>& objects) override final; void doSetClean(const std::vector<std::reference_wrapper<AbstractObject<Transformation::Dimensions, typename Transformation::Type>>>& objects) override final;
void MAGNUM_SCENEGRAPH_LOCAL setClean(const typename Transformation::DataType& absoluteTransformation); void MAGNUM_SCENEGRAPH_LOCAL setCleanInternal(const typename Transformation::DataType& absoluteTransformation);
typedef Implementation::ObjectFlag Flag; typedef Implementation::ObjectFlag Flag;
typedef Implementation::ObjectFlags Flags; typedef Implementation::ObjectFlags Flags;

166
src/Magnum/SceneGraph/Object.hpp

@ -38,9 +38,35 @@
namespace Magnum { namespace SceneGraph { namespace Magnum { namespace SceneGraph {
#ifdef MAGNUM_BUILD_DEPRECATED
template<UnsignedInt dimensions, class T> void AbstractObject<dimensions, T>::setClean(const std::vector<AbstractObject<dimensions, T>*>& objects) {
std::vector<std::reference_wrapper<const AbstractObject<dimensions, T>>> references;
references.reserve(objects.size());
for(auto o: objects) {
CORRADE_INTERNAL_ASSERT(o != nullptr);
references.push_back(*o);
}
setClean(references);
}
#endif
template<UnsignedInt dimensions, class T> AbstractObject<dimensions, T>::AbstractObject() {} template<UnsignedInt dimensions, class T> AbstractObject<dimensions, T>::AbstractObject() {}
template<UnsignedInt dimensions, class T> AbstractObject<dimensions, T>::~AbstractObject() {} template<UnsignedInt dimensions, class T> AbstractObject<dimensions, T>::~AbstractObject() {}
#ifdef MAGNUM_BUILD_DEPRECATED
template<UnsignedInt dimensions, class T> auto AbstractObject<dimensions, T>::transformationMatrices(const std::vector<AbstractObject<dimensions, T>*>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector<MatrixType> {
std::vector<std::reference_wrapper<const AbstractObject<dimensions, T>>> references;
references.reserve(objects.size());
for(auto o: objects) {
CORRADE_INTERNAL_ASSERT(o != nullptr);
references.push_back(*o);
}
return transformationMatrices(references, initialTransformationMatrix);
}
#endif
template<UnsignedInt dimensions, class T> AbstractTransformation<dimensions, T>::AbstractTransformation() {} template<UnsignedInt dimensions, class T> AbstractTransformation<dimensions, T>::AbstractTransformation() {}
template<class Transformation> Object<Transformation>::Object(Object<Transformation>* parent): counter(0xFFFFu), flags(Flag::Dirty) { template<class Transformation> Object<Transformation>::Object(Object<Transformation>* parent): counter(0xFFFFu), flags(Flag::Dirty) {
@ -159,22 +185,21 @@ template<class Transformation> void Object<Transformation>::setClean() {
/* Compose transformation and clean object */ /* Compose transformation and clean object */
absoluteTransformation = Implementation::Transformation<Transformation>::compose(absoluteTransformation, o->transformation()); absoluteTransformation = Implementation::Transformation<Transformation>::compose(absoluteTransformation, o->transformation());
CORRADE_INTERNAL_ASSERT(o->isDirty()); CORRADE_INTERNAL_ASSERT(o->isDirty());
o->setClean(absoluteTransformation); o->setCleanInternal(absoluteTransformation);
CORRADE_ASSERT(!o->isDirty(), "SceneGraph::Object::setClean(): original implementation was not called", ); CORRADE_ASSERT(!o->isDirty(), "SceneGraph::Object::setClean(): original implementation was not called", );
} }
} }
template<class Transformation> auto Object<Transformation>::doTransformationMatrices(const std::vector<AbstractObject<Transformation::Dimensions, typename Transformation::Type>*>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector<MatrixType> { template<class Transformation> auto Object<Transformation>::doTransformationMatrices(const std::vector<std::reference_wrapper<AbstractObject<Transformation::Dimensions, typename Transformation::Type>>>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector<MatrixType> {
std::vector<Object<Transformation>*> castObjects(objects.size()); std::vector<std::reference_wrapper<Object<Transformation>>> castObjects;
for(std::size_t i = 0; i != objects.size(); ++i) castObjects.reserve(objects.size());
/* Non-null is checked in transformations() */ /** @todo Ensure this doesn't crash, somehow */
/** @todo Ensure this doesn't crash, somehow */ for(auto o: objects) castObjects.push_back(static_cast<Object<Transformation>&>(o.get()));
castObjects[i] = static_cast<Object<Transformation>*>(objects[i]);
return transformationMatrices(std::move(castObjects), initialTransformationMatrix); return transformationMatrices(std::move(castObjects), initialTransformationMatrix);
} }
template<class Transformation> auto Object<Transformation>::transformationMatrices(const std::vector<Object<Transformation>*>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector<MatrixType> { template<class Transformation> auto Object<Transformation>::transformationMatrices(const std::vector<std::reference_wrapper<Object<Transformation>>>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector<MatrixType> {
std::vector<typename Transformation::DataType> transformations = this->transformations(std::move(objects), Implementation::Transformation<Transformation>::fromMatrix(initialTransformationMatrix)); std::vector<typename Transformation::DataType> transformations = this->transformations(std::move(objects), Implementation::Transformation<Transformation>::fromMatrix(initialTransformationMatrix));
std::vector<MatrixType> transformationMatrices(transformations.size()); std::vector<MatrixType> transformationMatrices(transformations.size());
for(std::size_t i = 0; i != objects.size(); ++i) for(std::size_t i = 0; i != objects.size(); ++i)
@ -183,6 +208,19 @@ template<class Transformation> auto Object<Transformation>::transformationMatric
return transformationMatrices; return transformationMatrices;
} }
#ifdef MAGNUM_BUILD_DEPRECATED
template<class Transformation> auto Object<Transformation>::transformationMatrices(const std::vector<Object<Transformation>*>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector<MatrixType> {
std::vector<std::reference_wrapper<Object<Transformation>>> references;
references.reserve(objects.size());
for(auto o: objects) {
CORRADE_INTERNAL_ASSERT(o != nullptr);
references.push_back(*o);
}
return transformationMatrices(references, initialTransformationMatrix);
}
#endif
/* /*
Computing absolute transformations for given list of objects Computing absolute transformations for given list of objects
@ -197,7 +235,7 @@ Then for all joints their transformation (relative to parent joint) is
computed and recursively concatenated together. Resulting transformations for computed and recursively concatenated together. Resulting transformations for
joints which were originally in `object` list is then returned. joints which were originally in `object` list is then returned.
*/ */
template<class Transformation> std::vector<typename Transformation::DataType> Object<Transformation>::transformations(std::vector<Object<Transformation>*> objects, const typename Transformation::DataType& initialTransformation) const { template<class Transformation> std::vector<typename Transformation::DataType> Object<Transformation>::transformations(std::vector<std::reference_wrapper<Object<Transformation>>> objects, const typename Transformation::DataType& initialTransformation) const {
CORRADE_ASSERT(objects.size() < 0xFFFFu, "SceneGraph::Object::transformations(): too large scene", std::vector<typename Transformation::DataType>{}); CORRADE_ASSERT(objects.size() < 0xFFFFu, "SceneGraph::Object::transformations(): too large scene", std::vector<typename Transformation::DataType>{});
/* Remember object count for later */ /* Remember object count for later */
@ -206,16 +244,14 @@ template<class Transformation> std::vector<typename Transformation::DataType> Ob
/* Mark all original objects as joints and create initial list of joints /* Mark all original objects as joints and create initial list of joints
from them */ from them */
for(std::size_t i = 0; i != objects.size(); ++i) { for(std::size_t i = 0; i != objects.size(); ++i) {
CORRADE_INTERNAL_ASSERT(objects[i]);
/* Multiple occurences of one object in the array, don't overwrite it /* Multiple occurences of one object in the array, don't overwrite it
with different counter */ with different counter */
if(objects[i]->counter != 0xFFFFu) continue; if(objects[i].get().counter != 0xFFFFu) continue;
objects[i]->counter = UnsignedShort(i); objects[i].get().counter = UnsignedShort(i);
objects[i]->flags |= Flag::Joint; objects[i].get().flags |= Flag::Joint;
} }
std::vector<Object<Transformation>*> jointObjects(objects); std::vector<std::reference_wrapper<Object<Transformation>>> jointObjects(objects);
/* Scene object */ /* Scene object */
const Scene<Transformation>* scene = this->scene(); const Scene<Transformation>* scene = this->scene();
@ -227,19 +263,19 @@ template<class Transformation> std::vector<typename Transformation::DataType> Ob
auto it = objects.begin(); auto it = objects.begin();
while(!objects.empty()) { while(!objects.empty()) {
/* Already visited, remove and continue to next (duplicate occurence) */ /* Already visited, remove and continue to next (duplicate occurence) */
if((*it)->flags & Flag::Visited) { if(it->get().flags & Flag::Visited) {
it = objects.erase(it); it = objects.erase(it);
continue; continue;
} }
/* Mark the object as visited */ /* Mark the object as visited */
(*it)->flags |= Flag::Visited; it->get().flags |= Flag::Visited;
Object<Transformation>* parent = (*it)->parent(); Object<Transformation>* parent = it->get().parent();
/* If this is root object, remove from list */ /* If this is root object, remove from list */
if(!parent) { if(!parent) {
CORRADE_ASSERT(*it == scene, "SceneGraph::Object::transformations(): the objects are not part of the same tree", std::vector<typename Transformation::DataType>{}); CORRADE_ASSERT(&it->get() == scene, "SceneGraph::Object::transformations(): the objects are not part of the same tree", std::vector<typename Transformation::DataType>{});
it = objects.erase(it); it = objects.erase(it);
/* Parent is an joint or already visited - remove current from list */ /* Parent is an joint or already visited - remove current from list */
@ -254,11 +290,11 @@ template<class Transformation> std::vector<typename Transformation::DataType> Ob
CORRADE_INTERNAL_ASSERT(parent->counter == 0xFFFFu); CORRADE_INTERNAL_ASSERT(parent->counter == 0xFFFFu);
parent->counter = UnsignedShort(jointObjects.size()); parent->counter = UnsignedShort(jointObjects.size());
parent->flags |= Flag::Joint; parent->flags |= Flag::Joint;
jointObjects.push_back(parent); jointObjects.push_back(*parent);
} }
/* Else go up the hierarchy */ /* Else go up the hierarchy */
} else *it = parent; } else *it = *parent;
/* Cycle if reached end */ /* Cycle if reached end */
if(it == objects.end()) it = objects.begin(); if(it == objects.end()) it = objects.begin();
@ -274,17 +310,17 @@ template<class Transformation> std::vector<typename Transformation::DataType> Ob
/* Copy transformation for second or next occurences from first occurence /* Copy transformation for second or next occurences from first occurence
of duplicate object */ of duplicate object */
for(std::size_t i = 0; i != objectCount; ++i) { for(std::size_t i = 0; i != objectCount; ++i) {
if(jointObjects[i]->counter != i) if(jointObjects[i].get().counter != i)
jointTransformations[i] = jointTransformations[jointObjects[i]->counter]; jointTransformations[i] = jointTransformations[jointObjects[i].get().counter];
} }
/* All visited marks are now cleaned, clean joint marks and counters */ /* All visited marks are now cleaned, clean joint marks and counters */
for(auto i: jointObjects) { for(auto i: jointObjects) {
/* All not-already cleaned objects (...duplicate occurences) should /* All not-already cleaned objects (...duplicate occurences) should
have joint mark */ have joint mark */
CORRADE_INTERNAL_ASSERT(i->counter == 0xFFFFu || i->flags & Flag::Joint); CORRADE_INTERNAL_ASSERT(i.get().counter == 0xFFFFu || i.get().flags & Flag::Joint);
i->flags &= ~Flag::Joint; i.get().flags &= ~Flag::Joint;
i->counter = 0xFFFFu; i.get().counter = 0xFFFFu;
} }
/* Shrink the array to contain only transformations of requested objects and return */ /* Shrink the array to contain only transformations of requested objects and return */
@ -292,27 +328,40 @@ template<class Transformation> std::vector<typename Transformation::DataType> Ob
return jointTransformations; return jointTransformations;
} }
template<class Transformation> typename Transformation::DataType Object<Transformation>::computeJointTransformation(const std::vector<Object<Transformation>*>& jointObjects, std::vector<typename Transformation::DataType>& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const { #ifdef MAGNUM_BUILD_DEPRECATED
Object<Transformation>* o = jointObjects[joint]; template<class Transformation> std::vector<typename Transformation::DataType> Object<Transformation>::transformations(std::vector<Object<Transformation>*> objects, const typename Transformation::DataType& initialTransformation) const {
std::vector<std::reference_wrapper<Object<Transformation>>> references;
references.reserve(objects.size());
for(auto o: objects) {
CORRADE_INTERNAL_ASSERT(o != nullptr);
references.push_back(*o);
}
return transformations(references, initialTransformation);
}
#endif
template<class Transformation> typename Transformation::DataType Object<Transformation>::computeJointTransformation(const std::vector<std::reference_wrapper<Object<Transformation>>>& jointObjects, std::vector<typename Transformation::DataType>& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const {
std::reference_wrapper<Object<Transformation>> o = jointObjects[joint];
/* Transformation already computed ("unvisited" by this function before /* Transformation already computed ("unvisited" by this function before
either due to recursion or duplicate object occurences), done */ either due to recursion or duplicate object occurences), done */
if(!(o->flags & Flag::Visited)) return jointTransformations[joint]; if(!(o.get().flags & Flag::Visited)) return jointTransformations[joint];
/* Initialize transformation */ /* Initialize transformation */
jointTransformations[joint] = o->transformation(); jointTransformations[joint] = o.get().transformation();
/* Go up until next joint or root */ /* Go up until next joint or root */
for(;;) { for(;;) {
/* Clean visited mark */ /* Clean visited mark */
CORRADE_INTERNAL_ASSERT(o->flags & Flag::Visited); CORRADE_INTERNAL_ASSERT(o.get().flags & Flag::Visited);
o->flags &= ~Flag::Visited; o.get().flags &= ~Flag::Visited;
Object<Transformation>* parent = o->parent(); Object<Transformation>* parent = o.get().parent();
/* Root object, compose transformation with initial, done */ /* Root object, compose transformation with initial, done */
if(!parent) { if(!parent) {
CORRADE_INTERNAL_ASSERT(o->isScene()); CORRADE_INTERNAL_ASSERT(o.get().isScene());
return (jointTransformations[joint] = return (jointTransformations[joint] =
Implementation::Transformation<Transformation>::compose(initialTransformation, jointTransformations[joint])); Implementation::Transformation<Transformation>::compose(initialTransformation, jointTransformations[joint]));
@ -324,23 +373,23 @@ template<class Transformation> typename Transformation::DataType Object<Transfor
/* Else compose transformation with parent, go up the hierarchy */ /* Else compose transformation with parent, go up the hierarchy */
} else { } else {
jointTransformations[joint] = Implementation::Transformation<Transformation>::compose(parent->transformation(), jointTransformations[joint]); jointTransformations[joint] = Implementation::Transformation<Transformation>::compose(parent->transformation(), jointTransformations[joint]);
o = parent; o = *parent;
} }
} }
} }
template<class Transformation> void Object<Transformation>::doSetClean(const std::vector<AbstractObject<Transformation::Dimensions, typename Transformation::Type>*>& objects) { template<class Transformation> void Object<Transformation>::doSetClean(const std::vector<std::reference_wrapper<AbstractObject<Transformation::Dimensions, typename Transformation::Type>>>& objects) {
std::vector<Object<Transformation>*> castObjects(objects.size()); std::vector<std::reference_wrapper<Object<Transformation>>> castObjects;
for(std::size_t i = 0; i != objects.size(); ++i) castObjects.reserve(objects.size());
/** @todo Ensure this doesn't crash, somehow */ /** @todo Ensure this doesn't crash, somehow */
castObjects[i] = static_cast<Object<Transformation>*>(objects[i]); for(auto o: objects) castObjects.push_back(static_cast<Object<Transformation>&>(o.get()));
setClean(std::move(castObjects)); setClean(std::move(castObjects));
} }
template<class Transformation> void Object<Transformation>::setClean(std::vector<Object<Transformation>*> objects) { template<class Transformation> void Object<Transformation>::setClean(std::vector<std::reference_wrapper<Object<Transformation>>> objects) {
/* Remove all clean objects from the list */ /* Remove all clean objects from the list */
auto firstClean = std::remove_if(objects.begin(), objects.end(), [](Object<Transformation>* o) { return !o->isDirty(); }); auto firstClean = std::remove_if(objects.begin(), objects.end(), [](Object<Transformation>& o) { return !o.isDirty(); });
objects.erase(firstClean, objects.end()); objects.erase(firstClean, objects.end());
/* No dirty objects left, done */ /* No dirty objects left, done */
@ -349,35 +398,48 @@ template<class Transformation> void Object<Transformation>::setClean(std::vector
/* Add non-clean parents to the list. Mark each added object as visited, so /* Add non-clean parents to the list. Mark each added object as visited, so
they aren't added more than once */ they aren't added more than once */
for(std::size_t end = objects.size(), i = 0; i != end; ++i) { for(std::size_t end = objects.size(), i = 0; i != end; ++i) {
Object<Transformation>* o = objects[i]; Object<Transformation>& o = objects[i];
o->flags |= Flag::Visited; o.flags |= Flag::Visited;
Object<Transformation>* parent = o->parent(); Object<Transformation>* parent = o.parent();
while(parent && !(parent->flags & Flag::Visited) && parent->isDirty()) { while(parent && !(parent->flags & Flag::Visited) && parent->isDirty()) {
objects.push_back(parent); objects.push_back(*parent);
parent = parent->parent(); parent = parent->parent();
} }
} }
/* Cleanup all marks */ /* Cleanup all marks */
for(auto o: objects) o->flags &= ~Flag::Visited; for(auto o: objects) o.get().flags &= ~Flag::Visited;
/* Compute absolute transformations */ /* Compute absolute transformations */
Scene<Transformation>* scene = objects[0]->scene(); Scene<Transformation>* scene = objects[0].get().scene();
CORRADE_ASSERT(scene, "Object::setClean(): objects must be part of some scene", ); CORRADE_ASSERT(scene, "Object::setClean(): objects must be part of some scene", );
std::vector<typename Transformation::DataType> transformations(scene->transformations(objects)); std::vector<typename Transformation::DataType> transformations(scene->transformations(objects));
/* Go through all objects and clean them */ /* Go through all objects and clean them */
for(std::size_t i = 0; i != objects.size(); ++i) { for(std::size_t i = 0; i != objects.size(); ++i) {
/* The object might be duplicated in the list, don't clean it more than once */ /* The object might be duplicated in the list, don't clean it more than once */
if(!objects[i]->isDirty()) continue; if(!objects[i].get().isDirty()) continue;
objects[i].get().setCleanInternal(transformations[i]);
CORRADE_ASSERT(!objects[i].get().isDirty(), "SceneGraph::Object::setClean(): original implementation was not called", );
}
}
objects[i]->setClean(transformations[i]); #ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_ASSERT(!objects[i]->isDirty(), "SceneGraph::Object::setClean(): original implementation was not called", ); template<class Transformation> void Object<Transformation>::setClean(std::vector<Object<Transformation>*> objects) {
std::vector<std::reference_wrapper<Object<Transformation>>> references;
references.reserve(objects.size());
for(auto o: objects) {
CORRADE_INTERNAL_ASSERT(o != nullptr);
references.push_back(*o);
} }
return setClean(objects);
} }
#endif
template<class Transformation> void Object<Transformation>::setClean(const typename Transformation::DataType& absoluteTransformation) { template<class Transformation> void Object<Transformation>::setCleanInternal(const typename Transformation::DataType& absoluteTransformation) {
/* "Lazy storage" for transformation matrix and inverted transformation matrix */ /* "Lazy storage" for transformation matrix and inverted transformation matrix */
CachedTransformations cached; CachedTransformations cached;
MatrixType matrix, invertedMatrix; MatrixType matrix, invertedMatrix;

31
src/Magnum/SceneGraph/Test/ObjectTest.cpp

@ -174,22 +174,22 @@ void ObjectTest::transformations() {
Matrix4 initial = Matrix4::rotationX(Deg(90.0f)).inverted(); Matrix4 initial = Matrix4::rotationX(Deg(90.0f)).inverted();
/* Empty list */ /* Empty list */
CORRADE_COMPARE(s.transformations(std::vector<Object3D*>(), initial), std::vector<Matrix4>()); CORRADE_COMPARE(s.transformations({}, initial), std::vector<Matrix4>());
/* Scene alone */ /* Scene alone */
CORRADE_COMPARE(s.transformations({&s}, initial), std::vector<Matrix4>{initial}); CORRADE_COMPARE(s.transformations({s}, initial), std::vector<Matrix4>{initial});
/* One object */ /* One object */
Object3D first(&s); Object3D first(&s);
first.rotateZ(Deg(30.0f)); first.rotateZ(Deg(30.0f));
Object3D second(&first); Object3D second(&first);
second.scale(Vector3(0.5f)); second.scale(Vector3(0.5f));
CORRADE_COMPARE(s.transformations({&second}, initial), std::vector<Matrix4>{ CORRADE_COMPARE(s.transformations({second}, initial), std::vector<Matrix4>{
initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)) initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f))
}); });
/* One object and scene */ /* One object and scene */
CORRADE_COMPARE(s.transformations({&second, &s}, initial), (std::vector<Matrix4>{ CORRADE_COMPARE(s.transformations({second, s}, initial), (std::vector<Matrix4>{
initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)),
initial initial
})); }));
@ -197,13 +197,13 @@ void ObjectTest::transformations() {
/* Two objects with foreign joint */ /* Two objects with foreign joint */
Object3D third(&first); Object3D third(&first);
third.translate(Vector3::xAxis(5.0f)); third.translate(Vector3::xAxis(5.0f));
CORRADE_COMPARE(s.transformations({&second, &third}, initial), (std::vector<Matrix4>{ CORRADE_COMPARE(s.transformations({second, third}, initial), (std::vector<Matrix4>{
initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)),
initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)), initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)),
})); }));
/* Three objects with joint as one of them */ /* Three objects with joint as one of them */
CORRADE_COMPARE(s.transformations({&second, &third, &first}, initial), (std::vector<Matrix4>{ CORRADE_COMPARE(s.transformations({second, third, first}, initial), (std::vector<Matrix4>{
initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)),
initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)), initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)),
initial*Matrix4::rotationZ(Deg(30.0f)), initial*Matrix4::rotationZ(Deg(30.0f)),
@ -222,7 +222,7 @@ void ObjectTest::transformationsRelative() {
third.translate(Vector3::xAxis(5.0f)); third.translate(Vector3::xAxis(5.0f));
/* Transformation relative to another object */ /* Transformation relative to another object */
CORRADE_COMPARE(second.transformations({&third}), std::vector<Matrix4>{ CORRADE_COMPARE(second.transformations({third}), std::vector<Matrix4>{
Matrix4::scaling(Vector3(0.5f)).inverted()*Matrix4::translation(Vector3::xAxis(5.0f)) Matrix4::scaling(Vector3(0.5f)).inverted()*Matrix4::translation(Vector3::xAxis(5.0f))
}); });
@ -234,7 +234,7 @@ void ObjectTest::transformationsRelative() {
orphan1.scale(Vector3::xScale(3.0f)); orphan1.scale(Vector3::xScale(3.0f));
Object3D orphan2(&orphanParent); Object3D orphan2(&orphanParent);
orphan2.translate(Vector3::zAxis(5.0f)); orphan2.translate(Vector3::zAxis(5.0f));
CORRADE_COMPARE(orphan1.transformations({&orphan2}), std::vector<Matrix4>{ CORRADE_COMPARE(orphan1.transformations({orphan2}), std::vector<Matrix4>{
Matrix4::scaling(Vector3::xScale(3.0f)).inverted()*Matrix4::translation(Vector3::zAxis(5.0f)) Matrix4::scaling(Vector3::xScale(3.0f)).inverted()*Matrix4::translation(Vector3::zAxis(5.0f))
}); });
} }
@ -246,7 +246,7 @@ void ObjectTest::transformationsOrphan() {
/* Transformation of objects not part of the same scene */ /* Transformation of objects not part of the same scene */
Scene3D s; Scene3D s;
Object3D orphan; Object3D orphan;
CORRADE_COMPARE(s.transformations({&orphan}), std::vector<Matrix4>()); CORRADE_COMPARE(s.transformations({orphan}), std::vector<Matrix4>());
CORRADE_COMPARE(o.str(), "SceneGraph::Object::transformations(): the objects are not part of the same tree\n"); CORRADE_COMPARE(o.str(), "SceneGraph::Object::transformations(): the objects are not part of the same tree\n");
} }
@ -262,7 +262,7 @@ void ObjectTest::transformationsDuplicate() {
Matrix4 firstExpected = Matrix4::rotationZ(Deg(30.0f)); Matrix4 firstExpected = Matrix4::rotationZ(Deg(30.0f));
Matrix4 secondExpected = Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)); Matrix4 secondExpected = Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f));
Matrix4 thirdExpected = Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)); Matrix4 thirdExpected = Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f));
CORRADE_COMPARE(s.transformations({&second, &third, &second, &first, &third}), (std::vector<Matrix4>{ CORRADE_COMPARE(s.transformations({second, third, second, first, third}), (std::vector<Matrix4>{
secondExpected, thirdExpected, secondExpected, firstExpected, thirdExpected secondExpected, thirdExpected, secondExpected, firstExpected, thirdExpected
})); }));
} }
@ -392,7 +392,7 @@ void ObjectTest::setCleanListHierarchy() {
childThree->rotate(Deg(90.0f), Vector3::yAxis()); childThree->rotate(Deg(90.0f), Vector3::yAxis());
/* Clean the object and all its dirty parents (but not children) */ /* Clean the object and all its dirty parents (but not children) */
Scene3D::setClean(std::vector<Object3D*>{childTwo}); Scene3D::setClean({*childTwo});
CORRADE_VERIFY(!scene.isDirty()); CORRADE_VERIFY(!scene.isDirty());
CORRADE_VERIFY(!childOne->isDirty()); CORRADE_VERIFY(!childOne->isDirty());
CORRADE_VERIFY(!childTwo->isDirty()); CORRADE_VERIFY(!childTwo->isDirty());
@ -406,19 +406,19 @@ void ObjectTest::setCleanListHierarchy() {
/* If the object itself is already clean, it shouldn't clean it again */ /* If the object itself is already clean, it shouldn't clean it again */
childOne->cleanedAbsoluteTransformation = Matrix4(Matrix4::Zero); childOne->cleanedAbsoluteTransformation = Matrix4(Matrix4::Zero);
CORRADE_VERIFY(!childOne->isDirty()); CORRADE_VERIFY(!childOne->isDirty());
Scene3D::setClean(std::vector<Object3D*>{childOne}); Scene3D::setClean({*childOne});
CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Matrix4(Matrix4::Zero)); CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Matrix4(Matrix4::Zero));
/* If any object in the hierarchy is already clean, it shouldn't clean it again */ /* If any object in the hierarchy is already clean, it shouldn't clean it again */
CORRADE_VERIFY(!childOne->isDirty()); CORRADE_VERIFY(!childOne->isDirty());
childTwo->setDirty(); childTwo->setDirty();
Scene3D::setClean(std::vector<Object3D*>{childTwo}); Scene3D::setClean({*childTwo});
CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Matrix4(Matrix4::Zero)); CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Matrix4(Matrix4::Zero));
} }
void ObjectTest::setCleanListBulk() { void ObjectTest::setCleanListBulk() {
/* Verify it doesn't crash when passed empty list */ /* Verify it doesn't crash when passed empty list */
Object3D::setClean(std::vector<Object3D*>()); Object3D::setClean({});
Scene3D scene; Scene3D scene;
Object3D a(&scene); Object3D a(&scene);
@ -429,7 +429,6 @@ void ObjectTest::setCleanListBulk() {
CachingObject d(&c); CachingObject d(&c);
d.scale(Vector3(-2.0f)); d.scale(Vector3(-2.0f));
Object3D e(&scene); Object3D e(&scene);
std::vector<Object3D*> cleanAll{&a, &b, &c, &d, &e};
/* All objects should be cleaned */ /* All objects should be cleaned */
CORRADE_VERIFY(a.isDirty()); CORRADE_VERIFY(a.isDirty());
@ -437,7 +436,7 @@ void ObjectTest::setCleanListBulk() {
CORRADE_VERIFY(c.isDirty()); CORRADE_VERIFY(c.isDirty());
CORRADE_VERIFY(d.isDirty()); CORRADE_VERIFY(d.isDirty());
CORRADE_VERIFY(e.isDirty()); CORRADE_VERIFY(e.isDirty());
Object3D::setClean(cleanAll); Object3D::setClean({a, b, c, d, e});
CORRADE_VERIFY(!a.isDirty()); CORRADE_VERIFY(!a.isDirty());
CORRADE_VERIFY(!b.isDirty()); CORRADE_VERIFY(!b.isDirty());
CORRADE_VERIFY(!c.isDirty()); CORRADE_VERIFY(!c.isDirty());

5
src/Magnum/Shapes/ShapeGroup.cpp

@ -32,9 +32,10 @@ namespace Magnum { namespace Shapes {
template<UnsignedInt dimensions> void ShapeGroup<dimensions>::setClean() { template<UnsignedInt dimensions> void ShapeGroup<dimensions>::setClean() {
/* Clean all objects */ /* Clean all objects */
if(!this->isEmpty()) { if(!this->isEmpty()) {
std::vector<SceneGraph::AbstractObject<dimensions, Float>*> objects(this->size()); std::vector<std::reference_wrapper<SceneGraph::AbstractObject<dimensions, Float>>> objects;
objects.reserve(this->size());
for(std::size_t i = 0; i != this->size(); ++i) for(std::size_t i = 0; i != this->size(); ++i)
objects[i] = &(*this)[i].object(); objects.push_back((*this)[i].object());
SceneGraph::AbstractObject<dimensions, Float>::setClean(objects); SceneGraph::AbstractObject<dimensions, Float>::setClean(objects);
} }

Loading…
Cancel
Save