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();
/* 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)
objects[i] = &group[i].object();
objects.push_back(group[i].object());
std::vector<typename DimensionTraits<dimensions, T>::MatrixType> transformations =
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
*/
#include <functional>
#include <vector>
#include <Corrade/Containers/LinkedList.h>
@ -154,10 +155,18 @@ template<UnsignedInt dimensions, class T> class AbstractObject
* @ref Object type, use typesafe @ref Object::transformationMatrices()
* 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);
}
#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
* 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;
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
*
@ -223,12 +240,12 @@ template<UnsignedInt dimensions, class T> class AbstractObject
virtual MatrixType doTransformationMatrix() 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 void doSetDirty() = 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

40
src/Magnum/SceneGraph/Object.h

@ -247,7 +247,15 @@ template<class Transformation> class Object: public AbstractObject<Transformatio
* if specified.
* @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
@ -258,7 +266,15 @@ template<class Transformation> class Object: public AbstractObject<Transformatio
*/
/* `objects` passed by copy intentionally (to allow move from
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()
*/
/* `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() */
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
* 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
* @ref setClean() on each object individually.
* @see @ref scenegraph-caching, @ref setDirty(), @ref isDirty()
@ -317,16 +341,16 @@ template<class Transformation> class Object: public AbstractObject<Transformatio
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(); }
void MAGNUM_SCENEGRAPH_LOCAL doSetDirty() override final { setDirty(); }
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::ObjectFlags Flags;

166
src/Magnum/SceneGraph/Object.hpp

