|
|
|
|
@ -162,6 +162,130 @@ template<class Transformation> void Object<Transformation>::setClean() {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template<class Transformation> std::vector<typename DimensionTraits<Transformation::Dimensions, typename Transformation::Type>::MatrixType> Object<Transformation>::transformationMatrices(const std::vector<AbstractObject<Transformation::Dimensions, typename Transformation::Type>*>& objects, const typename DimensionTraits<Transformation::Dimensions, typename Transformation::Type>::MatrixType& initialTransformationMatrix) const { |
|
|
|
|
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]); |
|
|
|
|
|
|
|
|
|
std::vector<typename Transformation::DataType> transformations = this->transformations(std::move(castObjects), Transformation::fromMatrix(initialTransformationMatrix)); |
|
|
|
|
std::vector<typename DimensionTraits<Transformation::Dimensions, typename Transformation::Type>::MatrixType> transformationMatrices(transformations.size()); |
|
|
|
|
for(std::size_t i = 0; i != objects.size(); ++i) |
|
|
|
|
transformationMatrices[i] = Transformation::toMatrix(transformations[i]); |
|
|
|
|
|
|
|
|
|
return transformationMatrices; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template<class Transformation> std::vector<typename Transformation::DataType> Object<Transformation>::transformations(std::vector<Object<Transformation>*> objects, const typename Transformation::DataType& initialTransformation) const { |
|
|
|
|
/* Remember object count for later */ |
|
|
|
|
std::size_t objectCount = objects.size(); |
|
|
|
|
|
|
|
|
|
/* Create initial list of joints from original objects */ |
|
|
|
|
std::vector<Object<Transformation>*> jointObjects(objects.size()); |
|
|
|
|
for(std::size_t i = 0; i != jointObjects.size(); ++i) { |
|
|
|
|
jointObjects[i] = static_cast<Object<Transformation>*>(objects[i]); |
|
|
|
|
CORRADE_INTERNAL_ASSERT(jointObjects[i]->counter == 0xFFFFu); |
|
|
|
|
jointObjects[i]->counter = i; |
|
|
|
|
jointObjects[i]->flags |= Flag::Joint; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Scene object */ |
|
|
|
|
const Scene<Transformation>* scene = this->scene(); |
|
|
|
|
|
|
|
|
|
/* Nearest common ancestor not yet implemented - assert this is done on scene */ |
|
|
|
|
CORRADE_ASSERT(scene == this, "SceneGraph::Object::transformationMatrices(): currently implemented only for Scene", {}); |
|
|
|
|
|
|
|
|
|
/* Mark all objects up the hierarchy as visited */ |
|
|
|
|
auto it = objects.begin(); |
|
|
|
|
while(!objects.empty()) { |
|
|
|
|
/* Mark the object as visited */ |
|
|
|
|
CORRADE_INTERNAL_ASSERT(!((*it)->flags & Flag::Visited)); |
|
|
|
|
(*it)->flags |= Flag::Visited; |
|
|
|
|
|
|
|
|
|
Object<Transformation>* parent = (*it)->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", {}); |
|
|
|
|
it = objects.erase(it); |
|
|
|
|
|
|
|
|
|
/* Parent is an joint or already visited - remove current from list */ |
|
|
|
|
} else if(parent->flags & (Flag::Visited|Flag::Joint)) { |
|
|
|
|
it = objects.erase(it); |
|
|
|
|
|
|
|
|
|
/* If not already marked as joint, mark it as such and add it to
|
|
|
|
|
list of joint objects */ |
|
|
|
|
if(!(parent->flags & Flag::Joint)) { |
|
|
|
|
CORRADE_INTERNAL_ASSERT(parent->counter == 0xFFFFu); |
|
|
|
|
parent->counter = jointObjects.size(); |
|
|
|
|
parent->flags |= Flag::Joint; |
|
|
|
|
jointObjects.push_back(parent); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Else go up the hierarchy */ |
|
|
|
|
} else *it = parent; |
|
|
|
|
|
|
|
|
|
/* Cycle if reached end */ |
|
|
|
|
if(it == objects.end()) it = objects.begin(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CORRADE_ASSERT(objects.size() < 0xFFFFu, "SceneGraph::Object::transformations(): too large scene", {}); |
|
|
|
|
|
|
|
|
|
/* Array of absolute transformations in joints */ |
|
|
|
|
std::vector<typename Transformation::DataType> jointTransformations(jointObjects.size()); |
|
|
|
|
|
|
|
|
|
/* Compute transformations for all joints */ |
|
|
|
|
for(std::size_t i = 0; i != jointTransformations.size(); ++i) |
|
|
|
|
computeJointTransformation(jointObjects, jointTransformations, i, initialTransformation); |
|
|
|
|
|
|
|
|
|
/* All visited marks are now cleaned, clean joint marks and counters */ |
|
|
|
|
for(auto i: jointObjects) { |
|
|
|
|
CORRADE_INTERNAL_ASSERT(i->flags & Flag::Joint); |
|
|
|
|
i->flags &= ~Flag::Joint; |
|
|
|
|
i->counter = 0xFFFFu; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Shrink the array to contain only transformations of requested objects and return */ |
|
|
|
|
jointTransformations.resize(objectCount); |
|
|
|
|
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]; |
|
|
|
|
|
|
|
|
|
/* Transformation already computed ("unvisited" by this function before), done */ |
|
|
|
|
if(!(o->flags & Flag::Visited)) return jointTransformations[joint]; |
|
|
|
|
|
|
|
|
|
/* Initialize transformation */ |
|
|
|
|
jointTransformations[joint] = o->transformation(); |
|
|
|
|
|
|
|
|
|
/* Go up until next joint or root */ |
|
|
|
|
for(;;) { |
|
|
|
|
/* Clean visited mark */ |
|
|
|
|
CORRADE_INTERNAL_ASSERT(o->flags & Flag::Visited); |
|
|
|
|
o->flags &= ~Flag::Visited; |
|
|
|
|
|
|
|
|
|
Object<Transformation>* parent = o->parent(); |
|
|
|
|
|
|
|
|
|
/* Root object, compose transformation with initial, done */ |
|
|
|
|
if(!parent) { |
|
|
|
|
CORRADE_INTERNAL_ASSERT(o->isScene()); |
|
|
|
|
return (jointTransformations[joint] = |
|
|
|
|
Transformation::compose(initialTransformation, jointTransformations[joint])); |
|
|
|
|
|
|
|
|
|
/* Joint object, compose transformation with the joint, done */ |
|
|
|
|
} else if(parent->flags & Flag::Joint) { |
|
|
|
|
return (jointTransformations[joint] = |
|
|
|
|
Transformation::compose(computeJointTransformation(jointObjects, jointTransformations, parent->counter, initialTransformation), jointTransformations[joint])); |
|
|
|
|
|
|
|
|
|
/* Else compose transformation with parent, go up the hierarchy */ |
|
|
|
|
} else { |
|
|
|
|
jointTransformations[joint] = Transformation::compose(parent->transformation(), jointTransformations[joint]); |
|
|
|
|
o = parent; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
|
|