diff --git a/VisualStudio/osgParticle/osgParticle.dsp b/VisualStudio/osgParticle/osgParticle.dsp index 55700269f..d87e6998f 100644 --- a/VisualStudio/osgParticle/osgParticle.dsp +++ b/VisualStudio/osgParticle/osgParticle.dsp @@ -145,6 +145,10 @@ SOURCE=..\..\include\osgParticle\AccelOperator # End Source File # Begin Source File +SOURCE=..\..\include\osgParticle\AngularAccelOperator +# End Source File +# Begin Source File + SOURCE=..\..\include\osgParticle\CenteredPlacer # End Source File # Begin Source File diff --git a/VisualStudio/osgPlugins/osgParticle/dot_osgParticle.dsp b/VisualStudio/osgPlugins/osgParticle/dot_osgParticle.dsp index 63b85d7a7..ccbc740b8 100644 --- a/VisualStudio/osgPlugins/osgParticle/dot_osgParticle.dsp +++ b/VisualStudio/osgPlugins/osgParticle/dot_osgParticle.dsp @@ -98,6 +98,10 @@ SOURCE=..\..\..\src\osgPlugins\osgParticle\IO_AccelOperator.cpp # End Source File # Begin Source File +SOURCE=..\..\..\src\osgPlugins\osgParticle\IO_AngularAccelOperator.cpp +# End Source File +# Begin Source File + SOURCE=..\..\..\src\osgPlugins\osgParticle\IO_CenteredPlacer.cpp # End Source File # Begin Source File diff --git a/include/osgParticle/AngularAccelOperator b/include/osgParticle/AngularAccelOperator new file mode 100644 index 000000000..b1518786c --- /dev/null +++ b/include/osgParticle/AngularAccelOperator @@ -0,0 +1,99 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield + * + * 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. +*/ +//osgParticle - Copyright (C) 2002 Marco Jez + +#ifndef OSGPARTICLE_ANGULARACCELOPERATOR_ +#define OSGPARTICLE_ANGULARACCELOPERATOR_ 1 + +#include +#include +#include + +#include +#include +#include + +namespace osgParticle +{ + + /** An operator class that applies a constant angular acceleration to + * the particles. + */ + class AngularAccelOperator: public Operator { + public: + inline AngularAccelOperator(); + inline AngularAccelOperator(const AngularAccelOperator ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY); + + META_Object(osgParticle, AngularAccelOperator); + + /// Get the angular acceleration vector. + inline const osg::Vec3 &getAngularAcceleration() const; + + /// Set the angular acceleration vector. + inline void setAngularAcceleration(const osg::Vec3 &v); + + /// Apply the angular acceleration to a particle. Do not call this method manually. + inline void operate(Particle *P, double dt); + + /// Perform some initializations. Do not call this method manually. + inline void beginOperate(Program *prg); + + protected: + virtual ~AngularAccelOperator() {} + AngularAccelOperator &operator=(const AngularAccelOperator &) { return *this; } + + private: + osg::Vec3 angular_accel_; + osg::Vec3 xf_angular_accel_; + }; + + // INLINE FUNCTIONS + + inline AngularAccelOperator::AngularAccelOperator() + : Operator(), angular_accel_(0, 0, 0) + { + } + + inline AngularAccelOperator::AngularAccelOperator(const AngularAccelOperator ©, const osg::CopyOp ©op) + : Operator(copy, copyop), angular_accel_(copy.angular_accel_) + { + } + + inline const osg::Vec3 &AngularAccelOperator::getAngularAcceleration() const + { + return angular_accel_; + } + + inline void AngularAccelOperator::setAngularAcceleration(const osg::Vec3 &v) + { + angular_accel_ = v; + } + + inline void AngularAccelOperator::operate(Particle *P, double dt) + { + P->addAngularVelocity(xf_angular_accel_ * dt); + } + + inline void AngularAccelOperator::beginOperate(Program *prg) + { + if (prg->getReferenceFrame() == ModularProgram::RELATIVE_TO_PARENTS) { + xf_angular_accel_ = prg->rotateLocalToWorld(angular_accel_); + } else { + xf_angular_accel_ = angular_accel_; + } + } + +} + + +#endif diff --git a/include/osgParticle/Particle b/include/osgParticle/Particle index b0ec8aa81..d9fc3b604 100644 --- a/include/osgParticle/Particle +++ b/include/osgParticle/Particle @@ -45,11 +45,16 @@ namespace osgParticle class OSGPARTICLE_EXPORT Particle { public: - enum Shape { + /** + Shape of particles. + NOTE: the LINE shape should be used in conjunction with FIXED alignment mode (see ParticleSystem). + */ + enum Shape { POINT, // uses GL_POINTS as primitive QUAD, // uses GL_QUADS as primitive QUAD_TRIANGLESTRIP, // uses GL_TRIANGLE_STRIP as primitive, but each particle needs a glBegin/glEnd pair - HEXAGON // may save some filling time, but uses more triangles + HEXAGON, // may save some filling time, but uses more triangles + LINE // uses GL_LINES to draw line segments that point to the direction of motion }; Particle(); @@ -112,6 +117,15 @@ namespace osgParticle /// Get the previous position (the position before last update). inline const osg::Vec3 &getPreviousPosition() const; + /// Get the angle vector. + inline const osg::Vec3 &getAngle() const; + + /// Get the rotational velocity vector. + inline const osg::Vec3 &getAngularVelocity() const; + + /// Get the previous angle vector. + inline const osg::Vec3 &getPreviousAngle() const; + /** Kill the particle on next update NOTE: after calling this function, the isAlive() method will still return true until the particle is updated again. @@ -164,6 +178,21 @@ namespace osgParticle /// Transform position and velocity vectors by a matrix. inline void transformPositionVelocity(const osg::Matrix &xform); + /// Set the angle vector. + inline void setAngle(const osg::Vec3 &a); + + /** + Set the angular velocity vector. + Components x, y and z are angles of rotation around the respective axis (in radians). + */ + inline void setAngularVelocity(const osg::Vec3 &v); + + /// Add a vector to the angular velocity vector. + inline void addAngularVelocity(const osg::Vec3 &dv); + + /// Transform angle and angularVelocity vectors by a matrix. + inline void transformAngleVelocity(const osg::Matrix &xform); + /** Update the particle (don't call this method manually). This method is called automatically by ParticleSystem::update(); it updates the graphical properties of the particle for the current time, @@ -206,6 +235,10 @@ namespace osgParticle osg::Vec3 position_; osg::Vec3 velocity_; + osg::Vec3 prev_angle_; + osg::Vec3 angle_; + osg::Vec3 angular_vel_; + double t0_; float current_size_; @@ -295,6 +328,21 @@ namespace osgParticle return prev_pos_; } + inline const osg::Vec3 &Particle::getAngle() const + { + return angle_; + } + + inline const osg::Vec3 &Particle::getAngularVelocity() const + { + return angular_vel_; + } + + inline const osg::Vec3 &Particle::getPreviousAngle() const + { + return prev_angle_; + } + inline void Particle::kill() { mustdie_ = true; @@ -345,9 +393,9 @@ namespace osgParticle velocity_ = v; } - inline void Particle::addVelocity(const osg::Vec3 &v) + inline void Particle::addVelocity(const osg::Vec3 &dv) { - velocity_ += v; + velocity_ += dv; } inline void Particle::transformPositionVelocity(const osg::Matrix &xform) @@ -362,6 +410,33 @@ namespace osgParticle velocity_ = p1 - position_; } + inline void Particle::setAngle(const osg::Vec3 &a) + { + angle_ = a; + } + + inline void Particle::setAngularVelocity(const osg::Vec3 &v) + { + angular_vel_ = v; + } + + inline void Particle::addAngularVelocity(const osg::Vec3 &dv) + { + angular_vel_ += dv; + } + + inline void Particle::transformAngleVelocity(const osg::Matrix &xform) + { + // this should be optimized! + + osg::Vec3 a1 = angle_ + angular_vel_; + + angle_ = xform.preMult(angle_); + a1 = xform.preMult(a1); + + angular_vel_ = a1 - angle_; + } + inline float Particle::getMass() const { return mass_; @@ -388,6 +463,9 @@ namespace osgParticle case QUAD: glBegin(GL_QUADS); break; + case LINE: + glBegin(GL_LINES); + break; default: ; } } @@ -398,6 +476,7 @@ namespace osgParticle { case POINT: case QUAD: + case LINE: glEnd(); break; default: ; diff --git a/include/osgParticle/ParticleProcessor b/include/osgParticle/ParticleProcessor index 0fb06108d..9b66abdcb 100644 --- a/include/osgParticle/ParticleProcessor +++ b/include/osgParticle/ParticleProcessor @@ -72,6 +72,36 @@ namespace osgParticle /// Set the destination particle system. inline void setParticleSystem(ParticleSystem *ps); + /// Set the endless flag of this processor. + inline void setEndless(bool type); + + /// Check whether this processor is endless. + inline bool isEndless() const; + + /// Set the lifetime of this processor. + inline void setLifeTime(double t); + + /// Get the lifetime of this processor. + inline double getLifeTime() const; + + /// Set the start time of this processor. + inline void setStartTime(double t); + + /// Get the start time of this processor. + inline double getStartTime() const; + + /// Set the current time of this processor. + inline void setCurrentTime(double t); + + /// Get the current time of this processor. + inline double getCurrentTime() const; + + /// Set the reset time of this processor. A value of 0 disables reset. + inline void setResetTime(double t); + + /// Get the reset time of this processor. + inline double getResetTime() const; + void traverse(osg::NodeVisitor &nv); /// Get the current local-to-world transformation matrix (valid only during cull traversal). @@ -110,6 +140,13 @@ namespace osgParticle osg::Matrix ltw_matrix_; osg::Matrix wtl_matrix_; osg::NodeVisitor *current_nodevisitor_; + + bool endless_; + + double lifeTime_; + double startTime_; + double currentTime_; + double resetTime_; }; // INLINE FUNCTIONS @@ -132,7 +169,10 @@ namespace osgParticle inline void ParticleProcessor::setEnabled(bool v) { enabled_ = v; - if (enabled_) t0_ = -1; + if (enabled_) { + t0_ = -1; + currentTime_ = 0; + } } inline ParticleSystem *ParticleProcessor::getParticleSystem() @@ -149,6 +189,56 @@ namespace osgParticle { ps_ = ps; } + + inline void ParticleProcessor::setEndless(bool type) + { + endless_ = type; + } + + inline bool ParticleProcessor::isEndless() const + { + return endless_; + } + + inline void ParticleProcessor::setLifeTime(double t) + { + lifeTime_ = t; + endless_ = false; + } + + inline double ParticleProcessor::getLifeTime() const + { + return lifeTime_; + } + + inline void ParticleProcessor::setStartTime(double t) + { + startTime_ = t; + } + + inline double ParticleProcessor::getStartTime() const + { + return startTime_; + } + inline void ParticleProcessor::setCurrentTime(double t) + { + currentTime_ = t; + } + + inline double ParticleProcessor::getCurrentTime() const + { + return currentTime_; + } + + inline void ParticleProcessor::setResetTime(double t) + { + resetTime_ = t; + } + + inline double ParticleProcessor::getResetTime() const + { + return resetTime_; + } inline bool ParticleProcessor::computeBound() const { diff --git a/include/osgParticle/ParticleSystem b/include/osgParticle/ParticleSystem index 3b4a33448..25c3fe67f 100644 --- a/include/osgParticle/ParticleSystem +++ b/include/osgParticle/ParticleSystem @@ -297,8 +297,8 @@ namespace osgParticle if (!bounds_computed_) { _bbox = def_bbox_; } else { - _bbox._min = bmin_; - _bbox._max = bmax_; + _bbox._min = bmin_; + _bbox._max = bmax_; } _bbox_computed = true; return true; diff --git a/include/osgParticle/RadialShooter b/include/osgParticle/RadialShooter index a4b9b790a..2cf400b3e 100644 --- a/include/osgParticle/RadialShooter +++ b/include/osgParticle/RadialShooter @@ -67,6 +67,15 @@ namespace osgParticle /// Set the range of possible values for initial speed of particles. inline void setInitialSpeedRange(float r1, float r2); + /// Get the range of possible values for initial rotational speed of particles. + inline const rangev3 &getInitialRotationalSpeedRange() const; + + /// Set the range of possible values for initial rotational speed of particles. + inline void setInitialRotationalSpeedRange(const rangev3 &r); + + /// Set the range of possible values for initial rotational speed of particles. + inline void setInitialRotationalSpeedRange(const osg::Vec3 &r1, const osg::Vec3 &r2); + /// Shoot a particle. Do not call this method manually. inline void shoot(Particle *P) const; @@ -78,6 +87,7 @@ namespace osgParticle rangef theta_range_; rangef phi_range_; rangef speed_range_; + rangev3 rot_speed_range_; }; // INLINE FUNCTIONS @@ -86,7 +96,8 @@ namespace osgParticle : Shooter(), theta_range_(0, 0.5f*osg::PI_4), phi_range_(0, 2*osg::PI), - speed_range_(10, 10) + speed_range_(10, 10), + rot_speed_range_(osg::Vec3(0,0,0), osg::Vec3(0,0,0)) { } @@ -94,7 +105,8 @@ namespace osgParticle : Shooter(copy, copyop), theta_range_(copy.theta_range_), phi_range_(copy.phi_range_), - speed_range_(copy.speed_range_) + speed_range_(copy.speed_range_), + rot_speed_range_(copy.rot_speed_range_) { } @@ -113,6 +125,11 @@ namespace osgParticle return speed_range_; } + inline const rangev3 &RadialShooter::getInitialRotationalSpeedRange() const + { + return rot_speed_range_; + } + inline void RadialShooter::setThetaRange(const rangef &r) { theta_range_ = r; @@ -146,17 +163,31 @@ namespace osgParticle speed_range_.maximum = r2; } + inline void RadialShooter::setInitialRotationalSpeedRange(const rangev3 &r) + { + rot_speed_range_ = r; + } + + inline void RadialShooter::setInitialRotationalSpeedRange(const osg::Vec3 &r1, const osg::Vec3 &r2) + { + rot_speed_range_.minimum = r1; + rot_speed_range_.maximum = r2; + } + inline void RadialShooter::shoot(Particle *P) const { float theta = theta_range_.get_random(); float phi = phi_range_.get_random(); float speed = speed_range_.get_random(); + osg::Vec3 rot_speed = rot_speed_range_.get_random(); P->setVelocity(osg::Vec3( speed * sinf(theta) * cosf(phi), speed * sinf(theta) * sinf(phi), speed * cosf(theta) )); + + P->setAngularVelocity(rot_speed); } } diff --git a/src/osgParticle/FluidFrictionOperator.cpp b/src/osgParticle/FluidFrictionOperator.cpp index 71f41512c..5fac08be7 100644 --- a/src/osgParticle/FluidFrictionOperator.cpp +++ b/src/osgParticle/FluidFrictionOperator.cpp @@ -27,7 +27,7 @@ osgParticle::FluidFrictionOperator::FluidFrictionOperator(const FluidFrictionOpe { } -void osgParticle::FluidFrictionOperator::operate(Particle *P, double) +void osgParticle::FluidFrictionOperator::operate(Particle *P, double dt) { float r = (ovr_rad_ > 0)? ovr_rad_ : P->getRadius(); osg::Vec3 v = P->getVelocity(); @@ -42,7 +42,7 @@ void osgParticle::FluidFrictionOperator::operate(Particle *P, double) } // correct unwanted velocity increments - osg::Vec3 dv = Fr * (P->getMassInv() * 0.01); + osg::Vec3 dv = Fr * P->getMassInv() * dt; float dvl = dv.length(); if (dvl > vm) { dv *= vm / dvl; diff --git a/src/osgParticle/ModularEmitter.cpp b/src/osgParticle/ModularEmitter.cpp index e654ac6f5..f9fb3a346 100644 --- a/src/osgParticle/ModularEmitter.cpp +++ b/src/osgParticle/ModularEmitter.cpp @@ -17,7 +17,7 @@ osgParticle::ModularEmitter::ModularEmitter(const ModularEmitter ©, const os { } -void osgParticle::ModularEmitter::emit(double dt) +void osgParticle::ModularEmitter::emit(double dt) { int n = counter_->numParticlesToCreate(dt); for (int i=0; i osg::PI*2) angle_.x() -= osg::PI*2; + if (angle_.x() < -osg::PI*2) angle_.x() += osg::PI*2; + if (angle_.y() > osg::PI*2) angle_.y() -= osg::PI*2; + if (angle_.y() < -osg::PI*2) angle_.y() += osg::PI*2; + if (angle_.z() > osg::PI*2) angle_.z() -= osg::PI*2; + if (angle_.z() < -osg::PI*2) angle_.z() += osg::PI*2; + return true; } @@ -85,67 +99,90 @@ void osgParticle::Particle::render(const osg::Vec3 &xpos, const osg::Vec3 &px, c current_color_.z(), current_color_.w() * current_alpha_); + osg::Matrix R; + R.makeRotate( + angle_.x(), osg::Vec3(1, 0, 0), + angle_.y(), osg::Vec3(0, 1, 0), + angle_.z(), osg::Vec3(0, 0, 1)); + osg::Vec3 p1(px * current_size_ * scale); osg::Vec3 p2(py * current_size_ * scale); switch (shape_) { case POINT: - glVertex3f(xpos.x(), xpos.y(), xpos.z()); + glVertex3f(xpos.x(), xpos.y(), xpos.z()); break; case QUAD: glTexCoord2f(0, 0); - glVertex3fv((xpos-p1-p2).ptr()); + glVertex3fv((xpos-(p1+p2)*R).ptr()); glTexCoord2f(1, 0); - glVertex3fv((xpos+p1-p2).ptr()); + glVertex3fv((xpos+(p1-p2)*R).ptr()); glTexCoord2f(1, 1); - glVertex3fv((xpos+p1+p2).ptr()); + glVertex3fv((xpos+(p1+p2)*R).ptr()); glTexCoord2f(0, 1); - glVertex3fv((xpos-p1+p2).ptr()); + glVertex3fv((xpos-(p1-p2)*R).ptr()); break; case QUAD_TRIANGLESTRIP: - // we must glBegin() and glEnd() here, because each particle is a single strip + glPushMatrix(); + glTranslatef(xpos.x(), xpos.y(), xpos.z()); + glMultMatrixf(R.ptr()); + // we must glBegin() and glEnd() here, because each particle is a single strip glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(1, 1); - glVertex3fv((xpos+p1+p2).ptr()); + glVertex3fv((p1+p2).ptr()); glTexCoord2f(0, 1); - glVertex3fv((xpos-p1+p2).ptr()); + glVertex3fv((-p1+p2).ptr()); glTexCoord2f(1, 0); - glVertex3fv((xpos+p1-p2).ptr()); + glVertex3fv((p1-p2).ptr()); glTexCoord2f(0, 0); - glVertex3fv((xpos-p1-p2).ptr()); + glVertex3fv((-p1-p2).ptr()); glEnd(); + glPopMatrix(); break; case HEXAGON: + glPushMatrix(); + glTranslatef(xpos.x(), xpos.y(), xpos.z()); + glMultMatrixf(R.ptr()); // we must glBegin() and glEnd() here, because each particle is a single fan glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0.5f, 0.5f); - glVertex3fv(xpos.ptr()); + glVertex3f(0,0,0); glTexCoord2f(hex_texcoord_x1, hex_texcoord_y1); - glVertex3fv((xpos+p1*cosPI3+p2*sinPI3).ptr()); - //glVertex3f(xpos.x() + cs * cosPI3, xpos.y() + cs * sinPI3, xpos.z()); + glVertex3fv((p1*cosPI3+p2*sinPI3).ptr()); glTexCoord2f(hex_texcoord_x2, hex_texcoord_y1); - glVertex3fv((xpos-p1*cosPI3+p2*sinPI3).ptr()); - //glVertex3f(xpos.x() - cs * cosPI3, xpos.y() + cs * sinPI3, xpos.z()); + glVertex3fv((-p1*cosPI3+p2*sinPI3).ptr()); glTexCoord2f(0, 0.5f); - glVertex3fv((xpos-p1).ptr()); - //glVertex3f(xpos.x() - cs, xpos.y(), xpos.z()); + glVertex3fv((-p1).ptr()); glTexCoord2f(hex_texcoord_x2, hex_texcoord_y2); - glVertex3fv((xpos-p1*cosPI3-p2*sinPI3).ptr()); - //glVertex3f(xpos.x() - cs * cosPI3, xpos.y() - cs * sinPI3, xpos.z()); + glVertex3fv((-p1*cosPI3-p2*sinPI3).ptr()); glTexCoord2f(hex_texcoord_x1, hex_texcoord_y2); - glVertex3fv((xpos+p1*cosPI3-p2*sinPI3).ptr()); - //glVertex3f(xpos.x() + cs * cosPI3, xpos.y() - cs * sinPI3, xpos.z()); + glVertex3fv((p1*cosPI3-p2*sinPI3).ptr()); glTexCoord2f(1, 0.5f); - glVertex3fv((xpos+p1).ptr()); - //glVertex3f(xpos.x() + cs, xpos.y(), xpos.z()); + glVertex3fv((p1).ptr()); glTexCoord2f(hex_texcoord_x1, hex_texcoord_y1); - glVertex3fv((xpos+p1*cosPI3+p2*sinPI3).ptr()); - //glVertex3f(xpos.x() + cs * cosPI3, xpos.y() + cs * sinPI3, xpos.z()); + glVertex3fv((p1*cosPI3+p2*sinPI3).ptr()); glEnd(); + glPopMatrix(); + break; + + case LINE: + { + // Get the normalized direction of the particle, to be used in the + // calculation of one of the linesegment endpoints. + float vl = velocity_.length(); + if (vl != 0) { + osg::Vec3 v = velocity_ * current_size_ * scale / vl; + + glTexCoord1f(0); + glVertex3f(xpos.x(), xpos.y(), xpos.z()); + glTexCoord1f(1); + glVertex3f(xpos.x() + v.x(), xpos.y() + v.y(), xpos.z() + v.z()); + } + } break; default: diff --git a/src/osgParticle/ParticleProcessor.cpp b/src/osgParticle/ParticleProcessor.cpp index b2f64b76d..7a6f2873c 100644 --- a/src/osgParticle/ParticleProcessor.cpp +++ b/src/osgParticle/ParticleProcessor.cpp @@ -19,7 +19,12 @@ osgParticle::ParticleProcessor::ParticleProcessor() ps_(0), need_ltw_matrix_(false), need_wtl_matrix_(false), - current_nodevisitor_(0) + current_nodevisitor_(0), + endless_(true), + lifeTime_(0.0), + startTime_(0.0), + currentTime_(0.0), + resetTime_(0.0) { setCullingActive(false); } @@ -32,65 +37,84 @@ osgParticle::ParticleProcessor::ParticleProcessor(const ParticleProcessor ©, ps_(static_cast(copyop(copy.ps_.get()))), need_ltw_matrix_(copy.need_ltw_matrix_), need_wtl_matrix_(copy.need_wtl_matrix_), - current_nodevisitor_(0) + current_nodevisitor_(0), + endless_(copy.endless_), + lifeTime_(copy.lifeTime_), + startTime_(copy.startTime_), + currentTime_(copy.currentTime_), + resetTime_(copy.resetTime_) { } void osgParticle::ParticleProcessor::traverse(osg::NodeVisitor &nv) { - // continue only if enabled - if (enabled_ ) - { - + // typecast the NodeVisitor to CullVisitor + osgUtil::CullVisitor *cv = dynamic_cast(&nv); - // typecast the NodeVisitor to CullVisitor - osgUtil::CullVisitor *cv = dynamic_cast(&nv); + // continue only if the visitor actually is a cull visitor + if (cv) { - // continue only if the visitor actually is a cull visitor - if (cv) { + // continue only if the particle system is valid + if (ps_.valid()) + { - // continue only if the particle system is valid - if (ps_.valid()) + if (nv.getFrameStamp()) { - if (nv.getFrameStamp()) - { + // retrieve the current time + double t = nv.getFrameStamp()->getReferenceTime(); - // retrieve the current time - double t = nv.getFrameStamp()->getReferenceTime(); + // reset this processor if we've reached the reset point + if ((currentTime_ >= resetTime_) && (resetTime_ > 0)) { + currentTime_ = 0; + t0_ = -1; + } - // skip if we haven't initialized t0_ yet - if (t0_ != -1) { + // skip if we haven't initialized t0_ yet + if (t0_ != -1) { - // check whether the particle system is frozen/culled - if (!ps_->isFrozen() && (ps_->getLastFrameNumber() >= (nv.getFrameStamp()->getFrameNumber() - 1) || !ps_->getFreezeOnCull())) { + // check whether the processor is alive + bool alive = false; + if (currentTime_ >= startTime_) { + if (endless_ || (currentTime_ < (startTime_ + lifeTime_))) + alive = true; + } - // initialize matrix flags - need_ltw_matrix_ = true; - need_wtl_matrix_ = true; - current_nodevisitor_ = &nv; + // update current time + currentTime_ += t - t0_; - // do some process (unimplemented in this base class) - process(t - t0_); - } + // process only if the particle system is not frozen/culled + if (alive && + enabled_ && + !ps_->isFrozen() && + (ps_->getLastFrameNumber() >= (nv.getFrameStamp()->getFrameNumber() - 1) || !ps_->getFreezeOnCull())) { + + // initialize matrix flags + need_ltw_matrix_ = true; + need_wtl_matrix_ = true; + current_nodevisitor_ = &nv; + + // do some process (unimplemented in this base class) + process(t - t0_); } - - // update t0_ - t0_ = t; - - } - else - { - osg::notify(osg::WARN) << "osgParticle::ParticleProcessor::traverse(NodeVisitor&) requires a valid FrameStamp to function, particles not updated.\n"; } - } else - { - osg::notify(osg::WARN) << "ParticleProcessor \"" << getName() << "\": invalid particle system\n"; + // update t0_ + t0_ = t; + } + else + { + osg::notify(osg::WARN) << "osgParticle::ParticleProcessor::traverse(NodeVisitor&) requires a valid FrameStamp to function, particles not updated.\n"; + } + + } else + { + osg::notify(osg::WARN) << "ParticleProcessor \"" << getName() << "\": invalid particle system\n"; } } + // call the inherited method Node::traverse(nv); } diff --git a/src/osgParticle/ParticleSystem.cpp b/src/osgParticle/ParticleSystem.cpp index bf8a51958..9beadf1ec 100644 --- a/src/osgParticle/ParticleSystem.cpp +++ b/src/osgParticle/ParticleSystem.cpp @@ -30,7 +30,7 @@ osgParticle::ParticleSystem::ParticleSystem() bounds_computed_(false), def_ptemp_(Particle()), last_frame_(0), - freeze_on_cull_(true), + freeze_on_cull_(false), detail_(1), draw_count_(0) { diff --git a/src/osgPlugins/ive/DataInputStream.cpp b/src/osgPlugins/ive/DataInputStream.cpp index 34498b79e..cf2beffa2 100644 --- a/src/osgPlugins/ive/DataInputStream.cpp +++ b/src/osgPlugins/ive/DataInputStream.cpp @@ -68,11 +68,11 @@ DataInputStream::DataInputStream(std::istream* istream){ DataInputStream::~DataInputStream(){} bool DataInputStream::readBool(){ - bool b; - _istream->read((char*)&b, BOOLSIZE); + char c; + _istream->read(&c, CHARSIZE); if (_istream->rdstate() & _istream->failbit) throw Exception("DataInputStream::readBool(): Failed to read boolean value."); - return b; + return c; } char DataInputStream::readChar(){ diff --git a/src/osgPlugins/ive/DataOutputStream.cpp b/src/osgPlugins/ive/DataOutputStream.cpp index e060a31e2..08aca0a4d 100644 --- a/src/osgPlugins/ive/DataOutputStream.cpp +++ b/src/osgPlugins/ive/DataOutputStream.cpp @@ -58,8 +58,10 @@ DataOutputStream::DataOutputStream(std::ostream * ostream){ DataOutputStream::~DataOutputStream(){} -void DataOutputStream::writeBool(bool b){ - _ostream->write((char*)&b, BOOLSIZE); +void DataOutputStream::writeBool(bool b) +{ + char c = b; + _ostream->write(&c, CHARSIZE); } void DataOutputStream::writeChar(char c){ diff --git a/src/osgPlugins/osgParticle/GNUmakefile b/src/osgPlugins/osgParticle/GNUmakefile index d8a953ca2..a6e95c292 100644 --- a/src/osgPlugins/osgParticle/GNUmakefile +++ b/src/osgPlugins/osgParticle/GNUmakefile @@ -3,6 +3,7 @@ include $(TOPDIR)/Make/makedefs CXXFILES =\ IO_AccelOperator.cpp\ + IO_AngularAccelOperator.cpp\ IO_CenteredPlacer.cpp\ IO_Emitter.cpp\ IO_FluidFrictionOperator.cpp\ diff --git a/src/osgPlugins/osgParticle/IO_AngularAccelOperator.cpp b/src/osgPlugins/osgParticle/IO_AngularAccelOperator.cpp new file mode 100644 index 000000000..5332baa24 --- /dev/null +++ b/src/osgPlugins/osgParticle/IO_AngularAccelOperator.cpp @@ -0,0 +1,48 @@ + +#include + +#include +#include +#include + +#include + +#include + +bool AngularAccelOperator_readLocalData(osg::Object &obj, osgDB::Input &fr); +bool AngularAccelOperator_writeLocalData(const osg::Object &obj, osgDB::Output &fw); + +osgDB::RegisterDotOsgWrapperProxy AngularAccelOperator_Proxy +( + new osgParticle::AngularAccelOperator, + "AngularAccelOperator", + "Object Operator AngularAccelOperator", + AngularAccelOperator_readLocalData, + AngularAccelOperator_writeLocalData +); + +bool AngularAccelOperator_readLocalData(osg::Object &obj, osgDB::Input &fr) +{ + osgParticle::AngularAccelOperator &aop = static_cast(obj); + bool itAdvanced = false; + + osg::Vec3 a; + + if (fr[0].matchWord("angularAcceleration")) { + if (fr[1].getFloat(a.x()) && fr[2].getFloat(a.y()) && fr[3].getFloat(a.z())) { + aop.setAngularAcceleration(a); + fr += 4; + itAdvanced = true; + } + } + + return itAdvanced; +} + +bool AngularAccelOperator_writeLocalData(const osg::Object &obj, osgDB::Output &fw) +{ + const osgParticle::AngularAccelOperator &aop = static_cast(obj); + osg::Vec3 a = aop.getAngularAcceleration(); + fw.indent() << "angularAcceleration " << a.x() << " " << a.y() << " " << a.z() << std::endl; + return true; +} diff --git a/src/osgPlugins/osgParticle/IO_Particle.cpp b/src/osgPlugins/osgParticle/IO_Particle.cpp index b5f800434..3aa09a76e 100644 --- a/src/osgPlugins/osgParticle/IO_Particle.cpp +++ b/src/osgPlugins/osgParticle/IO_Particle.cpp @@ -32,6 +32,8 @@ bool read_particle(osgDB::Input &fr, osgParticle::Particle &P) P.setShape(osgParticle::Particle::POINT); } else if (std::string(ptstr) == "QUAD_TRIANGLESTRIP") { P.setShape(osgParticle::Particle::QUAD_TRIANGLESTRIP); + } else if (std::string(ptstr) == "LINE") { + P.setShape(osgParticle::Particle::LINE); } else { osg::notify(osg::WARN) << "Particle reader warning: invalid shape: " << ptstr << std::endl; } @@ -87,6 +89,22 @@ bool read_particle(osgDB::Input &fr, osgParticle::Particle &P) fr += 4; itAdvanced = true; } + } + if (fr[0].matchWord("angle")) { + osg::Vec3 v; + if (fr[1].getFloat(v.x()) && fr[2].getFloat(v.y()) && fr[3].getFloat(v.z())) { + P.setAngle(v); + fr += 4; + itAdvanced = true; + } + } + if (fr[0].matchWord("angularVelocity")) { + osg::Vec3 v; + if (fr[1].getFloat(v.x()) && fr[2].getFloat(v.y()) && fr[3].getFloat(v.z())) { + P.setAngularVelocity(v); + fr += 4; + itAdvanced = true; + } } if (fr[0].matchWord("radius")) { float f; @@ -152,8 +170,9 @@ void write_particle(const osgParticle::Particle &P, osgDB::Output &fw) case osgParticle::Particle::POINT: fw << "POINT" << std::endl; break; case osgParticle::Particle::HEXAGON: fw << "HEXAGON" << std::endl; break; case osgParticle::Particle::QUAD_TRIANGLESTRIP: fw << "QUAD_TRIANGLESTRIP" << std::endl; break; - case osgParticle::Particle::QUAD: - default: fw << "QUAD" << std::endl; break; + case osgParticle::Particle::QUAD: fw << "QUAD" << std::endl; break; + case osgParticle::Particle::LINE: + default: fw << "LINE" << std::endl; break; } fw.indent() << "lifeTime " << P.getLifeTime() << std::endl; @@ -177,8 +196,16 @@ void write_particle(const osgParticle::Particle &P, osgDB::Output &fw) fw.indent() << "velocity "; fw << v.x() << " " << v.y() << " " << v.z() << std::endl; - fw.indent() << "mass " << P.getMass() << std::endl; + v = P.getAngle(); + fw.indent() << "angle "; + fw << v.x() << " " << v.y() << " " << v.z() << std::endl; + + v = P.getAngularVelocity(); + fw.indent() << "angularVelocity "; + fw << v.x() << " " << v.y() << " " << v.z() << std::endl; + fw.indent() << "radius " << P.getRadius() << std::endl; + fw.indent() << "mass " << P.getMass() << std::endl; // interpolators diff --git a/src/osgPlugins/osgParticle/IO_ParticleProcessor.cpp b/src/osgPlugins/osgParticle/IO_ParticleProcessor.cpp index 9f2e66be1..d4de419b1 100644 --- a/src/osgPlugins/osgParticle/IO_ParticleProcessor.cpp +++ b/src/osgPlugins/osgParticle/IO_ParticleProcessor.cpp @@ -63,6 +63,54 @@ bool ParticleProcessor_readLocalData(osg::Object &obj, osgDB::Input &fr) } } + if (fr[0].matchWord("endless")) { + if (fr[1].matchWord("TRUE")) { + myobj.setEndless(true); + fr += 2; + itAdvanced = true; + } else if (fr[1].matchWord("FALSE")) { + myobj.setEndless(false); + fr += 2; + itAdvanced = true; + } + } + + if (fr[0].matchWord("lifeTime")) { + float lt; + if (fr[1].getFloat(lt)) { + myobj.setLifeTime(lt); + fr += 2; + itAdvanced = true; + } + } + + if (fr[0].matchWord("startTime")) { + float st; + if (fr[1].getFloat(st)) { + myobj.setStartTime(st); + fr += 2; + itAdvanced = true; + } + } + + if (fr[0].matchWord("currentTime")) { + float ct; + if (fr[1].getFloat(ct)) { + myobj.setCurrentTime(ct); + fr += 2; + itAdvanced = true; + } + } + + if (fr[0].matchWord("resetTime")) { + float ct; + if (fr[1].getFloat(ct)) { + myobj.setResetTime(ct); + fr += 2; + itAdvanced = true; + } + } + return itAdvanced; } @@ -89,5 +137,16 @@ bool ParticleProcessor_writeLocalData(const osg::Object &obj, osgDB::Output &fw) fw << "RELATIVE_TO_PARENTS" << std::endl; } + fw.indent() << "endless "; + if (myobj.isEndless()) + fw << "TRUE" << std::endl; + else + fw << "FALSE" << std::endl; + + fw.indent() << "lifeTime " << myobj.getLifeTime() << std::endl; + fw.indent() << "startTime " << myobj.getStartTime() << std::endl; + fw.indent() << "currentTime " << myobj.getCurrentTime() << std::endl; + fw.indent() << "resetTime " << myobj.getResetTime() << std::endl; + return true; } diff --git a/src/osgPlugins/osgParticle/IO_RadialShooter.cpp b/src/osgPlugins/osgParticle/IO_RadialShooter.cpp index 1daead192..7a5538be1 100644 --- a/src/osgPlugins/osgParticle/IO_RadialShooter.cpp +++ b/src/osgPlugins/osgParticle/IO_RadialShooter.cpp @@ -49,6 +49,17 @@ bool RadialShooter_readLocalData(osg::Object &obj, osgDB::Input &fr) } } + if (fr[0].matchWord("initialRotationalSpeedRange")) { + osg::Vec3 r1; + osg::Vec3 r2; + if (fr[1].getFloat(r1.x()) && fr[2].getFloat(r1.y()) && fr[3].getFloat(r1.z()) && \ + fr[4].getFloat(r2.x()) && fr[5].getFloat(r2.y()) && fr[6].getFloat(r2.z())) { + myobj.setInitialRotationalSpeedRange(r1,r2); + fr += 7; + itAdvanced = true; + } + } + return itAdvanced; } @@ -63,6 +74,13 @@ bool RadialShooter_writeLocalData(const osg::Object &obj, osgDB::Output &fw) fw.indent() << "phiRange " << r.minimum << " " << r.maximum << std::endl; r = myobj.getInitialSpeedRange(); fw.indent() << "initialSpeedRange " << r.minimum << " " << r.maximum << std::endl; + + osgParticle::rangev3 rv = myobj.getInitialRotationalSpeedRange(); + osg::Vec3 v1 = rv.minimum; + osg::Vec3 v2 = rv.maximum; + fw.indent() << "initialRotationalSpeedRange "; + fw << v1.x() << " " << v1.y() << " " << v1.z() << " "; + fw << v2.x() << " " << v2.y() << " " << v2.z() << std::endl; return true; }