1 #ifndef OPENMW_COMPONENTS_NIFOSG_PARTICLE_H
2 #define OPENMW_COMPONENTS_NIFOSG_PARTICLE_H
3 
4 #include <osgParticle/Particle>
5 #include <osgParticle/Shooter>
6 #include <osgParticle/Operator>
7 #include <osgParticle/Emitter>
8 #include <osgParticle/Placer>
9 #include <osgParticle/Counter>
10 
11 #include <osg/NodeCallback>
12 
13 #include "controller.hpp" // ValueInterpolator
14 
15 namespace Nif
16 {
17     struct NiGravity;
18     struct NiPlanarCollider;
19     struct NiSphericalCollider;
20     struct NiColorData;
21 }
22 
23 namespace NifOsg
24 {
25 
26     // Subclass ParticleSystem to support a limit on the number of active particles.
27     class ParticleSystem : public osgParticle::ParticleSystem
28     {
29     public:
30         ParticleSystem();
31         ParticleSystem(const ParticleSystem& copy, const osg::CopyOp& copyop);
32 
33         META_Object(NifOsg, ParticleSystem)
34 
35         osgParticle::Particle* createParticle(const osgParticle::Particle *ptemplate) override;
36 
37         void setQuota(int quota);
38 
39         void drawImplementation(osg::RenderInfo& renderInfo) const override;
40 
41     private:
42         int mQuota;
43         osg::ref_ptr<osg::Vec3Array> mNormalArray;
44     };
45 
46     // HACK: Particle doesn't allow setting the initial age, but we need this for loading the particle system state
47     class ParticleAgeSetter : public osgParticle::Particle
48     {
49     public:
ParticleAgeSetter(float age)50         ParticleAgeSetter(float age)
51             : Particle()
52         {
53             _t0 = age;
54         }
55     };
56 
57     // Node callback used to set the inverse of the parent's world matrix on the MatrixTransform
58     // that the callback is attached to. Used for certain particle systems,
59     // so that the particles do not move with the node they are attached to.
60     class InverseWorldMatrix : public osg::NodeCallback
61     {
62     public:
InverseWorldMatrix()63         InverseWorldMatrix()
64         {
65         }
InverseWorldMatrix(const InverseWorldMatrix & copy,const osg::CopyOp & op)66         InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op)
67             : osg::Object(), osg::NodeCallback()
68         {
69         }
70 
71         META_Object(NifOsg, InverseWorldMatrix)
72 
73         void operator()(osg::Node* node, osg::NodeVisitor* nv) override;
74     };
75 
76     class ParticleShooter : public osgParticle::Shooter
77     {
78     public:
79         ParticleShooter(float minSpeed, float maxSpeed, float horizontalDir, float horizontalAngle, float verticalDir, float verticalAngle,
80                         float lifetime, float lifetimeRandom);
81         ParticleShooter();
82         ParticleShooter(const ParticleShooter& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
83 
84         ParticleShooter& operator=(const ParticleShooter&) = delete;
85 
86         META_Object(NifOsg, ParticleShooter)
87 
88         void shoot(osgParticle::Particle* particle) const override;
89 
90     private:
91         float mMinSpeed;
92         float mMaxSpeed;
93         float mHorizontalDir;
94         float mHorizontalAngle;
95         float mVerticalDir;
96         float mVerticalAngle;
97         float mLifetime;
98         float mLifetimeRandom;
99     };
100 
101     class PlanarCollider : public osgParticle::Operator
102     {
103     public:
104         PlanarCollider(const Nif::NiPlanarCollider* collider);
105         PlanarCollider();
106         PlanarCollider(const PlanarCollider& copy, const osg::CopyOp& copyop);
107 
108         META_Object(NifOsg, PlanarCollider)
109 
110         void beginOperate(osgParticle::Program* program) override;
111         void operate(osgParticle::Particle* particle, double dt) override;
112 
113     private:
114         float mBounceFactor;
115         osg::Plane mPlane;
116         osg::Plane mPlaneInParticleSpace;
117     };
118 
119     class SphericalCollider : public osgParticle::Operator
120     {
121     public:
122         SphericalCollider(const Nif::NiSphericalCollider* collider);
123         SphericalCollider();
124         SphericalCollider(const SphericalCollider& copy, const osg::CopyOp& copyop);
125 
126         META_Object(NifOsg, SphericalCollider)
127 
128         void beginOperate(osgParticle::Program* program) override;
129         void operate(osgParticle::Particle* particle, double dt) override;
130     private:
131         float mBounceFactor;
132         osg::BoundingSphere mSphere;
133         osg::BoundingSphere mSphereInParticleSpace;
134     };
135 
136     class GrowFadeAffector : public osgParticle::Operator
137     {
138     public:
139         GrowFadeAffector(float growTime, float fadeTime);
140         GrowFadeAffector();
141         GrowFadeAffector(const GrowFadeAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
142 
143         GrowFadeAffector& operator=(const GrowFadeAffector&) = delete;
144 
145         META_Object(NifOsg, GrowFadeAffector)
146 
147         void beginOperate(osgParticle::Program* program) override;
148         void operate(osgParticle::Particle* particle, double dt) override;
149 
150     private:
151         float mGrowTime;
152         float mFadeTime;
153 
154         float mCachedDefaultSize;
155     };
156 
157     class ParticleColorAffector : public osgParticle::Operator
158     {
159     public:
160         ParticleColorAffector(const Nif::NiColorData* clrdata);
161         ParticleColorAffector();
162         ParticleColorAffector(const ParticleColorAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
163 
164         ParticleColorAffector& operator=(const ParticleColorAffector&) = delete;
165 
166         META_Object(NifOsg, ParticleColorAffector)
167 
168         void operate(osgParticle::Particle* particle, double dt) override;
169 
170     private:
171         Vec4Interpolator mData;
172     };
173 
174     class GravityAffector : public osgParticle::Operator
175     {
176     public:
177         GravityAffector(const Nif::NiGravity* gravity);
178         GravityAffector();
179         GravityAffector(const GravityAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
180 
181         GravityAffector& operator=(const GravityAffector&) = delete;
182 
183         META_Object(NifOsg, GravityAffector)
184 
185         void operate(osgParticle::Particle* particle, double dt) override;
186         void beginOperate(osgParticle::Program *) override ;
187 
188     private:
189         float mForce;
190         enum ForceType {
191             Type_Wind,
192             Type_Point
193         };
194         ForceType mType;
195         osg::Vec3f mPosition;
196         osg::Vec3f mDirection;
197         float mDecay;
198         osg::Vec3f mCachedWorldPosition;
199         osg::Vec3f mCachedWorldDirection;
200     };
201 
202     // NodeVisitor to find a Group node with the given record index, stored in the node's user data container.
203     // Alternatively, returns the node's parent Group if that node is not a Group (i.e. a leaf node).
204     class FindGroupByRecIndex : public osg::NodeVisitor
205     {
206     public:
207         FindGroupByRecIndex(unsigned int recIndex);
208 
209         void apply(osg::Node &node) override;
210 
211         // Technically not required as the default implementation would trickle down to apply(Node&) anyway,
212         // but we'll shortcut instead to avoid the chain of virtual function calls
213         void apply(osg::MatrixTransform& node) override;
214         void apply(osg::Geometry& node) override;
215 
216         void applyNode(osg::Node& searchNode);
217 
218         osg::Group* mFound;
219         osg::NodePath mFoundPath;
220     private:
221         unsigned int mRecIndex;
222     };
223 
224     // Subclass emitter to support randomly choosing one of the child node's transforms for the emit position of new particles.
225     class Emitter : public osgParticle::Emitter
226     {
227     public:
228         Emitter(const std::vector<int>& targets);
229         Emitter();
230         Emitter(const Emitter& copy, const osg::CopyOp& copyop);
231 
232         META_Object(NifOsg, Emitter)
233 
234         void emitParticles(double dt) override;
235 
236         void setShooter(osgParticle::Shooter* shooter);
237         void setPlacer(osgParticle::Placer* placer);
238         void setCounter(osgParticle::Counter* counter);
239 
240     private:
241         // NIF Record indices
242         std::vector<int> mTargets;
243 
244         osg::ref_ptr<osgParticle::Placer> mPlacer;
245         osg::ref_ptr<osgParticle::Shooter> mShooter;
246         osg::ref_ptr<osgParticle::Counter> mCounter;
247     };
248 
249 }
250 
251 #endif
252