@ -38,9 +38,35 @@
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() {}
#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<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 */
absoluteTransformation = Implementation::Transformation<Transformation>::compose(absoluteTransformation, o->transformation());
CORRADE_INTERNAL_ASSERT(o->isDirty());
o->setClean(absoluteTransformation);
o->setCleanInternal(absoluteTransformation);
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> {
std::vector<Object<Transformation>*> castObjects(objects.size());
for(std::size_t i = 0; i != objects.size(); ++i)
/* Non-null is checked in transformations() */
/** @todo Ensure this doesn't crash, somehow */
castObjects[i] = static_cast<Object<Transformation>*>(objects[i]);
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<std::reference_wrapper<Object<Transformation>>> castObjects;
castObjects.reserve(objects.size());
/** @todo Ensure this doesn't crash, somehow */
for(auto o: objects) castObjects.push_back(static_cast<Object<Transformation>&>(o.get()));
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<MatrixType> transformationMatrices(transformations.size());
for(std::size_t i = 0; i != objects.size(); ++i)
@ -183,6 +208,19 @@ template<class Transformation> auto Object<Transformation>::transformationMatric
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
@ -197,7 +235,7 @@ Then for all joints their transformation (relative to parent joint) is
computed and recursively concatenated together. Resulting transformations for
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>{});
/* 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
from them */
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
with different counter */
if(objects[i]->counter != 0xFFFFu) continue;
if(objects[i].get().counter != 0xFFFFu) continue;
objects[i]->counter = UnsignedShort(i);
objects[i]->flags |= Flag::Joint;
objects[i].get().counter = UnsignedShort(i);
objects[i].get().flags |= Flag::Joint;
}
std::vector<Object<Transformation>*> jointObjects(objects);
std::vector<std::reference_wrapper<Object<Transformation>>> jointObjects(objects);
/* Scene object */
const Scene<Transformation>* scene = this->scene();
@ -227,19 +263,19 @@ template<class Transformation> std::vector<typename Transformation::DataType> Ob
auto it = objects.begin();
while(!objects.empty()) {
/* Already visited, remove and continue to next (duplicate occurence) */
if((*it)->flags & Flag::Visited) {
if(it->get().flags & Flag::Visited) {
it = objects.erase(it);
continue;
}
/* 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(!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);
/* 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);
parent->counter = UnsignedShort(jointObjects.size());
parent->flags |= Flag::Joint;
jointObjects.push_back(parent);
jointObjects.push_back(*parent);
}
/* Else go up the hierarchy */
} else *it = parent;
} else *it = *parent;
/* Cycle if reached end */
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
of duplicate object */
for(std::size_t i = 0; i != objectCount; ++i) {
if(jointObjects[i]->counter != i)
jointTransformations[i] = jointTransformations[jointObjects[i]->counter];
if(jointObjects[i].get().counter != i)
jointTransformations[i] = jointTransformations[jointObjects[i].get().counter];
}
/* All visited marks are now cleaned, clean joint marks and counters */
for(auto i: jointObjects) {
/* All not-already cleaned objects (...duplicate occurences) should
have joint mark */
CORRADE_INTERNAL_ASSERT(i->counter == 0xFFFFu || i->flags & Flag::Joint);
i->flags &= ~Flag::Joint;
i->counter = 0xFFFFu;
CORRADE_INTERNAL_ASSERT(i.get().counter == 0xFFFFu || i.get().flags & Flag::Joint);
i.get().flags &= ~Flag::Joint;
i.get().counter = 0xFFFFu;
}
/* 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;
}
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 {
Object<Transformation>* o = jointObjects[joint];
#ifdef MAGNUM_BUILD_DEPRECATED
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
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 */
jointTransformations[joint] = o->transformation();
jointTransformations[joint] = o.get().transformation();
/* Go up until next joint or root */
for(;;) {
/* Clean visited mark */
CORRADE_INTERNAL_ASSERT(o->flags & Flag::Visited);
o->flags &= ~Flag::Visited;
CORRADE_INTERNAL_ASSERT(o.get().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 */
if(!parent) {
CORRADE_INTERNAL_ASSERT(o->isScene());
CORRADE_INTERNAL_ASSERT(o.get().isScene());
return (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 {
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) {
std::vector<Object<Transformation>*> castObjects(objects.size());
for(std::size_t i = 0; i != objects.size(); ++i)
/** @todo Ensure this doesn't crash, somehow */
castObjects[i] = static_cast<Object<Transformation>*>(objects[i]);
template<class Transformation> void Object<Transformation>::doSetClean(const std::vector<std::reference_wrapper<AbstractObject<Transformation::Dimensions, typename Transformation::Type>>>& objects) {
std::vector<std::reference_wrapper<Object<Transformation>>> castObjects;
castObjects.reserve(objects.size());
/** @todo Ensure this doesn't crash, somehow */
for(auto o: objects) castObjects.push_back(static_cast<Object<Transformation>&>(o.get()));
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 */
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());
/* 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
they aren't added more than once */
for(std::size_t end = objects.size(), i = 0; i != end; ++i) {
Object<Transformation>* o = objects[i];
o->flags |= Flag::Visited;
Object<Transformation>& o = objects[i];
o.flags |= Flag::Visited;
Object<Transformation>* parent = o->parent();
Object<Transformation>* parent = o.parent();
while(parent && !(parent->flags & Flag::Visited) && parent->isDirty()) {
objects.push_back(parent);
objects.push_back(*parent);
parent = parent->parent();
}
}
/* Cleanup all marks */
for(auto o: objects) o->flags &= ~Flag::Visited;
for(auto o: objects) o.get().flags &= ~Flag::Visited;
/* 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", );
std::vector<typename Transformation::DataType> transformations(scene->transformations(objects));
/* Go through all objects and clean them */
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 */
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]);
CORRADE_ASSERT(!objects[i]->isDirty(), "SceneGraph::Object::setClean(): original implementation was not called", );
#ifdef MAGNUM_BUILD_DEPRECATED
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 */
CachedTransformations cached;
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();
/* Empty list */
CORRADE_COMPARE(s.transformations(std::vector<Object3D*>(), initial), std::vector<Matrix4>());
CORRADE_COMPARE(s.transformations({}, initial), std::vector<Matrix4>());
/* Scene alone */
CORRADE_COMPARE(s.transformations({&s}, initial), std::vector<Matrix4>{initial});
CORRADE_COMPARE(s.transformations({s}, initial), std::vector<Matrix4>{initial});
/* One object */
Object3D first(&s);
first.rotateZ(Deg(30.0f));
Object3D second(&first);
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))
});
/* 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
}));
@ -197,13 +197,13 @@ void ObjectTest::transformations() {
/* Two objects with foreign joint */
Object3D third(&first);
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::translation(Vector3::xAxis(5.0f)),
}));
/* 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::translation(Vector3::xAxis(5.0f)),
initial*Matrix4::rotationZ(Deg(30.0f)),
@ -222,7 +222,7 @@ void ObjectTest::transformationsRelative() {
third.translate(Vector3::xAxis(5.0f));
/* 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))
});
@ -234,7 +234,7 @@ void ObjectTest::transformationsRelative() {
orphan1.scale(Vector3::xScale(3.0f));
Object3D orphan2(&orphanParent);
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))
});
}
@ -246,7 +246,7 @@ void ObjectTest::transformationsOrphan() {
/* Transformation of objects not part of the same scene */
Scene3D s;
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");
}
@ -262,7 +262,7 @@ void ObjectTest::transformationsDuplicate() {
Matrix4 firstExpected = Matrix4::rotationZ(Deg(30.0f));
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));
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
}));
}
@ -392,7 +392,7 @@ void ObjectTest::setCleanListHierarchy() {
childThree->rotate(Deg(90.0f), Vector3::yAxis());
/* 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(!childOne->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 */
childOne->cleanedAbsoluteTransformation = Matrix4(Matrix4::Zero);
CORRADE_VERIFY(!childOne->isDirty());
Scene3D::setClean(std::vector<Object3D*>{childOne});
Scene3D::setClean({*childOne});
CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Matrix4(Matrix4::Zero));
/* If any object in the hierarchy is already clean, it shouldn't clean it again */
CORRADE_VERIFY(!childOne->isDirty());
childTwo->setDirty();
Scene3D::setClean(std::vector<Object3D*>{childTwo});
Scene3D::setClean({*childTwo});
CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Matrix4(Matrix4::Zero));
}
void ObjectTest::setCleanListBulk() {
/* Verify it doesn't crash when passed empty list */
Object3D::setClean(std::vector<Object3D*>());
Object3D::setClean({});
Scene3D scene;
Object3D a(&scene);
@ -429,7 +429,6 @@ void ObjectTest::setCleanListBulk() {
CachingObject d(&c);
d.scale(Vector3(-2.0f));
Object3D e(&scene);
std::vector<Object3D*> cleanAll{&a, &b, &c, &d, &e};
/* All objects should be cleaned */
CORRADE_VERIFY(a.isDirty());
@ -437,7 +436,7 @@ void ObjectTest::setCleanListBulk() {
CORRADE_VERIFY(c.isDirty());
CORRADE_VERIFY(d.isDirty());
CORRADE_VERIFY(e.isDirty());
Object3D::setClean(cleanAll);
Object3D::setClean({a, b, c, d, e});
CORRADE_VERIFY(!a.isDirty());
CORRADE_VERIFY(!b.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() {
/* Clean all objects */
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)
objects[i] = &(*this)[i].object();
objects.push_back((*this)[i].object());
SceneGraph::AbstractObject<dimensions, Float>::setClean(objects);
}

Loading…
Cancel
Save