TextureView shows empty screen with OpenGl - java

I am trying to use open gl in my android app . i followed this doc https://developer.android.com/training/graphics/opengl/draw and i'm able to draw triangles and some complex animations using GlSurfaceView .
Now i want to use these inside a list but that can't be done with GLSurfaceView so i switcheed to TextureView . Here is an implementation to show how to do it in Grafika
https://github.com/google/grafika/blob/master/app/src/main/java/com/android/grafika/TextureViewGLActivity.java
Now when i put my code in the doAnimation() it doesn't work ..
i'm attaching some code
public class Triangle {
private static final String TAG = "Triangle";
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private int mProgram;
//for draw function
private int mPositionHandle;
private int mColorHandle;
private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
// Use to access and set the view transformation
private int mMVPMatrixHandle;
private FloatBuffer vertexBuffer;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float triangleCoords[] = { // in counterclockwise order:
0.0f, 0.622008459f, 0.0f, // top
-0.5f, -0.311004243f, 0.0f, // bottom left
0.5f, -0.311004243f, 0.0f // bottom right
};
// Set color with red, green, blue and alpha (opacity) values
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
public Triangle() {
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (number of coordinate values * 4 bytes per float)
triangleCoords.length * 4);
// use the device hardware's native byte order
bb.order(ByteOrder.nativeOrder());
// create a floating point buffer from the ByteBuffer
vertexBuffer = bb.asFloatBuffer();
// add the coordinates to the FloatBuffer
vertexBuffer.put(triangleCoords);
// set the buffer to read the first coordinate
vertexBuffer.position(0);
setUpShaders();
}
private void setUpShaders(){
int vertexShader = OpenGlUtil.loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = OpenGlUtil.loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
// create empty OpenGL ES Program
mProgram = GLES20.glCreateProgram();
// add the vertex shader to program
GLES20.glAttachShader(mProgram, vertexShader);
// add the fragment shader to program
GLES20.glAttachShader(mProgram, fragmentShader);
// creates OpenGL ES program executables
GLES20.glLinkProgram(mProgram);
GlUtil.checkGlError("glGenTextures");
}
public void draw(float[] mvpMatrix) {
// Add program to OpenGL ES environment
GLES20.glUseProgram(mProgram);
GlUtil.checkGlError("glUseProgram");
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
GlUtil.checkGlError("glGetAttribLocation");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
GlUtil.checkGlError("glEnableVertexAttribArray");
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
GlUtil.checkGlError("glVertexAttribPointer");
// get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
GlUtil.checkGlError("glUniform4fv");
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
// Pass the projection and view transformation to the shader
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GlUtil.checkGlError("glUniformMatrix4fv");
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
GlUtil.checkGlError("glDrawArrays");
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GlUtil.checkGlError("glDisableVertexAttribArray");
}
}
this is the texture view class
public class TestTextureView extends TextureView {
private static final String TAG = "TestTextureView";
private Renderer mRenderer;
private static volatile boolean sReleaseInCallback = true;
public TestTextureView(Context context) {
super(context);
init(context);
}
public TestTextureView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public TestTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public TestTextureView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context){
// Start up the Renderer thread. It'll sleep until the TextureView is ready.
mRenderer = new Renderer(context);
mRenderer.start();
// Set the Renderer for drawing on the GLSurfaceView
setSurfaceTextureListener(mRenderer);
}
public void onDestroy(){
mRenderer.halt();
}
public Renderer getmRenderer() {
return mRenderer;
}
/**
* Handles GL rendering and SurfaceTexture callbacks.
* <p>
* We don't create a Looper, so the SurfaceTexture-by-way-of-TextureView callbacks
* happen on the UI thread.
*/
public static class Renderer extends Thread implements SurfaceTextureListener {
private Object mLock = new Object(); // guards mSurfaceTexture, mDone
private SurfaceTexture mSurfaceTexture;
private EglCore mEglCore;
private boolean mDone;
// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private int starshipType=Config.TYPE_STARSHIP_LIFE,numMoons=1,type_phase=1;
private int level=1;
private Bitmap newProfileBitmap,newVesselBitmap;
//for life
private ArrayList<Shape> list;
private String name;
private Image image,imageStar,imageStar2,imageStar3;
private CircleImage circleImage,planet;
float degrees=0,degrees2=120,degrees3=240;
float shrinkingDegrees=0,animScale=0;
private float[] star1Array,star2Array,star3Array;
private float[] vesselArray,profileArray,planetArray;
private float baseTranslation=1;
private Context context;
public Renderer(Context context) {
this.context = context;
}
/**
* Tells the thread to stop running.
*/
public void halt() {
synchronized (mLock) {
mDone = true;
mLock.notify();
}
}
#Override // will be called on UI thread
public void onSurfaceTextureAvailable(SurfaceTexture st, int width, int height) {
Log.d(TAG, "onSurfaceTextureAvailable(" + width + "x" + height + ")");
synchronized (mLock) {
mSurfaceTexture = st;
mLock.notify();
}
}
#Override // will be called on UI thread
public void onSurfaceTextureSizeChanged(SurfaceTexture st, int width, int height) {
Log.d(TAG, "onSurfaceTextureSizeChanged(" + width + "x" + height + ")");
// TODO: ?
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
// this projection matrix is applied to object coordinates
// in the onDrawFrame() method
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
#Override // will be called on UI thread
public boolean onSurfaceTextureDestroyed(SurfaceTexture st) {
Log.d(TAG, "onSurfaceTextureDestroyed");
// We set the SurfaceTexture reference to null to tell the Renderer thread that
// it needs to stop. The renderer might be in the middle of drawing, so we want
// to return false here so that the caller doesn't try to release the ST out
// from under us.
//
// In theory.
//
// In 4.4, the buffer queue was changed to be synchronous, which means we block
// in dequeueBuffer(). If the renderer has been running flat out and is currently
// sleeping in eglSwapBuffers(), it's going to be stuck there until somebody
// tears down the SurfaceTexture. So we need to tear it down here to ensure
// that the renderer thread will break. If we don't, the thread sticks there
// forever.
//
// The only down side to releasing it here is we'll get some complaints in logcat
// when eglSwapBuffers() fails.
synchronized (mLock) {
mSurfaceTexture = null;
}
if (sReleaseInCallback) {
Log.i(TAG, "Allowing TextureView to release SurfaceTexture");
}
return sReleaseInCallback;
}
#Override // will be called on UI thread
public void onSurfaceTextureUpdated(SurfaceTexture st) {
//Log.d(TAG, "onSurfaceTextureUpdated");
}
#Override
public void run() {
while (true) {
SurfaceTexture surfaceTexture = null;
// Latch the SurfaceTexture when it becomes available. We have to wait for
// the TextureView to create it.
synchronized (mLock) {
while (!mDone && (surfaceTexture = mSurfaceTexture) == null) {
try {
mLock.wait();
} catch (InterruptedException ie) {
throw new RuntimeException(ie); // not expected
}
}
if (mDone) {
break;
}
}
Log.d(TAG, "Got surfaceTexture=" + surfaceTexture);
// Create an EGL surface for our new SurfaceTexture. We're not on the same
// thread as the SurfaceTexture, which is a concern for the *consumer*, which
// wants to call updateTexImage(). Because we're the *producer*, i.e. the
// one generating the frames, we don't need to worry about being on the same
// thread.
mEglCore = new EglCore(null, EglCore.FLAG_TRY_GLES3);
WindowSurface windowSurface = new WindowSurface(mEglCore, mSurfaceTexture);
windowSurface.makeCurrent();
//setEGLContextClientVersion();
// Render frames until we're told to stop or the SurfaceTexture is destroyed.
doAnimation(windowSurface);
windowSurface.release();
mEglCore.release();
if (!sReleaseInCallback) {
Log.i(TAG, "Releasing SurfaceTexture in renderer thread");
surfaceTexture.release();
}
}
Log.d(TAG, "Renderer thread exiting");
}
/**
* Draws updates as fast as the system will allow.
* <p>
* In 4.4, with the synchronous buffer queue queue, the frame rate will be limited.
* In previous (and future) releases, with the async queue, many of the frames we
* render may be dropped.
* <p>
* The correct thing to do here is use Choreographer to schedule frame updates off
* of vsync, but that's not nearly as much fun.
*/
private void doAnimation(WindowSurface eglSurface) {
final int BLOCK_WIDTH = 80;
final int BLOCK_SPEED = 2;
float clearColor = 0.0f;
int xpos = -BLOCK_WIDTH / 2;
int xdir = BLOCK_SPEED;
int width = eglSurface.getWidth();
int height = eglSurface.getHeight();
Log.d(TAG, "Animating " + width + "x" + height + " EGL surface");
while (true) {
// Check to see if the TextureView's SurfaceTexture is still valid.
synchronized (mLock) {
SurfaceTexture surfaceTexture = mSurfaceTexture;
if (surfaceTexture == null) {
Log.d(TAG, "doAnimation exiting");
return;
}
}
//Log.d(TAG, "doAnimation: loading new frame");
/*
//ORIGINAL CODE IN GRAFIKA ----------------------------------------------
// Still alive, render a frame.
GLES20.glClearColor(clearColor, clearColor, clearColor, 1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
GLES20.glScissor(xpos, height / 4, BLOCK_WIDTH, height / 2);
GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
// Publish the frame. If we overrun the consumer, frames will be dropped,
// so on a sufficiently fast device the animation will run at faster than
// the display refresh rate.
//
// If the SurfaceTexture has been destroyed, this will throw an exception.
eglSurface.swapBuffers();
// Advance state
clearColor += 0.015625f;
if (clearColor > 1.0f) {
clearColor = 0.0f;
}
xpos += xdir;
if (xpos <= -BLOCK_WIDTH / 2 || xpos >= width - BLOCK_WIDTH / 2) {
Log.d(TAG, "change direction");
xdir = -xdir;
}
*/
//MY CODE -----------------------------------------
onDrawFrame();
//eglSurface.swapBuffers();
if (!eglSurface.swapBuffers()) {
Log.e(TAG, "cannot swap buffers!");
}
GlUtil.checkGlError("cannot swap buffers");
}
}
boolean created=false;
Triangle triangle;
private void setUpObjects(){
image=new Image(context, -1);
imageStar=new Image(context,R.drawable.moon1);
imageStar2=new Image(context,R.drawable.moon2);
imageStar3=new Image(context,R.drawable.moon3);
circleImage=new CircleImage(context,R.drawable.profile);
planet=new CircleImage(context,R.drawable.earth);
triangle=new Triangle();
setInitialSettings();
}
private void setInitialSettings(){
// Set the background color to black ( rgba ).
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0f);
GLES20.glClearDepthf(1.0f);
GLES20.glEnable( GLES20.GL_DEPTH_TEST );
GLES20.glDepthFunc( GLES20.GL_LEQUAL );
//https://stackoverflow.com/questions/3388294/opengl-question-about-the-usage-of-gldepthmask/3390094#3390094
GLES20.glDepthMask( true );
}
private void onDrawFrame(){
//Log.d(TAG, "onDrawFrame: ");
if(!created){
setUpObjects();
created=true;
}
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT|GLES20.GL_DEPTH_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
triangle.draw(mProjectionMatrix);
}
}
}

