Index: include/IMeshBuffer.h =================================================================== --- include/IMeshBuffer.h (revision 165) +++ include/IMeshBuffer.h (working copy) @@ -47,7 +47,10 @@ EPT_QUADS, //! Just as LINE_LOOP, but filled. - EPT_POLYGON + EPT_POLYGON, + + //! The single vertices are expanded to quad billboards on the GPU. + EPT_POINT_SPRITES }; //! Struct for holding a mesh with a single material Index: source/Irrlicht/CParticleSystemSceneNode.h =================================================================== --- source/Irrlicht/CParticleSystemSceneNode.h (revision 168) +++ source/Irrlicht/CParticleSystemSceneNode.h (working copy) @@ -16,8 +16,8 @@ { //! A particle system scene node. -/** A scene node controlling a particle System. The behavior of the particles -can be controlling by setting the right particle emitters and effectors. +/** A scene node controlling a particle system. The behavior of the particles +can be controlled by setting the right particle emitters and affectors. */ class CParticleSystemSceneNode : public IParticleSystemSceneNode { @@ -36,7 +36,7 @@ //! Sets the particle emitter, which creates the particles. virtual void setEmitter(IParticleEmitter* emitter); - //! Adds new particle effector to the particle system. + //! Adds new particle affector to the particle system. virtual void addAffector(IParticleAffector* affector); //! Removes all particle affectors in the particle system. @@ -92,8 +92,8 @@ virtual void setParticleSize( const core::dimension2d &size = core::dimension2d(5.0f, 5.0f)); - //! Sets if the particles should be global. If it is, the particles are affected by - //! the movement of the particle system scene node too, otherwise they completely + //! Sets if the particles should be global. If they are, the particles are affected by + //! the movement of the particle system scene node too, otherwise they completely //! ignore it. Default is true. virtual void setParticlesAreGlobal(bool global); @@ -114,11 +114,20 @@ core::list AffectorList; IParticleEmitter* Emitter; core::array Particles; + core::dimension2d ParticleSize; u32 LastEmitTime; - core::dimension2d ParticleSize; + s32 MaxParticles; SMeshBuffer Buffer; + enum E_PARTICLES_PRIMITIVE + { + EPP_POINT=0, + EPP_BILLBOARD, + EPP_POINTSPRITE + }; + E_PARTICLES_PRIMITIVE ParticlePrimitive; + bool ParticlesAreGlobal; }; Index: source/Irrlicht/CD3D9Driver.cpp =================================================================== --- source/Irrlicht/CD3D9Driver.cpp (revision 168) +++ source/Irrlicht/CD3D9Driver.cpp (working copy) @@ -759,8 +759,19 @@ switch (pType) { case scene::EPT_POINTS: + { + pID3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_POINTSIZE, *(DWORD*)(&Material.Thickness)); + f32 tmp=1.0f; + pID3DDevice->SetRenderState(D3DRS_POINTSIZE_MIN, *(DWORD*)(&tmp)); + pID3DDevice->SetRenderState(D3DRS_POINTSCALE_C, *(DWORD*)(&tmp)); + tmp=0.0f; + pID3DDevice->SetRenderState(D3DRS_POINTSCALE_A, *(DWORD*)(&tmp)); + pID3DDevice->SetRenderState(D3DRS_POINTSCALE_B, *(DWORD*)(&tmp)); pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_POINTLIST, 0, vertexCount, primitiveCount, indexList, D3DFMT_INDEX16, vertices, stride); + pID3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, FALSE); + } break; case scene::EPT_LINE_STRIP: pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINESTRIP, 0, vertexCount, @@ -791,6 +802,23 @@ pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, vertexCount, primitiveCount, indexList, D3DFMT_INDEX16, vertices, stride); break; + case scene::EPT_POINT_SPRITES: + { + pID3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_POINTSIZE, *(DWORD*)(&Material.Thickness)); + f32 tmp=1.0f; + pID3DDevice->SetRenderState(D3DRS_POINTSIZE_MIN, *(DWORD*)(&tmp)); + pID3DDevice->SetRenderState(D3DRS_POINTSCALE_C, *(DWORD*)(&tmp)); + tmp=0.0f; + pID3DDevice->SetRenderState(D3DRS_POINTSCALE_A, *(DWORD*)(&tmp)); + pID3DDevice->SetRenderState(D3DRS_POINTSCALE_B, *(DWORD*)(&tmp)); + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_POINTLIST, 0, vertexCount, + primitiveCount, indexList, D3DFMT_INDEX16, vertices, stride); + pID3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE); + pID3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, FALSE); + } + break; } } } Index: source/Irrlicht/COpenGLDriver.cpp =================================================================== --- source/Irrlicht/COpenGLDriver.cpp (revision 169) +++ source/Irrlicht/COpenGLDriver.cpp (working copy) @@ -291,6 +291,7 @@ glFrontFace( GL_CW ); glEnable(GL_POINT_SMOOTH); glEnable(GL_LINE_SMOOTH); + glEnable(GL_POINT_SPRITE_ARB); // create material renderers createMaterialRenderers(); @@ -361,7 +362,7 @@ os::Printer::log("OpenGL driver version is not 1.2 or better.", ELL_WARNING); const GLubyte* t = glGetString(GL_EXTENSIONS); -// os::Printer::log((const c8*)t, ELL_INFORMATION); + os::Printer::log((const c8*)t, ELL_INFORMATION); #ifdef GLU_VERSION_1_3 const GLubyte* gluVersion = gluGetString(GLU_VERSION); @@ -775,9 +776,9 @@ glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); - if (pType!=scene::EPT_POINTS) + if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (pType!=scene::EPT_POINTS) + if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) glEnableClientState(GL_NORMAL_ARRAY); glColorPointer(4, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); @@ -824,7 +825,16 @@ switch (pType) { case scene::EPT_POINTS: + { + float quadratic[] = {0.0f, 0.0f, 1.0f}; + extGlPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, quadratic); + float maxParticleSize=1.0f; + glGetFloatv(GL_POINT_SIZE_MAX_ARB, &maxParticleSize); + extGlPointParameterfARB(GL_POINT_SIZE_MAX_ARB,maxParticleSizegetTarget() - camera->getAbsolutePosition()); - view.normalize(); - - core::vector3df horizontal = camera->getUpVector().crossProduct(view); - horizontal.normalize(); - horizontal *= 0.5f * ParticleSize.Width; - - core::vector3df vertical = horizontal.crossProduct(view); - vertical.normalize(); - vertical *= 0.5f * ParticleSize.Height; - - view *= -1.0f; - // reallocate arrays, if they are too small reallocateBuffers(); // create particle vertex data - s32 idx = 0; - for (u32 i=0; igetTarget() - camera->getAbsolutePosition()); + view.normalize(); - Buffer.Vertices[0+idx].Pos = particle.pos + horizontal + vertical; - Buffer.Vertices[0+idx].Color = particle.color; - Buffer.Vertices[0+idx].Normal = view; + core::vector3df horizontal = camera->getUpVector().crossProduct(view); + horizontal.normalize(); + horizontal *= 0.5f * ParticleSize.Width; - Buffer.Vertices[1+idx].Pos = particle.pos + horizontal - vertical; - Buffer.Vertices[1+idx].Color = particle.color; - Buffer.Vertices[1+idx].Normal = view; + core::vector3df vertical = horizontal.crossProduct(view); + vertical.normalize(); + vertical *= 0.5f * ParticleSize.Height; - Buffer.Vertices[2+idx].Pos = particle.pos - horizontal - vertical; - Buffer.Vertices[2+idx].Color = particle.color; - Buffer.Vertices[2+idx].Normal = view; + view *= -1.0f; - Buffer.Vertices[3+idx].Pos = particle.pos - horizontal + vertical; - Buffer.Vertices[3+idx].Color = particle.color; - Buffer.Vertices[3+idx].Normal = view; + s32 idx = 0; + for (u32 i=0; isetMaterial(Buffer.Material); - driver->drawVertexPrimitiveList(Buffer.getVertices(), Particles.size()*4, - Buffer.getIndices(), Particles.size()*2, video::EVT_STANDARD, EPT_TRIANGLES); + switch (ParticlePrimitive) + { + case EPP_POINT: + driver->drawVertexPrimitiveList(Buffer.getVertices(), Particles.size(), + Buffer.getIndices(), Particles.size(), video::EVT_STANDARD, EPT_POINTS); + break; + case EPP_BILLBOARD: + driver->drawVertexPrimitiveList(Buffer.getVertices(), Particles.size()*4, + Buffer.getIndices(), Particles.size()*2, video::EVT_STANDARD, EPT_TRIANGLES); + break; + case EPP_POINTSPRITE: + driver->drawVertexPrimitiveList(Buffer.getVertices(), Particles.size(), + Buffer.getIndices(), Particles.size(), video::EVT_STANDARD, EPT_POINT_SPRITES); + break; + } // for debug purposes only: if (DebugDataVisible) @@ -254,7 +285,6 @@ return; } - u32 now = time; u32 timediff = time - LastEmitTime; LastEmitTime = time; @@ -263,13 +293,13 @@ if (Emitter && IsVisible) { SParticle* array = 0; - s32 newParticles = Emitter->emitt(now, timediff, array); + s32 newParticles = Emitter->emitt(time, timediff, array); if (newParticles && array) { s32 j=Particles.size(); - if (newParticles > 16250-j) - newParticles=16250-j; + if (newParticles > MaxParticles-j) + newParticles = MaxParticles-j; Particles.set_used(j+newParticles); for (s32 i=0; i::Iterator ait; - ait = AffectorList.begin(); + core::list::Iterator ait = AffectorList.begin(); while (ait != AffectorList.end()) { - (*ait)->affect(now, Particles.pointer(), Particles.size()); + (*ait)->affect(time, Particles.pointer(), Particles.size()); ++ait; } @@ -302,7 +331,7 @@ for (s32 i=0; i<(s32)Particles.size();) { - if (now > Particles[i].endTime) + if (time > Particles[i].endTime) Particles.erase(i); else { @@ -345,11 +374,31 @@ void CParticleSystemSceneNode::setParticleSize(const core::dimension2d &size) { ParticleSize = size; + Buffer.Material.Thickness=size.Width; } + void CParticleSystemSceneNode::reallocateBuffers() { + switch (ParticlePrimitive) + { + case EPP_POINT: + case EPP_POINTSPRITE: + if (Particles.size() > (u32)Buffer.getVertexCount()) + Buffer.Vertices.set_used(Particles.size()); + { + Buffer.Vertices.set_used(Particles.size()); + + // fill remaining indices + s32 i = Buffer.getIndexCount(); + Buffer.Indices.set_used(Particles.size()); + + for (; i<(s32)Particles.size(); ++i) + Buffer.Indices[i] = i; + } + break; + case EPP_BILLBOARD: if (Particles.size() * 4 > (u32)Buffer.getVertexCount() || Particles.size() * 6 > (u32)Buffer.getIndexCount()) { @@ -369,23 +418,25 @@ // fill remaining indices s32 oldIdxSize = Buffer.getIndexCount(); - s32 oldvertices = oldSize; Buffer.Indices.set_used(Particles.size() * 6); for (i=oldIdxSize; i