/* -*-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. */ #ifndef OSGANIMATION_RIGGEOMETRY_H #define OSGANIMATION_RIGGEOMETRY_H #include #include #include #include #include namespace osgAnimation { // The idea is to compute a bounding box with a factor x of the first step we compute the bounding box class OSGANIMATION_EXPORT RigComputeBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback { public: RigComputeBoundingBoxCallback(double factor = 2.0): _computed(false), _factor(factor) {} RigComputeBoundingBoxCallback(const RigComputeBoundingBoxCallback& rhs, const osg::CopyOp& copyop) : osg::Drawable::ComputeBoundingBoxCallback(rhs, copyop), _computed(false), _factor(rhs._factor) {} META_Object(osgAnimation, RigComputeBoundingBoxCallback); void reset() { _computed = false; } virtual osg::BoundingBox computeBound(const osg::Drawable& drawable) const; protected: mutable bool _computed; double _factor; mutable osg::BoundingBox _boundingBox; }; class OSGANIMATION_EXPORT RigGeometry : public osg::Geometry { public: RigGeometry(); RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); META_Object(osgAnimation, RigGeometry); void setInfluenceMap(VertexInfluenceMap* vertexInfluenceMap) { _vertexInfluenceMap = vertexInfluenceMap; } const VertexInfluenceMap* getInfluenceMap() const { return _vertexInfluenceMap.get();} VertexInfluenceMap* getInfluenceMap() { return _vertexInfluenceMap.get();} const Skeleton* getSkeleton() const; Skeleton* getSkeleton(); // will be used by the update callback to init correctly the rig mesh void setSkeleton(Skeleton*); void setNeedToComputeMatrix(bool state) { _needToComputeMatrix = state;} bool getNeedToComputeMatrix() const { return _needToComputeMatrix;} // this build the internal database about vertex influence and bones void buildVertexInfluenceSet(); const VertexInfluenceSet& getVertexInfluenceSet() const; void computeMatrixFromRootSkeleton(); // set implementation of rig method void setRigTransformImplementation(RigTransform*); RigTransform* getRigTransformImplementation(); const RigTransform* getRigTransformImplementation() const { return _rigTransformImplementation.get(); } virtual void drawImplementation(osg::RenderInfo& renderInfo) const; void update(); const osg::Matrix& getMatrixFromSkeletonToGeometry() const; const osg::Matrix& getInvMatrixFromSkeletonToGeometry() const; osg::Geometry* getSourceGeometry(); const osg::Geometry* getSourceGeometry() const; void setSourceGeometry(osg::Geometry* geometry); void copyFrom(osg::Geometry& from); struct FindNearestParentSkeleton : public osg::NodeVisitor { osg::ref_ptr _root; FindNearestParentSkeleton() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {} void apply(osg::Transform& node) { if (_root.valid()) return; _root = dynamic_cast(&node); traverse(node); } }; protected: osg::ref_ptr _geometry; osg::ref_ptr _rigTransformImplementation; VertexInfluenceSet _vertexInfluenceSet; osg::ref_ptr _vertexInfluenceMap; osg::Matrix _matrixFromSkeletonToGeometry; osg::Matrix _invMatrixFromSkeletonToGeometry; osg::observer_ptr _root; bool _needToComputeMatrix; }; struct UpdateRigGeometry : public osg::Drawable::UpdateCallback { UpdateRigGeometry() {} UpdateRigGeometry(const UpdateRigGeometry&, const osg::CopyOp&) {} META_Object(osgAnimation, UpdateRigGeometry); virtual void update(osg::NodeVisitor* nv, osg::Drawable* drw) { RigGeometry* geom = dynamic_cast(drw); if(!geom) return; if(!geom->getSkeleton() && !geom->getParents().empty()) { RigGeometry::FindNearestParentSkeleton finder; if(geom->getParents().size() > 1) osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << geom->getName() << " )" << std::endl; geom->getParents()[0]->accept(finder); if(!finder._root.valid()) { osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << geom->getName() << " )" << std::endl; return; } geom->buildVertexInfluenceSet(); geom->setSkeleton(finder._root.get()); } if(!geom->getSkeleton()) return; if(geom->getNeedToComputeMatrix()) geom->computeMatrixFromRootSkeleton(); if(geom->getSourceGeometry()) { osg::Drawable::UpdateCallback * up = dynamic_cast(geom->getSourceGeometry()->getUpdateCallback()); if(up) up->update(nv, geom->getSourceGeometry()); } geom->update(); } }; } #endif