Related

GP/GPU : ping pong technique with JOGL

I've tried to implement an reaction-diffusion model on GPU with JOGL and GLSL.
I use a ping pong technique with 2 FramebufferObject ( I've tried too with one FBO and 2 Colors attachements without success).
Shader seems correct since I've tried it in unity (with some adaptations) and it works.
After one week of trying many things, i'm completely out of idea to make this code works. I'm really not specialist of JOGL, so maybe i miss something evident.
The result is an image which becomes white with time : no reaction-diffusion behaviors and I don't understand why !
Thanks in advance for helps. Here is my code :
package gpu2;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.nio.IntBuffer;
import java.nio.FloatBuffer;
import java.io.File;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.util.FPSAnimator;
import com.jogamp.opengl.GLFBODrawable;
import com.jogamp.opengl.FBObject;
import com.jogamp.opengl.FBObject.Colorbuffer;
import com.jogamp.opengl.FBObject.ColorAttachment;
import com.jogamp.opengl.FBObject.TextureAttachment;
import com.jogamp.opengl.util.glsl.ShaderCode;
import com.jogamp.opengl.util.glsl.ShaderProgram;
import com.jogamp.opengl.util.glsl.ShaderUtil;
import com.jogamp.opengl.util.GLBuffers;
import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureIO;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLOffscreenAutoDrawable;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.util.awt.AWTGLReadBufferUtil;
import com.jogamp.opengl.GLDrawableFactory;
import static com.jogamp.opengl.GL.*; // GL constants
import static com.jogamp.opengl.GL2.*; // GL2 constants
import gpu2.ModelParam;
/**
* JOGL 2.0 Program Template (GLCanvas)
* This is a "Component" which can be added into a top-level "Container".
* It also handles the OpenGL events to render graphics.
*/
#SuppressWarnings("serial")
public class JOGL2Setup_GLCanvas extends GLCanvas implements GLEventListener {
// Define constants for the top-level container
private static String TITLE = "JOGL 2.0 Setup (GLCanvas)"; // window's title
private static final int CANVAS_WIDTH = 512; // width of the drawable
private static final int CANVAS_HEIGHT = 512; // height of the drawable
private static final int FPS = 30; // animator's target frames per second
private final float[] canvasVertices = {
-1f, -1f, 0.0f,
-1f, 1f, 0.0f,
1f, -1f, 0.0f,
1f, 1f, 0.0f,
};
private final float[] canvasTexCoords = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f,
};
/** The entry main() method to setup the top-level container and animator */
public static void main(String[] args) {
// Run the GUI codes in the event-dispatching thread for thread safety
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// Create the OpenGL rendering canvas
GLCanvas canvas = new JOGL2Setup_GLCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
// Create a animator that drives canvas' display() at the specified FPS.
final FPSAnimator animator = new FPSAnimator(canvas, FPS, true);
// Create the top-level container
final JFrame frame = new JFrame(); // Swing's JFrame or AWT's Frame
frame.getContentPane().add(canvas);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
// Use a dedicate thread to run the stop() to ensure that the
// animator stops before program exits.
new Thread() {
#Override
public void run() {
if (animator.isStarted()) animator.stop();
System.exit(0);
}
}.start();
}
});
frame.setTitle(TITLE);
frame.pack();
frame.setVisible(true);
animator.start(); // start the animation loop
}
});
}
// Setup OpenGL Graphics Renderer
private GLU glu; // for the GL Utility
private GL2 gl;
//OpenGl data
private int vboVertices;
private int vboTextCoord;
private Texture textureFile;
private FBObject fbo[];
private ShaderProgram shaderCompute;
private ShaderProgram shaderVisu;
private ShaderProgram shaderComputeInit;
private int currentSourceBuffer = 0;
private int currentDestBuffer = 1;
private int currentFrame = 0;
private int maxFrameCount = 5000000;
private float clearUniform = 0;
ModelParam params = new ModelParam();
public JOGL2Setup_GLCanvas() {
this.addGLEventListener(this);
}
#Override
public void init(GLAutoDrawable drawable) {
gl = drawable.getGL().getGL2(); // get the OpenGL graphics context
glu = new GLU(); // get GL Utilities
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // set background (clear) color
gl.glEnable(GL_TEXTURE_2D);
gl.glEnable( GL_COLOR_MATERIAL );
gl.glEnable( GL_FRAMEBUFFER );
gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NEAREST); // best perspective correction
viewOrtho(gl);
gl.glViewport(0,0,CANVAS_WIDTH,CANVAS_HEIGHT);
int[] buffers = new int[2];
gl.glGenBuffers(2, buffers, 0);
vboVertices = buffers[0];
vboTextCoord = buffers[1];
gl.glBindBuffer(GL_ARRAY_BUFFER, vboVertices);
gl.glBufferData(GL_ARRAY_BUFFER, canvasVertices.length*(Float.SIZE/Byte.SIZE)*3, FloatBuffer.wrap(canvasVertices), GL_STATIC_DRAW);
gl.glBindBuffer(GL_ARRAY_BUFFER, vboTextCoord);
gl.glBufferData(GL_ARRAY_BUFFER, canvasTexCoords.length*(Float.SIZE/Byte.SIZE)*2, FloatBuffer.wrap(canvasTexCoords), GL_STATIC_DRAW);
gl.glBindBuffer( GL_ARRAY_BUFFER, 0 );
// ------------ create Texture Source------------------------
textureFile = initializeTexture();
if (textureFile==null) {
System.out.println("cannot load texture from disk");
}
// ------------ load shaders ------------------------
shaderCompute = loadShader(gl, "compute.vsh", "compute.fsh");
shaderComputeInit = loadShader(gl, "compute.vsh", "computeInit.fsh");
shaderVisu = loadShader(gl, "visu.vsh", "visu.fsh");
// ------------ create FBO ------------------------
initFBO();
}
/**
* Called back by the animator to perform rendering.
*/
#Override
public void display(GLAutoDrawable drawable) {
if (currentFrame < maxFrameCount) {
prepareNextStep();
renderToFBO();
currentFrame++;
}
renderFBOToScreen();
}
private void prepareNextStep() {
currentSourceBuffer = 1 - currentSourceBuffer;
currentDestBuffer = 1 - currentDestBuffer;
}
private void renderToFBO()
{
fbo[currentDestBuffer].bind(gl);
//gl.glClear(GL_COLOR_BUFFER_BIT);
viewOrtho(gl);
shaderCompute.useProgram(gl, true);
setShaderUniformFloat(gl, shaderCompute.program(), "diffuseU", 0.211f);
setShaderUniformFloat(gl, shaderCompute.program(), "diffuseV", 0.088f);
setShaderUniformFloat(gl, shaderCompute.program(), "feed", 0.007f);
setShaderUniformFloat(gl, shaderCompute.program(), "kill", 0.08f);
setShaderUniformFloat(gl, shaderCompute.program(), "Tech", 1f);
setShaderUniformFloat(gl, shaderCompute.program(), "currentFrame", currentFrame);
setShaderUniformFloat2(gl, shaderCompute.program(), "resolution", CANVAS_WIDTH, CANVAS_HEIGHT);
drawDataBuffer(shaderCompute, true);
shaderCompute.useProgram(gl, false);
fbo[currentDestBuffer].unbind(gl);
}
void drawDataBuffer(ShaderProgram currentShader, boolean sencondImage) {
// --- draw vbo
gl.glEnableClientState(GL_VERTEX_ARRAY);
gl.glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//textcoords
gl.glBindBuffer(GL_ARRAY_BUFFER,vboTextCoord);
gl.glTexCoordPointer(2, GL_FLOAT, 0, 0);
//vertices
gl.glBindBuffer( GL_ARRAY_BUFFER, vboVertices );
gl.glVertexPointer(3, GL_FLOAT, 0, 0);
//activate texture data from last fbo
final FBObject.Colorbuffer texSource = (FBObject.Colorbuffer) fbo[currentSourceBuffer].getColorbuffer(0);
gl.glActiveTexture(GL_TEXTURE0);
gl.glBindTexture(GL_TEXTURE_2D, texSource.getName());
setShaderUniform1i(gl, currentShader.program(), "textureData", 0);
if (sencondImage) {
//activate texture with image from file
gl.glActiveTexture(GL_TEXTURE1);
gl.glBindTexture(GL_TEXTURE_2D, textureFile.getTextureObject());
textureFile.bind(gl);
setShaderUniform1i(gl, currentShader.program(), "textureImage", 1);
}
//draw buffer on screens
gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, canvasVertices.length / 3);
//disable texture image
if (sencondImage) {
gl.glActiveTexture(GL_TEXTURE1);
textureFile.disable(gl);
}
//disable texture data
gl.glActiveTexture(GL_TEXTURE0);
gl.glDisable(texSource.getName());
gl.glDisableClientState(GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL_VERTEX_ARRAY);
}
public void renderFBOToScreen()
{
gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear color and depth buffers
gl.glLoadIdentity(); // reset the model-view matrix
viewOrtho(gl);
gl.glEnable(GL_TEXTURE_2D);
final FBObject.Colorbuffer tex0 = (FBObject.Colorbuffer) fbo[currentDestBuffer].getColorbuffer(0);
gl.glActiveTexture(GL_TEXTURE0);
gl.glBindTexture(GL_TEXTURE_2D, tex0.getName());
//activate shader
shaderVisu.useProgram(gl, true);
// --- draw vbo
gl.glEnableClientState(GL_VERTEX_ARRAY);
gl.glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//textcoords
gl.glBindBuffer(GL_ARRAY_BUFFER, vboTextCoord);
gl.glTexCoordPointer(2, GL_FLOAT, 0, 0);
//vertices
gl.glBindBuffer( GL_ARRAY_BUFFER, vboVertices );
gl.glVertexPointer(3, GL_FLOAT, 0, 0);
//draw buffer on screens
gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, canvasVertices.length / 3);
gl.glDisableClientState(GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL_VERTEX_ARRAY);
gl.glBindBuffer( GL_ARRAY_BUFFER, 0 );
//desactivate shader
shaderVisu.useProgram(gl, false);
}
private void initFBO()
{
try {
gl.glEnable(GL_TEXTURE_2D);
fbo = new FBObject[2];
//first fbo
fbo[currentSourceBuffer] = new FBObject(); // Create FrameBuffer
fbo[currentSourceBuffer].init(gl, CANVAS_WIDTH, CANVAS_HEIGHT, 0);
fbo[currentSourceBuffer].reset(gl, CANVAS_WIDTH, CANVAS_HEIGHT, 0); // int width, height - size of FBO, can be resized with the same call
fbo[currentSourceBuffer].bind(gl);
int tex = genTexture(gl);
gl.glBindTexture(GL_TEXTURE_2D, tex);
gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, CANVAS_WIDTH, CANVAS_HEIGHT, 0, GL_RGBA, GL_FLOAT, null);
fbo[currentSourceBuffer].attachTexture2D(gl, 0, GL_RGBA32F, GL_RGBA, GL_FLOAT, GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
//gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
int DrawBuffers[] = {GL_COLOR_ATTACHMENT0};
gl.glDrawBuffers(1, DrawBuffers, 0); // "1" is the size of DrawBuffers
fbo[currentSourceBuffer].unbind(gl);
//second fbo
fbo[currentDestBuffer] = new FBObject(); // Create FrameBuffer
fbo[currentDestBuffer].init(gl, CANVAS_WIDTH, CANVAS_HEIGHT, 0);
fbo[currentDestBuffer].reset(gl, CANVAS_WIDTH, CANVAS_HEIGHT, 0); // int width, height - size of FBO, can be resized with the same call
fbo[currentDestBuffer].bind(gl);
tex = genTexture(gl);
gl.glBindTexture(GL_TEXTURE_2D, tex);
gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, CANVAS_WIDTH, CANVAS_HEIGHT, 0, GL_RGBA, GL_FLOAT, null);
fbo[currentDestBuffer].attachTexture2D(gl, 0, GL_RGBA32F, GL_RGBA, GL_FLOAT, GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
//ogl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
gl.glDrawBuffers(1, DrawBuffers, 1); // "1" is the size of DrawBuffers
fbo[currentDestBuffer].unbind(gl);
} catch (Exception e) {
System.out.println("Problem with fbo init " + e);
e.printStackTrace();
}
}
private Texture initializeTexture() {
Texture t = null;
try {
t = TextureIO.newTexture(new File("e:/shaders/wiki.jpg"), false);
t.setTexParameteri(gl, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
t.setTexParameteri(gl, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
t.setTexParameteri(gl, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
t.setTexParameteri(gl, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} catch (Exception e) {
System.out.println("Unable to read texture file: " + e);
e.printStackTrace();
}
return t;
}
private ShaderProgram loadShader(GL2 gl, String vertexShader, String fragmentShader)
{
ShaderCode vertShader = ShaderCode.create(gl, GL2.GL_VERTEX_SHADER, 1, getClass(), new String[]{"e:/shaders/"+vertexShader},false);
vertShader.compile(gl);
ShaderCode fragShader = ShaderCode.create(gl, GL2.GL_FRAGMENT_SHADER, 1, getClass(), new String[]{"e:/shaders/"+fragmentShader},false);
fragShader.compile(gl);
ShaderProgram newShader = new ShaderProgram();
newShader.init(gl);
newShader.add(vertShader);
newShader.add(fragShader);
newShader.link(gl, System.out);
vertShader.destroy(gl);
fragShader.destroy(gl);
return newShader;
}
public static void setShaderUniform1i(GL2 inGL,int inProgramID,String inName,int inValue) {
int tUniformLocation = inGL.glGetUniformLocation(inProgramID,inName);
if (tUniformLocation != -1) {
inGL.glUniform1i(tUniformLocation, inValue);
} else {
System.out.println("UNIFORM COULD NOT BE FOUND! NAME="+inName);
}
}
public static void setShaderUniformFloat(GL2 inGL,int inProgramID,String inName,float inValue) {
int tUniformLocation = inGL.glGetUniformLocation(inProgramID,inName);
if (tUniformLocation != -1) {
inGL.glUniform1f(tUniformLocation, inValue);
} else {
System.out.println("UNIFORM COULD NOT BE FOUND! NAME="+inName);
}
}
public static void setShaderUniformFloat2(GL2 inGL,int inProgramID,String inName,float inValue1 ,float inValue2) {
int tUniformLocation = inGL.glGetUniformLocation(inProgramID,inName);
if (tUniformLocation != -1) {
inGL.glUniform2f(tUniformLocation, inValue1, inValue2);
} else {
System.out.println("UNIFORM COULD NOT BE FOUND! NAME="+inName);
}
}
private void viewOrtho(GL2 gl) // Set Up An Ortho View
{
gl.glMatrixMode(GL_PROJECTION); // Select Projection
gl.glPushMatrix(); // Push The Matrix
gl.glLoadIdentity(); // Reset The Matrix
gl.glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
gl.glMatrixMode(GL_MODELVIEW); // Select Modelview Matrix
gl.glPushMatrix(); // Push The Matrix
gl.glLoadIdentity(); // Reset The Matrix
}
private int genTexture(GL2 gl) {
final int[] tmp = new int[1];
gl.glGenTextures(1, tmp, 0);
return tmp[0];
}
/**
* Called back before the OpenGL context is destroyed. Release resource such as buffers.
*/
#Override
public void dispose(GLAutoDrawable drawable) { }
}
And the corresponding GLSL Shader :
#version 120
uniform sampler2D textureData;
uniform sampler2D textureImage;
uniform vec2 resolution;
uniform float diffuseU;
uniform float diffuseV;
uniform float feed;
uniform float kill;
uniform float Tech = 1.0;
uniform float currentFrame = 0.0;
void main() {
//coords
vec2 position = ( gl_FragCoord.xy / resolution.xy );
vec2 pixel = 1./resolution;
//get data from texture
vec4 imgSource = texture2D(textureImage, gl_TexCoord[0].st);
vec2 oldUV = texture2D(textureData, gl_TexCoord[0].st).rg;
if(currentFrame<10){
if (distance(position,vec2(0.5,0.5 - currentFrame * 0.01f)) < 0.2f)
oldUV = vec2(0.0,0.2);
else if (distance(position,vec2(0.5,0.5 - currentFrame * 0.01f)) < 0.3f)
oldUV = vec2(0.5,0.1);
else
oldUV = vec2(0.1,0.0);
gl_FragColor = vec4(oldUV.rg, 0.0, 1.0);
return;
}
//get neightboors
vec2 dataUp = texture2D(textureData, position + pixel * vec2(0., 1.)).rg;
vec2 dataDown = texture2D(textureData, position + pixel * vec2(0., -1.)).rg;
vec2 dataLeft = texture2D(textureData, position + pixel * vec2(-1., 0.)).rg;
vec2 dataRight = texture2D(textureData, position + pixel * vec2(1., 0.)).rg;
//adapt parameters
vec2 imgParam = imgSource.rg;
float dU = diffuseU ;//+ 0.01 * (imgParam - 0.5);
float dV = diffuseV ;//+ 0.01 * (imgParam - 0.5);
float F = feed ;//+ 0.01 * (imgParam - 0.5);
float K = kill ;//+ 0.01 * (imgParam - 0.5);
//compute new values
vec2 laplace = (dataUp+dataDown+dataLeft+dataRight) - 4.0 * oldUV;
float uvv = oldUV.r * oldUV.g * oldUV.g;
// calculate delta quantities
float du = dU * laplace.r - uvv + F*(1.0 - oldUV.r);
float dv = dV * laplace.g + uvv - (F+K)*oldUV.g;
vec2 newUV = oldUV + vec2(du, dv)* Tech;
gl_FragColor = vec4(newUV.rg, 0.0, 1.0);
}
Few considerations:
avoid deprecated OpenGL (and GLU), use GL4 (or GL3)
unless you need awt/swt/swing, prefer newt, more here
prefer Animator instead of FPSAnimator, more here
prefer direct buffers instead of arrays, since otherwise jogl has to create them underneath and you can't keep trace (= deallocate when done) of those native allocations
GL4 will allow you also to avoid all those uniform overhead (and also potential bugs) you have to deal with (especially during runtime), thanks to explicit locations
prefer direct buffer management instead of FBObject for the moment unless you really know what FBObject is doing. Once you get it working, you can move on using that class. This may be (one of the) cause your code is not working, because something is not getting setup up as you need. Moreover, the lines of codes needed to replace FBObject are essentially the same
(if you can't use explicit location for any reason) prefer some literal way to define the texture uniform location, it is usually another tricky part causing bugs, something like this
prefer also a sampler for the textures, gives you more flexibility
don't wait one week next time, let us know earlier! :) Frustation can be a nasty thing that put you down easily. Together we can help you getting it working ;)

OpenGL 2.0 glGetUniformLocation: glError 1282 in draw()

I've made a game that draws openGL shapes correctly to screen for most of the game. But for some reason at random intervals in the game I get the 1282 glGetUniformLocation error. Whats strange is that it works for a while but then fails?
This is the stack trace
12-12 12:31:54.781: E/AndroidRuntime(2531): FATAL EXCEPTION: GLThread 86993
12-12 12:31:54.781: E/AndroidRuntime(2531): Process: com.laytonlabs.android.levelup, PID: 2531
12-12 12:31:54.781: E/AndroidRuntime(2531): java.lang.RuntimeException: glGetUniformLocation: glError 1282
12-12 12:31:54.781: E/AndroidRuntime(2531): at com.laytonlabs.android.levelup.MyGLRenderer.checkGlError(MyGLRenderer.java:460)
12-12 12:31:54.781: E/AndroidRuntime(2531): at com.laytonlabs.android.levelup.shapes.Shape.draw(Shape.java:240)
12-12 12:31:54.781: E/AndroidRuntime(2531): at com.laytonlabs.android.levelup.MyGLRenderer.drawShapes(MyGLRenderer.java:350)
12-12 12:31:54.781: E/AndroidRuntime(2531): at com.laytonlabs.android.levelup.MyGLRenderer.drawFixedShapes(MyGLRenderer.java:324)
12-12 12:31:54.781: E/AndroidRuntime(2531): at com.laytonlabs.android.levelup.MyGLRenderer.onDrawFrame(MyGLRenderer.java:205)
12-12 12:31:54.781: E/AndroidRuntime(2531): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1531)
12-12 12:31:54.781: E/AndroidRuntime(2531): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1248)
This is the part which is generating the error (I think), inside Shape.java draw() function.
Shape.java
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
MyGLRenderer.checkGlError("glGetUniformLocation");
The below is the full code for the java classes referenced in the error stack.
MyGLRenderer.java
package com.laytonlabs.android.levelup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import com.laytonlabs.android.levelup.game.Cell;
import com.laytonlabs.android.levelup.game.CurrentAnswer;
import com.laytonlabs.android.levelup.game.Equation;
import com.laytonlabs.android.levelup.game.Game;
import com.laytonlabs.android.levelup.game.Level;
import com.laytonlabs.android.levelup.game.Score;
import com.laytonlabs.android.levelup.game.Stage;
import com.laytonlabs.android.levelup.game.Time;
import com.laytonlabs.android.levelup.shapes.Color;
import com.laytonlabs.android.levelup.shapes.EquationRectangle;
import com.laytonlabs.android.levelup.shapes.Hexagon;
import com.laytonlabs.android.levelup.shapes.InputSquare;
import com.laytonlabs.android.levelup.shapes.Shape;
import com.laytonlabs.android.levelup.shapes.StatsRectangle;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;
public class MyGLRenderer implements GLSurfaceView.Renderer {
private static final String TAG = "MyGLRenderer";
private static StatsRectangle levelRectangle;
private static StatsRectangle timeRectangle;
private static StatsRectangle scoreRectangle;
private static EquationRectangle equationRectangle;
private static EquationRectangle answerRectangle;
private ArrayList<Shape> gridShapes;
private ArrayList<Shape> bottomRowShapes;
private static ArrayList<Shape> inputShapes;
// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mMVPFixed = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private final float[] mGridModelMatrix = new float[16];
private float[] mFixedModelMatrix = new float[16];
private float[] mTempMatrix = new float[16];
private float mMovementY;
private float mBottomRowScale;
private static String mAnswerText = CurrentAnswer.getLabel();
private boolean isCorrectGuess = false;
private boolean renderCorrectGuess = false;
private boolean isWrongGuess = false;
private boolean renderOutput = false;
//To limit the number of renders per second
private long startTime;
private long endTime;
private long timeElapsed;
private int currentFrame = 0; // active frame
private int outputCurrentFrame = 0; // active frame
private final int FPS = 33; // Frames per second
private final int FPS_ANIMATION_10 = 10;
private final int FPS_ANIMATION_20 = 20;
//Reducer values, these are used for animation scenes
private float mFPSMovementY;
private float mFPSBottomRowScale;
private int gridLevel = 0; //The cell layout level in the grid.
private int rowLevel = 1; //The current row in the grid user is selected.
//Constants for grid presentation
private final float CELL_SCALE = 0.3f;
private final float CELL_OFFSET_Y = 0.7f;
#Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
// Set the background frame color
GLES20.glClearColor(Color.DARK_GREY[0], Color.DARK_GREY[1], Color.DARK_GREY[2], Color.DARK_GREY[3]);
startTime = System.currentTimeMillis();
//TODO Add code that sets current answer to whatever the current answer is.
//Initialise fixed shapes
equationRectangle = new EquationRectangle(-0.35f);
answerRectangle = new EquationRectangle(-0.5f);
equationRectangle.setShapes(0.2f, Equation.get());
answerRectangle.setShapes(0.3f, mAnswerText);
//TODO - Change the below calculations to be align_left, align_centre, align_right, etc.
levelRectangle = new StatsRectangle(0 - (Screen.DEFAULT_WIDTH/3), Color.TURQUOISE, Color.TURQUOISE);
timeRectangle = new StatsRectangle(0, Color.PURPLE, Color.PURPLE);
scoreRectangle = new StatsRectangle(0 + (Screen.DEFAULT_WIDTH/3), Color.TURQUOISE, Color.TURQUOISE);
levelRectangle.setShapes(-1f, Level.getLabel());
scoreRectangle.setShapes(-1f, Score.getScoreLabel());
timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel());
setGridShapes();
//Complete the bottom row for inputting guesses
bottomRowShapes = new ArrayList<Shape>();
setBottomRowShapes();
buildInputGrid();
setBottomRowScale(1.0f);
setFPSBottomRowScale(getBottomRowScale() / FPS_ANIMATION_20);
setFPSMovementY((CELL_OFFSET_Y*CELL_SCALE) / FPS_ANIMATION_20);
}
private void buildInputGrid() {
inputShapes = new ArrayList<Shape>();
inputShapes.add(new InputSquare(0.16f, -3.0f, 1.15f, "1")); //1
inputShapes.add(new InputSquare(0.16f, -1.8f, 1.15f, "2")); //2
inputShapes.add(new InputSquare(0.16f, -0.6f, 1.15f, "3")); //3
inputShapes.add(new InputSquare(0.16f, 0.6f, 1.15f, "4")); //4
inputShapes.add(new InputSquare(0.16f, 1.8f, 1.15f, "5")); //5
inputShapes.add(new InputSquare(0.16f, 3.0f, 1.15f, "6")); //6
inputShapes.add(new InputSquare(0.16f, -2.4f, 0, "7")); //7
inputShapes.add(new InputSquare(0.16f, -1.2f, 0, "8")); //8
inputShapes.add(new InputSquare(0.16f, 0, 0, "9")); //9
inputShapes.add(new InputSquare(0.16f, 1.2f, 0, "0")); //0
inputShapes.add(new InputSquare(0.16f, 2.4f, 0, "x")); //X - This is to clear input
}
#Override
public void onDrawFrame(GL10 unused) {
//We dont need continuous rendering, only needed for animation and time switching
endTime = System.currentTimeMillis();
timeElapsed = endTime - startTime;
if (timeElapsed < FPS) {
try {
Log.d(TAG, "Sleeping until "+FPS+" millsecs pass");
Thread.sleep(FPS - timeElapsed);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
startTime = endTime;
//Update the timers by deducting timeRemaining
Time.update();
Matrix.setIdentityM(mGridModelMatrix, 0); // initialize to identity matrix
//Setup the equation display before we start moving the grid around
Matrix.setIdentityM(mFixedModelMatrix, 0); // initialize to identity matrix
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Enable transparency options for colors.
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
//Clone this for use with fixed and grid MVPs
mTempMatrix = mMVPMatrix.clone();
// Create a rotation for the triangle
// Use the following code to generate constant rotation.
// Leave this code out when using TouchEvents.
// long time = SystemClock.uptimeMillis() % 4000L;
// float angle = 0.090f * ((int) time);
drawGridShapes();
drawFixedShapes();
}
private void drawGridShapes() {
//Start the grid drawing at bottom of screen.
Matrix.translateM(mGridModelMatrix, 0, 0, -0.1f, 0);
//Move the grid down or up the screen depending on touch events.
Matrix.translateM(mGridModelMatrix, 0, 0, mMovementY, 0);
// Combine the rotation matrix with the projection and camera view
// Note that the mMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
//Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
//Add the movement to the matrix
Matrix.multiplyMM(mMVPMatrix, 0, mTempMatrix, 0, mGridModelMatrix, 0);
if (isCorrectGuess()) {
renderCorrectGuess = true; //This is to change the answer text to green inside drawFixedShapes
currentFrame++; // step to next frame
setMovementY(getMovementY() - getFPSMovementY());
setBottomRowScale(getBottomRowScale() - getFPSBottomRowScale());
if (currentFrame >= FPS_ANIMATION_20) { // if end of sequence
currentFrame = 0; // restart sequence
setBottomRowScale(1.0f); // Reset the scale
removeBottomRow();
setCorrectGuess(false); //Mark as false so animation stops and user can make new guess
}
}
//Draw all grid shapes
if (isCorrectGuess()) {
drawAllShapesAndShrinkBottomRow(mMVPMatrix);
} else {
drawAllShapes(getGridShapes(), mMVPMatrix);
}
}
private void drawAllShapes(ArrayList<Shape> shapes, float[] mMVPMatrix) {
for (Shape shape : shapes) {
Log.d(TAG, "Scale Hexagon ("+shape.toString()+") Aft ("+shape.getCentreX()+", "+shape.getCentreY()+")");
drawShapes(shape, mMVPMatrix);
}
}
private void drawAllShapesAndShrinkBottomRow(float[] mMVPMatrix) {
float[] mMVPScaled = mMVPMatrix.clone();
Matrix.scaleM(mMVPScaled, 0, getBottomRowScale(), getBottomRowScale(), 0);
int lastCellIndex = getBottomRowLastCellIndex();
//Apply scaling to the bottom row and just move the other rows.
for (int i = 0; i < getGridShapes().size(); i++) {
if (i <= lastCellIndex) {
drawShapes(getGridShapes().get(i), mMVPScaled);
} else {
drawShapes(getGridShapes().get(i), mMVPMatrix);
}
}
}
private void drawFixedShapes() {
Matrix.multiplyMM(mMVPFixed, 0, mTempMatrix, 0, mFixedModelMatrix, 0);
if (isRenderOutput()) {
//Show the equation using the values from the selected cell.
equationRectangle.setShapes(0.2f, Equation.get());
answerRectangle.setShapes(0.3f, mAnswerText);
setRenderOutput(false);
}
//Update the time if time has changed
if (!timeRectangle.toString().equals(Time.getTimeRemainingLabel())) {
//If the time remaining is almost up then change text to red.
if (Time.isTimeAlmostUp()) {
timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel(), Color.RED);
} else {
timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel());
}
}
//Animation for changing color of the text
if (isWrongGuess()) {
if (outputCurrentFrame == 0) {
answerRectangle.setShapes(0.3f, mAnswerText, Color.RED);
}
outputCurrentFrame++;
if (outputCurrentFrame >= FPS_ANIMATION_10) {
outputCurrentFrame = 0;
setAnswerText("");
answerRectangle.setShapes(0.3f, mAnswerText);
setWrongGuess(false);
}
} else if (renderCorrectGuess) {
if (outputCurrentFrame == 0) {
answerRectangle.setShapes(0.3f, mAnswerText, Color.GREEN);
levelRectangle.setShapes(-1f, Level.getLabel(), Color.YELLOW);
scoreRectangle.setShapes(-1f, Score.getScoreLabel(), Color.YELLOW);
timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel(), Color.YELLOW);
}
outputCurrentFrame++;
if (outputCurrentFrame >= FPS_ANIMATION_20) {
outputCurrentFrame = 0;
answerRectangle.setShapes(0.3f, mAnswerText);
levelRectangle.setShapes(-1f, Level.getLabel());
scoreRectangle.setShapes(-1f, Score.getScoreLabel());
timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel());
setGridShapes();
renderCorrectGuess = false;
}
}
drawShapes(answerRectangle, mMVPFixed);
drawShapes(equationRectangle, mMVPFixed);
drawShapes(levelRectangle, mMVPFixed);
drawShapes(timeRectangle, mMVPFixed);
drawShapes(scoreRectangle, mMVPFixed);
//Draw all input grid shapess
drawAllShapes(inputShapes, mMVPFixed);
}
public static void printStack() {
Log.e(TAG,"Level: " + Level.getLabel());
Log.e(TAG,"Score: " + Score.getScoreLabel());
Log.e(TAG,"Time: " + Time.getTimeRemainingLabel());
Log.e(TAG,"mAnswerText: " + mAnswerText);
Log.e(TAG,"Equation: " + Equation.get());
for (int i = 0; i < inputShapes.size(); i++) {
Log.e(TAG,"inputShapes[" + i + "]: " + inputShapes.get(i).toString());
}
}
private void drawShapes(Shape parentShape, float[] mMVPMatrix) {
parentShape.draw(mMVPMatrix);
if (parentShape.getShapes() == null) {
return;
}
for (Shape nestedShapes : parentShape.getShapes()) {
nestedShapes.draw(mMVPMatrix);
}
}
private ArrayList<Shape> getGridShapes() {
return gridShapes;
}
private int getBottomRowLastCellIndex() {
int lastCellIndex = 0;
Shape prevShape = null;
for (int i = 0; i < getGridShapes().size(); i++) {
if (prevShape == null || getGridShapes().get(i).getCentreY() == prevShape.getCentreY()) {
lastCellIndex = i;
prevShape = getGridShapes().get(i);
} else {
return lastCellIndex;
}
}
return lastCellIndex;
}
private void removeBottomRow() {
for (int i = getBottomRowLastCellIndex(); i >= 0 ; i--) {
getGridShapes().remove(i);
}
//Reset the bottom row shapes
setBottomRowShapes();
}
public ArrayList<Shape> getBottomRowShapes() {
return bottomRowShapes;
}
private void setBottomRowShapes() {
ArrayList<Shape> tempRowShapes = new ArrayList<Shape>();
//Apply scaling to the bottom row and just move the other rows.
for (int i = 0; i <= getBottomRowLastCellIndex(); i++) {
tempRowShapes.add(getGridShapes().get(i));
}
bottomRowShapes = tempRowShapes;
}
#Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
// Adjust the viewport based on geometry changes,
// such as screen rotation
GLES20.glViewport(0, 0, width, height);
//Log.d("MyGLRenderer", "Width: " + width + " Height: " + height);
float ratio = (float) width / height;
Log.d("Screen","Width: "+ width +" - Height: "+ height +" - Ratio: "+ ratio);
// this projection matrix is applied to object coordinates
// in the onDrawFrame() method
if (ratio > 1) {
ratio = Screen.DEFAULT_LANDSCAPE_RATIO;
} else {
ratio = Screen.DEFAULT_PORTRAIT_RATIO;
}
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
//TODO Store the current answer, the current answer Text and the current Equation.
}
public static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
public static void checkGlError(String glOperation) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e(TAG, glOperation + ": 1glError " + error);
printStack();
//TODO - Print out the fixed shapes values to see if something wierd is being displayed after a while.
throw new RuntimeException(glOperation + ": glError " + error);
}
}
public float getMovementY() {
return mMovementY;
}
public void setMovementY(float movementY) {
mMovementY = movementY;
}
public float[] getProjectionMatrix() {
return mProjectionMatrix;
}
public float[] getGridModelMatrix() {
return mGridModelMatrix;
}
public float[] getFixedModelMatrix() {
return mFixedModelMatrix;
}
public String getAnswerText() {
return mAnswerText;
}
public void setAnswerText(String guessInput) {
if (guessInput == "") {
this.mAnswerText = getInputUnderscores();
return;
}
this.mAnswerText = this.mAnswerText.replaceFirst("_", guessInput);
}
public void resetAnswerText() {
this.mAnswerText = CurrentAnswer.getLabel();
}
private String getInputUnderscores() {
if (Equation.getExpectedAnswer() <= 0) {
return "";
}
return Equation.getExpectedAnswerLabel().replaceAll("[0-9]", "_");
}
public ArrayList<Shape> getInputShapes() {
return inputShapes;
}
Shape.java
package com.laytonlabs.android.levelup.shapes;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import android.opengl.GLES20;
import com.laytonlabs.android.levelup.MyGLRenderer;
import com.laytonlabs.android.levelup.Vec2;
import com.laytonlabs.android.levelup.game.Cell;
/**
* A two-dimensional square for use as a drawn object in OpenGL ES 2.0.
*/
public abstract class Shape {
private final String TAG = "Shape";
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// The matrix must be included as a modifier of gl_Position.
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private final FloatBuffer vertexBuffer;
private final ShortBuffer drawListBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
protected float[] shapeCoords;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
//These will be initiated by the abstract class
private final float[] ORIGINAL_COORDS;
private final short[] DRAW_ORDER; // order to draw vertices
//#RGB: white (255, 255, 255)
private final float[] COLOR;
//Sets the scale of the shape and where the X centre is.
private final float SCALE;
private final float CENTRE_X;
private final float CENTRE_Y;
public abstract float getCentreX();
public abstract float getCentreY();
public float[] getNestedTextColor() {
return null;
}
public void setNestedTextColor(float[] textColor) {}
public Cell getCell() {
return null;
}
public ArrayList<Shape> getShapes() {
return null;
}
public void setShapes(float scale, String nestedText) {}
public void setShapes(float scale, String nestedText, float[] textColor) {}
public boolean intersects(Vec2 touchCoords) {
return false;
}
public float getMinX() {return getMin(getArraySubset(0));}
public float getMaxX() {return getMax(getArraySubset(0));}
public float getMinY() {return getMin(getArraySubset(1));}
public float getMaxY() {return getMax(getArraySubset(1));}
private float getMin(float[] values) {
float minVal = 1000f;
for (float value : values) {
if (value < minVal) {
minVal = value;
}
}
return minVal;
}
private float getMax(float[] values) {
float maxVal = -1000f;
for (float value : values) {
if (value > maxVal) {
maxVal = value;
}
}
return maxVal;
}
private float[] getArraySubset(int offset) {
if (shapeCoords == null || shapeCoords.length == 0) {
return null;
}
float[] subsetArray = new float[shapeCoords.length / COORDS_PER_VERTEX];
int subsetIndex = 0;
for (int i = offset; i < shapeCoords.length; i=(i+COORDS_PER_VERTEX)) {
subsetArray[subsetIndex] = shapeCoords[i];
subsetIndex++;
}
return subsetArray;
}
/**
* Sets up the drawing object data for use in an OpenGL ES context.
*/
public Shape(float[] originalCoords, short[] drawOrder, float[] color,
float scale, float centreX, float centreY) {
this.ORIGINAL_COORDS = originalCoords;
this.DRAW_ORDER = drawOrder;
this.COLOR = color;
this.SCALE = scale;
this.CENTRE_X = centreX;
this.CENTRE_Y = centreY;
this.shapeCoords = ORIGINAL_COORDS.clone();
adjustShape(scale, centreX, centreY);
//Resize based on the scale
//adjustSize(scale);
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (# of coordinate values * 4 bytes per float)
shapeCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(shapeCoords);
vertexBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(
// (# of coordinate values * 2 bytes per short)
DRAW_ORDER.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(DRAW_ORDER);
drawListBuffer.position(0);
// prepare shaders and OpenGL program
int vertexShader = MyGLRenderer.loadShader(
GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(
GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL Program
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram); // create OpenGL program executables
}
//Adjust the original scale of the shape and position
private void adjustShape(float scale, float centreX, float centreY) {
for (int i = 0; i < shapeCoords.length; i++) {
//Apply the scale
shapeCoords[i] = (ORIGINAL_COORDS[i] * scale);
//Apply the x offset
shapeCoords[i] += (i % 3 == 0 ? centreX : 0);
//Apply the y offset
shapeCoords[i] += (i % 3 == 1 ? centreY : 0);
}
}
/**
* Encapsulates the OpenGL ES instructions for drawing this shape.
*
* #param mvpMatrix - The Model View Project matrix in which to draw
* this shape.
*/
public void draw(float[] mvpMatrix) {
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(
mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, COLOR, 0);
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
MyGLRenderer.checkGlError("glGetUniformLocation");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
MyGLRenderer.checkGlError("glUniformMatrix4fv");
// Draw the square
GLES20.glDrawElements(
GLES20.GL_TRIANGLES, DRAW_ORDER.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
There are only two reasons why glGetUniformLocation would emit a GL_INVALID_OPERATION error: because the program isn't a program object or because it wasn't successfully linked.
I see no code where you actually test whether glLinkProgram was successful. You never call glGetProgramiv(program, GL_LINK_STATUS) to test whether the program linked correctly. Clearly, linking failed at some point.
The general code for error handling (in C++) would be:
//Link the program.
glLinkProgram(program);
GLint isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
if(isLinked == GL_FALSE)
{
GLint maxLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
//The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
//The program is useless now. So delete it.
glDeleteProgram(program);
//Provide the infolog in whatever manner you deem best.
//Exit with failure.
return;
}

LWJGL 3, VAO and Shader not rendering

I am using LWJGL 3 and Shaders with VAO's. My current implementation does not draw the VAO when using the shaders. However the VAO will draw when not using shaders but the VAO will be white. My question is what am I missing in my shader setup that is preventing me from seeing the VAO when using shaders?
Main Class.
Shader and VAO setup is in the gameStart() method.
public class Test {
/** Window Properties **/
private int
HEIGHT = 800,
WIDTH = 1200,
RESIZABLE = GL11.GL_FALSE,
REFRESH_RATE = 60;
private String TITLE = "test";
// The window handler
private long window;
// callback reference instances
private GLFWErrorCallback errorCallback;
private GLFWKeyCallback keyCallback;
private void preWindowSetup() {
// Setup an error callback
GLFW.glfwSetErrorCallback(errorCallback = errorCallbackPrint(System.err));
// Initialize GLFW
if (GLFW.glfwInit() != GL11.GL_TRUE)
exit();
}
private void windowSetup() {
// Configure Window Properties
glfwDefaultWindowHints();
GLFW.glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // Keep the window hidden
glfwWindowHint(GLFW_RESIZABLE, RESIZABLE); // Do not allow resizing
glfwWindowHint(GLFW_REFRESH_RATE, REFRESH_RATE); // Refresh rate
// Create the window
window = glfwCreateWindow(WIDTH, HEIGHT, TITLE, NULL, NULL);
if ( window == NULL )
exit();
// Get the resolution of the primary monitor
ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center our window
glfwSetWindowPos(
window,
(GLFWvidmode.width(vidmode) - WIDTH) / 2,
(GLFWvidmode.height(vidmode) - HEIGHT) / 2
);
}
private void callbackSetup() {
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
#Override
public void invoke(long window, int key, int scancode, int action, int mods) {//TODO Dispatch key events
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
Tasker.executeASyncTask("GLFW_MAIN_THREAD");
}
});
}
public void initGL() {
preWindowSetup();
windowSetup();
callbackSetup();
glfwMakeContextCurrent(window); // Make the OpenGL context current
glfwShowWindow(window); // Make the window visible
GLContext.createFromCurrent(); // Bind lwjgl with GLFW
// Initialize openGl
GL11.glViewport(0, 0, WIDTH, HEIGHT);
GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, WIDTH, 0, HEIGHT, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
// Enable alpha transparency (for overlay image)
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glDepthFunc(GL11.GL_LEQUAL);
GL11.glShadeModel(GL11.GL_SMOOTH);
}
public void gameStart() {
System.out.println("LWJGL Version: ["+Sys.getVersion()+"]");
System.out.println("OpenGL Version: ["+GL11.glGetString(GL11.GL_VERSION)+"]");
// ===============================================================================================
// =================== Shader Setup =====================
String vertPath = "src/test/java/org/ajgl/test/graphics/shaders/VertexShaderTest.glsl";
String fragPath = "src/test/java/org/ajgl/test/graphics/shaders/FragmentShaderTest.glsl";
int sahderVert = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
GL20.glShaderSource(sahderVert, Shader.loadShader(vertPath));
GL20.glCompileShader(sahderVert);
int sahderFrag = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
GL20.glShaderSource(sahderFrag, Shader.loadShader(fragPath));
GL20.glCompileShader(sahderFrag);
// =================== Shader Setup =====================
// =================== Shader Check =====================
int status = GL20.glGetShaderi(sahderVert, GL20.GL_COMPILE_STATUS);
if (status != GL11.GL_TRUE) {
throw new RuntimeException(GL20.glGetShaderInfoLog(sahderVert));
}
int statusN = GL20.glGetShaderi(sahderFrag, GL20.GL_COMPILE_STATUS);
if (statusN != GL11.GL_TRUE) {
throw new RuntimeException(GL20.glGetShaderInfoLog(sahderFrag));
}
// =================== Shader Check =====================
// =================== Shader Program ===================
int programID = GL20.glCreateProgram();
GL20.glAttachShader(programID, sahderVert);
GL20.glAttachShader(programID, sahderFrag);
GL20.glBindAttribLocation(programID, 0, "position");
GL20.glBindAttribLocation(programID, 1, "color");
GL20.glLinkProgram(programID);
// =================== Shader Program ===================
// =============== Shader Program Check =================
int statusP = GL20.glGetProgrami(programID, GL20.GL_LINK_STATUS);
if (statusP != GL11.GL_TRUE) {
throw new RuntimeException(GL20.glGetProgramInfoLog(programID));
}
// =============== Shader Program Check =================
// =================== VAO Setup ========================
FloatBuffer vertexBufferVAO = BufferUtils.createFloatBuffer(9);
vertexBufferVAO.put(new float[]{600,10,0, 550,50,0, 500,10,0});
vertexBufferVAO.flip();
FloatBuffer colorBufferVAO = BufferUtils.createFloatBuffer(9);
colorBufferVAO.put(new float[]{1,0,0, 0,1,0, 0,0,1});
colorBufferVAO.flip();
int vaoID = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vaoID);
{
int vertHandle = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vertHandle);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertexBufferVAO, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
int colorHandle = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, colorHandle);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, colorBufferVAO, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(1, 3, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
GL30.glBindVertexArray(0);
// =================== VAO Setup ========================
// ===============================================================================================
while ( glfwWindowShouldClose(window) == GL_FALSE ) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Run Cycles
input();
GL20.glUseProgram(programID);
GL30.glBindVertexArray(vaoID);
{
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, 3);
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
}
GL30.glBindVertexArray(0);
GL20.glUseProgram(0);
// Display Buffer swap
glfwSwapBuffers(window);
}
// Release window and window call backs
glfwDestroyWindow(window);
keyCallback.release();
exit();
}
private void input() {
glfwPollEvents();
Tasker.executeASyncTask("GLFW_MAIN_THREAD");
}
public void exit() {
// Terminate GLFW and release the GLFWerrorfun
glfwTerminate();
errorCallback.release();
System.exit(1);
}
public static void main(String[] args) {
Test test = new Test();
test.initGL();
test.gameStart();
}
}
Shader class.
public class Shader {
public static CharSequence loadShader(String path) {
StringBuilder shaderSource = new StringBuilder();
int shaderID = 0;
try {
BufferedReader reader = new BufferedReader(new FileReader(path));
String line;
while ((line = reader.readLine()) != null) {
shaderSource.append(line).append("\n");
}
reader.close();
} catch (IOException e) {
System.err.println("Could not read file.");
e.printStackTrace();
System.exit(-1);
}
return shaderSource;
}
}
Vertex and fragment shaders.
// Vertex Shader
#version 400
in vec3 position;
in vec3 color;
out vec3 Color;
void main()
{
Color = color;
gl_Position = vec4(position, 1.0);
}
// Fragment shader
#version 400
in vec3 Color;
out vec4 fragColor;
void main()
{
fragColor = vec4(Color, 1.0);
}
I found the solution to the problem using this site here. The issue is that I was not using device coordinates as said in the link. Instead I was Using the cartesian coordinate system.
The fix.
FloatBuffer vertexBufferVAO = BufferUtils.createFloatBuffer(9);
**vertexBufferVAO.put(new float[]{{-0.95f,-0.95f,0, -0.5f,-0.95f,0, -0.95f,-0.5f,0});
vertexBufferVAO.flip();

Android Open GL not drawing square

I have been following the Android Developer Open GL tutorial and iv just trying to draw a square in my own program as am starting to rewrite my android game in Open GL as opposed to using the Canvas class. I have encountered a problem where it wont draw the square that i am trying to draw but it will color the background.
I am trying to draw the GLSquareEntity class which is extended from the GLEntity class, below is the code
GLSquareEntity Class:
public class GLSquareEntity extends GLEntity
{
public GLSquareEntity()
{
super();
cords = new float[] {
-0.5f, 0.5f, 0.0f, // top left
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f, // bottom right
0.5f, 0.5f, 0.0f }; // top right
CORDS_PER_VERTEX = 3;
drawOrder = new short[] { 0, 1, 2, 0 , 2, 3 };
// Initlise the class
setup();
}
}
GLEntity Class:
public class GLEntity
{
protected final String TAG = "GLENTITY";
// Shaders
private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
// Open GL Variables
protected FloatBuffer vertexBuffer;
protected ShortBuffer drawListBuffer;
protected short[] drawOrder;
protected int CORDS_PER_VERTEX;
protected int vertexStride;
protected int vertexCount;
protected float[] cords;
// Just unill i can get an image to display
protected float[] color = {0.0f, 0.0f, 1.0f, 1.0f};
protected int program;
protected int positionHandle;
protected int colorHandle;
public GLEntity()
{
}
protected void setup()
{
Log.d(TAG, "GLEntity Setup");
vertexStride = CORDS_PER_VERTEX * 4;
vertexCount = cords.length / CORDS_PER_VERTEX;
// Initilise buffer for vertex cordernats
ByteBuffer vbuffer = ByteBuffer.allocateDirect(cords.length * 4);
vbuffer.order(ByteOrder.nativeOrder());
vertexBuffer = vbuffer.asFloatBuffer();
vertexBuffer.put(cords);
vertexBuffer.position(0);
// Initilise buffer for the draw list
ByteBuffer dlbuffer = ByteBuffer.allocateDirect(drawOrder.length * 2);
dlbuffer.order(ByteOrder.nativeOrder());
drawListBuffer = dlbuffer.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
// Set up the shaders
int vertexShader = OpenGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = OpenGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
}
public void draw()
{
//Log.d(TAG, "Drawing GL Entity");
// Select shader program to use
GLES20.glUseProgram(program);
positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
GLES20.glEnableVertexAttribArray(positionHandle);
// Prepar the data
GLES20.glVertexAttribPointer(positionHandle, CORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
// Prepare and set the color
colorHandle = GLES20.glGetUniformLocation(program, "vColor");
GLES20.glUniform4fv(colorHandle, 1, color, 0);
//GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, vertexCount);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
GLES20.glDisableVertexAttribArray(positionHandle);
}
}
The next classes are the GLSurfaceView class and the GLRenderer class
GLSurfaceView Class:
public class OpenGLSurfaceView extends GLSurfaceView
{
public OpenGLSurfaceView(Context context)
{
super(context);
// Set to OpenGL ES 2
setEGLContextClientVersion(2);
// Set the renderer for drawing
//OpenGLRenderer glRenderer = ;
setRenderer( new OpenGLRenderer() );
// Set to only rerender when function called
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
}
OpenGLRenderer Class:
public class OpenGLRenderer implements GLSurfaceView.Renderer
{
GLPlayer player;
#Override
public void onDrawFrame(GL10 gl)
{
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
player.draw();
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height)
{
GLES20.glViewport(0, 0, width, height);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
GLES20.glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
player = new GLPlayer();
}
public static int loadShader(int type, String shaderCode)
{
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
Any help figuring out what the problem is would be much appreciated :)
Thanks

VBO with textures, without deprecated functions

I am trying to write a basic Quad-renderer, using VBO, VAO, IBO and shaders.
I am trying to use mainly only one VBO, VAO, IBO and rebuffer the data when an element is added/removed.
Mostly everything worked fine, until I decided to implement textures, instead of color gradings.
It just doesn't draw anyhting, no matter what I try, because I want to avoid using deprecated functions like ClientStates and maybe use the textures inside the shaders.
Next to the problem, that nothing is being drawn, I have the problem that the Textures are saved inside the BRectangle class, and now I don't know, how to access them while using DrawElements.
And can I reuse my IBO, so I don't have to add the additional indices?
My current approach:
The Renderer, you can add a Rectangle atm and it will buffer the needed data.
public class ShaderRenderer {
public static final int POSITION_INDEX = 0; // index of vertex attribute "in_Position"
public static final int TEXTURE_INDEX = 1; // index of vertex attribute "in_Texture"
public static final int FLOAT_NUM_BYTES; // sizeof(float) in bytes
public static final int INT_NUM_BYTES; // sizeof(int) in bytes
public static final int VEC4_BYTES; // sizeof(vec4) in bytes
static {
FLOAT_NUM_BYTES = Float.SIZE / Byte.SIZE;
INT_NUM_BYTES = Integer.SIZE / Byte.SIZE;
VEC4_BYTES = 4 * FLOAT_NUM_BYTES;
}
private VAO vao = new VAO();
private VBO vbo = new VBO();
private IBO ibo = new IBO();
private int elements = 0;
public ShaderRenderer() {
try {
ShaderUtilities.compileShader("shaders/screen.vert", "shaders/screen.frag", POSITION_INDEX, TEXTURE_INDEX);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void add( BRectangle rect ) {
// Bind the VAO
// This OpenGL-object groups the "in_Position" and "in_Color"
// vertex attributes.
vao.bind();
// Bind the VBO and add the FloatBuffer from the Rect
vbo.bind();
vbo.addBuffer(rect.vertexData);
ibo.bind();
ibo.addIndices(generateIndices());
ibo.buffer();
//==============================================================
// Now we tell OpenGL that we will use POSITION_INDEX and COLOR_INDEX
// to communicate respectively the vertex positions and vertex colors
// to our shaders.
{
// First we enable the indices. This will affect the vertex
// array object from above.
glEnableVertexAttribArray(POSITION_INDEX);
Util.checkGLError();
// Then we tell OpenGL how it should read the GL_ARRAY_BUFFER
// (to which we have bound our vertex data, see above).
// The position data starts at the beginning of the vertex data
glVertexAttribPointer(POSITION_INDEX, 4, GL_FLOAT, false,
2 * VEC4_BYTES, 0);
Util.checkGLError();
// The color data starts after the first 4 floats of position data
glVertexAttribPointer(TEXTURE_INDEX, 2, GL_FLOAT, false,
0, VEC4_BYTES);
Util.checkGLError();
}
vbo.bufferData();
// Just to be VERY clean, we will unbind the vertex attribute object
// and only bind it when we render. This way we cannot accidentally modify
// it anymore.
vao.unbind();
// Only after the vertex array is disabled, we unbind the buffers
// to the GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER targets, because
// otherwise the vertex array object would become invalid again.
vbo.unbind();
ibo.unbind();
}
void DestroyVBO() {
glDisableVertexAttribArray(POSITION_INDEX);
Util.checkGLError();
glDisableVertexAttribArray(TEXTURE_INDEX);
Util.checkGLError();
glBindBuffer(GL_ARRAY_BUFFER, 0);
Util.checkGLError();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Util.checkGLError();
glDeleteBuffers(ibo.id);
Util.checkGLError();
glDeleteBuffers(vbo.id);
Util.checkGLError();
glBindVertexArray(0);
Util.checkGLError();
glDeleteVertexArrays(vao.id);
Util.checkGLError();
}
private int[] generateIndices() {
int c = elements * 3;
int v[] = { c, c+1, c+2,
c, c+3, c+2};
elements++;
return v;
}
public void render () {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Util.checkGLError();
vao.bind();
glDrawElements(
GL_TRIANGLES,
ibo.size,
GL_UNSIGNED_INT,
0);
Util.checkGLError();
vao.unbind();
}
}
My basic Rectangle class
public class BRectangle {
final int amountOfVertices = 8;
final int vertexSize = 3;
final int textureSize = 2;
public FloatBuffer vertexData;
Texture texture;
public BRectangle(float x, float y ) {
float[] VerticesArray = new float[]{
-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.1f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
-0.1f, 0.4f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.4f, 0.0f, 1.0f, 0.0f, 1.0f
};
vertexData = BufferUtils.createFloatBuffer(24);
vertexData.put(VerticesArray);
try {
texture = Textures.loadTexture("data/floor.jpg");
} catch (IOException e) {
e.printStackTrace();
}
glBindTexture(GL_TEXTURE_2D, texture.getTextureID());
}
}
The test with main[]
public class ShaderTest {
ShaderRenderer sr;
FpsCounter c;
public ShaderTest() {
}
public void create() throws LWJGLException, Exception {
new SimpleDisplay(800, 600, "test", false, false);
glOrtho(0, 800, 0, 600, 1, -1);
//Keyboard
Keyboard.create();
c = new FpsCounter();
Textures.setUpTextureLoader();
//Mouse
Mouse.setGrabbed(false);
Mouse.create();
sr = new ShaderRenderer();
//OpenGL
initGL();
}
public void destroy() {
Mouse.destroy();
Keyboard.destroy();
Display.destroy();
}
public void initGL() throws IOException {
ShaderUtilities.compileShader("shaders/screen.vert", "shaders/screen.frag", ShaderRenderer.POSITION_INDEX, ShaderRenderer.TEXTURE_INDEX);
sr.add(new BRectangle(0f, 0f));
}
public void processKeyboard() {
}
public void processMouse() {
}
public void render() throws LWJGLException {
sr.render();
}
public void run() throws LWJGLException {
while (!Display.isCloseRequested() && !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
if (Display.isVisible()) {
processKeyboard();
processMouse();
update();
render();
} else {
if (Display.isDirty()) {
render();
}
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
}
Display.update();
//Display.sync(60);
}
}
public void update() {
c.updateFPS();
}
public static void main(String[] args) {
ShaderTest main = null;
try {
main = new ShaderTest();
main.create();
main.run();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (main != null) {
main.destroy();
}
}
}
}
and the openglinit
public static void initGLSlim() {
glClearColor(0, 0, 0, 0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL11.GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 800, 600, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
vertex shader
#version 140
in vec4 in_Position;
in vec2 in_Texture;
out vec2 out_Texture;
void main(void)
{
gl_Position = vec4(in_Position.x *0.75 ,in_Position.y, in_Position.z, in_Position.w);
out_Texture = in_Texture;
}
fragment shader
#version 140
in vec2 out_Texture;
uniform sampler2D mytexture;
out vec4 fragColor;
void main(void)
{
fragColor = texture2D(mytexture, out_Texture);
}
Your stride parameters are not correct.
Here's what you have:
glVertexAttribPointer(POSITION_INDEX, 4, GL_FLOAT, false, 2 * VEC4_BYTES, 0);
glVertexAttribPointer(TEXTURE_INDEX, 2, GL_FLOAT, false, 0, VEC4_BYTES);
You're telling the position index that it has 8 float stride, which is not correct. As far as I can tell you're uploading 4 vertices, with 6 floats per vertex (4x position + 2x texture). That means your POSITION stride should be 6 * FLOAT_NUM_BYTES.
Your texture stride should be the same, as it's packed into the same array. Here you're telling it that the texcoords are tightly packed, but in reality theres only one pair of texcoords per 6 floats. So again you need 6 * FLOAT_NUM_BYTES here.
And can I reuse my IBO, so I don't have to add the additional indices?
Yes, you can use an IBO to draw as many objects as you want, provided that they all want the same indices.
Other less serious comments:
You don't need to clearColor to zero in initialization, it's zero by
default.
You don't need to disable depth_test/lighting in
initialization, they are off by default.
Don't call glEnable(GL_TEXTURE_2D) when you're using shaders. This
switch only enables texturing for the fixed pipeline, and it has no effect on shader programs. This will generate an error if you ever move to a core profile, so just get rid of it.

Categories