/* -*-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_NOTICE<setPreviousParticle(_lastParticleCreated); } // set the new particle as the last particle created. _lastParticleCreated = particleIndex; } return particle; } void ConnectedParticleSystem::reuseParticle(int particleIndex) { // 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 { ScopedReadLock lock(_readWriteMutex); osg::State& state = *renderInfo.getState(); const Particle* particle = (_startParticle != Particle::INVALID_INDEX) ? &_particles[_startParticle] : 0; if (!particle) return; ArrayData& ad = _bufferedArrayData[state.getContextID()]; if (!ad.vertices.valid()) { ad.init(); ad.reserve(_particles.capacity()*2); } ad.clear(); ad.dirty(); // set up arrays and primitives ready to fill in osg::Vec3Array& vertices = *ad.vertices; osg::Vec4Array& colors = *ad.colors; osg::Vec2Array& texcoords = *ad.texcoords2; ArrayData::Primitives& primitives = ad.primitives; 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 while(particle != 0) { const osg::Vec4& color = particle->getCurrentColor(); const osg::Vec3& pos = particle->getPosition(); colors.push_back(osg::Vec4( color.r(), color.g(), color.b(), color.a() * particle->getCurrentAlpha())); texcoords.push_back(osg::Vec2( particle->getSTexCoord(), 0.5f )); vertices.push_back(pos); const Particle* nextParticle = (particle->getNextParticle() != Particle::INVALID_INDEX) ? &_particles[particle->getNextParticle()] : 0; if (nextParticle) { osg::Vec3 startDelta = nextParticle->getPosition()-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()]; osg::Vec3 delta = nextParticle->getPosition()-pos; distance2 = (delta^startDelta).length2(); } } particle = nextParticle; } primitives.push_back(ArrayData::ModeCount(GL_LINE_STRIP, vertices.size())); } 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); 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) { osg::Vec3 startDelta = nextParticle->getPosition()-pos; delta = startDelta; 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()]; delta = nextParticle->getPosition()-pos; distance2 = (delta^startDelta).length2(); } } osg::Vec3 normal( delta ^ (pos-eyeLocal)); normal.normalize(); normal *= particle->getCurrentSize(); osg::Vec3 bottom(pos-normal); osg::Vec3 top(pos+normal); colors.push_back(osg::Vec4( color.r(), color.g(), color.b(), color.a() * particle->getCurrentAlpha())); texcoords.push_back( osg::Vec2( particle->getSTexCoord(), 0.0f )); vertices.push_back(bottom); colors.push_back(colors.back()); texcoords.push_back( osg::Vec2( particle->getSTexCoord(), 1.0f )); vertices.push_back(top); particle = nextParticle; } primitives.push_back(ArrayData::ModeCount(GL_QUAD_STRIP, vertices.size())); } ad.dispatchArrays(state); ad.dispatchPrimitives(); }