forked from Mirrors/openclonk
Use an IBO for the particle system
glDrawElements needs an IBO when using a core profile. The particle system's IBO is actually quite static since it's always a triangle strip with 2 triangles followed by a PRI. Therefore, this reduces the amount of data we have to send to the GPU compared to the previous solution. Also, remove the workaround when glPrimitiveRestartIndex is not available since it is always available with OpenGL 3.1 and when using a core profile we are guaranteed to have OpenGL 3.1 anyway.objectmenu
parent
686a32764c
commit
e13cda4bd0
|
@ -185,9 +185,6 @@ bool C4Application::DoInit(int argc, char * argv[])
|
|||
pWindow->SetSize(Config.Graphics.WindowX, Config.Graphics.WindowY);
|
||||
}
|
||||
|
||||
// after initializing graphics, the particle system can check for compatibility
|
||||
::Particles.DoInit();
|
||||
|
||||
// Initialize gamepad
|
||||
if (!pGamePadControl && Config.General.GamepadEnabled)
|
||||
pGamePadControl = new C4GamePadControl();
|
||||
|
|
|
@ -967,16 +967,6 @@ bool C4ParticleChunk::Exec(C4Object *obj, float timeDelta)
|
|||
return particleCount > 0;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#undef glGenVertexArrays
|
||||
#undef glBindVertexArray
|
||||
#undef glDeleteVertexArrays
|
||||
|
||||
#define glGenVertexArrays glGenVertexArraysAPPLE
|
||||
#define glBindVertexArray glBindVertexArrayAPPLE
|
||||
#define glDeleteVertexArrays glDeleteVertexArraysAPPLE
|
||||
#endif
|
||||
|
||||
void C4ParticleChunk::Draw(C4TargetFacet cgo, C4Object *obj, C4ShaderCall& call, int texUnit, const StdProjectionMatrix& modelview)
|
||||
{
|
||||
if (particleCount == 0) return;
|
||||
|
@ -1026,11 +1016,11 @@ void C4ParticleChunk::Draw(C4TargetFacet cgo, C4Object *obj, C4ShaderCall& call,
|
|||
assert (drawingDataVertexArraysObject != 0 && "Could not generate a VAO ID.");
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, drawingDataVertexBufferObject);
|
||||
|
||||
// Push the new vertex data
|
||||
// this has to be done before binding the vertex arrays object
|
||||
glBindBuffer(GL_ARRAY_BUFFER, drawingDataVertexBufferObject);
|
||||
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(C4Particle::DrawingData::Vertex) * particleCount, &vertexCoordinates[0], GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
// set up the vertex array structure
|
||||
GLuint vao;
|
||||
|
@ -1042,6 +1032,8 @@ void C4ParticleChunk::Draw(C4TargetFacet cgo, C4Object *obj, C4ShaderCall& call,
|
|||
|
||||
if (!has_vao)
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, drawingDataVertexBufferObject);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ::Particles.GetIBO());
|
||||
#ifdef GL_KHR_debug
|
||||
if (glObjectLabel)
|
||||
glObjectLabel(GL_VERTEX_ARRAY, vao, -1, "<particles>/VAO");
|
||||
|
@ -1055,18 +1047,10 @@ void C4ParticleChunk::Draw(C4TargetFacet cgo, C4Object *obj, C4ShaderCall& call,
|
|||
glVertexAttribPointer(call.GetAttribute(C4SSA_Color), 4, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<GLvoid*>(offsetof(C4Particle::DrawingData::Vertex, r)));
|
||||
}
|
||||
|
||||
if (!Particles.usePrimitiveRestartIndexWorkaround)
|
||||
{
|
||||
glDrawElements(GL_TRIANGLE_STRIP, static_cast<GLsizei> (5 * particleCount), GL_UNSIGNED_INT, ::Particles.GetPrimitiveRestartArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
glMultiDrawElements(GL_TRIANGLE_STRIP, ::Particles.GetMultiDrawElementsCountArray(), GL_UNSIGNED_INT, const_cast<const GLvoid**>(::Particles.GetMultiDrawElementsIndexArray()), static_cast<GLsizei> (particleCount));
|
||||
}
|
||||
glDrawElements(GL_TRIANGLE_STRIP, static_cast<GLsizei> (5 * particleCount), GL_UNSIGNED_INT, 0);
|
||||
|
||||
// reset buffer data
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
bool C4ParticleChunk::IsOfType(C4ParticleDef *def, uint32_t _blitMode, uint32_t _attachment) const
|
||||
|
@ -1144,11 +1128,8 @@ void C4ParticleList::Draw(C4TargetFacet cgo, C4Object *obj)
|
|||
pDraw->DeactivateBlitModulation();
|
||||
pDraw->ResetBlitMode();
|
||||
|
||||
if (!Particles.usePrimitiveRestartIndexWorkaround)
|
||||
{
|
||||
glPrimitiveRestartIndex(0xffffffff);
|
||||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
}
|
||||
glPrimitiveRestartIndex(0xffffffff);
|
||||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
|
||||
// enable shader
|
||||
C4ShaderCall call(pGL->GetSpriteShader(true, false, false));
|
||||
|
@ -1182,10 +1163,7 @@ void C4ParticleList::Draw(C4TargetFacet cgo, C4Object *obj)
|
|||
|
||||
accessMutex.Leave();
|
||||
|
||||
if (!Particles.usePrimitiveRestartIndexWorkaround)
|
||||
{
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
}
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
}
|
||||
|
||||
void C4ParticleList::Clear()
|
||||
|
@ -1255,7 +1233,8 @@ C4ParticleSystem::C4ParticleSystem() : frameCounterAdvancedEvent(false)
|
|||
{
|
||||
currentSimulationTime = 0;
|
||||
globalParticles = 0;
|
||||
usePrimitiveRestartIndexWorkaround = false;
|
||||
ibo = 0;
|
||||
ibo_size = 0;
|
||||
}
|
||||
|
||||
C4ParticleSystem::~C4ParticleSystem()
|
||||
|
@ -1264,21 +1243,6 @@ C4ParticleSystem::~C4ParticleSystem()
|
|||
|
||||
calculationThread.SignalStop();
|
||||
CalculateNextStep();
|
||||
|
||||
for (std::vector<uint32_t *>::iterator iter = multiDrawElementsIndexArray.begin(); iter != multiDrawElementsIndexArray.end(); ++iter)
|
||||
delete[] (*iter);
|
||||
}
|
||||
|
||||
void C4ParticleSystem::DoInit()
|
||||
{
|
||||
// we use features that are only supported from 3.1 upwards. Check whether the graphics card supports that and - if not - use workarounds
|
||||
if (!GLEW_VERSION_3_1 || (glPrimitiveRestartIndex == 0))
|
||||
{
|
||||
usePrimitiveRestartIndexWorkaround = true;
|
||||
LogSilent("WARNING (particle system): Your graphics card does not support glPrimitiveRestartIndex - a (slower) fallback will be used!");
|
||||
}
|
||||
|
||||
assert (glGenBuffers != 0 && "Your graphics card does not seem to support buffer objects.");
|
||||
}
|
||||
|
||||
void C4ParticleSystem::ExecuteCalculation()
|
||||
|
@ -1304,8 +1268,6 @@ void C4ParticleSystem::ExecuteCalculation()
|
|||
particleListAccessMutex.Leave();
|
||||
}
|
||||
}
|
||||
#else // ifdef USE_CONSOLE
|
||||
void C4ParticleSystem::DoInit() {}
|
||||
#endif
|
||||
|
||||
C4ParticleList *C4ParticleSystem::GetNewParticleList(C4Object *forObject)
|
||||
|
@ -1451,59 +1413,31 @@ void C4ParticleSystem::Create(C4ParticleDef *of_def, C4ParticleValueProvider &x,
|
|||
|
||||
void C4ParticleSystem::PreparePrimitiveRestartIndices(uint32_t forAmount)
|
||||
{
|
||||
if (!usePrimitiveRestartIndexWorkaround)
|
||||
// prepare array with indices, separated by special primitive restart index
|
||||
const uint32_t PRI = 0xffffffff;
|
||||
size_t neededAmount = 5 * forAmount;
|
||||
|
||||
if (ibo == 0) glGenBuffers(1, &ibo);
|
||||
|
||||
if (ibo_size < neededAmount * sizeof(GLuint))
|
||||
{
|
||||
// prepare array with indices, separated by special primitive restart index
|
||||
const uint32_t PRI = 0xffffffff;
|
||||
size_t neededAmount = 5 * forAmount;
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
|
||||
if (primitiveRestartIndices.size() < neededAmount)
|
||||
std::vector<GLuint> ibo_data;
|
||||
ibo_data.reserve(neededAmount);
|
||||
|
||||
unsigned int index = 0;
|
||||
for (unsigned int i = 0; i < neededAmount; ++i)
|
||||
{
|
||||
uint32_t oldValue = 0;
|
||||
|
||||
if (primitiveRestartIndices.size() > 2)
|
||||
{
|
||||
oldValue = primitiveRestartIndices[primitiveRestartIndices.size()-1];
|
||||
if (oldValue == PRI)
|
||||
oldValue = primitiveRestartIndices[primitiveRestartIndices.size()-2];
|
||||
++oldValue;
|
||||
}
|
||||
size_t oldSize = primitiveRestartIndices.size();
|
||||
primitiveRestartIndices.resize(neededAmount);
|
||||
|
||||
for (size_t i = oldSize; i < neededAmount; ++i)
|
||||
{
|
||||
if (((i+1) % 5 == 0) && (i != 0))
|
||||
{
|
||||
primitiveRestartIndices[i] = PRI;
|
||||
}
|
||||
else
|
||||
{
|
||||
primitiveRestartIndices[i] = oldValue++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// prepare arrays for glMultiDrawElements
|
||||
if (multiDrawElementsCountArray.size() <= forAmount)
|
||||
{
|
||||
multiDrawElementsCountArray.resize(forAmount, 4);
|
||||
if ((i+1) % 5 == 0)
|
||||
ibo_data.push_back(PRI);
|
||||
else
|
||||
ibo_data.push_back(index++);
|
||||
}
|
||||
|
||||
if (multiDrawElementsIndexArray.size() <= forAmount)
|
||||
{
|
||||
uint32_t oldSize = multiDrawElementsIndexArray.size();
|
||||
multiDrawElementsIndexArray.resize(forAmount);
|
||||
|
||||
for (; oldSize < forAmount; ++oldSize)
|
||||
{
|
||||
multiDrawElementsIndexArray[oldSize] = new uint32_t[4];
|
||||
for (uint32_t i = 0; i < 4; ++i)
|
||||
multiDrawElementsIndexArray[oldSize][i] = 4 * oldSize + i;
|
||||
}
|
||||
}
|
||||
ibo_size = neededAmount * sizeof(GLuint);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibo_size, &ibo_data[0], GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1511,6 +1445,9 @@ void C4ParticleSystem::PreparePrimitiveRestartIndices(uint32_t forAmount)
|
|||
void C4ParticleSystem::Clear()
|
||||
{
|
||||
#ifndef USE_CONSOLE
|
||||
if (ibo != 0) glDeleteBuffers(1, &ibo);
|
||||
ibo = 0; ibo_size = 0;
|
||||
|
||||
currentSimulationTime = 0;
|
||||
ClearAllParticles();
|
||||
#endif
|
||||
|
|
|
@ -445,10 +445,8 @@ class C4ParticleSystem
|
|||
|
||||
private:
|
||||
// contains an array with indices for vertices, separated by a primitive restart index
|
||||
std::vector<uint32_t> primitiveRestartIndices;
|
||||
// these are fallbacks for if primitiveRestartIndex is not supported by the graphics card
|
||||
std::vector<GLsizei> multiDrawElementsCountArray;
|
||||
std::vector<uint32_t *> multiDrawElementsIndexArray;
|
||||
GLuint ibo;
|
||||
size_t ibo_size;
|
||||
std::list<C4ParticleList> particleLists;
|
||||
|
||||
CStdCSec particleListAccessMutex;
|
||||
|
@ -475,7 +473,6 @@ public:
|
|||
frameCounterAdvancedEvent.Set();
|
||||
#endif
|
||||
}
|
||||
void DoInit();
|
||||
// resets the internal state of the particle system and unloads all definitions
|
||||
void Clear();
|
||||
void DrawGlobalParticles(C4TargetFacet cgo)
|
||||
|
@ -502,14 +499,9 @@ public:
|
|||
C4ParticleSystemDefinitionList definitions;
|
||||
|
||||
#ifndef USE_CONSOLE
|
||||
// on some graphics card, glPrimitiveRestartIndex might not be supported
|
||||
bool usePrimitiveRestartIndexWorkaround;
|
||||
GLsizei *GetMultiDrawElementsCountArray() { return &multiDrawElementsCountArray[0]; }
|
||||
GLvoid **GetMultiDrawElementsIndexArray() { return reinterpret_cast<GLvoid**> (&multiDrawElementsIndexArray[0]); }
|
||||
|
||||
// usually, the following methods are used for drawing
|
||||
GLuint GetIBO() const { return ibo; }
|
||||
void PreparePrimitiveRestartIndices(uint32_t forSize);
|
||||
void *GetPrimitiveRestartArray() { return (void*)&primitiveRestartIndices[0]; }
|
||||
|
||||
// creates a new particle
|
||||
void Create(C4ParticleDef *of_def, C4ParticleValueProvider &x, C4ParticleValueProvider &y, C4ParticleValueProvider &speedX, C4ParticleValueProvider &speedY, C4ParticleValueProvider &lifetime, C4PropList *properties, int amount = 1, C4Object *object=NULL);
|
||||
|
|
Loading…
Reference in New Issue