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