Initial commit

This commit is contained in:
rnentjes
2014-01-17 12:34:48 +01:00
commit 9f68d51064
35 changed files with 1732 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
package com.persesgames.jogl;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.KeyListener;
/**
* Date: 12/30/13
* Time: 9:25 PM
*/
public class Keyboard implements KeyListener {
private boolean [] pressed = new boolean[127];
private boolean [] released = new boolean[127];
@Override
public void keyPressed(KeyEvent keyEvent) {
if (keyEvent.getKeyCode() > 0 && keyEvent.getKeyCode() < pressed.length) {
pressed[keyEvent.getKeyCode()] = true;
}
}
@Override
public void keyReleased(KeyEvent keyEvent) {
if (keyEvent.getKeyCode() > 0 && keyEvent.getKeyCode() < pressed.length) {
pressed[keyEvent.getKeyCode()] = false;
released[keyEvent.getKeyCode()] = true;
}
}
public boolean isPressed(short keyCode) {
return keyCode < pressed.length && pressed[keyCode];
}
public boolean isReleased(short keyCode) {
boolean result = keyCode < pressed.length && released[keyCode];
released[keyCode] = false;
return result;
}
}

View File

@@ -0,0 +1,216 @@
package com.persesgames.jogl;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.opengl.GLWindow;
import com.persesgames.jogl.explosion.ExplosionComputeHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.media.opengl.*;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* Date: 10/25/13
* Time: 7:42 PM
*/
public class Renderer implements GLEventListener {
private final static Logger logger = LoggerFactory.getLogger(Renderer.class);
private final static int MAX_ENTITIES_PER_COLOR = 2000000;
private final Random random = new Random(System.nanoTime());
private volatile boolean stopped = false;
private volatile boolean dirty = true;
private final GLWindow glWindow;
private int width = 100, height = 100;
private Keyboard keyboard;
private boolean checkError = false;
private long lastLog = System.nanoTime();
private long start = System.currentTimeMillis();
private Timer timer = new Timer(TimeUnit.SECONDS, 1);
private ExplosionComputeHandler explosionComputeHandler;
public Renderer(GLWindow glWindow, Keyboard keyboard) {
this.glWindow = glWindow;
this.keyboard = keyboard;
}
public void stop() {
stopped = true;
}
public void redraw() {
dirty = true;
}
public void run() {
Renderer.this.glWindow.display();
while(!stopped) {
if (dirty) {
//logger.info("rendering+" + System.currentTimeMillis());
Renderer.this.glWindow.display();
//Renderer.this.glWindow.swapBuffers();
dirty = true;
} else {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
logger.warn(e.getMessage(), e);
}
}
stopped = keyboard.isPressed(KeyEvent.VK_ESCAPE);
}
Renderer.this.glWindow.destroy();
}
@Override
public void init(GLAutoDrawable drawable) {
timer.start("init");
GL4 gl = drawable.getGL().getGL4();
gl.setSwapInterval(0);
// debug init
//gl = new DebugGL4(gl);
logger.info("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities());
logger.info("INIT GL IS: " + gl.getClass().getName());
logger.info("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR));
logger.info("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER));
logger.info("GL_VERSION: " + gl.glGetString(GL.GL_VERSION));
int [] result = new int[3];
gl.glGetIntegerv(GL2.GL_MAX_VERTEX_ATTRIBS, result, 0);
logger.info("GL_MAX_VERTEX_ATTRIBS=" + result[0]);
gl.glGetIntegerv(GL4.GL_MAX_COMPUTE_WORK_GROUP_SIZE, result, 0);
logger.info("GL_MAX_COMPUTE_WORK_GROUP_SIZE= {},{},{}", result[0], result[1], result[2]);
gl.glGetIntegerv(GL4.GL_MAX_COMPUTE_WORK_GROUP_COUNT, result, 0);
logger.info("GL_MAX_COMPUTE_WORK_GROUP_COUNT= {},{},{}", result[0], result[1], result[2]);
explosionComputeHandler = new ExplosionComputeHandler(gl);
explosionComputeHandler.init();
explosionComputeHandler.createNewExplosionData();
explosionComputeHandler.updateGpu();
timer.stop("init");
}
@Override
public void dispose(GLAutoDrawable drawable) {
explosionComputeHandler.dispose();
}
private long lastDelta = System.nanoTime();
private float delta = 0f;
private void calculateCurrentDelta() {
long nanoDelta = System.nanoTime() - lastDelta;
delta = (nanoDelta / 1000000000f);
lastDelta = System.nanoTime();
}
@Override
public void display(GLAutoDrawable drawable) {
//logger.info("display+" + System.currentTimeMillis());
calculateCurrentDelta();
GL4 gl = drawable.getGL().getGL4();
if (checkError) {
// debug
gl.glGetError();
gl = new DebugGL4(gl);
}
if (keyboard.isPressed(KeyEvent.VK_SHIFT)) {
explosionComputeHandler.createNewExplosionData();
explosionComputeHandler.updateGpu();
}
if (keyboard.isReleased(KeyEvent.VK_SPACE)) {
explosionComputeHandler.createNewExplosionData();
explosionComputeHandler.updateGpu();
}
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_DST_ALPHA);
gl.glViewport(0, 0, width, height);
// Clear screen
gl.glClearColor(0.1f, 0.0f, 0.1f, 1f);
gl.glClear(GL2ES2.GL_COLOR_BUFFER_BIT);
timer.start("getCount");
/*
timer.start("BindBuffer");
gl.glBindBuffer(GL4.GL_ATOMIC_COUNTER_BUFFER, atomicHandle);
timer.stop("BindBuffer");
// again we map the buffer to userCounters, but this time for read-only access
timer.start("MapBufferRange");
ByteBuffer last = gl.glMapBufferRange(GL4.GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL4.GL_MAP_READ_BIT);
timer.stop("MapBufferRange");
particleCount = last.getInt();
timer.start("UnmapBuffer");
gl.glUnmapBuffer(GL4.GL_ATOMIC_COUNTER_BUFFER);
timer.stop("UnmapBuffer");
*/
timer.stop("getCount");
timer.start("compute");
explosionComputeHandler.execute(delta);
explosionComputeHandler.cleanUp();
timer.stop("compute");
timer.start("getGpuData");
explosionComputeHandler.getGpuData();
timer.stop("getGpuData");
timer.start("draw");
explosionComputeHandler.render();
timer.stop("draw");
timer.log();
if (lastLog < System.nanoTime() - TimeUnit.SECONDS.toNanos(1)) {
lastLog = System.nanoTime();
logger.info("Explosion particles: {}", explosionComputeHandler.getParticleCount());
}
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
logger.info("reshape+" + System.currentTimeMillis());
this.width = w;
this.height = h;
}
}

View File

@@ -0,0 +1,50 @@
package com.persesgames.jogl;
import com.jogamp.newt.opengl.GLWindow;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLProfile;
/**
* Date: 10/25/13
* Time: 7:27 PM
*/
public class TestJogl {
public static void main(String [] args) {
TestJogl test = new TestJogl();
test.run();
}
private final Renderer renderer;
public TestJogl() {
GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GL4ES3));
caps.setDoubleBuffered(true);
GLWindow glWindow = GLWindow.create(caps);
glWindow.setTitle("jogl-triangle");
glWindow.setSize(800, 800);
glWindow.setFullscreen(false);
glWindow.setUndecorated(false);
glWindow.setPointerVisible(true);
glWindow.setVisible(true);
Keyboard keyboard = new Keyboard();
glWindow.addKeyListener(keyboard);
renderer = new Renderer(glWindow, keyboard);
glWindow.addGLEventListener(renderer);
}
public void run() {
renderer.run();
}
}

