From 59a3a7029df0524d93fe5015113c668356da93ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 24 Jan 2013 18:52:17 +0100 Subject: [PATCH] SceneGraph: allow duplicate occurences in Object::transformations(). Fixes common case where one Object has multiple Drawable features attached (one for regular mesh and one e.g. debug renderer). --- src/SceneGraph/Object.hpp | 26 ++++++++++++++++++++++---- src/SceneGraph/Test/ObjectTest.cpp | 19 +++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/SceneGraph/Object.hpp b/src/SceneGraph/Object.hpp index 902ba3e83..e0911bbd3 100644 --- a/src/SceneGraph/Object.hpp +++ b/src/SceneGraph/Object.hpp @@ -169,7 +169,10 @@ template std::vector 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]->counter == 0xFFFFu); + /* Multiple occurences of one object in the array, don't overwrite it + with different counter */ + if(objects[i]->counter != 0xFFFFu) continue; + objects[i]->counter = i; objects[i]->flags |= Flag::Joint; } @@ -184,8 +187,13 @@ template std::vector Ob /* Mark all objects up the hierarchy as visited */ auto it = objects.begin(); while(!objects.empty()) { + /* Already visited, remove and continue to next (duplicate occurence) */ + if((*it)->flags & Flag::Visited) { + it = objects.erase(it); + continue; + } + /* Mark the object as visited */ - CORRADE_INTERNAL_ASSERT(!((*it)->flags & Flag::Visited)); (*it)->flags |= Flag::Visited; Object* parent = (*it)->parent(); @@ -224,9 +232,18 @@ template std::vector Ob for(std::size_t i = 0; i != jointTransformations.size(); ++i) computeJointTransformation(jointObjects, jointTransformations, i, initialTransformation); + /* 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]; + } + /* All visited marks are now cleaned, clean joint marks and counters */ for(auto i: jointObjects) { - CORRADE_INTERNAL_ASSERT(i->flags & Flag::Joint); + /* 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; } @@ -239,7 +256,8 @@ template std::vector Ob template typename Transformation::DataType Object::computeJointTransformation(const std::vector*>& jointObjects, std::vector& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const { Object* o = jointObjects[joint]; - /* Transformation already computed ("unvisited" by this function before), done */ + /* 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]; /* Initialize transformation */ diff --git a/src/SceneGraph/Test/ObjectTest.cpp b/src/SceneGraph/Test/ObjectTest.cpp index 0ee556cb1..322d4014b 100644 --- a/src/SceneGraph/Test/ObjectTest.cpp +++ b/src/SceneGraph/Test/ObjectTest.cpp @@ -32,6 +32,7 @@ class ObjectTest: public Corrade::TestSuite::Tester { void transformations(); void transformationsRelative(); void transformationsOrphan(); + void transformationsDuplicate(); void setClean(); void bulkSetClean(); }; @@ -60,6 +61,7 @@ ObjectTest::ObjectTest() { &ObjectTest::transformations, &ObjectTest::transformationsRelative, &ObjectTest::transformationsOrphan, + &ObjectTest::transformationsDuplicate, &ObjectTest::setClean, &ObjectTest::bulkSetClean); } @@ -210,6 +212,23 @@ void ObjectTest::transformationsOrphan() { CORRADE_COMPARE(o.str(), "SceneGraph::Object::transformations(): the objects are not part of the same tree\n"); } +void ObjectTest::transformationsDuplicate() { + Scene3D s; + Object3D first(&s); + first.rotateZ(deg(30.0f)); + Object3D second(&first); + second.scale(Vector3(0.5f)); + Object3D third(&first); + third.translate(Vector3::xAxis(5.0f)); + + 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{ + secondExpected, thirdExpected, secondExpected, firstExpected, thirdExpected + })); +} + void ObjectTest::setClean() { Scene3D scene;