OpenGL 2.0 glGetUniformLocation: glError 1282 in draw() - java

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;
}

Related

LWJGL Tilerenderer only renders one type of tile/one texture

I'm learning LWJGL and OpenGL by following this tutorial i found, i tried my best to change the code to be compatible with the never versions and hadnt a problem with it so far. But now my Tilerenderer wont render more than one type of tile/one texture for the VBO's and i tried to fix it now since 3 days (in the beginning it didn't render anything at all) but couldn't find anything that fixes this problem.
I'm using Java 9.0.4 and LWJGL 3.2.1 build 12 with JOML 1.9.13, GLFW, OpenGL and stb.
So far i tried changing the entire code involved in this problem and changing different variables for shaders but nothing seemed to work so far.
Here are all classes i figured might have something to do with the problem.
The Main class
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.lwjgl.opengl.GL;
public class Main {
public static void main(String[] args) {
int speed = 5;
Window.setCallbacks();
if (!glfwInit()) {
throw new IllegalStateException("Failed to init GLFW");
}
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
Window window = new Window();
window.setSize(640, 480);
window.setFullscreen(false);
window.createWindow("GAME");
GL.createCapabilities();
Camera camera = new Camera(window.getWidth(), window.getHeight());
glEnable(GL_TEXTURE_2D);
TileRenderer tiles = new TileRenderer();
Shader shader = new Shader("shader");
World world = new World();
world.setTile(Tile.test_tile, 0, 0);
double frameCap = 1.0 / 60.0;
double frameTime = 0;
double time = Timer.getTime();
double unprocessed = 0;
int frames = 0;
while(!window.shouldClose()) {
boolean canRender = false;
double time2 = Timer.getTime();
double passed = time2 - time;
unprocessed+=passed;
frameTime += passed;
time = time2;
while (unprocessed >= frameCap) {
canRender = true;
unprocessed-=frameCap;
if(window.getInput().isMouseButtonDown(0)) {
glfwSetWindowShouldClose(window.getWindow(), true);
}
if (window.getInput().isKeyPressed(GLFW_KEY_ESCAPE)) {
glfwSetWindowShouldClose(window.getWindow(), true);
}
if(window.getInput().isKeyDown(GLFW_KEY_W)) {
camera.addPosition(new Vector3f(0, -speed, 0));
}
if(window.getInput().isKeyDown(GLFW_KEY_A)) {
camera.addPosition(new Vector3f(speed, 0, 0));
}
if(window.getInput().isKeyDown(GLFW_KEY_S)) {
camera.addPosition(new Vector3f(0, speed, 0));
}
if(window.getInput().isKeyDown(GLFW_KEY_D)) {
camera.addPosition(new Vector3f(-speed, 0, 0));
}
if(window.getInput().isKeyDown(GLFW_KEY_O)) {
speed = 5;
}
if(window.getInput().isKeyDown(GLFW_KEY_P)) {
speed = 25;
}
window.update();
if (frameTime >= 1.0) {
frameTime = 0;
System.out.println("FPS:" + frames);
frames = 0;
}
}
if (canRender) {
glClear(GL_COLOR_BUFFER_BIT);
world.render(tiles, shader, camera);
window.swapBuffers();
frames++;
}
}
glfwTerminate();
}
}
The World class
import org.joml.Matrix4f;
import org.joml.Vector3f;
public class World {
private byte[] tiles;
private int width;
private int height;
private Matrix4f world;
public World () {
width = 16;
height = 16;
tiles = new byte [width * height];
world = new Matrix4f().setTranslation(new Vector3f(0));
world.scale(32);
}
public void render(TileRenderer renderer, Shader shader, Camera camera) {
for (int x = 0; x < height; x++) {
for (int y = 0; y < width; y++) {
renderer.renderTile(tiles[x + y * width], y, -x, shader, world, camera);
}
}
}
public void setTile (Tile tile, int x, int y) {
System.err.println(tile.getId());
tiles[x + y * width] = tile.getId();
}
}
The Tilerenderer class
import java.util.HashMap;
import org.joml.Matrix4f;
import org.joml.Vector3f;
public class TileRenderer {
private HashMap<String, Texture> tileTextures;
private Model tileModel;
public TileRenderer() {
tileTextures = new HashMap<>();
float[] vertices = new float[]{
-1f, 1f, 0, // TOP LEFT 0
1f, 1f, 0, // TOP RIGHT 1
1f, -1f, 0, // BOTTOM RIGHT 2
-1f, -1f, 0,// BOTTOM LEFT 3
};
float[] texture = new float[]{0, 0, 1, 0, 1, 1, 0, 1,};
int[] indices = new int[]{0, 1, 2, 2, 3, 0};
tileModel = new Model(vertices, texture, indices);
for (int i = 0; i < Tile.tiles.length; i++) {
if (Tile.tiles[i] != null) {
if (!tileTextures.containsKey(Tile.tiles[i].getTexture())) {
String tex = Tile.tiles[i].getTexture();
tileTextures.put(tex, new Texture(tex + ".png"));
}
}
}
}
public void renderTile (byte id, int x, int y, Shader shader, Matrix4f world, Camera camera) {
shader.bind();
if (tileTextures.containsKey(Tile.tiles[id].getTexture())) {
tileTextures.get(Tile.tiles[id].getTexture()).bind(0);
}
Matrix4f tilePos = new Matrix4f().translate(new Vector3f(x*2, y*2, 0));
Matrix4f target = new Matrix4f();
camera.getProjection().mul(world, target);
target.mul(tilePos);
shader.setUniform("sampler", 0);
shader.setUniform("projection", target);
tileModel.render();
}
}
The Tile class
public class Tile {
public static Tile tiles[] = new Tile[16];
public static final Tile testTile = new Tile((byte)0, "Test");
public static final Tile testTile2 = new Tile((byte)1, "Test2");
private byte id;
private String texture;
public Tile(byte id, String texture) {
this.id = id;
this.texture = texture;
if (tiles[id] != null) {
throw new IllegalStateException("Tiles at: [" + id + "] is already being used!");
}
tiles[id] = this;
}
public byte getId () {return id;}
public String getTexture () {return texture;}
}
The Model class
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
public class Model {
private int draw_count;
private int v_id;
private int t_id;
private int i_id;
public Model (float[] vertices, float[] tex_coords, int[] indices) {
draw_count = indices.length;
IntBuffer buffer = BufferUtils.createIntBuffer(indices.length);
buffer.put(indices);
buffer.flip();
v_id = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, v_id);
glBufferData(GL_ARRAY_BUFFER, createBuffer(vertices), GL_STATIC_DRAW);
t_id = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, t_id);
glBufferData(GL_ARRAY_BUFFER, createBuffer(tex_coords), GL_STATIC_DRAW);
i_id = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
public void render() {
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, v_id);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, t_id);
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_id);
glDrawElements(GL_TRIANGLES, draw_count, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
private FloatBuffer createBuffer(float[] data) {
FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
}
The Texture class
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.stb.STBImage.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.*;
import org.lwjgl.BufferUtils;
public class Texture {
private int id;
private int width;
private int heigth;
public Texture (String filename) {
IntBuffer width = BufferUtils.createIntBuffer(1);
IntBuffer heigth = BufferUtils.createIntBuffer(1);
IntBuffer comp = BufferUtils.createIntBuffer(1);
ByteBuffer data = stbi_load("./res/" + filename, width, heigth, comp, 4);
this.width = width.get();
this.heigth = heigth.get();
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this.width, this.heigth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
}
public void bind (int sampler) {
if (sampler >= 0 && sampler <= 31) {
glActiveTexture(GL_TEXTURE0 + sampler);
glBindTexture(GL_TEXTURE_2D, sampler);
}
}
}
The Shader class
import static org.lwjgl.opengl.GL20.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.FloatBuffer;
import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;
public class Shader {
private int program;
private int vs;
private int fs;
public Shader (String filename) {
program = glCreateProgram();
vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, readFile(filename + ".vs"));
glCompileShader(vs);
if (glGetShaderi(vs, GL_COMPILE_STATUS) != 1) {
System.err.println(glGetShaderInfoLog(vs));
System.exit(1);
}
fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, readFile(filename + ".fs"));
glCompileShader(fs);
if (glGetShaderi(fs, GL_COMPILE_STATUS) != 1) {
System.err.println(glGetShaderInfoLog(fs));
System.exit(1);
}
glAttachShader(program, vs);
glAttachShader(program, fs);
glBindAttribLocation(program, 0, "vertices");
glBindAttribLocation(program, 1, "textures");
glLinkProgram(program);
if (glGetProgrami(program, GL_LINK_STATUS) != 1) {
System.err.println(glGetProgramInfoLog(program));
System.exit(1);
}
glValidateProgram(program);
if (glGetProgrami(program, GL_VALIDATE_STATUS) != 1) {
System.err.println(glGetProgramInfoLog(program));
System.exit(1);
}
}
public void bind () {
glUseProgram(program);
}
private String readFile (String filename) {
StringBuilder string = new StringBuilder();
BufferedReader br;
try {
br = new BufferedReader(new FileReader(new File("./shaders/" + filename)));
String line;
while((line = br.readLine()) != null) {
string.append(line);
string.append("\n");
}
} catch (IOException e ) {e.printStackTrace();}
return string.toString();
}
public void setUniform (String name, int value) {
int location = glGetUniformLocation(program, name);
if (location != -1) {
glUniform1i(location, value);
}
}
public void setUniform (String name, Matrix4f value) {
int location = glGetUniformLocation(program, name);
FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
value.get(buffer);
if (location != -1) {
glUniformMatrix4fv(location, false, buffer);
}
}
}
The Fragment Shader
#version 120
uniform sampler2D sampler;
varying vec2 tex_coords;
void main () {
gl_FragColor = texture2D(sampler, tex_coords);
}
The Vertex Shader
#version 120
attribute vec3 vertices;
attribute vec2 textures;
varying vec2 tex_coords;
uniform mat4 projection;
void main() {
tex_coords = textures;
gl_Position = projection*vec4(vertices, 1);
}
So far I'm creating 16x16 tiles all with the same texture but it is supposed to change the tile at 0, 0 (top left corner) to have a different texture
There is a basic misunderstanding, about how texturing works in OpenGL.
You have to create a separate texture object for each texture by glGenTextures. (See also Java Code Examples for org.lwjgl.opengl.GL11.glTexImage2D()).
int textureObject = glGenTextures();
This texture object has to be bound before loading the texture and before rendering the mesh. The texture is bound to the active texture unit, which is set by glActiveTexture.
int textureUnitIndex = 0; // e.g
glActiveTexture(GL_TEXTURE0 + textureUnitIndex);
glBindTexture(GL_TEXTURE_2D, textureObject);
The texture unit is a binding point for the shader program. The texture sampler in the shader program has to be associated to the same binding point. This can be done by glUniform1i:
GLSL:
uniform sampler2D sampler;
Java:
int location = glGetUniformLocation(program, "sampler");
glUniform1i(location, textureUnitIndex);
Sidenote: since GLSL version 4.2 this can be done in the fragment shader by specifying binding points - See OpenGL Shading Language 4.20 Specification - 4.4.4 Opaque-Uniform Layout Qualifiers; page 60:
#version 420
layout (binding = 0) uniform sampler2D sampler;
In your code never a texture object is generated. So the default texture object 0 is used for all textures. This causes that you code doesn't work.
Change the class Texture, somehow as follows, to solve the issue:
public class Texture {
private int textureObject;
private int width;
private int heigth;
public Texture (String filename) {
IntBuffer width = BufferUtils.createIntBuffer(1);
IntBuffer heigth = BufferUtils.createIntBuffer(1);
IntBuffer comp = BufferUtils.createIntBuffer(1);
ByteBuffer data = stbi_load("./res/" + filename, width, heigth, comp, 4);
this.width = width.get();
this.heigth = heigth.get();
textureObject = glGenTextures(); // generate texture name
glBindTexture(GL_TEXTURE_2D, textureObject);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this.width, this.heigth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
}
public void bind (int sampler) {
if (sampler >= 0 && sampler <= 31) {
glActiveTexture(GL_TEXTURE0 + sampler);
glBindTexture(GL_TEXTURE_2D, textureObject); // bind texture object
}
}
}

