
com.gempukku.libgdx.graph.plugin.particles.ParticlesDataContainer Maven / Gradle / Ivy
package com.gempukku.libgdx.graph.plugin.particles;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes;
import com.badlogic.gdx.graphics.glutils.IndexBufferObject;
import com.badlogic.gdx.graphics.glutils.IndexData;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.graphics.glutils.VertexData;
import com.badlogic.gdx.utils.Disposable;
import com.gempukku.libgdx.graph.plugin.particles.generator.ParticleGenerator;
import com.gempukku.libgdx.graph.shader.ShaderContext;
import com.gempukku.libgdx.graph.util.GdxCompatibilityUtils;
public class ParticlesDataContainer implements Disposable {
private final static ParticleGenerator.ParticleGenerateInfo tempGenerateInfo = new ParticleGenerator.ParticleGenerateInfo();
private final static ParticleUpdater.ParticleUpdateInfo tempUpdateInfo = new ParticleUpdater.ParticleUpdateInfo();
private Object[] particleDataStorage;
private float[] particlesData;
private VertexData vbo;
private IndexData ibo;
private final int numberOfParticles;
private final int numberOfFloatsInVertex;
private int nextParticleIndex = 0;
private float maxParticleDeath;
private int firstDirtyParticle = Integer.MAX_VALUE;
private int lastDirtyParticle = -1;
private int positionOffset = -1;
private int uvOffset = -1;
private int seedOffset = -1;
private int birthTimeOffset = -1;
private int deathTimeOffset = -1;
public ParticlesDataContainer(VertexAttributes vertexAttributes, int numberOfParticles, boolean storeParticleData) {
this.numberOfParticles = numberOfParticles;
this.numberOfFloatsInVertex = vertexAttributes.vertexSize / 4;
initOffsets(vertexAttributes);
initBuffers(vertexAttributes);
if (storeParticleData)
particleDataStorage = new Object[numberOfParticles];
}
private void initOffsets(VertexAttributes vertexAttributes) {
positionOffset = getAliasOffset(vertexAttributes, ShaderProgram.POSITION_ATTRIBUTE);
uvOffset = getAliasOffset(vertexAttributes, ShaderProgram.TEXCOORD_ATTRIBUTE + 0);
seedOffset = getAliasOffset(vertexAttributes, "a_seed");
birthTimeOffset = getAliasOffset(vertexAttributes, "a_birthTime");
deathTimeOffset = getAliasOffset(vertexAttributes, "a_deathTime");
}
private int getAliasOffset(VertexAttributes vertexAttributes, String alias) {
for (VertexAttribute vertexAttribute : vertexAttributes) {
if (vertexAttribute.alias.equals(alias))
return vertexAttribute.offset / 4;
}
return -1;
}
private void initBuffers(VertexAttributes vertexAttributes) {
vbo = GdxCompatibilityUtils.createVertexBuffer(false, numberOfParticles * 4, vertexAttributes);
int dataLength = numberOfParticles * 4 * numberOfFloatsInVertex;
particlesData = new float[dataLength];
if (uvOffset != -1) {
for (int particle = 0; particle < numberOfParticles; particle++) {
// Don't need to set UV for first vertex, as it's 0,0
for (int vertex = 1; vertex < 4; vertex++) {
int dataIndex = getVertexIndex(particle, vertex);
particlesData[dataIndex + uvOffset] = vertex % 2;
particlesData[dataIndex + uvOffset + 1] = (float) (vertex / 2);
}
}
}
vbo.setVertices(particlesData, 0, dataLength);
int numberOfIndices = 6 * numberOfParticles;
ibo = new IndexBufferObject(true, numberOfIndices);
short[] indices = new short[numberOfIndices];
int vertexIndex = 0;
for (int i = 0; i < numberOfIndices; i += 6) {
indices[i + 0] = (short) (vertexIndex * 4 + 0);
indices[i + 1] = (short) (vertexIndex * 4 + 2);
indices[i + 2] = (short) (vertexIndex * 4 + 1);
indices[i + 3] = (short) (vertexIndex * 4 + 2);
indices[i + 4] = (short) (vertexIndex * 4 + 3);
indices[i + 5] = (short) (vertexIndex * 4 + 1);
vertexIndex++;
}
ibo.setIndices(indices, 0, indices.length);
}
private int getVertexIndex(int particleIndex, int vertexInParticle) {
return ((particleIndex * 4) + vertexInParticle) * numberOfFloatsInVertex;
}
public int getNumberOfParticles() {
return numberOfParticles;
}
public int getRemainingCapacity() {
return numberOfParticles - nextParticleIndex;
}
public void generateParticle(float particleTime, ParticleGenerator particleGenerator) {
particleGenerator.generateParticle(tempGenerateInfo);
if (particleDataStorage != null)
particleDataStorage[nextParticleIndex] = tempGenerateInfo.particleData;
float particleDeath = particleTime + tempGenerateInfo.lifeLength;
for (int i = 0; i < 4; i++) {
int vertexIndex = getVertexIndex(nextParticleIndex, i);
if (positionOffset != -1) {
particlesData[vertexIndex + positionOffset + 0] = tempGenerateInfo.location.x;
particlesData[vertexIndex + positionOffset + 1] = tempGenerateInfo.location.y;
particlesData[vertexIndex + positionOffset + 2] = tempGenerateInfo.location.z;
}
if (seedOffset != -1)
particlesData[vertexIndex + seedOffset] = tempGenerateInfo.seed;
if (birthTimeOffset != -1)
particlesData[vertexIndex + birthTimeOffset] = particleTime;
if (deathTimeOffset != -1)
particlesData[vertexIndex + deathTimeOffset] = particleDeath;
}
maxParticleDeath = Math.max(maxParticleDeath, particleDeath);
firstDirtyParticle = Math.min(firstDirtyParticle, nextParticleIndex);
lastDirtyParticle = Math.max(lastDirtyParticle, nextParticleIndex);
nextParticleIndex = (nextParticleIndex + 1) % numberOfParticles;
}
public void applyPendingChanges() {
if (lastDirtyParticle >= 0) {
if (firstDirtyParticle == lastDirtyParticle) {
// Update all particles
vbo.updateVertices(0, particlesData, 0, particlesData.length);
} else if (firstDirtyParticle > lastDirtyParticle) {
// Updates are wrapper around
int firstData = getVertexIndex(firstDirtyParticle, 0);
vbo.updateVertices(firstData, particlesData, firstData, particlesData.length - firstData);
int lastData = getVertexIndex(lastDirtyParticle + 1, 0);
vbo.updateVertices(0, particlesData, 0, lastData);
} else {
int firstData = getVertexIndex(firstDirtyParticle, 0);
int lastData = getVertexIndex(lastDirtyParticle + 1, 0);
vbo.updateVertices(firstData, particlesData, firstData, lastData - firstData);
}
}
}
public void render(ParticlesGraphShader graphShader, ShaderContext shaderContext, float currentTime) {
if (currentTime < maxParticleDeath) {
graphShader.renderParticles(shaderContext, vbo, ibo);
}
}
@Override
public void dispose() {
vbo.dispose();
ibo.dispose();
}
public void update(ParticleUpdater particleUpdater, float currentTime, boolean accessToData) {
for (int i = 0; i < numberOfParticles; i++) {
int particleDataIndex = getVertexIndex(i, 0);
if (currentTime < particlesData[particleDataIndex + 5]) {
tempUpdateInfo.location.set(particlesData[particleDataIndex + 0], particlesData[particleDataIndex + 1], particlesData[particleDataIndex + 2]);
tempUpdateInfo.seed = particlesData[particleDataIndex + 3];
if (accessToData && particleDataStorage != null)
tempUpdateInfo.particleData = particleDataStorage[i];
particleUpdater.updateParticle(tempUpdateInfo);
if (accessToData && particleDataStorage != null)
particleDataStorage[i] = tempGenerateInfo.particleData;
for (int vertex = 0; vertex < 4; vertex++) {
int vertexIndex = getVertexIndex(i, vertex);
if (positionOffset > -1) {
particlesData[vertexIndex + positionOffset + 0] = tempUpdateInfo.location.x;
particlesData[vertexIndex + positionOffset + 1] = tempUpdateInfo.location.x;
particlesData[vertexIndex + positionOffset + 2] = tempUpdateInfo.location.x;
}
if (seedOffset > -1)
particlesData[vertexIndex + seedOffset] = tempUpdateInfo.seed;
}
firstDirtyParticle = Math.min(firstDirtyParticle, i);
lastDirtyParticle = Math.max(lastDirtyParticle, i);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy