/* -*-c++-*- * Copyright (C) 2008 Cedric Pinson * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include using namespace osgAnimation; struct computeBindMatrixVisitor : public osg::NodeVisitor { osg::Matrix _skeleton; computeBindMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} void apply(osg::Node& node) { return ;} void apply(osg::Transform& node) { Bone* bone = dynamic_cast(&node); if (!bone) return; bone->computeBindMatrix(); traverse(node); } }; struct updateMatrixVisitor : public osg::NodeVisitor { osg::Matrix _skeleton; updateMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} void apply(osg::Node& node) { return ;} void apply(osg::Transform& node) { // the idea is to traverse the skeleton or bone but to stop if other node is found Bone* bone = dynamic_cast(&node); if (!bone) return; Bone* parent = bone->getBoneParent(); if (bone->needToComputeBindMatrix()) { computeBindMatrixVisitor visitor; bone->accept(visitor); } if (parent) bone->_boneInSkeletonSpace = bone->getMatrixInBoneSpace() * bone->getBoneParent()->getMatrixInSkeletonSpace(); else bone->_boneInSkeletonSpace = bone->getMatrixInBoneSpace();// * _skeleton; traverse(node); } }; void Skeleton::UpdateCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) { if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) { Skeleton* b = dynamic_cast(node); if (b) { // apply the updater only on the root bone, The udpateMatrixVisitor will // traverse only bone and will update only bone. Then we continu on the classic // process. It's important to update Bone before other things because the update // of RigGeometry need it updateMatrixVisitor visitor; #if 0 visitor._skeleton = b->getMatrix(); int numChildren = b->getNumChildren(); for (int i = 0; i < numChildren; i++) { b->getChild(i)->accept(visitor); } #else b->accept(visitor); #endif } } traverse(node,nv); } Skeleton::Skeleton() { setUpdateCallback(new UpdateCallback()); }