/* -*-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_MORPHGEOMETRY_H #define OSGANIMATION_MORPHGEOMETRY_H #include #include #include #include namespace osgAnimation { class OSGANIMATION_EXPORT MorphGeometry : public osg::Geometry { public: enum Method { NORMALIZED, RELATIVE }; class MorphTarget { protected: osg::ref_ptr _geom; float _weight; public: MorphTarget(osg::Geometry* geom, float w = 1.0) : _geom(geom), _weight(w) {} void setWeight(float weight) { _weight = weight; } float getWeight() const { return _weight; } osg::Geometry* getGeometry() { return _geom.get(); } const osg::Geometry* getGeometry() const { return _geom.get(); } void setGeometry(osg::Geometry* geom) { _geom = geom; } }; typedef std::vector MorphTargetList; MorphGeometry(); MorphGeometry(const osg::Geometry& b); MorphGeometry(const MorphGeometry& b, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); virtual osg::Object* cloneType() const { return new MorphGeometry(); } virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new MorphGeometry(*this,copyop); } virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } virtual const char* libraryName() const { return "osgAnimation"; } virtual const char* className() const { return "MorphGeometry"; } virtual void transformSoftwareMethod(); /** Set the morphing method. */ void setMethod(Method method) { _method = method; } /** Get the morphing method. */ inline Method getMethod() const { return _method; } /** Set flag for morphing normals. */ void setMorphNormals(bool morphNormals) { _morphNormals = morphNormals; } /** Get the flag for morphing normals. */ inline bool getMorphNormals() const { return _morphNormals; } /** Add a \c MorphTarget to the \c MorphGeometry. * If \c MorphTarget is not \c NULL and is not contained in the \c MorphGeometry * then increment its reference count, add it to the MorphTargets list and * dirty the bounding sphere to force it to be recomputed on the next * call to \c getBound(). * @param morphTarget The \c MorphTarget to be added to the \c MorphGeometry. * @param weight The weight to be added to the \c MorphGeometry. * @return \c true for success; \c false otherwise. */ virtual void addMorphTarget( osg::Geometry *morphTarget, float weight = 1.0 ) { _morphTargets.push_back(MorphTarget(morphTarget, weight)); _dirty = true; } virtual void removeMorphTarget( osg::Geometry *morphTarget ) { for(MorphTargetList::iterator iterator = _morphTargets.begin() ; iterator != _morphTargets.end() ; ++ iterator) { if(iterator->getGeometry() == morphTarget) { _morphTargets.erase(iterator); break; } } } virtual void removeMorphTarget( const std::string& name ) { for(MorphTargetList::iterator iterator = _morphTargets.begin() ; iterator != _morphTargets.end() ; ++ iterator) { if(iterator->getGeometry() && iterator->getGeometry()->getName() == name) { _morphTargets.erase(iterator); break; } } } void setWeight(unsigned int index, float morphWeight) { if (index < _morphTargets.size()) { _morphTargets[index].setWeight(morphWeight); dirty(); } } /** Set the MorphGeometry dirty.*/ void dirty() { _dirty = true; } /** Get the list of MorphTargets.*/ const MorphTargetList& getMorphTargetList() const { return _morphTargets; } /** Get the list of MorphTargets. Warning if you modify this array you will have to call dirty() */ MorphTargetList& getMorphTargetList() { return _morphTargets; } /** Return the \c MorphTarget at position \c i.*/ inline const MorphTarget& getMorphTarget( unsigned int i ) const { return _morphTargets[i]; } /** Return the \c MorphTarget at position \c i.*/ inline MorphTarget& getMorphTarget( unsigned int i ) { return _morphTargets[i]; } protected: /// Do we need to recalculate the morphed geometry? bool _dirty; Method _method; MorphTargetList _morphTargets; std::vector _positionSource; std::vector _normalSource; /// Do we also morph between normals? bool _morphNormals; }; class OSGANIMATION_EXPORT UpdateMorph : public AnimationUpdateCallback { public: typedef std::vector TargetNames; typedef std::map< int, osg::ref_ptr > WeightTargets; META_Object(osgAnimation, UpdateMorph); UpdateMorph(const std::string& name = ""); UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop); void addTarget(const std::string& name) { _targetNames.push_back(name); } unsigned int getNumTarget() const { return _targetNames.size(); } const std::string& getTargetName(unsigned int index) { return _targetNames[index]; } void removeTarget(const std::string& name) { TargetNames::iterator found = std::find(_targetNames.begin(), _targetNames.end(), name); if(found != _targetNames.end()) _targetNames.erase(found); } // for serialization const std::vector& getTargetNames() const { return _targetNames; } std::vector& getTargetNames() { return _targetNames; } void setTargetNames(const TargetNames& targetNames) { _targetNames.assign(targetNames.begin(), targetNames.end()); } /** Callback method called by the NodeVisitor when visiting a node.*/ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); bool needLink() const; bool link(osgAnimation::Channel* channel); int link(Animation* animation); protected: WeightTargets _weightTargets; TargetNames _targetNames; }; struct UpdateMorphGeometry : public osg::DrawableUpdateCallback { UpdateMorphGeometry() {} UpdateMorphGeometry(const UpdateMorphGeometry&, const osg::CopyOp&) {} META_Object(osgAnimation, UpdateMorphGeometry); virtual void update(osg::NodeVisitor*, osg::Drawable* drw) { MorphGeometry* geom = dynamic_cast(drw); if (!geom) return; geom->transformSoftwareMethod(); } }; } #endif