View File

@@ -0,0 +1,106 @@
package com.persesgames.jogl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Date: 1/4/14
* Time: 8:00 PM
*/
public class Timer {
private final static Logger logger = LoggerFactory.getLogger(Timer.class);
private Map<String, Long> start = new HashMap<>();
private Map<String, Long> times = new HashMap<>();
private Map<String, Long> calls = new HashMap<>();
private long nanoStart = System.nanoTime();
private final TimeUnit unit;
private final int units;
private long lastLog = System.nanoTime();
public Timer(TimeUnit unit, int units) {
this.unit = unit;
this.units = units;
}
private long getStart(String timer) {
Long result = start.get(timer);
if (result == null) {
result = System.nanoTime();
start.put(timer, result);
}
return result;
}
private long getTime(String timer) {
Long result = times.get(timer);
if (result == null) {
result = 0l;
times.put(timer, result);
}
return result;
}
private long getCalls(String timer) {
Long result = calls.get(timer);
if (result == null) {
result = 0l;
calls.put(timer, result);
}
return result;
}
public void start(String timer) {
start.put(timer, System.nanoTime());
}
public void stop(String timer) {
long start = getStart(timer);
long delta = System.nanoTime() - start;
long time = getTime(timer);
time += delta;
times.put(timer, time);
calls.put(timer, getCalls(timer) + 1);
}
public void reset() {
lastLog = System.nanoTime();
start.clear();
times.clear();
calls.clear();
}
public void log() {
if (System.nanoTime() > (lastLog + unit.toNanos(units))) {
for (String timer : times.keySet()) {
logger.info("Timer '{}' calls '{}' time '{}ms' time/call '{}ms'", timer, getCalls(timer), (getTime(timer) / 1000000d), (getTime(timer) / 1000000d) / (double)getCalls(timer));
}
reset();
}
}
}

