/* -*-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; Skeleton::Skeleton() {} Skeleton::Skeleton(const Skeleton& b, const osg::CopyOp& copyop) : Bone(b,copyop) {} Skeleton::UpdateSkeleton::UpdateSkeleton() : _needValidate(true) {} Skeleton::UpdateSkeleton::UpdateSkeleton(const UpdateSkeleton& us, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) : osg::Object(us, copyop), osg::NodeCallback(us, copyop) { _needValidate = true; } bool Skeleton::UpdateSkeleton::needToValidate() const { return _needValidate; } class ValidateSkeletonVisitor : public osg::NodeVisitor { public: ValidateSkeletonVisitor(): 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; bool foundNonBone = false; for (unsigned i = 0; i < bone->getNumChildren(); ++i) { if (dynamic_cast(bone->getChild(i))) { if (foundNonBone) { osg::notify(osg::WARN) << "Warning: a Bone was found after a non-Bone child " "within a Skeleton. Children of a Bone must be ordered " "with all child Bones first for correct update order." << std::endl; setTraversalMode(TRAVERSE_NONE); return; } } else { foundNonBone = true; } } traverse(node); } }; void Skeleton::UpdateSkeleton::operator()(osg::Node* node, osg::NodeVisitor* nv) { if (nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) { Skeleton* skeleton = dynamic_cast(node); if (_needValidate && skeleton) { ValidateSkeletonVisitor visitor; node->accept(visitor); _needValidate = false; } if (skeleton->needToComputeBindMatrix()) skeleton->computeBindMatrix(); } traverse(node,nv); } void Skeleton::setDefaultUpdateCallback() { setUpdateCallback(new Skeleton::UpdateSkeleton ); } void Skeleton::computeBindMatrix() { _invBindInSkeletonSpace = osg::Matrix::inverse(_bindInBoneSpace); _needToRecomputeBindMatrix = false; }