/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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 #include #include #include using namespace osgParticle; ConnectedParticleSystem::ConnectedParticleSystem(): _lastParticleCreated(Particle::INVALID_INDEX), _maxNumberOfParticlesToSkip(200), _startParticle(Particle::INVALID_INDEX) { } ConnectedParticleSystem::ConnectedParticleSystem(const ConnectedParticleSystem& copy, const osg::CopyOp& copyop): ParticleSystem(copy,copyop), _lastParticleCreated(copy._lastParticleCreated), _maxNumberOfParticlesToSkip(200), _startParticle(copy._startParticle) { } ConnectedParticleSystem::~ConnectedParticleSystem() { } Particle* ConnectedParticleSystem::createParticle(const Particle* ptemplate) { // osg::notify(osg::NOTICE)<setPreviousParticle(_lastParticleCreated); } // set the new particle as the last particle created. _lastParticleCreated = particleIndex; } return particle; } void ConnectedParticleSystem::reuseParticle(int particleIndex) { // osg::notify(osg::NOTICE)<=(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); // put the particle on the death stack ParticleSystem::reuseParticle(particleIndex); } void ConnectedParticleSystem::drawImplementation(osg::RenderInfo& renderInfo) const { osg::State& state = *renderInfo.getState(); ScopedReadLock lock(_readWriteMutex); 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; 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<_maxNumberOfParticlesToSkip && ((distance2getNextParticle()!=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<_maxNumberOfParticlesToSkip && ((distance2getNextParticle()!=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(); } }