/* -*-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. * * Authors: * Cedric Pinson * Michael Platings */ #ifndef OSGANIMATION_BONE_H #define OSGANIMATION_BONE_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace osgAnimation { // A bone can't have more than one parent Bone, so sharing a part of Bone's hierarchy // makes no sense. You can share the entire hierarchy but not only a part of it. class OSGANIMATION_EXPORT Bone : public osg::Transform { public: typedef osg::ref_ptr PointerType; typedef std::map BoneMap; typedef osg::Matrix MatrixType; META_Node(osgAnimation, Bone); Bone(const Bone& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY); Bone(const std::string& name = ""); void setDefaultUpdateCallback(const std::string& name = ""); class OSGANIMATION_EXPORT UpdateBone : public AnimationUpdateCallback { protected: osg::ref_ptr _position; osg::ref_ptr _quaternion; osg::ref_ptr _scale; public: META_Object(osgAnimation, UpdateBone); UpdateBone(const UpdateBone& apc,const osg::CopyOp& copyop); UpdateBone(const std::string& name = "") : AnimationUpdateCallback (name) { setName(name); _quaternion = new osgAnimation::QuatTarget; _position = new osgAnimation::Vec3Target; _scale = new osgAnimation::Vec3Target; } void update(osgAnimation::Bone& bone) { bone.setTranslation(_position->getValue()); bone.setRotation(_quaternion->getValue()); bone.setScale(_scale->getValue()); bone.dirtyBound(); } osgAnimation::QuatTarget* getQuaternion() {return _quaternion.get();} osgAnimation::Vec3Target* getPosition() {return _position.get();} osgAnimation::Vec3Target* getScale() {return _scale.get();} bool needLink() const { // the idea is to return true if nothing is linked return !((_position->getCount() + _quaternion->getCount() + _scale->getCount()) > 3); } /** Link channel*/ bool link(osgAnimation::Channel* channel); /** Callback method called by the NodeVisitor when visiting a node.*/ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); }; virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const; virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const; Bone* getBoneParent(); const Bone* getBoneParent() const; void setTranslation(const osg::Vec3& trans) { _position = trans;} void setRotation(const osg::Quat& quat) { _rotation = quat;} void setScale(const osg::Vec3& scale) { _scale = scale;} const osg::Vec3& getTranslation() const { return _position;} const osg::Quat& getRotation() const { return _rotation;} const osg::Vec3& getScale() const { return _scale;} osg::Matrix getMatrixInBoneSpace() const { return (osg::Matrix(getRotation())) * osg::Matrix::translate(getTranslation()) * _bindInBoneSpace;} const osg::Matrix& getBindMatrixInBoneSpace() const { return _bindInBoneSpace; } const osg::Matrix& getMatrixInSkeletonSpace() const { return _boneInSkeletonSpace; } const osg::Matrix& getInvBindMatrixInSkeletonSpace() const { return _invBindInSkeletonSpace;} void setMatrixInSkeletonSpace(const osg::Matrix& matrix) { _boneInSkeletonSpace = matrix; } void setBindMatrixInBoneSpace(const osg::Matrix& matrix) { _bindInBoneSpace = matrix; _needToRecomputeBindMatrix = true; } inline bool needToComputeBindMatrix() { return _needToRecomputeBindMatrix;} virtual void computeBindMatrix(); void setNeedToComputeBindMatrix(bool state) { _needToRecomputeBindMatrix = state; } /** Add Node to Group. * If node is not NULL and is not contained in Group then increment its * reference count, add it to the child list and dirty the bounding * sphere to force it to recompute on next getBound() and return true for success. * Otherwise return false. Scene nodes can't be added as child nodes. */ virtual bool addChild( Node *child ); BoneMap getBoneMap(); protected: osg::Vec3 _position; osg::Quat _rotation; osg::Vec3 _scale; // flag to recompute bind pose bool _needToRecomputeBindMatrix; // bind data osg::Matrix _bindInBoneSpace; osg::Matrix _invBindInSkeletonSpace; // bone updated osg::Matrix _boneInSkeletonSpace; }; inline bool Bone::computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const { if (_referenceFrame==RELATIVE_RF) matrix.preMult(getMatrixInBoneSpace()); else matrix = getMatrixInBoneSpace(); return true; } inline bool Bone::computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const { if (_referenceFrame==RELATIVE_RF) matrix.postMult(osg::Matrix::inverse(getMatrixInBoneSpace())); else matrix = osg::Matrix::inverse(getMatrixInBoneSpace()); return true; } } #endif