TextureView shows empty screen with OpenGl

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);
}
}
}

OpenGL rendering order (EXCEPTION_ACCESS_VIOLATION)

I am trying to render a 2D square, but my program crashes. I think my order of methods is incorrect. I am using LWJGL3, with the jars Lwjgl, GLFW, and OpenGL. The stacktrace shows the error is an EXCEPTION_ACCESS_VIOLATION, and the error is at the first openGL function depending on which one is first (with current code it is GL20.glGetAttribLocation() (following the guid here: https://github.com/SilverTiger/lwjgl3-tutorial/wiki/Rendering)
I am also not using legacyGL
If your having this problem:
add the lines GLFW.makeContextCurrent(window) and Gl.createCapabilities()
Main:
public class DungeonRunners {
private double lastTick;
private float timeCount;
private int fps;
private int fpsCount;
private int ups;
private int upsCount;
public static void main(String[] args) {
System.out.println("LWJGL Version: " + Version.getVersion());
int width = 1240;
int height = 720;
boolean legacyGL = false;
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if(arg.equals("width:")) {
try {
width = Integer.parseInt(args[i+1]);
i++;
} catch (NumberFormatException ignored) { }
} else if(arg.equals("height:")) {
try {
height = Integer.parseInt(args[i+1]);
} catch (NumberFormatException ignored) { }
} else if(arg.equals("-useLegacyGL")) {
legacyGL = true;
}
}
DungeonRunners dungeonRunners = new DungeonRunners();
dungeonRunners.start(width, height, legacyGL);
}
private void start(int width, int height, Boolean legacyGL) {
long window;
GLFW.glfwInit();
if(!legacyGL) {
GLFW.glfwDefaultWindowHints();
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, GLFW.GLFW_TRUE);
window = GLFW.glfwCreateWindow(width, height, "Dungeon Runners", MemoryUtil.NULL, MemoryUtil.NULL);
} else {
GLFW.glfwDefaultWindowHints();
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 2);
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 1);
window = GLFW.glfwCreateWindow(width, height, "Dungeon Runners", MemoryUtil.NULL, MemoryUtil.NULL);
}
RenderEngine engine = new RenderEngine(legacyGL);
while(!GLFW.glfwWindowShouldClose(window)) {
update();
engine.frame();
}
}
private void update() {
if (timeCount > 1f) {
fps = fpsCount;
fpsCount = 0;
ups = upsCount;
upsCount = 0;
timeCount -= 1f;
}
}
private float getDelta() {
double time = getTime();
float delta = (float) (time - lastTick);
lastTick = time;
timeCount += delta;
return delta;
}
public double getTime() {
return System.nanoTime() / 1000000000.0;
}
private void updateFPS() {
fpsCount++;
}
private void updateUPS() {
upsCount++;
}
}
The code is pretty explanatory, here is my RenderEngine class:
public class RenderEngine {
private int shaderProgram;
public RenderEngine(Boolean legacyGL) {
setVertexAttribs();
bindImage();
int vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao);
setupShaders(legacyGL);
GL20.glUseProgram(shaderProgram);
setUniformVars();
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, 3);
}
private void bindImage() {
try (MemoryStack stack = MemoryStack.stackPush()) {
FloatBuffer vertices = stack.mallocFloat(3 * 6);
vertices.put(-0.6f).put(-0.4f).put(0f).put(1f).put(0f).put(0f);
vertices.put(0.6f).put(-0.4f).put(0f).put(0f).put(1f).put(0f);
vertices.put(0f).put(0.6f).put(0f).put(0f).put(0f).put(1f);
vertices.flip();
int vbo = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertices, GL15.GL_STATIC_DRAW);
MemoryStack.stackPop();
}
}
public void frame() {
}
private void setUniformVars() {
int uniModel = GL20.glGetUniformLocation(shaderProgram, "model");
UtilMatrix4f model = new UtilMatrix4f();
GL20.glUniformMatrix4fv(uniModel, false, model.getBuffer());
int uniView = GL20.glGetUniformLocation(shaderProgram, "view");
UtilMatrix4f view = new UtilMatrix4f();
GL20.glUniformMatrix4fv(uniView, false, view.getBuffer());
int uniProjection = GL20.glGetUniformLocation(shaderProgram, "projection");
float ratio = 640f / 480f;
UtilMatrix4f projection = UtilMatrix4f.orthographic(-ratio, ratio, -1f, 1f, -1f, 1f);
GL20.glUniformMatrix4fv(uniProjection, false, projection.getBuffer());
}
private void setVertexAttribs() {
int floatSize = 4;
int posAttrib = GL20.glGetAttribLocation(shaderProgram, "position");
GL20.glEnableVertexAttribArray(posAttrib);
GL20.glVertexAttribPointer(posAttrib, 3, GL11.GL_FLOAT, false, 6 * floatSize, 0);
int colAttrib = GL20.glGetAttribLocation(shaderProgram, "color");
GL20.glEnableVertexAttribArray(colAttrib);
GL20.glVertexAttribPointer(colAttrib, 3, GL11.GL_FLOAT, false, 6 * floatSize, 3 * floatSize);
}
private void setupShaders(boolean legacyGL) {
int vertexShader = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
if(legacyGL)
GL20.glShaderSource(vertexShader, "src\\main\\java\\bigbade\\dungeonrunners\\renderer\\shaders\\legacyVertexShader.txt");
else
GL20.glShaderSource(vertexShader, "src\\main\\java\\bigbade\\dungeonrunners\\renderer\\shaders\\vertexShader.txt");
GL20.glCompileShader(vertexShader);
int status = GL20.glGetShaderi(vertexShader, GL20.GL_COMPILE_STATUS);
if (status != GL11.GL_TRUE) {
throw new RuntimeException(GL20.glGetShaderInfoLog(vertexShader));
}
int fragmentShader = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
if(legacyGL)
GL20.glShaderSource(vertexShader, "src\\main\\java\\bigbade\\dungeonrunners\\renderer\\shaders\\legacyFragmentShader.txt");
else
GL20.glShaderSource(fragmentShader, "src\\main\\java\\bigbade\\dungeonrunners\\renderer\\shaders\\fragmentShader.txt");
GL20.glCompileShader(fragmentShader);
status = GL20.glGetShaderi(fragmentShader, GL20.GL_COMPILE_STATUS);
if (status != GL11.GL_TRUE) {
throw new RuntimeException(GL20.glGetShaderInfoLog(fragmentShader));
}
shaderProgram = GL20.glCreateProgram();
GL20.glAttachShader(shaderProgram, vertexShader);
GL20.glAttachShader(shaderProgram, fragmentShader);
GL30.glBindFragDataLocation(shaderProgram, 0, "fragColor");
GL20.glLinkProgram(shaderProgram);
status = GL20.glGetProgrami(shaderProgram, GL20.GL_LINK_STATUS);
if (status != GL11.GL_TRUE) {
throw new RuntimeException(GL20.glGetProgramInfoLog(shaderProgram));
}
}
}

