Files
OpenSceneGraph/src/osgParticle/ConnectedParticleSystem.cpp
Robert Osfield 1e508d432b Added SmokeTrailEffect which renders created particles as single quad or line
strip, in the case of the quad strip the strip is aligned to the be orthogonal with
the eye point.
2005-10-12 18:42:36 +00:00

221 lines
7.9 KiB
C++

/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 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.
*/
#include <osg/Notify>
#include <osg/CullingSet>
#include <osg/io_utils>
#include <osgParticle/ConnectedParticleSystem>
using namespace osgParticle;
ConnectedParticleSystem::ConnectedParticleSystem():
_startParticle(Particle::INVALID_INDEX),
_lastParticleCreated(Particle::INVALID_INDEX)
{
}
ConnectedParticleSystem::ConnectedParticleSystem(const ConnectedParticleSystem& copy, const osg::CopyOp& copyop):
ParticleSystem(copy,copyop),
_startParticle(copy._startParticle),
_lastParticleCreated(copy._lastParticleCreated)
{
}
ConnectedParticleSystem::~ConnectedParticleSystem()
{
}
Particle* ConnectedParticleSystem::createParticle(const Particle* ptemplate)
{
// osg::notify(osg::NOTICE)<<this<< " Creating particle "<<std::endl;
Particle* particle = ParticleSystem::createParticle(ptemplate);
int particleIndex = (int)(particle - &_particles[0]);
if (particle)
{
if (_startParticle == Particle::INVALID_INDEX)
{
// we are the fisrt particle create, so start the connect particle list
_startParticle = particleIndex;
}
if (_lastParticleCreated != Particle::INVALID_INDEX)
{
// osg::notify(osg::NOTICE)<<this<< " Connecting "<<_lastParticleCreated<<" to "<<particleIndex<<std::endl;
// write up the last created particle to this new particle
_particles[_lastParticleCreated].setNextParticle(particleIndex);
particle->setPreviousParticle(_lastParticleCreated);
}
// set the new particle as the last particle created.
_lastParticleCreated = particleIndex;
}
return particle;
}
void ConnectedParticleSystem::reuseParticle(int particleIndex)
{
// osg::notify(osg::NOTICE)<<this<< " Reusing particle "<<particleIndex<<std::endl;
if (particleIndex<0 || particleIndex>=(int)_particles.size()) return;
Particle* particle = &_particles[particleIndex];
int previous = particle->getPreviousParticle();
int next = particle->getNextParticle();
// update start and last entries
if (_startParticle == particleIndex)
{
_startParticle = particle->getNextParticle();
}
if (_lastParticleCreated == particleIndex)
{
_lastParticleCreated = Particle::INVALID_INDEX;
}
// join up the previous and next particles to account for
// the deletion of the this particle
if (previous != Particle::INVALID_INDEX)
{
_particles[previous].setNextParticle(next);
}
if (next != Particle::INVALID_INDEX)
{
_particles[next].setPreviousParticle(previous);
}
// reset the next and previous particle entries of this particle
particle->setPreviousParticle(Particle::INVALID_INDEX);
particle->setNextParticle(Particle::INVALID_INDEX);
// do the actual destroy of the particle
ParticleSystem::destroyParticle(particleIndex);
}
void ConnectedParticleSystem::drawImplementation(osg::State& state) const
{
const Particle* particle = (_startParticle != Particle::INVALID_INDEX) ? &_particles[_startParticle] : 0;
if (!particle) return;
osg::Vec4 pixelSizeVector = osg::CullingSet::computePixelSizeVector(*state.getCurrentViewport(),state.getProjectionMatrix(),state.getModelViewMatrix());
float unitPixelSize = fabs(1.0/(particle->getPosition()*pixelSizeVector));
float pixelSizeOfFirstParticle = unitPixelSize * particle->getCurrentSize();
float desiredGapBetweenDrawnParticles = 50.0f/unitPixelSize;
float desiredGapBetweenDrawnParticles2 = desiredGapBetweenDrawnParticles*desiredGapBetweenDrawnParticles;
unsigned int maxNumParticlesToSkip = 200;
float maxPixelError2 = osg::square(1.0f/unitPixelSize);
if (pixelSizeOfFirstParticle<1.0)
{
// draw the connected particles as a line
glBegin(GL_LINE_STRIP);
while(particle != 0)
{
const osg::Vec4& color = particle->getCurrentColor();
const osg::Vec3& pos = particle->getPosition();
glColor4f( color.r(), color.g(), color.b(), color.a() * particle->getCurrentAlpha());
glTexCoord2f( particle->getSTexCoord(), 0.5f );
glVertex3fv(pos.ptr());
const Particle* nextParticle = (particle->getNextParticle() != Particle::INVALID_INDEX) ? &_particles[particle->getNextParticle()] : 0;
if (nextParticle)
{
const osg::Vec3& nextPos = nextParticle->getPosition();
osg::Vec3 startDelta = nextPos-pos;
startDelta.normalize();
float distance2 = 0.0;
// now skip particles of required
for(unsigned int i=0;
i<maxNumParticlesToSkip && ((distance2<maxPixelError2) && (nextParticle->getNextParticle()!=Particle::INVALID_INDEX));
++i)
{
nextParticle = &_particles[nextParticle->getNextParticle()];
const osg::Vec3& nextPos = nextParticle->getPosition();
osg::Vec3 delta = nextPos-pos;
distance2 = (delta^startDelta).length2();
}
}
particle = nextParticle;
}
glEnd();
}
else
{
// draw the connected particles as a quad stripped aligned to be orthogonal to the eye
osg::Matrix eyeToLocalTransform;
eyeToLocalTransform.invert(state.getModelViewMatrix());
osg::Vec3 eyeLocal = osg::Vec3(0.0f,0.0,0.0f)*eyeToLocalTransform;
osg::Vec3 delta(0.0f,0.0f,1.0f);
glBegin(GL_QUAD_STRIP);
while(particle != 0)
{
const osg::Vec4& color = particle->getCurrentColor();
const osg::Vec3& pos = particle->getPosition();
const Particle* nextParticle = (particle->getNextParticle() != Particle::INVALID_INDEX) ? &_particles[particle->getNextParticle()] : 0;
if (nextParticle)
{
const osg::Vec3& nextPos = nextParticle->getPosition();
osg::Vec3 startDelta = nextPos-pos;
startDelta.normalize();
float distance2 = 0.0;
// now skip particles of required
for(unsigned int i=0;
i<maxNumParticlesToSkip && ((distance2<maxPixelError2) && (nextParticle->getNextParticle()!=Particle::INVALID_INDEX));
++i)
{
nextParticle = &_particles[nextParticle->getNextParticle()];
const osg::Vec3& nextPos = nextParticle->getPosition();
delta = nextPos-pos;
distance2 = (delta^startDelta).length2();
}
delta = nextPos-pos;
}
osg::Vec3 normal( delta ^ (pos-eyeLocal));
normal.normalize();
normal *= particle->getCurrentSize();
osg::Vec3 bottom(pos-normal);
osg::Vec3 top(pos+normal);
glColor4f( color.r(), color.g(), color.b(), color.a() * particle->getCurrentAlpha());
glTexCoord2f( particle->getSTexCoord(), 0.0f );
glVertex3fv(bottom.ptr());
glTexCoord2f( particle->getSTexCoord(), 1.0f );
glVertex3fv(top.ptr());
particle = nextParticle;
}
glEnd();
}
}