/* -*-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; if (bone->needToComputeBindMatrix()) 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->setMatrixInSkeletonSpace(bone->getMatrixInBoneSpace() * bone->getBoneParent()->getMatrixInSkeletonSpace()); else bone->setMatrixInSkeletonSpace(bone->getMatrixInBoneSpace()); traverse(node); } }; void Skeleton::UpdateSkeleton::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; b->accept(visitor); } } traverse(node,nv); } Skeleton::Skeleton() { } void Skeleton::setDefaultUpdateCallback() { setUpdateCallback(new Skeleton::UpdateSkeleton ); }