1 #ifndef OPENMW_COMPONENTS_MORPHGEOMETRY_H 2 #define OPENMW_COMPONENTS_MORPHGEOMETRY_H 3 4 #include <osg/Geometry> 5 6 namespace SceneUtil 7 { 8 9 /// @brief Vertex morphing implementation. 10 /// @note The internal Geometry used for rendering is double buffered, this allows updates to be done in a thread safe way while 11 /// not compromising rendering performance. This is crucial when using osg's default threading model of DrawThreadPerContext. 12 class MorphGeometry : public osg::Drawable 13 { 14 public: 15 MorphGeometry(); 16 MorphGeometry(const MorphGeometry& copy, const osg::CopyOp& copyop); 17 18 META_Object(SceneUtil, MorphGeometry) 19 20 /// Initialize this geometry from the source geometry. 21 /// @note The source geometry will not be modified. 22 void setSourceGeometry(osg::ref_ptr<osg::Geometry> sourceGeom); 23 24 // Currently empty as this is difficult to implement. Technically we would need to compile both internal geometries in separate frames but this method is only called once. Alternatively we could compile just the static parts of the model. compileGLObjects(osg::RenderInfo & renderInfo) const25 void compileGLObjects(osg::RenderInfo& renderInfo) const override {} 26 27 class MorphTarget 28 { 29 protected: 30 osg::ref_ptr<osg::Vec3Array> mOffsets; 31 float mWeight; 32 public: MorphTarget(osg::Vec3Array * offsets,float w=1.0)33 MorphTarget(osg::Vec3Array* offsets, float w = 1.0) : mOffsets(offsets), mWeight(w) {} setWeight(float weight)34 void setWeight(float weight) { mWeight = weight; } getWeight() const35 float getWeight() const { return mWeight; } getOffsets()36 osg::Vec3Array* getOffsets() { return mOffsets.get(); } getOffsets() const37 const osg::Vec3Array* getOffsets() const { return mOffsets.get(); } setOffsets(osg::Vec3Array * offsets)38 void setOffsets(osg::Vec3Array* offsets) { mOffsets = offsets; } 39 }; 40 41 typedef std::vector<MorphTarget> MorphTargetList; 42 43 virtual void addMorphTarget( osg::Vec3Array* offsets, float weight = 1.0 ); 44 45 /** Set the MorphGeometry dirty.*/ 46 void dirty(); 47 48 /** Get the list of MorphTargets.*/ getMorphTargetList() const49 const MorphTargetList& getMorphTargetList() const { return mMorphTargets; } 50 51 /** Get the list of MorphTargets. Warning if you modify this array you will have to call dirty() */ getMorphTargetList()52 MorphTargetList& getMorphTargetList() { return mMorphTargets; } 53 54 /** Return the \c MorphTarget at position \c i.*/ getMorphTarget(unsigned int i) const55 inline const MorphTarget& getMorphTarget( unsigned int i ) const { return mMorphTargets[i]; } 56 57 /** Return the \c MorphTarget at position \c i.*/ getMorphTarget(unsigned int i)58 inline MorphTarget& getMorphTarget( unsigned int i ) { return mMorphTargets[i]; } 59 60 osg::ref_ptr<osg::Geometry> getSourceGeometry() const; 61 62 void accept(osg::NodeVisitor &nv) override; supports(const osg::PrimitiveFunctor &) const63 bool supports(const osg::PrimitiveFunctor&) const override { return true; } 64 void accept(osg::PrimitiveFunctor&) const override; 65 66 osg::BoundingBox computeBoundingBox() const override; 67 68 private: 69 void cull(osg::NodeVisitor* nv); 70 71 MorphTargetList mMorphTargets; 72 73 osg::ref_ptr<osg::Geometry> mSourceGeometry; 74 75 osg::ref_ptr<osg::Geometry> mGeometry[2]; 76 osg::Geometry* getGeometry(unsigned int frame) const; 77 78 unsigned int mLastFrameNumber; 79 bool mDirty; // Have any morph targets changed? 80 81 mutable bool mMorphedBoundingBox; 82 }; 83 84 } 85 86 #endif 87