Skybox is fully Black

I am new at openGL
I created this skybox on LWJGL but It's all black
SkyboxRenderer Class :
private static String[] TEXTURE_FILES = {"right","left","bottom","back","front"};
private RawModel cube;
private int texture;
private SkyboxShader shader;
public SkyboxRenderer(Loader loader, Matrix4f projectionMatirx) {
cube = loader.loadToVAO(VERTICES, 3);
texture = loader.loadCubeMap(TEXTURE_FILES);
shader = new SkyboxShader();
shader.start();
shader.loadProjectionMatrix(projectionMatirx);
shader.stop();
}
public void render(Camera camera){
shader.start();
shader.loadViewMatrix(camera);
GL30.glBindVertexArray(cube.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, texture);
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, cube.getVertexCount());
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
shader.stop();
}
Loader loadCubeMap function :
public int loadCubeMap(String[] textureFiles){
int texID = GL11.glGenTextures();
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, texID);
for(int i = 0; i < textureFiles.length;i++){
TextureData data = decodeTextureFile("res/" + textureFiles[i] + ".png");
GL11.glTexImage2D(GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL11.GL_RGBA, data.getWidth(), data.getHeight(), 0, GL11.GL_RGBA,
GL11.GL_UNSIGNED_BYTE, data.getBuffer());
}
GL11.glTexParameteri(GL13.GL_TEXTURE_CUBE_MAP, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL13.GL_TEXTURE_CUBE_MAP, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL13.GL_TEXTURE_CUBE_MAP, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL13.GL_TEXTURE_CUBE_MAP, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
textures.add(texID);
return texID;
}
private TextureData decodeTextureFile(String fileName) {
int width = 0;
int height = 0;
ByteBuffer buffer = null;
try {
FileInputStream in = new FileInputStream(fileName);
PNGDecoder decoder = new PNGDecoder(in);
width = decoder.getWidth();
height = decoder.getHeight();
buffer = ByteBuffer.allocateDirect(4 * width * height);
decoder.decode(buffer, width * 4, Format.RGBA);
buffer.flip();
in.close();
} catch (Exception e) {
e.printStackTrace();
System.err.println("Tried to load texture " + fileName + ", didn't work");
System.exit(-1);
}
return new TextureData(buffer, width, height);
}
Textures exist, but skybox is fullyblack can someone help me!
How can i fix it
I need to add more details for posting because there is too much code...
SkyboxShader :
public class SkyboxShader extends ShaderProgram{
private static final String VERTEX_FILE = "src/com/redcatengine/skybox/skyboxVertexShader.txt";
private static final String FRAGMENT_FILE = "src/com/redcatengine/skybox/skyboxFragmentShader.txt";
private int location_projectionMatrix;
private int location_viewMatrix;
public SkyboxShader() {
super(VERTEX_FILE, FRAGMENT_FILE);
}
public void loadProjectionMatrix(Matrix4f matrix){
super.loadMatrix(location_projectionMatrix, matrix);
}
public void loadViewMatrix(Camera camera){
Matrix4f matrix = Maths.createViewMatrix(camera);
matrix.m30 = 0;
matrix.m31 = 0;
matrix.m32 = 0;
super.loadMatrix(location_viewMatrix, matrix);
}
#Override
protected void getAllUniformLocations() {
location_projectionMatrix = super.getUniformLocation("projectionMatrix");
location_viewMatrix = super.getUniformLocation("viewMatrix");
}
#Override
protected void bindAttributes() {
super.bindAttribute(0, "position");
}
}
public abstract class ShaderProgram {
private int programID;
private int vertexShaderID;
private int fragmentShaderID;
private static FloatBuffer matrixBuffer = BufferUtils.createFloatBuffer(16);
public ShaderProgram(String vertexFile, String fragmentFile) {
vertexShaderID = loadShader(vertexFile, GL20.GL_VERTEX_SHADER);
fragmentShaderID = loadShader(fragmentFile, GL20.GL_FRAGMENT_SHADER);
programID = GL20.glCreateProgram();
GL20.glAttachShader(programID, vertexShaderID);
GL20.glAttachShader(programID, fragmentShaderID);
bindAttributes();
GL20.glLinkProgram(programID);
GL20.glValidateProgram(programID);
getAllUniformLocations();
}
protected abstract void getAllUniformLocations();
protected int getUniformLocation(String uniformName){
return GL20.glGetUniformLocation(programID, uniformName);
}
public void start(){
GL20.glUseProgram(programID);
}
public void stop(){
GL20.glUseProgram(0);
}
public void cleanUp(){
stop();
GL20.glDetachShader(programID, vertexShaderID);
GL20.glDetachShader(programID, fragmentShaderID);
GL20.glDeleteShader(vertexShaderID);
GL20.glDeleteShader(fragmentShaderID);
GL20.glDeleteProgram(programID);
}
protected abstract void bindAttributes();
protected void bindAttribute(int attribute, String variableName){
GL20.glBindAttribLocation(programID, attribute, variableName);
}
protected void loadInt(int location, int value){
GL20.glUniform1i(location, value);
}
protected void loadFloat(int location, float value){
GL20.glUniform1f(location, value);
}
protected void loadVector(int location, Vector3f value){
GL20.glUniform3f(location, value.x, value.y, value.z);
}
protected void load2DVector(int location, Vector2f value){
GL20.glUniform2f(location, value.x, value.y);
}
protected void loadBoolean(int location, boolean value){
float toLoad = 0;
if(value)toLoad = 1;else toLoad = 0;
GL20.glUniform1f(location, toLoad);
}
protected void loadMatrix(int location, Matrix4f matrix){
matrix.store(matrixBuffer);
matrixBuffer.flip();
GL20.glUniformMatrix4(location, false, matrixBuffer);
}
private static int loadShader(String file, int type){
StringBuilder shaderSource = new StringBuilder();
try{
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine()) != null){
shaderSource.append(line).append("\n");
}
reader.close();
}catch(IOException e){
System.err.println("Could not read shader file!");
e.printStackTrace();
System.exit(-1);
}
int shaderID = GL20.glCreateShader(type);
GL20.glShaderSource(shaderID, shaderSource);
GL20.glCompileShader(shaderID);
if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS)==GL11.GL_FALSE){
System.out.println(GL20.glGetShaderInfoLog(shaderID, 500));
System.out.println("Could not compile shader.");
System.exit(-1);
}
return shaderID;
}
}
skyboxFragmentShader :
#version 400
in vec3 textureCoords;
out vec4 out_Color;
uniform samplerCube cubeMap;
void main(void){
out_Color = texture(cubeMap, textureCoords);
}
skyboxVertexShader
#version 400
in vec3 position;
out vec3 textureCoords;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
void main(void){
gl_Position = projectionMatrix * viewMatrix * vec4(position, 1.0);
textureCoords = position;
}`
Your cube map texture is not cube complete:
Your loader code iterates over all files in the array it is called with:
for(int i = 0; i < textureFiles.length;i++){
// [...]
GL11.glTexImage2D(GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, [...])
}
However, your input array contains only 5 entires:
String[] TEXTURE_FILES = {"right","left","bottom","back","front"};
You provide only 5 faces for the cube, and forgot the "top" face.
According to the GL spec (quotes are from section 8.17 of the OpenGL 4.5 core profile specification),
A cube map texture is mipmap complete if each of the six texture
images, considered individually, is mipmap complete. Additionally, a
cube map texture is cube complete if the following conditions all hold
true:
The level_base texture images of each of the six cube map faces have identical, positive, and square dimensions.
The levelbase
images were each specified with the same internal format.
It further goes on define texture completeness:
Using the preceding definitions, a texture is complete unless any of the following
conditions hold true:
[...]
The texture is a cube map texture, and is not cube complete.
[...]
So your cube map texture is not complete.
Section 11.1.3.5 states:
If a sampler is used in a shader and the sampler’s associated texture is not
complete, as defined in section 8.17, (0; 0; 0; 1) will be returned for a non-shadow sampler and 0 for a shadow sampler.
So indeed, your cube map should appear completely black.

Is it possible to draw more than one object using OpenGL ES 2.0

This is an update to a question I recently asked, but with new problems after I tried some stuff. What I want is to draw multiple circles on the screen. I created a class for the circle object. In my renderer class, I created an array list of these circles each with a different position. When called to draw, it only draws one of them. I logged what was going on and each object is being called to get drawn, but it seems only one appears on the screen. It's not just my circles. It appears throughout personal testing OpenGL ES 2.0 will only draw one object on the screen. I have no idea how to fix this. Is there something special I have to do in OpenGL ES 2.0? Here is my code. Ignore the incredibly sloppy and inefficient code right now. I am aware of it and will fix it later. Here is my circle object class:
GLCircle:
package com.background.gl.objects;
import static android.opengl.GLES20.GL_TRIANGLE_FAN;
import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.Matrix.multiplyMM;
import static android.opengl.Matrix.setIdentityM;
import static android.opengl.Matrix.translateM;
import static com.background.gl.glcirclebackgroundanimation.Constants.BYTES_PER_FLOAT;
import java.util.Random;
import android.opengl.Matrix;
import android.util.Log;
import com.background.gl.data.VertexArray;
import com.background.gl.helper.TextureShaderProgram;
public class GLCircle {
private static final int POSITION_COMPONENT_COUNT = 2;
private static final int TEXTURE_COORDINATES_COMPONENT_COUNT = 2;
private static final int STRIDE = (POSITION_COMPONENT_COUNT
+ TEXTURE_COORDINATES_COMPONENT_COUNT) * BYTES_PER_FLOAT;
public float x;
public float y;
protected float[] wallBounds;
protected boolean positiveX, positiveY;
public boolean nullify;
protected float xCounter = 0f;
protected float yCounter = 0f;
public float[] bounds;
protected Random ran;
private float[] VERTEX_DATA = {
// Order of coordinates: X, Y, S, T
// Triangle Fan
0f, 0f, 0.5f, 0.5f,
-0.25f, -0.25f, 0f, 0.9f,
0.25f, -0.25f, 1f, 0.9f,
0.25f, 0.25f, 1f, 0.1f,
-0.25f, 0.25f, 0f, 0.1f,
-0.25f, -0.25f, 0f, 0.9f };
private final VertexArray vertexArray;
public GLCircle(float x, float y) {
vertexArray = new VertexArray(VERTEX_DATA);
ran = new Random();
wallBounds = new float[4];
nullify = false;
this.x = x;
this.y = y;
}
public void bindData(TextureShaderProgram textureProgram) {
//Bind the position data to the shader attribute
vertexArray.setVertexAttribPointer(
0,
textureProgram.getPositionAttributeLocation(),
POSITION_COMPONENT_COUNT,
STRIDE);
//Bind the texture coordinate data to the shader attribute
vertexArray.setVertexAttribPointer(
POSITION_COMPONENT_COUNT,
textureProgram.getTextureCoordinatesAttributeLocation(),
TEXTURE_COORDINATES_COMPONENT_COUNT,
STRIDE);
}
public void drawCircle() {
glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
}
public float getX() {
return this.x;
}
public float getY() {
return this.y;
}
public boolean isPositiveX() {
return positiveX;
}
public boolean isPositiveY() {
return positiveY;
}
public float[] getBounds(float ranX, float ranY) {
if(!positiveX) {
/*if(ranX >= 0f) {
wallBounds[0] = 1.05f + ranX;
} else {*/
this.wallBounds[0] = 1.05f + ranX;
//}
} else {
/*
if(ranX >= 0f) {
wallBounds[0] = 1.05f - ranX;
} else {*/
this.wallBounds[1] = 1.05f - ranX;
//}
}
if(!positiveY) {
this.wallBounds[2] = 1.75f + ranY;
} else {
this.wallBounds[3] = 1.75f - ranY;
}
return this.wallBounds;
}
public void setPos(float[] modelMatrix,
float[] projectionMatrix, TextureShaderProgram textureProgram,
int texture, float x, float y, String log) {
setIdentityM(modelMatrix, 0);
translateM(modelMatrix, 0, 0f, 0.01f, 0f);
final float[] temp = new float[16];
multiplyMM(temp, 0, projectionMatrix, 0, modelMatrix, 0);
System.arraycopy(temp, 0, projectionMatrix, 0, temp.length);
textureProgram.useProgram();
textureProgram.setUniforms(projectionMatrix, texture);
bindData(textureProgram);
drawCircle();
Log.d("Drawing", "Drawing " + log);
}
public void scaleCircle(float[] modelMatrix, float x, float y, float z) {
Matrix.scaleM(modelMatrix, 0, x, y, z);
}
public void storeResults(float[] results) {
this.x = results[0];
this.y = results[1];
}
public void translateCircle(float x, float[] modelMatrix, float[] projectionMatrix) {
setIdentityM(modelMatrix, 0);
translateM(modelMatrix, 0, /*-0.001f*/ x, -3f, -2f);
final float[] temp = new float[16];
multiplyMM(temp, 0, projectionMatrix, 0, modelMatrix, 0);
System.arraycopy(temp, 0, projectionMatrix, 0, temp.length);
}
}
Again, I'm aware of most things I'm doing incorrectly, but currently I just need to figure out why I can't draw multiple objects on the screen. Here is my renderer code:
package com.background.gl.glcirclebackgroundanimation;
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glClearColor;
import static android.opengl.GLES20.glViewport;
import static android.opengl.Matrix.multiplyMM;
import static android.opengl.Matrix.setIdentityM;
import static android.opengl.Matrix.translateM;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;
import com.background.gl.helper.TextureShaderProgram;
import com.background.gl.objects.GLCircle;
import com.background.gl.objects.Mallet;
import com.background.gl.objects.Table;
import com.background.gl.util.MatrixHelper;
import com.background.gl.util.TextureHelper;
public class CircleDynamicBackgroundRenderer implements Renderer {
private final Context context;
private final float[] projectionMatrix = new float[16];
private final float[] modelMatrix = new float[16];
protected static float ranX,
ranY, ranSignX, ranSignY, ranSignVeloX, ranSignVeloY;
public boolean logNums;
private Table table;
private Mallet mallet;
private List<GLCircle> circles;
private GLCircle circle2;
float xPos, yPos;
int x = 1;
float[] bounds;
Random ran;
private TextureShaderProgram textureProgram;
private int texture;
public CircleDynamicBackgroundRenderer(Context context) {
this.context = context;
circles = new ArrayList<GLCircle>();
xPos = 0.1f;
ran = new Random();
logNums = true;
}
#Override
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
glViewport(0, 0, width, height);
Log.w("Width and height", Integer.toString(width) + ", " + Integer.toString(height));
MatrixHelper.perspectiveM(projectionMatrix, 90, (float) width
/ (float) height, 1f, 10f);
for(int i = 0; i < circles.size(); i++) {
circles.get(i).translateCircle(circles.get(i).x, modelMatrix, projectionMatrix);
}
// /circle2.translateCircle(circle2.x, modelMatrix);
/*final float[] temp = new float[16];
multiplyMM(temp, 0, projectionMatrix, 0, modelMatrix, 0);
System.arraycopy(temp, 0, projectionMatrix, 0, temp.length);*/
}
#Override
public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
table = new Table();
mallet = new Mallet();
textureProgram = new TextureShaderProgram(context);
texture = TextureHelper.loadTexture(context, R.drawable.air_hockey_surface);
//texture2 = TextureHelper.loadTexture(context, R.drawable.air_hockey_surface_2);
for(int i = 0; i < 3; i++) {
GLCircle circle = new GLCircle(generateRanFloats()[0], generateRanFloats()[1]);
circles.add(circle);
/*circle[i].x = circle[i].getX();
circle[i].y = circle[i].getY();
circle[i].bounds = circle[i].getBounds();*/
}
//circle2 = new GLCircle(generateRanFloats()[0], generateRanFloats()[1]);
Log.d("Circles size", Integer.toString(circles.size()));
Log.d("circles", Float.toString(circles.get(1).getX()) + " " + Float.toString(circles.get(2).getX()));
}
#Override
public void onDrawFrame(GL10 glUnused) {
//Clear the rendering surface
glClear(GL_COLOR_BUFFER_BIT);
for(int i = 0; i < circles.size(); i++) {
circles.get(i).setPos(modelMatrix, projectionMatrix, textureProgram, texture, circles.get(i).x, circles.get(i).y, "1"); if(logNums) {
Log.d("Circle1, c2", Float.toString(circles.get(i).x) + ", " + Float.toString(circles.get(i).x));
logNums = false;
}
//Log.d("Circles", Float.toString(circles.get(i).x));
}
}
public float[] generateRanFloats() {
ranSignX = ran.nextFloat();
ranSignY = ran.nextFloat();
ranSignX = ranSignX > 0.5f? -1:1;
ranSignY = ranSignY > 0.5f? -1:1;
ranSignVeloX = ran.nextFloat();
ranSignVeloY = ran.nextFloat();
ranX = ran.nextFloat() * 1.05f;
ranY = ran.nextFloat() * 1.75f;
ranX = ranSignX > 0.5? -ranX:ranX;
ranY = ranSignY > 0.5? -ranY:ranY;
Log.d("Generated", Float.toString(ranX));
return new float[] {ranX, ranY};
}
}
It's been two days now and I cannot for the live of me figure out what is wrong and how to fix this. I really need to figure out a way to fix this. Any assistance will be greatly appreciated. If you need to see more code, let me know.
Per the last discussion - did you work on the perspective matrix ? I would recommend first starting with the ortho projection, get your code working, then move to working with perspective projection. You can use the below as a starting point for ortho projection.
mat4.ortho(-1.0, 1.0, -1, 1.0, -10.0, 100.0, projectionMatrix);
Also remove all the z translations in your code, make your code work on xy, then add z translations.
PS: Isnt it better to continue in the same thread as (OpenGL ES 2.0 only draws the object once) ?

Categories