|
From: <axl...@us...> - 2009-12-23 01:29:43
|
Revision: 633
http://hgengine.svn.sourceforge.net/hgengine/?rev=633&view=rev
Author: axlecrusher
Date: 2009-12-23 01:29:35 +0000 (Wed, 23 Dec 2009)
Log Message:
-----------
working on faster particles
Modified Paths:
--------------
Mercury2/modules/ParticleEmitter.cpp
Mercury2/modules/ParticleEmitter.h
Modified: Mercury2/modules/ParticleEmitter.cpp
===================================================================
--- Mercury2/modules/ParticleEmitter.cpp 2009-12-22 16:08:48 UTC (rev 632)
+++ Mercury2/modules/ParticleEmitter.cpp 2009-12-23 01:29:35 UTC (rev 633)
@@ -2,23 +2,28 @@
#include <Shader.h>
#include <GLHeaders.h>
+#include <MercuryVBO.h>
+#include <Texture.h>
+
//REGISTER_NODE_TYPE(ParticleBase);
REGISTER_NODE_TYPE(ParticleEmitter);
+#define BUFFER_OFFSET(i) ((char*)NULL + (i))
ParticleBase::ParticleBase()
- :m_nextParticle(NULL), m_age(0), m_lifespan(0)
+ :m_nextParticle(NULL), m_age(0), m_lifespan(0), m_particleVobData(NULL)
{
}
ParticleBase::~ParticleBase()
{
+ m_particleVobData = NULL;
// m_children.clear();
}
void ParticleBase::Init()
{
- base::Init();
+// base::Init();
m_age = 0;
// m_lifespan = (rand()%5000)/1000.f;
// LOG.Write("init particle");
@@ -26,20 +31,26 @@
void ParticleBase::Update(float dTime)
{
- base::Update(dTime);
+// base::Update(dTime);
m_age += dTime;
- if (m_age >= m_lifespan) m_emitter->DeactivateParticle(this);
+ WriteAgeToVBO();
+
+ if (m_age >= m_lifespan)
+ {
+ m_emitter->DeactivateParticle(this);
+ Deactivate();
+ }
}
-
+/*
void ParticleBase::RecursiveRender()
{
ShaderAttribute sa;
sa.type = ShaderAttribute::TYPE_FLOATV4;
sa.value.fFloatV4[0] = m_age;
sa.value.fFloatV4[1] = m_lifespan;
- sa.value.fFloatV4[2] = m_seed1;
- sa.value.fFloatV4[3] = m_seed2;
+ sa.value.fFloatV4[2] = m_rand1;
+ sa.value.fFloatV4[3] = m_rand2;
Shader::SetAttribute("HG_ParticleTime", sa);
GLCALL( glPushAttrib(GL_ENABLE_BIT|GL_DEPTH_BUFFER_BIT) );
@@ -50,6 +61,89 @@
GLCALL( glPopAttrib() );
}
+*/
+void ParticleBase::WriteAgeToVBO()
+{
+ m_emitter->SetDirtyVBO();
+ for (uint8_t i = 0; i < 4; ++i)
+ WriteFloatToVertices(m_age,i,3);
+}
+
+void ParticleBase::WriteLifespanToVBO()
+{
+ m_emitter->SetDirtyVBO();
+ for (uint8_t i = 0; i < 4; ++i)
+ WriteFloatToVertices(m_lifespan,i,4);
+}
+
+void ParticleBase::WriteRand1ToVBO()
+{
+ m_emitter->SetDirtyVBO();
+ for (uint8_t i = 0; i < 4; ++i)
+ WriteFloatToVertices(m_rand1,i,5);
+}
+
+void ParticleBase::WriteRand2ToVBO()
+{
+ m_emitter->SetDirtyVBO();
+ for (uint8_t i = 0; i < 4; ++i)
+ WriteFloatToVertices(m_rand2,i,6);
+}
+
+void ParticleBase::Activate()
+{
+ uint8_t i = 0;
+
+ //upper left
+ m_particleVobData[i++] = -0.5; m_particleVobData[i++] = 0.5; m_particleVobData[i++] = 0;
+ i+=4; m_particleVobData[i++] = 1; m_particleVobData[i++] = 0; //skip color data and set U,V
+
+ //lower left
+ m_particleVobData[i++] = -0.5; m_particleVobData[i++] = -0.5; m_particleVobData[i++] = 0;
+ i+=4; m_particleVobData[i++] = 0; m_particleVobData[i++] = 0; //skip color data and set U,V
+
+ //lower right
+ m_particleVobData[i++] = 0.5; m_particleVobData[i++] = -0.5; m_particleVobData[i++] = 0;
+ i+=4; m_particleVobData[i++] = 0; m_particleVobData[i++] = 1; //skip color data and set U,V
+
+ //upper right
+ m_particleVobData[i++] = 0.5; m_particleVobData[i++] = 0.5; m_particleVobData[i++] = 0;
+ i+=4; m_particleVobData[i++] = 1; m_particleVobData[i++] = 1; //skip color data and set U,V
+
+/* for (uint8_t i = 0; i < 4; ++i)
+ {
+ WriteFloatToVertices(0,i,0);
+ WriteFloatToVertices(0,i,1);
+ WriteFloatToVertices(0,i,2);
+ }
+*/
+ m_emitter->SetDirtyVBO();
+}
+
+void ParticleBase::Deactivate()
+{
+ m_emitter->SetDirtyVBO();
+ for (uint8_t i = 0; i < 4; ++i)
+ {
+ WriteFloatToVertices(0,i,0);
+ WriteFloatToVertices(0,i,1);
+ WriteFloatToVertices(0,i,2);
+ }
+}
+
+void ParticleBase::WriteFloatToVertices(float v, uint8_t vertexIndex, uint8_t offset)
+{
+ *(m_particleVobData+((STRIDE*vertexIndex)+offset)) = v;
+}
+
+void ParticleBase::WriteToVBO()
+{
+ WriteAgeToVBO();
+ WriteLifespanToVBO();
+ WriteRand1ToVBO();
+ WriteRand2ToVBO();
+}
+
/*
void ParticleBase::Activate()
{
@@ -67,7 +161,8 @@
ParticleEmitter::ParticleEmitter()
:m_maxParticles(50), m_age(0), m_emitDelay(0.01), m_lifespan(0),
m_particlesEmitted(0), m_particleMinLife(0.01), m_particleMaxLife(5),
- m_inactiveParticles(NULL), m_particles(NULL), GenerateParticlesClbk(NULL)
+ m_inactiveParticles(NULL), m_particles(NULL), GenerateParticlesClbk(NULL),
+ m_bufferID(0), m_dirtyVBO(false)
{
Init();
}
@@ -77,6 +172,8 @@
{
DestroyParticles();
+ if (m_bufferID > 0) { GLCALL( glDeleteBuffersARB(1, &m_bufferID) ); }
+
SAFE_DELETE(GenerateParticlesClbk);
// SAFE_DELETE(m_masterParticle);
}
@@ -86,18 +183,15 @@
{
MercuryNode::Init();
DestroyParticles();
-
- if (GenerateParticlesClbk) m_particles = (*GenerateParticlesClbk)(m_maxParticles);
- m_particles = new ParticleBase[m_maxParticles];
- m_inactiveParticles = m_particles;
- FillUnusedParticleList(m_particles, 0);
+
+ SetMaxParticleCount(m_maxParticles);
}
void ParticleEmitter::DestroyParticles()
{
- for (uint32_t i = 0; (i < m_maxParticles) && m_particles; ++i)
- RemoveChild(m_particles+i);
+/// for (uint32_t i = 0; (i < m_maxParticles) && m_particles; ++i)
+// RemoveChild(m_particles+i);
SAFE_DELETE_ARRAY(m_particles); //do we need to destroy each element????
}
@@ -123,22 +217,23 @@
m_inactiveParticles = p->m_nextParticle;
p->m_nextParticle = NULL;
p->Init();
+ p->Activate();
p->m_lifespan = m_particleMinLife;
p->m_lifespan += (rand()%(int(m_particleMaxLife*1000) - int(m_particleMinLife*1000)))/1000.0f;
- p->m_seed1 = rand()%100000;
- p->m_seed2 = rand()%100000;
+ p->m_rand1 = rand()%100000;
+ p->m_rand2 = rand()%100000;
// +((rand()%((m_particleMaxLife*1000)-(m_particleMinLife*1000)))/1000.0f);
- AddChild(p);
+// AddChild(p);
}
}
void ParticleEmitter::DeactivateParticle(ParticleBase* p)
{
// LOG.Write("Deactivate");
- RemoveChild(p);
+// RemoveChild(p);
if (!m_inactiveParticles)
{
m_inactiveParticles = p;
@@ -165,7 +260,7 @@
void ParticleEmitter::LoadFromXML(const XMLNode& node)
{
base::LoadFromXML(node);
-
+/*
XMLNode particleXML;
for (XMLNode n = node.Child(); n.IsValid(); n=n.NextNode())
if (n.Name() == "particle")
@@ -173,9 +268,82 @@
for (uint32_t i = 0; (i < m_maxParticles) && m_particles; ++i)
m_particles[i].LoadFromXML(particleXML);
+ */
}
+void ParticleEmitter::SetMaxParticleCount(uint16_t count)
+{
+ //3 floats for position
+ //1 age, 1 lifespan, 2 random
+ //7 floats total per particle
+ m_maxParticles = count;
+ m_vertexData.Allocate(m_maxParticles*ParticleBase::STRIDE*4);
+
+ SAFE_DELETE_ARRAY(m_particles);
+// if (GenerateParticlesClbk) m_particles = (*GenerateParticlesClbk)(m_maxParticles);
+ m_particles = new ParticleBase[m_maxParticles];
+ m_inactiveParticles = m_particles;
+ InitNewParticles(m_particles, 0, ParticleBase::STRIDE*4, m_vertexData.Buffer());
+}
+
+void ParticleEmitter::InitNewParticles(ParticleBase* p, uint32_t i, uint16_t vobStep, float* vob)
+{
+ if (p)
+ {
+ p->m_emitter = this;
+ p->m_particleVobData = vob;
+ p->Deactivate();
+ ++i;
+ if (i<m_maxParticles) p->m_nextParticle = m_particles+i;
+ InitNewParticles(p->m_nextParticle, i, vobStep, vob+vobStep);
+ }
+}
+
+void ParticleEmitter::Render(const MercuryMatrix& matrix)
+{
+ GLCALL( glPushAttrib(GL_ENABLE_BIT|GL_DEPTH_BUFFER_BIT) );
+ GLCALL( glDepthMask( false ) );
+ GLCALL( glDisable(GL_CULL_FACE) );
+
+ if (m_bufferID==0)
+ {
+ GLCALL( glGenBuffersARB(1, &m_bufferID) );
+ }
+
+ GLCALL( glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_bufferID) );
+ MercuryVBO::m_lastVBOrendered = this;
+
+ if (m_dirtyVBO)
+ {
+ m_dirtyVBO = false;
+ GLCALL( glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_vertexData.LengthInBytes(), m_vertexData.Buffer(), GL_STATIC_DRAW_ARB) );
+ }
+
+ GLCALL( glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT) );
+
+ //do render stuff here
+// GLCALL( glDisableClientState(GL_TEXTURE_COORD_ARRAY) );
+ Texture::ApplyActiveTextures(ParticleBase::STRIDE*sizeof(float));
+
+ GLCALL( glEnableClientState(GL_VERTEX_ARRAY) );
+ GLCALL( glEnableClientState( GL_COLOR_ARRAY ) ); //used for attributes
+ GLCALL( glVertexPointer(3, GL_FLOAT, ParticleBase::STRIDE*sizeof(float), BUFFER_OFFSET( 0*sizeof(float) ) ) );
+ GLCALL( glColorPointer(4, GL_FLOAT, ParticleBase::STRIDE*sizeof(float), BUFFER_OFFSET( 3*sizeof(float) ) ) );
+ GLCALL( glTexCoordPointer(3, GL_FLOAT, ParticleBase::STRIDE*sizeof(float), BUFFER_OFFSET( 7*sizeof(float) ) ) );
+
+// GLCALL( glDrawRangeElements(GL_QUADS, 0, m_indexData.Length()-1, m_indexData.Length(), GL_UNSIGNED_SHORT, NULL) );
+// GLCALL( glDrawElements(GL_QUADS, m_maxParticles*4, GL_UNSIGNED_BYTE, 0) );
+ GLCALL( glDrawArrays(GL_QUADS, 0, m_maxParticles*4) );
+
+ GLCALL( glPopClientAttrib() );
+
+ base::Render(matrix);
+
+ GLCALL( glPopAttrib() );
+
+}
+
/****************************************************************************
* Copyright (C) 2009 by Joshua Allen *
* *
Modified: Mercury2/modules/ParticleEmitter.h
===================================================================
--- Mercury2/modules/ParticleEmitter.h 2009-12-22 16:08:48 UTC (rev 632)
+++ Mercury2/modules/ParticleEmitter.h 2009-12-23 01:29:35 UTC (rev 633)
@@ -6,7 +6,7 @@
class ParticleEmitter;
-class ParticleBase : public MercuryNode
+class ParticleBase
{
public:
ParticleBase();
@@ -15,22 +15,32 @@
virtual void Init();
virtual void Update(float dTime);
- virtual void RecursiveRender();
+// virtual void RecursiveRender();
-// void Activate();
-// void Deactivate();
+ void Activate();
+ void Deactivate();
+ void WriteToVBO();
- GENRTTI( ParticleBase );
+// GENRTTI( ParticleBase );
private:
- CLASS_HELPERS( MercuryNode );
+// CLASS_HELPERS( MercuryNode );
+ static const uint8_t STRIDE = 9;
+
+ void WriteAgeToVBO();
+ void WriteLifespanToVBO();
+ void WriteRand1ToVBO();
+ void WriteRand2ToVBO();
+ void WriteFloatToVertices(float v, uint8_t vertexIndex, uint8_t offset);
+
friend class ParticleEmitter;
ParticleBase* m_nextParticle;
float m_age;
float m_lifespan;
- float m_seed1, m_seed2;
+ float m_rand1, m_rand2;
ParticleEmitter* m_emitter;
// MercuryNode* m_particleGraph;
+ float* m_particleVobData; //pointer to position in VBO
};
class ParticleEmitter : public MercuryNode
@@ -44,12 +54,19 @@
void DeactivateParticle(ParticleBase* p);
virtual void LoadFromXML(const XMLNode& node);
+ virtual void Render(const MercuryMatrix& matrix);
+ void SetMaxParticleCount(uint16_t count);
+ inline void SetDirtyVBO() { m_dirtyVBO=true; }
+
GENRTTI( ParticleEmitter );
private:
void DestroyParticles();
void ActivateParticle();
- void FillUnusedParticleList(ParticleBase* p, uint32_t);
+
+ void FillUnusedParticleList(ParticleBase* p, uint32_t i);
+ void InitNewParticles(ParticleBase* p, uint32_t i, uint16_t vobStep, float* vob);
+
CLASS_HELPERS( MercuryNode );
uint32_t m_maxParticles;
@@ -63,7 +80,11 @@
ParticleBase* m_particles;
Callback1R<uint32_t,ParticleBase*>* GenerateParticlesClbk;
+ AlignedBuffer<float> m_vertexData;
+ unsigned int m_bufferID;
+ bool m_dirtyVBO;
+
// MercuryNode* m_masterParticle;
};
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|