View File

@@ -0,0 +1,27 @@
package com.persesgames.jogl;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Date: 10/25/13
* Time: 11:03 PM
*/
public class Util {
public static String loadAsText(Class cls, String name) {
byte [] buffer = new byte[1024];
int nr;
try (InputStream in = cls.getResourceAsStream(name); ByteArrayOutputStream out = new ByteArrayOutputStream()) {
while((nr = in.read(buffer)) > 0) {
out.write(buffer,0,nr);
}
return new String(out.toByteArray(), "UTF-8");
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
}

View File

@@ -0,0 +1,203 @@
package com.persesgames.jogl.explosion;
import com.jogamp.common.nio.Buffers;
import com.persesgames.jogl.shader.ComputeProgram;
import com.persesgames.jogl.shader.ShaderProgram;
import com.persesgames.jogl.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GL4;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Random;
/**
* 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 = 1000000;
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 (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.glBufferData(GL.GL_ARRAY_BUFFER, particleCount * 4 * 8, explBuffer, GL.GL_DYNAMIC_DRAW);
gl.glBufferSubData(GL.GL_ARRAY_BUFFER, particleCount * 4 * 8, newParticleCount * 4 * 8, explBuffer);
// Select the VBO, GPU memory data, to use for vertices
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(GL2ES2.GL_ARRAY_BUFFER, 0);
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();
}
}

View File

@@ -0,0 +1,19 @@
#if __VERSION__ >= 130
#define varying in
out vec4 mgl_FragColor;
#define texture2D texture
#define gl_FragColor mgl_FragColor
#endif
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
varying vec4 varying_Color;
void main (void) {
float alpha = 1 - smoothstep(0, 1, 2 * distance(gl_PointCoord.st, vec2(0.5, 0.5)));
gl_FragColor = vec4(varying_Color.rgb, varying_Color.a * alpha);
}

View File

@@ -0,0 +1,22 @@
#if __VERSION__ >= 130
#define attribute in
#define varying out
#endif
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
attribute vec4 attribute_Position;
attribute vec4 attribute_Color;
varying vec4 varying_Color;
void main(void) {
mat4 uniform_Projection = mat4(1);
gl_PointSize = 15f;
gl_Position = uniform_Projection * attribute_Position; //vec4(attribute_Position.x, attribute_Position.y, 0, 1);
varying_Color = attribute_Color;
}

View File

@@ -0,0 +1,42 @@
#version 430 core
#define pi 3.141592653589793238462643383279
precision mediump float;
precision mediump int;
struct explosion {
vec4 positionVelocity;
vec4 color;
};
layout (std430, binding = 0) buffer entities {
explosion e[];
};
layout(binding = 1, offset = 0) uniform atomic_uint lastCounter;
uniform float delta;
layout(local_size_x = 512) in;
void main() {
uint gid = gl_GlobalInvocationID.x;
uint last = atomicCounter(lastCounter);
if (gid < last) {
vec2 position = e[gid].positionVelocity.xy;
vec2 velocity = e[gid].positionVelocity.zw;
vec4 color = e[gid].color;
if (color.a > 0.0) {
//velocity = velocity * 0.99;
position = position + velocity * delta * color.a;
color.a = color.a - (delta / 2);
} else {
color.a = 0.0;
}
e[gid].positionVelocity = vec4(position, velocity);
e[gid].color = color;
}
}

View File

@@ -0,0 +1,36 @@
#version 430 core
#define pi 3.141592653589793238462643383279
precision mediump float;
precision mediump int;
struct explosion {
vec4 positionVelocity;
vec4 color;
};
layout (std430, binding = 0) buffer entities {
explosion e[];
};
layout(binding = 1, offset = 0) uniform atomic_uint lastCounter;
layout (local_size_x = 512) in;
void main() {
uint gid = gl_GlobalInvocationID.x;
uint last = atomicCounter(lastCounter);
if (gid < last && last > 0) {
vec4 color = e[gid].color;
if (color.a == 0.0) {
uint old = atomicCounterDecrement(lastCounter);
e[gid].positionVelocity = e[old].positionVelocity;
e[gid].color = e[old].color;
e[old].color.a = 0;
}
}
}

View File

@@ -0,0 +1,126 @@
package com.persesgames.jogl.shader;
import com.persesgames.jogl.Renderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GL4;
import java.util.HashMap;
import java.util.Map;
/*-----------------------------------------------------+
| App |
| pPPAPPp |
| APP PPa |
| APA pPP PapA PapA |
| PPA APA pP P pP P |
| APPPPPPPA PPp Ap Ap Ap Ap |
| apPPA aPP P P |
| APA pPP p p |
| pPP PPA |
| PPp PPPp |
| |
| Created by: App Software |
| Email: info@appsoftware.nl |
| Web: http://www.appsoftware.nl/ |
| |
+-----------------------------------------------------*/
public class ComputeProgram {
private final static Logger logger = LoggerFactory.getLogger(Renderer.class);
protected GL4 gl;
private int shaderProgram;
private int computeShader;
private Map<String, Integer> uniformLocations = new HashMap<>();
private Map<String, Integer> attribLocations = new HashMap<>();
public ComputeProgram(GL4 gl, String compute) {
this.gl = gl;
computeShader = createAndCompileShader(GL4.GL_COMPUTE_SHADER, compute);
shaderProgram = gl.glCreateProgram();
gl.glAttachShader(shaderProgram, computeShader);
gl.glLinkProgram(shaderProgram);
}
public int getUniformLocation(String uniform) {
Integer result = uniformLocations.get(uniform);
if (result == null) {
result = gl.glGetUniformLocation(shaderProgram, uniform);
uniformLocations.put(uniform, result);
}
return result;
}
public int getAttribLocation(String attrib) {
Integer result = attribLocations.get(attrib);
if (result == null) {
result = gl.glGetAttribLocation(shaderProgram, attrib);
attribLocations.put(attrib, result);
}
return result;
}
public void bindAttributeLocation(int location, String name) {
gl.glBindAttribLocation(shaderProgram, location, name);
}
public void begin() {
gl.glUseProgram(shaderProgram);
}
public void compute(int x, int y, int z) {
gl.glDispatchCompute(x, y, z);
}
public void end() {
gl.glUseProgram(0);
}
public void dispose() {
gl.glDetachShader(shaderProgram, computeShader);
gl.glDeleteShader(computeShader);
gl.glDeleteProgram(shaderProgram);
}
private int createAndCompileShader(int type, String shaderString) {
int shader = gl.glCreateShader(type);
String[] vlines = new String[]{shaderString};
int[] vlengths = new int[]{vlines[0].length()};
gl.glShaderSource(shader, vlines.length, vlines, vlengths, 0);
gl.glCompileShader(shader);
int[] compiled = new int[1];
gl.glGetShaderiv(shader, GL2ES2.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
int[] logLength = new int[1];
gl.glGetShaderiv(shader, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);
byte[] log = new byte[logLength[0]];
gl.glGetShaderInfoLog(shader, logLength[0], (int[]) null, 0, log, 0);
throw new IllegalStateException("Error compiling the shader: " + new String(log));
}
return shader;
}
}

View File

@@ -0,0 +1,131 @@
package com.persesgames.jogl.shader;
import com.persesgames.jogl.Renderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.media.opengl.GL2ES2;
import java.util.HashMap;
import java.util.Map;
/*-----------------------------------------------------+
| App |
| pPPAPPp |
| APP PPa |
| APA pPP PapA PapA |
| PPA APA pP P pP P |
| APPPPPPPA PPp Ap Ap Ap Ap |
| apPPA aPP P P |
| APA pPP p p |
| pPP PPA |
| PPp PPPp |
| |
| Created by: App Software |
| Email: info@appsoftware.nl |
| Web: http://www.appsoftware.nl/ |
| |
+-----------------------------------------------------*/
public class ShaderProgram {
private final static Logger logger = LoggerFactory.getLogger(Renderer.class);
private GL2ES2 gl;
private int shaderProgram;
private int vertShader;
private int fragShader;
private Map<String, Integer> uniformLocations = new HashMap<>();
private Map<String, Integer> attribLocations = new HashMap<>();
public ShaderProgram(GL2ES2 gl, String vertex, String fragment) {
this.gl = gl;
if (gl.isGL3core()) {
logger.info("GL3 core detected: explicit adding #version 130 to shaders");
vertex = "#version 130\n" + vertex;
fragment = "#version 130\n" + fragment;
}
vertShader = createAndCompileShader(GL2ES2.GL_VERTEX_SHADER, vertex);
fragShader = createAndCompileShader(GL2ES2.GL_FRAGMENT_SHADER, fragment);
shaderProgram = gl.glCreateProgram();
gl.glAttachShader(shaderProgram, vertShader);
gl.glAttachShader(shaderProgram, fragShader);
gl.glLinkProgram(shaderProgram);
}
public int getUniformLocation(String uniform) {
Integer result = uniformLocations.get(uniform);
if (result == null) {
result = gl.glGetUniformLocation(shaderProgram, uniform);
uniformLocations.put(uniform, result);
}
return result;
}
public int getAttribLocation(String attrib) {
Integer result = attribLocations.get(attrib);
if (result == null) {
result = gl.glGetAttribLocation(shaderProgram, attrib);
attribLocations.put(attrib, result);
}
return result;
}
public void bindAttributeLocation(int location, String name) {
gl.glBindAttribLocation(shaderProgram, location, name);
}
public void begin() {
gl.glUseProgram(shaderProgram);
}
public void end() {
gl.glUseProgram(0);
}
public void dispose() {
gl.glDetachShader(shaderProgram, vertShader);
gl.glDeleteShader(vertShader);
gl.glDetachShader(shaderProgram, fragShader);
gl.glDeleteShader(fragShader);
gl.glDeleteProgram(shaderProgram);
}
private int createAndCompileShader(int type, String shaderString) {
int shader = gl.glCreateShader(type);
String[] vlines = new String[]{shaderString};
int[] vlengths = new int[]{vlines[0].length()};
gl.glShaderSource(shader, vlines.length, vlines, vlengths, 0);
gl.glCompileShader(shader);
int[] compiled = new int[1];
gl.glGetShaderiv(shader, GL2ES2.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
int[] logLength = new int[1];
gl.glGetShaderiv(shader, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);
byte[] log = new byte[logLength[0]];
gl.glGetShaderInfoLog(shader, logLength[0], (int[]) null, 0, log, 0);
throw new IllegalStateException("Error compiling the shader: " + new String(log));
}
return shader;
}
}