|
From: <axl...@us...> - 2010-05-22 19:12:13
|
Revision: 744
http://hgengine.svn.sourceforge.net/hgengine/?rev=744&view=rev
Author: axlecrusher
Date: 2010-05-22 19:12:07 +0000 (Sat, 22 May 2010)
Log Message:
-----------
Copy less data each render. A little faster.
Modified Paths:
--------------
Mercury2/modules/ParticleEmitter.cpp
Mercury2/modules/ParticleEmitter.h
Modified: Mercury2/modules/ParticleEmitter.cpp
===================================================================
--- Mercury2/modules/ParticleEmitter.cpp 2010-05-19 22:07:06 UTC (rev 743)
+++ Mercury2/modules/ParticleEmitter.cpp 2010-05-22 19:12:07 UTC (rev 744)
@@ -4,6 +4,7 @@
#include <MercuryVBO.h>
#include <Texture.h>
+#include <Shader.h>
#include <list>
using namespace std;
@@ -13,95 +14,71 @@
#define BUFFER_OFFSET(i) ((char*)NULL + (i))
ParticleBase::ParticleBase()
- :m_age(0), m_lifespan(0), m_particleVobData(NULL), m_particleIndexData(NULL)
+ :m_startTime(0), m_currentTime(0), m_lifespan(0), m_particleDynamicData(NULL), m_particleIndexData(NULL)
{
}
ParticleBase::~ParticleBase()
{
- m_particleVobData = NULL;
+ m_particleDynamicData = NULL;
m_particleIndexData = NULL;
}
-void ParticleBase::Init()
+void ParticleBase::Init(float time)
{
- m_age = 0;
+ //absolute time
+ m_startTime = m_currentTime = time;
}
-void ParticleBase::Update(float dTime)
+void ParticleBase::Update(float currentTime)
{
- m_age += dTime;
- WriteAgeToVBO();
-
- if (m_age >= m_lifespan) Deactivate();
+ m_currentTime = currentTime;
+ if ( !IsActive() ) Deactivate();
}
void ParticleBase::WriteAgeToVBO()
{
- m_emitter->SetDirtyVertices();
for (uint8_t i = 0; i < 4; ++i)
- WriteFloatToVertices(m_age,i,3);
+ WriteFloatToVertices(m_startTime,i,0);
}
void ParticleBase::WriteLifespanToVBO()
{
- m_emitter->SetDirtyVertices();
for (uint8_t i = 0; i < 4; ++i)
- WriteFloatToVertices(m_lifespan,i,4);
+ WriteFloatToVertices(m_lifespan,i,1);
}
void ParticleBase::WriteRand1ToVBO()
{
- m_emitter->SetDirtyVertices();
for (uint8_t i = 0; i < 4; ++i)
- WriteFloatToVertices(m_rand1,i,5);
+ WriteFloatToVertices(m_rand1,i,2);
}
void ParticleBase::WriteRand2ToVBO()
{
- m_emitter->SetDirtyVertices();
for (uint8_t i = 0; i < 4; ++i)
- WriteFloatToVertices(m_rand2,i,6);
+ WriteFloatToVertices(m_rand2,i,3);
}
void ParticleBase::Activate()
{
-// printf("Activate\n");
- 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 = 1; i < 4; ++i)
m_particleIndexData[i] = m_particleIndexData[0]+i; //reconstruct indices
-
- m_emitter->SetDirtyVertices();
- m_emitter->SetDirtyIndices();
+ m_emitter->SetIndexUpdateRange(m_particleIndexData,m_particleIndexData+4);
}
void ParticleBase::Deactivate()
{
for (uint8_t i = 1; i < 4; ++i)
m_particleIndexData[i] = m_particleIndexData[0]; //degenerate triangle renders nothing
- m_emitter->SetDirtyIndices();
+ m_emitter->SetIndexUpdateRange(m_particleIndexData,m_particleIndexData+4);
}
void ParticleBase::WriteFloatToVertices(float v, uint8_t vertexIndex, uint8_t offset)
{
- *(m_particleVobData+((STRIDE*vertexIndex)+offset)) = v;
+ unsigned long o = (4*vertexIndex)+offset;
+ *(m_particleDynamicData+o) = v;
+ m_emitter->SetDynamicUpdateRange(m_particleDynamicData+o,m_particleDynamicData+o+1);
}
void ParticleBase::WriteToVBO()
@@ -116,7 +93,9 @@
:base(), m_maxParticles(50), m_age(0), m_emitDelay(0.1f), m_lifespan(0),
m_particlesEmitted(0), m_particleMinLife(0.1f), m_particleMaxLife(5.0f),
m_particles(NULL), GenerateParticlesClbk(NULL),
- m_dirtyVBO(0)
+ m_fLastD(0),m_fLastI(0),
+ m_dBegin(0), m_dEnd(0),
+ m_iBegin(0), m_iEnd(0)
{
m_bufferID[0] = 0;
m_iForcePasses = m_iForcePasses | (1<<15);
@@ -127,9 +106,9 @@
ParticleEmitter::~ParticleEmitter()
{
- if (m_bufferID[0] > 0) { GLCALL( glDeleteBuffersARB(2, m_bufferID) ); }
+ if (m_bufferID[0] > 0) { GLCALL( glDeleteBuffersARB(3, m_bufferID) ); }
- SAFE_DELETE_ARRAY(m_particles); //do we need to destroy each element????
+ SAFE_DELETE_ARRAY(m_particles);
SAFE_DELETE(GenerateParticlesClbk);
}
@@ -137,29 +116,53 @@
void ParticleEmitter::Init()
{
MercuryNode::Init();
- SAFE_DELETE_ARRAY(m_particles); //do we need to destroy each element????
+ SAFE_DELETE_ARRAY(m_particles);
SetMaxParticleCount(m_maxParticles);
}
+void ParticleEmitter::InitGeometry(float* g)
+{
+ uint8_t i = 0;
+
+ //upper left
+ g[i++] = -0.5; g[i++] = 0.5; g[i++] = 0;
+ g[i++] = 1; g[i++] = 0; //U,V
+
+ //lower left
+ g[i++] = -0.5; g[i++] = -0.5; g[i++] = 0;
+ g[i++] = 0; g[i++] = 0; //U,V
+
+ //lower right
+ g[i++] = 0.5; g[i++] = -0.5; g[i++] = 0;
+ g[i++] = 0; g[i++] = 1; //U,V
+
+ //upper right
+ g[i++] = 0.5; g[i++] = 0.5; g[i++] = 0;
+ g[i++] = 1; g[i++] = 1; //U,V
+}
+
void ParticleEmitter::Update(float dTime)
{
m_age += dTime;
+ ++m_fLastD;
+ ++m_fLastI;
+
/* create particles until we meet the total number of
particles possible in terms of the age of the emitter */
while (((m_age-(m_particlesEmitted*m_emitDelay)) > m_emitDelay) && (m_emitDelay>0))
{
// LOG.Write("Emit");
++m_particlesEmitted; //always increment even if the maximum number of particles exist
- ActivateParticle();
+ ActivateParticle(m_age);
}
list< ParticleBase* >::iterator i = m_active.begin();
while ( i!=m_active.end() )
{
ParticleBase *p = *i;
- p->Update(dTime);
+ p->Update(m_age);
if ( !p->IsActive() )
{
m_active.erase(i++); //don't invalidate iterator before incrementing it
@@ -172,30 +175,24 @@
}
}
-void ParticleEmitter::ActivateParticle()
+void ParticleEmitter::ActivateParticle(float genTime)
{
if (!m_inactive.empty())
{
ParticleBase* p = m_inactive.front();
m_inactive.pop_front();
- p->Init();
+ p->Init(genTime);
p->Activate();
p->m_lifespan = m_particleMinLife;
p->m_lifespan += (rand()%(int(m_particleMaxLife*1000) - int(m_particleMinLife*1000)))/1000.0f;
p->m_rand1 = float(rand()%100000);
p->m_rand2 = float(rand()%100000);
-// +((rand()%((m_particleMaxLife*1000)-(m_particleMinLife*1000)))/1000.0f);
+ p->WriteToVBO();
- p->WriteAgeToVBO();
- p->WriteLifespanToVBO();
- p->WriteRand1ToVBO();
- p->WriteRand2ToVBO();
-
//add to the active list
-// printf("push %p\n", p);
m_active.push_back(p);
}
}
@@ -216,14 +213,15 @@
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_maxParticles = count;
- m_vertexData.Allocate(m_maxParticles*ParticleBase::STRIDE*4);
+ m_vertexDynamicData.Allocate(m_maxParticles*4*4);
+ m_geometryData.Allocate(m_maxParticles*4*5);
m_indexData.Allocate(m_maxParticles*4);
+ for (uint16_t i = 0; i < m_maxParticles*4*5; i+=(5*4))
+ InitGeometry(m_geometryData.Buffer()+i);
+
SAFE_DELETE_ARRAY(m_particles);
// if (GenerateParticlesClbk) m_particles = (*GenerateParticlesClbk)(m_maxParticles);
m_particles = new ParticleBase[m_maxParticles];
@@ -237,7 +235,7 @@
{
ParticleBase* p = m_particles+i;
p->m_emitter = this;
- p->m_particleVobData = m_vertexData.Buffer()+(ParticleBase::STRIDE*4*i);
+ p->m_particleDynamicData = m_vertexDynamicData.Buffer()+(4*4*i);
p->m_particleIndexData = m_indexData.Buffer() + (4*i);
p->m_particleIndexData[0]=p->m_particleIndexData[1]=p->m_particleIndexData[2]=p->m_particleIndexData[3]=i*4; //initial degenerate
p->Deactivate();
@@ -252,45 +250,80 @@
SetCulled(false);
}
+void ParticleEmitter::UpdateVBO()
+{
+ if ( ( m_iBegin > 0 ) || ( m_dBegin > 0 ))
+ {
+// LOG.Write( ssprintf("%d %d",m_fLastD,m_fLastI) );
+// LOG.Write( ssprintf("%p %p, %p %p, %d %d\n", m_dBegin, m_dEnd, m_iBegin, m_iEnd, (unsigned long)m_dEnd-(unsigned long)m_dBegin, (unsigned long)m_iEnd-(unsigned long)m_iBegin) );
+ }
+
+ if ( m_dBegin > 0 )
+ {
+ unsigned long l = (unsigned long)m_dEnd-(unsigned long)m_dBegin;
+ unsigned long s = (unsigned long)m_dBegin - (unsigned long)m_vertexDynamicData.Buffer();
+ GLCALL( glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_vertexDynamicData.LengthInBytes(), NULL, GL_DYNAMIC_DRAW_ARB) );
+ GLCALL( glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, s, l, m_dBegin));
+ m_fLastD = 0;
+ }
+ if ( m_iBegin > 0 )
+ {
+ unsigned long l = (unsigned long)m_iEnd-(unsigned long)m_iBegin;
+ unsigned long s = (unsigned long)m_iBegin - (unsigned long)m_indexData.Buffer();
+ GLCALL( glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_vertexDynamicData.LengthInBytes(), NULL, GL_DYNAMIC_DRAW_ARB) );
+ GLCALL( glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, s, l, m_iBegin));
+ m_fLastI = 0;
+ }
+
+ m_dBegin = m_dEnd = m_iBegin = m_iEnd = 0;
+}
+
void ParticleEmitter::Render(const MercuryMatrix& matrix)
{
+ ShaderAttribute sa;
+ sa.type = ShaderAttribute::TYPE_FLOAT;
+ sa.value.fFloat = m_age;
+ Shader::SetAttribute("EmitterTime", sa);
+
GLCALL( glPushAttrib(GL_ENABLE_BIT|GL_CURRENT_BIT) );
GLCALL( glDisable(GL_CULL_FACE) );
if (m_bufferID[0]==0)
{
- GLCALL( glGenBuffersARB(2, m_bufferID) );
+ GLCALL( glGenBuffersARB(3, m_bufferID) );
+
+ GLCALL( glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_bufferID[0]) ); //geometry VBO
+ GLCALL( glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_geometryData.LengthInBytes(), m_geometryData.Buffer(), GL_STATIC_DRAW_ARB) );
+
+ GLCALL( glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_bufferID[1]) ); //dynamic data (age and randoms)
+ GLCALL( glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_vertexDynamicData.LengthInBytes(), m_vertexDynamicData.Buffer(), GL_DYNAMIC_DRAW_ARB) );
+
+ GLCALL( glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, m_bufferID[2]) );
+ GLCALL( glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, m_indexData.LengthInBytes(), m_indexData.Buffer(), GL_DYNAMIC_DRAW_ARB) );
+
+ m_dBegin = m_dEnd = m_iBegin = m_iEnd = 0;
}
- GLCALL( glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_bufferID[0]) );
- GLCALL( glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, m_bufferID[1]) );
-// GLCALL( glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0) );
-
MercuryVBO::SetLastRendered(this);
- if (m_dirtyVBO&&0x1)
- {
- GLCALL( glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_vertexData.LengthInBytes(), m_vertexData.Buffer(), GL_STREAM_DRAW_ARB) );
- }
- if (m_dirtyVBO&&0x2)
- {
- GLCALL( glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, m_indexData.LengthInBytes(), m_indexData.Buffer(), GL_STREAM_DRAW_ARB) );
- }
- m_dirtyVBO = 0;
+ GLCALL( glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_bufferID[0]) ); //geometry VBO contains XYZUV
+ Texture::ApplyActiveTextures(5*sizeof(float), 3*sizeof(float));
+ GLCALL( glEnableClientState(GL_VERTEX_ARRAY) );
+ GLCALL( glVertexPointer(3, GL_FLOAT, 5*sizeof(float), BUFFER_OFFSET( 0*sizeof(float) ) ) );
+
+ GLCALL( glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_bufferID[1]) ); //dynamic data (age and randoms)
+ GLCALL( glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, m_bufferID[2]) );
+
+ UpdateVBO();
+
GLCALL( glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT) );
//do render stuff here
- Texture::ApplyActiveTextures(ParticleBase::STRIDE*sizeof(float), 7*sizeof(float));
- GLCALL( glEnableClientState(GL_VERTEX_ARRAY) );
GLCALL( glEnableClientState( GL_COLOR_ARRAY ) ); //used for attributes
-// GLCALL( glDisableClientState( GL_NORMAL_ARRAY ) );
- 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( glColorPointer(4, GL_FLOAT, 4*sizeof(float), BUFFER_OFFSET( 0*sizeof(float) ) ) );
-// GLCALL( glDrawArrays(GL_QUADS, 0, m_maxParticles*4) );
-// GLCALL( glDrawRangeElements( GL_QUADS, 0, m_maxParticles*4,m_maxParticles*4, GL_UNSIGNED_SHORT, NULL) );
GLCALL( glDrawElements(GL_QUADS,m_maxParticles*4,GL_UNSIGNED_SHORT,0) );
GLCALL( glPopClientAttrib() );
@@ -302,6 +335,24 @@
base::Render(matrix);
}
+void ParticleEmitter::SetDynamicUpdateRange(void* begin, void* end)
+{
+ m_dBegin = m_dBegin==0?begin:m_dBegin;
+ m_dEnd = m_dEnd==0?end:m_dEnd;
+
+ m_dBegin = begin<m_dBegin?begin:m_dBegin;
+ m_dEnd = end>m_dEnd?end:m_dEnd;
+}
+
+void ParticleEmitter::SetIndexUpdateRange(void* begin, void* end)
+{
+ m_iBegin = m_iBegin==0?begin:m_iBegin;
+ m_iEnd = m_iEnd==0?end:m_iEnd;
+
+ m_iBegin = begin<m_iBegin?begin:m_iBegin;
+ m_iEnd = end>m_iEnd?end:m_iEnd;
+}
+
uint32_t ParticleEmitter::ResetDrawnCount()
{
uint32_t t = m_particlesDrawn;
@@ -309,6 +360,7 @@
return t;
}
+
uint32_t ParticleEmitter::m_particlesDrawn = 0;
/****************************************************************************
Modified: Mercury2/modules/ParticleEmitter.h
===================================================================
--- Mercury2/modules/ParticleEmitter.h 2010-05-19 22:07:06 UTC (rev 743)
+++ Mercury2/modules/ParticleEmitter.h 2010-05-22 19:12:07 UTC (rev 744)
@@ -12,23 +12,16 @@
ParticleBase();
~ParticleBase();
- virtual void Init();
virtual void Update(float dTime);
-// virtual void RecursiveRender();
-
void Activate();
void Deactivate();
void WriteToVBO();
+
+ void Init(float time);
- inline bool IsActive() const { return m_age < m_lifespan; }
-
-// GENRTTI( ParticleBase );
+ inline bool IsActive() const { return m_currentTime < m_lifespan+m_startTime; }
private:
-// CLASS_HELPERS( MercuryNode );
-
- static const uint8_t STRIDE = 9;
-
void WriteAgeToVBO();
void WriteLifespanToVBO();
void WriteRand1ToVBO();
@@ -36,13 +29,11 @@
void WriteFloatToVertices(float v, uint8_t vertexIndex, uint8_t offset);
friend class ParticleEmitter;
-// ParticleBase *m_prev, *m_next;
- float m_age;
+ float m_startTime,m_currentTime;
float m_lifespan;
float m_rand1, m_rand2;
ParticleEmitter* m_emitter;
-// MercuryNode* m_particleGraph;
- float* m_particleVobData; //pointer to position in VBO
+ float* m_particleDynamicData; //pointer to position in VBO
uint16_t* m_particleIndexData; //pointer to position in index list
};
@@ -64,19 +55,17 @@
void SetMaxParticleCount(uint16_t count);
- inline void SetDirtyVertices() { m_dirtyVBO = m_dirtyVBO||0x1; }
- inline void SetDirtyIndices() { m_dirtyVBO = m_dirtyVBO||0x2; }
+ void SetDynamicUpdateRange(void* begin, void* end);
+ void SetIndexUpdateRange(void* begin, void* end);
static uint32_t ResetDrawnCount();
GENRTTI( ParticleEmitter );
private:
-// void DestroyParticles();
- void ActivateParticle();
+ void ActivateParticle(float genTime);
+ void InitGeometry(float* g);
+ void UpdateVBO();
-// 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;
@@ -89,15 +78,17 @@
ParticleBase *m_particles;
Callback1R<uint32_t,ParticleBase*>* GenerateParticlesClbk;
- AlignedBuffer<float> m_vertexData;
+ AlignedBuffer<float> m_geometryData; //xyzuv, stride 5
+ AlignedBuffer<float> m_vertexDynamicData; //1 age, 1 lifespan, 2 random, stide 4
AlignedBuffer<uint16_t> m_indexData;
- unsigned int m_bufferID[2];
-// bool m_dirtyVBO;
- uint8_t m_dirtyVBO;
+ unsigned int m_bufferID[3];
+ unsigned int m_fLastD;
+ unsigned int m_fLastI;
+ void *m_dBegin, *m_dEnd; //pointers to area of the m_vertexDynamicData that changed
+ void *m_iBegin, *m_iEnd; //pointers to area of the m_indexData that changed
std::list< ParticleBase* > m_active, m_inactive;
-// MercuryNode* m_masterParticle;
static uint32_t m_particlesDrawn;
};
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|