202 lines
6.8 KiB
Java
202 lines
6.8 KiB
Java
package com.persesgames.jogl.explosion;
|
|
|
|
import java.nio.FloatBuffer;
|
|
import java.nio.IntBuffer;
|
|
import java.util.Random;
|
|
|
|
import javax.media.opengl.GL;
|
|
import javax.media.opengl.GL2ES2;
|
|
import javax.media.opengl.GL4;
|
|
|
|
import com.jogamp.common.nio.Buffers;
|
|
import com.persesgames.jogl.Util;
|
|
import com.persesgames.jogl.shader.ComputeProgram;
|
|
import com.persesgames.jogl.shader.ShaderProgram;
|
|
|
|
/**
|
|
* Date: 1/15/14
|
|
* Time: 8:23 PM
|
|
*/
|
|
public class ExplosionComputeHandler {
|
|
//private final static Logger logger = LoggerFactory.getLogger(ExplosionComputeHandler.class);
|
|
|
|
private final static int EXPLOSION_PARTICLES = 256;
|
|
private final static int MAX_EXPLOSION_PARTICLES = 250000;
|
|
|
|
private final Random random = new Random(System.nanoTime());
|
|
|
|
private GL4 gl;
|
|
|
|
private ShaderProgram explProgram;
|
|
|
|
private ComputeProgram explosionProgram;
|
|
private ComputeProgram explCleanUpProgram;
|
|
|
|
private FloatBuffer explBuffer = Buffers.newDirectFloatBuffer(MAX_EXPLOSION_PARTICLES * 8);
|
|
private IntBuffer atomicBuffer = Buffers.newDirectIntBuffer(5);
|
|
|
|
|
|
private int newParticleCount = 0;
|
|
private int particleCount = 0;
|
|
|
|
// opengl handles
|
|
private int explHandle;
|
|
private int atomicHandle;
|
|
|
|
public ExplosionComputeHandler(GL4 gl) {
|
|
this.gl = gl;
|
|
}
|
|
|
|
public void createNewExplosionData() {
|
|
float x = random.nextFloat() * 2f - 1f;
|
|
float y = random.nextFloat() * 2f - 1f;
|
|
|
|
if ((particleCount + newParticleCount) > (MAX_EXPLOSION_PARTICLES - EXPLOSION_PARTICLES)) {
|
|
return;
|
|
}
|
|
|
|
float r = random.nextFloat() * 0.25f;
|
|
float g = random.nextFloat() * 0.25f;
|
|
float b = random.nextFloat() * 0.25f;
|
|
|
|
for (int i = newParticleCount; i < newParticleCount + EXPLOSION_PARTICLES; i++) {
|
|
int offset = i * 8;
|
|
|
|
float angle = (float) (random.nextFloat() * Math.PI * 2f);
|
|
float velocity = (random.nextFloat() * 0.25f) + (random.nextFloat() * 0.25f);
|
|
|
|
explBuffer.put(offset + 0, x);
|
|
explBuffer.put(offset + 1, y);
|
|
explBuffer.put(offset + 2, (float) (Math.sin(angle) * velocity));
|
|
explBuffer.put(offset + 3, (float) (Math.cos(angle) * velocity));
|
|
|
|
explBuffer.put(offset + 4, r);
|
|
explBuffer.put(offset + 5, g);
|
|
explBuffer.put(offset + 6, b);
|
|
explBuffer.put(offset + 7, random.nextFloat() * 0.5f + 0.5f);
|
|
}
|
|
|
|
newParticleCount = newParticleCount + EXPLOSION_PARTICLES;
|
|
}
|
|
|
|
public void init() {
|
|
explosionProgram = new ComputeProgram(gl, Util.loadAsText(getClass(), "explosion.comp"));
|
|
explosionProgram.getUniformLocation("delta");
|
|
|
|
explCleanUpProgram = new ComputeProgram(gl, Util.loadAsText(getClass(), "explosionCleanUp.comp"));
|
|
|
|
explProgram = new ShaderProgram(gl,
|
|
Util.loadAsText(getClass(), "explShader.vert"),
|
|
Util.loadAsText(getClass(), "explShader.frag"));
|
|
|
|
int[] tmpHandle = new int[2];
|
|
gl.glGenBuffers(2, tmpHandle, 0);
|
|
|
|
explHandle = tmpHandle[0];
|
|
atomicHandle = tmpHandle[1];
|
|
|
|
// Select the VBO, GPU memory data, to use for vertices
|
|
gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, explHandle);
|
|
|
|
// transfer data to VBO, this perform the copy of data from CPU -> GPU memory
|
|
gl.glBufferData(GL.GL_ARRAY_BUFFER, explBuffer.limit() * 4, explBuffer, GL.GL_DYNAMIC_DRAW);
|
|
}
|
|
|
|
public void updateGpu() {
|
|
// Select the VBO, GPU memory data, to use for vertices
|
|
gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, explHandle);
|
|
|
|
// transfer data to VBO, this perform the copy of data from CPU -> GPU memory
|
|
gl.glBufferSubData(GL.GL_ARRAY_BUFFER, particleCount * 4 * 8, newParticleCount * 4 * 8, explBuffer);
|
|
|
|
gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
|
|
|
|
gl.glBindBuffer(GL4.GL_ATOMIC_COUNTER_BUFFER, atomicHandle);
|
|
|
|
atomicBuffer.put(0, particleCount + newParticleCount);
|
|
|
|
// transfer data to VBO, this perform the copy of data from CPU -> GPU memory
|
|
gl.glBufferData(GL4.GL_ATOMIC_COUNTER_BUFFER, 4, atomicBuffer, GL.GL_DYNAMIC_DRAW);
|
|
|
|
gl.glBindBuffer(GL4.GL_ATOMIC_COUNTER_BUFFER, 0);
|
|
|
|
newParticleCount = 0;
|
|
}
|
|
|
|
public void execute(float delta) {
|
|
explosionProgram.begin();
|
|
|
|
gl.glUniform1f(explosionProgram.getUniformLocation("delta"), delta);
|
|
|
|
gl.glBindBufferBase(GL4.GL_SHADER_STORAGE_BUFFER, 0, explHandle);
|
|
gl.glBindBufferBase(GL4.GL_ATOMIC_COUNTER_BUFFER, 1, atomicHandle);
|
|
|
|
explosionProgram.compute((particleCount / 512) + 1, 1, 1);
|
|
|
|
gl.glBindBufferBase(GL4.GL_SHADER_STORAGE_BUFFER, 0, 0);
|
|
gl.glBindBufferBase(GL4.GL_ATOMIC_COUNTER_BUFFER, 1, 0);
|
|
|
|
explosionProgram.end();
|
|
}
|
|
|
|
public void cleanUp() {
|
|
explCleanUpProgram.begin();
|
|
|
|
gl.glBindBufferBase(GL4.GL_SHADER_STORAGE_BUFFER, 0, explHandle);
|
|
gl.glBindBufferBase(GL4.GL_ATOMIC_COUNTER_BUFFER, 1, atomicHandle);
|
|
|
|
explCleanUpProgram.compute((particleCount / 512) + 1, 1, 1);
|
|
|
|
gl.glBindBufferBase(GL4.GL_SHADER_STORAGE_BUFFER, 0, 0);
|
|
gl.glBindBufferBase(GL4.GL_ATOMIC_COUNTER_BUFFER, 1, 0);
|
|
|
|
explCleanUpProgram.end();
|
|
}
|
|
|
|
public void render() {
|
|
explProgram.begin();
|
|
|
|
if (particleCount > 0) {
|
|
gl.glEnableVertexAttribArray(0);
|
|
gl.glEnableVertexAttribArray(1);
|
|
|
|
gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, explHandle);
|
|
|
|
// Associate Vertex attribute 0 with the last bound VBO
|
|
gl.glVertexAttribPointer(0 /* the vertex attribute */, 2,
|
|
GL2ES2.GL_FLOAT, false /* normalized? */, 32 /* stride */,
|
|
0 /* The bound VBO data offset */);
|
|
|
|
// Associate Vertex attribute 0 with the last bound VBO
|
|
gl.glVertexAttribPointer(1 /* the vertex attribute */, 4,
|
|
GL2ES2.GL_FLOAT, false /* normalized? */, 32 /* stride */,
|
|
16 /* The bound VBO data offset */);
|
|
|
|
gl.glDrawArrays(GL2ES2.GL_POINTS, 0, particleCount);
|
|
|
|
gl.glDisableVertexAttribArray(0);
|
|
gl.glDisableVertexAttribArray(1);
|
|
}
|
|
|
|
explProgram.end();
|
|
}
|
|
|
|
public void getGpuData() {
|
|
gl.glBindBuffer(GL4.GL_ATOMIC_COUNTER_BUFFER, atomicHandle);
|
|
gl.glGetBufferSubData(GL4.GL_ATOMIC_COUNTER_BUFFER, 0, 4, atomicBuffer);
|
|
particleCount = atomicBuffer.get(0);
|
|
newParticleCount = 0;
|
|
gl.glBindBuffer(GL4.GL_ATOMIC_COUNTER_BUFFER, 0);
|
|
}
|
|
|
|
public int getParticleCount() {
|
|
return particleCount;
|
|
}
|
|
|
|
public void dispose() {
|
|
explProgram.dispose();
|
|
explosionProgram.dispose();
|
|
explCleanUpProgram.dispose();
|
|
}
|
|
}
|