diff --git a/src/SceneGraph/AbstractObject.h b/src/SceneGraph/AbstractObject.h index 5335ad260..82b7514aa 100644 --- a/src/SceneGraph/AbstractObject.h +++ b/src/SceneGraph/AbstractObject.h @@ -151,10 +151,24 @@ template class AbstractObject * on all object features which have caching enabled and recursively * calls setClean() on every parent which is not already clean. If the * object is already clean, the function does nothing. + * + * See also setClean(const std::vector& objects), which cleans given + * set of objects more efficiently than when calling setClean() on + * each object individually. * @see @ref scenegraph-caching, setDirty(), isDirty() */ virtual void setClean() = 0; + /** + * @brief Clean absolute transformations of given set of objects + * + * Only dirty objects in the list are cleaned. + * @warning This function cannot check if all objects are of the same + * Object type, use typesafe Object::setClean(const std::vector& objects) when + * possible. + */ + virtual void setClean(const std::vector*>& objects) const = 0; + /*@}*/ }; diff --git a/src/SceneGraph/Object.h b/src/SceneGraph/Object.h index 0cda03b2d..005ea1687 100644 --- a/src/SceneGraph/Object.h +++ b/src/SceneGraph/Object.h @@ -78,6 +78,15 @@ template class Object: public AbstractObject*> objects); + /** * @brief Constructor * @param parent Parent object @@ -213,6 +222,8 @@ template class Object: public AbstractObject*>& jointObjects, std::vector& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const; + void setClean(const std::vector*>& objects) const override; + void setClean(const typename Transformation::DataType& absoluteTransformation); typedef Implementation::ObjectFlag Flag; diff --git a/src/SceneGraph/Object.hpp b/src/SceneGraph/Object.hpp index a663fc8bb..697af8daa 100644 --- a/src/SceneGraph/Object.hpp +++ b/src/SceneGraph/Object.hpp @@ -21,6 +21,7 @@ #include "Object.h" +#include #include #include "Scene.h" @@ -253,6 +254,33 @@ template typename Transformation::DataType Object void Object::setClean(const std::vector*>& objects) const { + std::vector*> castObjects(objects.size()); + for(std::size_t i = 0; i != objects.size(); ++i) + /** @todo Ensure this doesn't crash, somehow */ + castObjects[i] = static_cast*>(objects[i]); + + setClean(std::move(castObjects)); +} + +template void Object::setClean(std::vector*> objects) { + /* Remove all clean objects from the list */ + auto firstClean = std::remove_if(objects.begin(), objects.end(), [](Object* o) { return !o->isDirty(); }); + objects.erase(firstClean, objects.end()); + + /* No dirty objects left, done */ + if(objects.empty()) return; + + /* Compute absolute transformations */ + Scene* scene = objects[0]->scene(); + CORRADE_ASSERT(scene, "Object::setClean(): objects must be part of some scene", ); + std::vector transformations(scene->transformations(objects)); + + /* Go through all objects and clean them */ + for(std::size_t i = 0; i != objects.size(); ++i) + objects[i]->setClean(transformations[i]); +} + template void Object::setClean(const typename Transformation::DataType& absoluteTransformation) { /* "Lazy storage" for transformation matrix and inverted transformation matrix */ typedef typename AbstractFeature::CachedTransformation CachedTransformation; diff --git a/src/SceneGraph/Test/ObjectTest.cpp b/src/SceneGraph/Test/ObjectTest.cpp index 8b810bb23..2858bf604 100644 --- a/src/SceneGraph/Test/ObjectTest.cpp +++ b/src/SceneGraph/Test/ObjectTest.cpp @@ -30,12 +30,27 @@ namespace Magnum { namespace SceneGraph { namespace Test { typedef SceneGraph::Object> Object3D; typedef SceneGraph::Scene> Scene3D; +class CachingObject: public Object3D, AbstractFeature<3, GLfloat> { + public: + inline CachingObject(Object3D* parent = nullptr): Object3D(parent), AbstractFeature<3, GLfloat>(this) { + setCachedTransformations(CachedTransformation::Absolute); + } + + Matrix4 cleanedAbsoluteTransformation; + + protected: + void clean(const Matrix4& absoluteTransformation) override { + cleanedAbsoluteTransformation = absoluteTransformation; + } +}; + ObjectTest::ObjectTest() { addTests(&ObjectTest::parenting, &ObjectTest::scene, &ObjectTest::absoluteTransformation, &ObjectTest::transformations, - &ObjectTest::setClean); + &ObjectTest::setClean, + &ObjectTest::bulkSetClean); } void ObjectTest::parenting() { @@ -197,20 +212,6 @@ void ObjectTest::setClean() { } }; - class CachingObject: public Object3D, AbstractFeature<3, GLfloat> { - public: - inline CachingObject(Object3D* parent = nullptr): Object3D(parent), AbstractFeature<3, GLfloat>(this) { - setCachedTransformations(CachedTransformation::Absolute); - } - - Matrix4 cleanedAbsoluteTransformation; - - protected: - void clean(const Matrix4& absoluteTransformation) override { - cleanedAbsoluteTransformation = absoluteTransformation; - } - }; - CachingObject* childOne = new CachingObject(&scene); childOne->scale(Vector3(2.0f)); @@ -277,4 +278,36 @@ void ObjectTest::setClean() { CORRADE_VERIFY(childThree->isDirty()); } +void ObjectTest::bulkSetClean() { + /* Verify it doesn't crash when passed empty list */ + Object3D::setClean(vector()); + + Scene3D scene; + Object3D a(&scene); + Object3D b(&scene); + b.setClean(); + Object3D c(&scene); + c.translate(Vector3::zAxis(3.0f)); + CachingObject d(&c); + d.scale(Vector3(-2.0f)); + Object3D e(&scene); + vector cleanAll{&a, &b, &c, &d, &e}; + + /* All objects should be cleaned */ + CORRADE_VERIFY(a.isDirty()); + CORRADE_VERIFY(!b.isDirty()); + CORRADE_VERIFY(c.isDirty()); + CORRADE_VERIFY(d.isDirty()); + CORRADE_VERIFY(e.isDirty()); + Object3D::setClean(cleanAll); + CORRADE_VERIFY(!a.isDirty()); + CORRADE_VERIFY(!b.isDirty()); + CORRADE_VERIFY(!c.isDirty()); + CORRADE_VERIFY(!d.isDirty()); + CORRADE_VERIFY(!e.isDirty()); + + /* Verify that right transformation was passed */ + CORRADE_COMPARE(d.cleanedAbsoluteTransformation, Matrix4::translation(Vector3::zAxis(3.0f))*Matrix4::scaling(Vector3(-2.0f))); +} + }}} diff --git a/src/SceneGraph/Test/ObjectTest.h b/src/SceneGraph/Test/ObjectTest.h index 6d3860ace..7a04a1bd5 100644 --- a/src/SceneGraph/Test/ObjectTest.h +++ b/src/SceneGraph/Test/ObjectTest.h @@ -28,6 +28,7 @@ class ObjectTest: public Corrade::TestSuite::Tester { void absoluteTransformation(); void transformations(); void setClean(); + void bulkSetClean(); }; }}}