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