LWJGL Cannot use offsets when Array Buffer Object is disabled [duplicate] - java

This question already has answers here:
OpenGLException: Cannot use offsets when Array Buffer Object is disabled.. On a line after calling glEnable(GL_ARRAY_BUFFER)?
(2 answers)
Closed 8 years ago.
I have looked at a lot of posts, and cannot find what is wrong with my code.
I have bound my VBO however it doesn't work and gives me this error:
Exception in thread "main" org.lwjgl.opengl.OpenGLException: Cannot use
offsets when Array Buffer Object is disabled
at org.lwjgl.opengl.GLChecks.ensureArrayVBOenabled(GLChecks.java:77)
at org.lwjgl.opengl.GL20.glVertexAttribPointer(GL20.java:892)
at glsl.Main.main(Main.java:117)
I don't understand what is wrong here. I have looked everywhere and can't work out what is wrong with this. I have tried it with and without glEnable(GL_ARRAY_BUFFER_BINDING);
package glsl;
import java.nio.FloatBuffer;
import java.util.Scanner;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
public class Main
{
private static int initShaderProgram()
{
int shaderProgram = glCreateProgram();
int vertexShader = getShader(GL_VERTEX_SHADER, "/shader.vert");
glAttachShader(shaderProgram, vertexShader);
int fragmentShader = getShader(GL_FRAGMENT_SHADER, "/shader.frag");
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
checkError(shaderProgram, GL_LINK_STATUS, true);
glValidateProgram(shaderProgram);
checkError(shaderProgram, GL_VALIDATE_STATUS, true);
return shaderProgram;
}
private static int getShader(int shaderType, String shaderName)
{
int shader = glCreateShader(shaderType);
String shaderText = "";
Scanner scan = new Scanner(Main.class.getResourceAsStream(shaderName));
while(scan.hasNextLine())
shaderText = shaderText.concat(scan.nextLine().concat("\n"));
scan.close();
System.out.println("\n");
System.out.println(shaderName+" source: --------------------------------------------");
System.out.println("\n"+shaderText);
System.out.println("\n");
glShaderSource(shader, shaderText);
glCompileShader(shader);
checkError(shader, GL_COMPILE_STATUS, false);
return shader;
}
private static void checkError(int shader, int status, boolean isProgram)
{
if(!isProgram)
{
if(glGetShaderi(shader, status) == org.lwjgl.opengl.GL11.GL_FALSE)
{
System.err.println("Shader broken: " + glGetShaderInfoLog(shader, GL_INFO_LOG_LENGTH));
System.exit(1);
}
}else
{
if(glGetProgrami(shader, status) == org.lwjgl.opengl.GL11.GL_FALSE)
{
System.err.println("Shader broken: " + glGetProgramInfoLog(shader, GL_INFO_LOG_LENGTH));
System.exit(1);
}
}
}
public static void main(String[] args)
{
try
{
Display.setDisplayMode(new DisplayMode(800, 600));
Display.create();
}catch(org.lwjgl.LWJGLException e)
{
System.exit(1);
}
glEnable(GL_ARRAY_BUFFER_BINDING);
int shaderProgram = initShaderProgram();
String attribute_name = "coord2d";
int attribute_coord2d = glGetAttribLocation(shaderProgram, attribute_name);
int vboTriangle;
float[] triangleVerticesArray =
{
-1, -1,
0, 1f,
1, -1
};
FloatBuffer triangleVertices = (FloatBuffer) BufferUtils.createFloatBuffer(triangleVerticesArray.length).put(triangleVerticesArray).flip();
vboTriangle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboTriangle);
glBufferData(GL_ARRAY_BUFFER, triangleVertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
while(!Display.isCloseRequested())
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glEnableVertexAttribArray(attribute_coord2d);
glBindBuffer(GL_VERTEX_ARRAY, vboTriangle);
glVertexAttribPointer(attribute_coord2d, 2, GL_FLOAT, false, 0, 0l);
glBindBuffer(GL_VERTEX_ARRAY, 0);
glDisableVertexAttribArray(attribute_coord2d);
glUseProgram(0);
Display.update();
Display.sync(60);
}
cleanup(shaderProgram, new int[]{vboTriangle});
}
private static void cleanup(int shaderProgram, int[] vbos)
{
for(int i = 0; i < vbos.length; i++)
glDeleteBuffers(vbos[i]);
glDeleteProgram(shaderProgram);
Display.destroy();
}
}

You need to set up the pointers with a VAO, a Vertex Array Object.
int vaoID = glGenVertexArrays();
Then you need to bind it, and set up the pointers with the VBOs, Vertex Array Objects.
glBindVertexArray(vaoID);
glEnableVertexAttribArray(indexLocation);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glVertexAttribPointer(indexLocation, 2, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
Then everytime you render, bind the VAO, and issue a draw command.
glBindVertexArray(vaoID);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
Then finally, you need to dispose the VAO object.
glBindVertexArray(0);
glDeleteVertexArrays(vaoID);
Hope this helps.

Related

Java lwjgl GLSL shader issue with mac osx Validation Failed: No vertex array object bound [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I am building OPENGL application in Java using lwjgl and following part of tutorial on YouTube by thebennybox
I am able to create rectangle using Mesh class i build.
import engine.core.Util;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
public class Mesh {
private int vbo;
private int size;
public Mesh() {
this.vbo = glGenBuffers();
this.size = 0;
}
public void addVertices(Vertex[] vertices){
this.size = vertices.length * Vertex.SIZE;
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, Util.createFlippedBuffer(vertices), GL_STATIC_DRAW);
}
public void draw(){
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
glDrawArrays(GL_TRIANGLES, 0, this.size);
glDisableVertexAttribArray(0);
}
}
And util helper
import engine.render.Vertex;
import org.lwjgl.BufferUtils;
import java.nio.FloatBuffer;
public class Util {
public static FloatBuffer createFloatBuffer(int size){
return BufferUtils.createFloatBuffer(size);
}
public static FloatBuffer createFlippedBuffer(Vertex[] vertices){
FloatBuffer buffer = createFloatBuffer(vertices.length * Vertex.SIZE);
for(int i = 0; i < vertices.length; i++) {
buffer.put(vertices[i].getPos().getX());
buffer.put(vertices[i].getPos().getY());
buffer.put(vertices[i].getPos().getZ());
}
buffer.flip();
return buffer;
}
}
Here is how i am rendering
this.mesh = new Mesh();
Vertex[] data = new Vertex[]{
//1st triangle
new Vertex(new Vector3(0.5f,-0.5f,0)), //RB
new Vertex(new Vector3(-0.5f,-0.5f,0)), //LB
new Vertex(new Vector3(0.5f,0.5f,0)), //RT
//2nd triangle
new Vertex(new Vector3(-0.5f,0.5f,0)), //RB
new Vertex(new Vector3(0.5f,0.5f,0)), //RT
new Vertex(new Vector3(-0.5f,-0.5f,0)), //LB
};
mesh.addVertices(data);
public void render(){ //update per frame
mesh.draw();
}
So far it worked. Then I followed tutorial for shader and got error
Validation Failed: No vertex array object bound.
Here is shader class
import static org.lwjgl.opengl.GL32C.*;
public class Shader {
private int program;
public Shader() {
program = glCreateProgram();
if(program == 0){
System.out.println("Shader creation failed!");
System.exit(1);
}
}
public void addVertexShader(String text){
//System.out.println(text);
addProgram(text, GL_VERTEX_SHADER);
}
public void addGeometryShader(String text){
addProgram(text, GL_GEOMETRY_SHADER);
}
public void addFragmentShader(String text){
addProgram(text, GL_FRAGMENT_SHADER);
}
public void bind(){
glUseProgram(program);
}
public void compileShader(){
glLinkProgram(program);
if(glGetProgrami(program, GL_LINK_STATUS) == 0){
System.out.println(glGetProgramInfoLog(program, 1024));
System.exit(1);
}
glValidateProgram(program);
if(glGetProgrami(program, GL_VALIDATE_STATUS) == 0){
// System.out.println("ffff");
System.out.println( glGetProgramInfoLog(program, 1024));
System.exit(1);
}
}
public void addProgram(String text, int type){
int shader = glCreateShader(type);
if(shader == 0){
System.out.println("Shader creation failed!");
System.exit(1);
}
glShaderSource(shader, text);
glCompileShader(shader);
if(glGetShaderi(shader, GL_COMPILE_STATUS) == 0){
System.out.println(glGetShaderInfoLog(shader, 1024));
System.exit(1);
}
glAttachShader(program, shader);
}
}
And here is ResourceLoader
import java.io.BufferedReader;
import java.io.FileReader;
public class ResourceLoader {
public static String loadShader(String fileName){
StringBuilder shaderSource = new StringBuilder();
BufferedReader shaderReader = null;
try {
shaderReader = new BufferedReader(new FileReader(fileName));
String line;
while ((line = shaderReader.readLine()) != null){
shaderSource.append(line).append("\n");
}
} catch (Exception e){
System.out.println(e.getMessage());
}
return shaderSource.toString();
}
}
GLSL CODE FOR BOTH FILE
==== basicVertex.glsl
#version 410 core
out vec4 outColor;
void main(){
outColor = vec4(0.0, 1.0, 1.0, 1.0);
}
========= basicFragment.glsl
#version 410 core
layout (location = 0) in vec3 position;
void main(){
gl_Position = vec4(position, 1.0);
}
You've to create and use a Vertex Array Object.
The Vertex Array Object stores the specification of the arrays of generic vertex attribute data.
Create and bind the VAO when you specify the vertex arrays.e.g:
public class Mesh {
private int vao;
private int vbo;
private int size;
public Mesh() {
this.size = 0;
this.vao = glGenVertexArrays();
this.vbo = glGenBuffers();
glBindVertexArray(this.vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(0);
}
// [...]
}
And use it when you draw the geometry:
public class Mesh {
// [...]
public void draw(){
glBindVertexArray(this.vao);
glDrawArrays(GL_TRIANGLES, 0, this.size);
glBindVertexArray(0); // <--- Note, this is not needed
}
}

Program only uses one shader, whereas I am trying to connect 2 shaders

I am using OpenGl with Java and currenctly I am trying to connect 2 different shader programs (one for each object I wish to render) with my code. Despite that, at the end only one shader connects efficietly and I think (not sure though) that it overrides the first one. My code is pretty long so I am not sure how much information I should provide, so lets me know if I should post the code of my shaders as well:
public class Aufgabe3undFolgende extends AbstractOpenGLBase {
private ShaderProgram shaderProgram;
private ShaderProgram shaderProgram2;
private Matrix4 matrix = new Matrix4();
private Matrix4 secondMatrix = new Matrix4();
private Matrix4 projection = new Matrix4(0.8f,500f);
public static void main(String[] args) {
new Aufgabe3undFolgende().start("CG Aufgabe 3", 700, 700);
}
private int matrixID;
private int secondMatrixID;
private int snake;
private int greenSnake;
private GLFWKeyCallback input;
//cube normals
float[] normals = {..};
//cube vertices
float[] cube = {..};
//pyramid vertices
float[] pyramid = {..};
//uv coordinates for pyramid
float[] uv = {..};
//uv coordinates for cube
float[] uvCoords = {..};
#Override
protected void init() {
glfwSetKeyCallback(super.returnWindow(), input = new
MouseAndKeyboardControl());
shaderProgram = new ShaderProgram("aufgabe3");
//cube
glUseProgram(shaderProgram.getId());
matrixID = glGenVertexArrays();
glBindVertexArray(matrixID);
System.out.println(matrixID);
//pass data in the buffer
VBO(0, 3,cube);
VBO(1, 3, normals);
VBO( 2, 2, uvCoords);
Texture texture = new Texture("snake.jpg", 8);
snake = texture.getId();
glBindTexture(GL_TEXTURE_2D, snake);
//pyramid
shaderProgram2 = new ShaderProgram("render_pyramid");
glUseProgram(shaderProgram2.getId());
secondMatrixID = glGenVertexArrays();
glBindVertexArray(secondMatrixID);
System.out.println(secondMatrixID);
//pass data in the buffer
VBO(0, 3, pyramid);
VBO(1, 2,uv);
Texture texture2 = new Texture("greensnake.jpg", 8);
greenSnake = texture2.getId();
glBindTexture(GL_TEXTURE_2D, greenSnake);
glEnable(GL_DEPTH_TEST); // z-Buffer aktivieren
glEnable(GL_CULL_FACE); // backface culling aktivieren
int loc = glGetUniformLocation(shaderProgram.getId(),
"projectionMatrix");
glUniformMatrix4fv(loc, false,projection.getValuesAsArray());
}
public void VBO(int index, int size, float[] name) {
int vbold = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbold);
glBufferData(GL_ARRAY_BUFFER, name, GL_STATIC_DRAW);
glVertexAttribPointer(index,size, GL_FLOAT, false, 0,0);
glEnableVertexAttribArray(index);
}
#Override
public void update() {
matrix = new Matrix4();
matrix.translate(2, 2, -4);
secondMatrix = new Matrix4();
secondMatrix.translate(-2, -1, -4);
if (MouseAndKeyboardControl.keyPressed(49)) {
secondMatrix.rotateX(0.3f);
}
if (MouseAndKeyboardControl.keyPressed(50)) {
matrix.rotateY(0.3f);
}
}
#Override
protected void render() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int loc1 = glGetUniformLocation(shaderProgram.getId(), "viewMatrix");
glUniformMatrix4fv(loc1, false, matrix.getValuesAsArray());
glBindTexture(GL_TEXTURE_2D, snake);
glBindVertexArray(matrixID);
glDrawArrays(GL_TRIANGLES, 0, 36);
int loc2 = glGetUniformLocation(shaderProgram2.getId(), "viewMatrix2");
glUniformMatrix4fv(loc2, false, secondMatrix.getValuesAsArray());
glBindTexture(GL_TEXTURE_2D, greenSnake);
glBindVertexArray(secondMatrixID);
glDrawArrays(GL_TRIANGLES, 0, 12);
}
#Override
public void destroy() {
}
I have tried to connect the shaders with the program in the init() Method. The name of the first shader is aufgabe3 and the name of the second shader is render_pyramid. I appreciate any help you can provide!

LWJGL rendering nothing

I've looked over the following program over and over and cannot find why nothing renders to the screen when I run it:
Game.java:
public class Game {
private int fbid, fbid2;
public void start(){
DisplayManager.init();
glViewport(0, 0, DisplayManager.SCR_WIDTH, DisplayManager.SCR_HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 0, DisplayManager.SCR_WIDTH, DisplayManager.SCR_HEIGHT, 1, -1);
glMatrixMode(GL_MODELVIEW);
FloatBuffer fb = BufferUtils.createFloatBuffer(6);
fb.put(100).put(100).put(100).put(200).put(200).put(200);
fb.flip();
fbid = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, fbid);
glBufferData(GL_ARRAY_BUFFER, fb, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
FloatBuffer fb2 = BufferUtils.createFloatBuffer(9);
fb2.put(1).put(1).put(1).put(1).put(1).put(1).put(1).put(1).put(1);
fb2.flip();
fbid2 = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, fbid2);
glBufferData(GL_ARRAY_BUFFER, fb2, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
while(!DisplayManager.shouldClose()){
render();
}
DisplayManager.destroy();
}
public void render(){
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0, 0, 0, 0);
glColor3f(1, 1, 1);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, fbid);
glVertexPointer(2, GL_FLOAT, 0, 0);
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, fbid2);
glColorPointer(3, GL_FLOAT, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
DisplayManager.update();
}
}
DisplayManager.java:
public class DisplayManager {
public static final int SCR_WIDTH = 640;
public static final int SCR_HEIGHT = 480;
public static final int FPS = 30;
public static void init(){
try {
Display.setDisplayMode(new DisplayMode(SCR_WIDTH, SCR_HEIGHT));
Display.setTitle("StepBattler");
Display.setResizable(false);
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
Display.destroy();
System.exit(1);
}
}
public static void update(){
Display.update();
Display.sync(FPS);
}
public static void destroy(){
Display.destroy();
System.exit(0);
}
public static boolean shouldClose(){
return Display.isCloseRequested();
}
public static boolean shouldResize(){
return Display.wasResized();
}
}
When I run the screen, I just get a window filled with black, and I cannot understand why a white triangle won't render to the window. I've messed around with glClearColor(), and changing its values does succeed in changing the window background color, but I can't make a white triangle appear in the window. Also, I tried using glBegin()...glEnd() to render in immediate mode, with none of the code having to do with buffers in there, and it still didn't render anything. I'm really confused about this, what am I missing?
The arguments in you glOrtho() call look to be in the wrong order:
glOrtho(0, 0, DisplayManager.SCR_WIDTH, DisplayManager.SCR_HEIGHT, 1, -1);
The signature of glOrtho(), based on the man page, is:
void glOrtho(GLdouble left, GLdouble right,
GLdouble bottom, GLdouble top,
GLdouble nearVal, GLdouble farVal);
Since you're passing 0 for both left and right, the result would be an invalid projection matrix.
The correct call for your case is:
glOrtho(0, DisplayManager.SCR_WIDTH, 0, DisplayManager.SCR_HEIGHT, 1, -1);

LWJGL3 shader, triangle not showing up

I'm new to OpenGL and LWJGL3 and I'm trying to render a triangle. However, it isn't showing up, only the white, empty window. I guess it's a pretty small piece that I somehow forgot or where I just made a mistake. I don't find it after searching for hours now though. Here's the code:
MainLoop:
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.glfw.GLFW.*;
public class MainLoop {
private DisplayManager displayManager;
private Shader shader;
public MainLoop() {
displayManager = new DisplayManager();
displayManager.createDisplay();
shader = new Shader("src/shader.vert", "src/shader.frag");
}
private void start() {
float positions[] = {
-0.5f, 0.0f, 0.0f,
0.5f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f
};
int vao = glGenVertexArrays();
glBindVertexArray(vao);
int positionVbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, positionVbo);
glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(positions), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
while(!displayManager.isCloseRequested()) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vao);
render();
update();
displayManager.swapBuffers();
}
shader.cleanUp();
displayManager.destroyDisplay();
}
private void update() {
glfwPollEvents();
}
private void render() {
shader.bind();
//rendering stuff
glDrawArrays(GL_TRIANGLES, 0, 3);
shader.unbind();
}
public static void main(String[] args) {
new MainLoop().start();
}
}
Shader:
import static org.lwjgl.opengl.GL11.GL_FALSE;
import static org.lwjgl.opengl.GL20.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Shader {
private int program;
public Shader(final String vertexShaderFilePath, final String fragmentShaderFilePath) {
int vertexShader = createShader(loadShaderSource(vertexShaderFilePath), GL_VERTEX_SHADER);
int fragmentShader = createShader(loadShaderSource(fragmentShaderFilePath), GL_FRAGMENT_SHADER);
program = glCreateProgram();
glAttachShader(vertexShader, program);
glAttachShader(fragmentShader, program);
glLinkProgram(program);
glValidateProgram(program); //just during development
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
private String loadShaderSource(final String shaderFilePath) {
String shaderSourceString = "";
try {
shaderSourceString = new String(Files.readAllBytes(Paths.get(shaderFilePath)));
} catch (IOException e) {
e.printStackTrace();
}
return shaderSourceString;
}
private int createShader(final String shaderSourceString, final int type) {
int shader = glCreateShader(type);
glShaderSource(shader, shaderSourceString);
glCompileShader(shader);
checkShaderCompileError(shader);
return shader;
}
private void checkShaderCompileError(int shader) {
if(glGetShaderi(shader, GL_COMPILE_STATUS) == GL_FALSE) {
System.err.println("Could not compile shader.");
System.err.println(glGetShaderInfoLog(program));
System.exit(-1);
}
}
public void bind() {
glUseProgram(program);
}
public void unbind() {
glUseProgram(0);
}
public void cleanUp() {
glDeleteProgram(program);
}
}
BufferUtils:
import java.nio.FloatBuffer;
public class BufferUtils {
public static FloatBuffer createFloatBuffer(float[] array) {
FloatBuffer buffer = org.lwjgl.BufferUtils.createFloatBuffer(array.length);
buffer.put(array);
buffer.flip();
return buffer;
}
}
shader.vert:
#version 410 core
layout (location = 0) in vec3 vertex_position;
void main(void)
{
gl_Position = vec4(vertex_position, 1.0);
}
shader.frag:
#version 410 core
out vec4 frag_color;
void main(void)
{
frag_color = vec4(1.0, 0.0, 1.0, 1.0);
}
EDIT: and here's the DisplayManager:
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.system.MemoryUtil.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GLContext.*;
import java.nio.ByteBuffer;
import org.lwjgl.glfw.GLFWvidmode;
public class DisplayManager {
private static final int WIDTH = 1280;
private static final int HEIGHT = 800;
private long window;
private Keyboard keyCallback;
public void createDisplay() {
// initialize GLFW
if(glfwInit() != GL_TRUE) {
System.err.println("GLFW failed to initialize.");
System.exit(-1);
}
// set window hints
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, 4); //16 for production
// create window
window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL", NULL, NULL);
if(window == NULL) {
System.err.println("GLFW window failed to create.");
glfwTerminate();
System.exit(-1);
}
ByteBuffer videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, (GLFWvidmode.width(videoMode) - WIDTH) / 2, (GLFWvidmode.height(videoMode) - HEIGHT) / 2);
// set callback mechanisms
glfwSetKeyCallback(window, setKeyCallback(new Keyboard()));
// set context and show window
glfwMakeContextCurrent(window);
createFromCurrent();
glfwSwapInterval(1); // v-sync
glfwShowWindow(window);
// openGL functions
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glEnable(GL_DEPTH);
}
public void destroyDisplay() {
glfwDestroyWindow(window);
glfwTerminate();
}
public boolean isCloseRequested() {
if(glfwWindowShouldClose(window) == GL_TRUE) {
return true;
}
return false;
}
public void swapBuffers() {
glfwSwapBuffers(window);
}
public Keyboard getKeyCallback() {
return keyCallback;
}
public Keyboard setKeyCallback(Keyboard keyCallback) {
this.keyCallback = keyCallback;
return keyCallback;
}
}
Does anybody spot what's going wrong?
Thanks in advance!
I finally found the error, the order of parameters for the call glAttachShader(shader, program); were mixed up. You first have to pass the program and then the shader id like so: glAttachShader(program, shader);. Thank you for your answers though!

Textures in OpenGL ES 2.0 for Android

I'm new to OpenGL and I'm teaching myself by making a 2D game for Android with ES 2.0. I am starting off by creating a "Sprite" class that creates a plane and renders a texture to it. To practice, I have two Sprite objects that are drawn alternating in the same place. I got this much working fine and well with ES 1.0, but now that I've switched to 2.0, I am getting a black screen with no errors. I'm exhausted trying to figure out what I'm doing wrong, but I have a strong feeling it has to do with my shaders. I'm going to dump all the relevant code here and hopefully somebody can give me an answer or some advice as to what I'm doing wrong. And if it's not immediately apparent what I'm doing wrong, perhaps some advice on how to figure it out? Thanks in advance for looking through all the code I'm about to post.
The three classes I'm posting are:
GameRenderer - the renderer for my GLSurfaceView
Shader - creates a shader program object
Sprite - creates a square and draws a texture on it
Also, I'll post my vertex and fragment shader source.
Related classes I didn't think were relevant enough to post:
GameActivity
GameView - A GLSurfaceView
GameLoopThread - My main game loop
FPSCounter - outputs the average FPS to logcat every 100 frames.
GameRender class:
package com.detour.raw;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLU;
import android.opengl.Matrix;
import android.opengl.GLSurfaceView;
public class GameRenderer implements GLSurfaceView.Renderer{
private static final String LOG_TAG = GameRenderer.class.getSimpleName();
Context mContext;
Bitmap bitmap;
private float red = 0.0f;
private float green = 0.0f;
private float blue = 0.0f;
Shader shader;
FPSCounter fps;
Sprite sprite;
Sprite sprite2;
int x = 0;
private float[] mProjMatrix = new float[16];
private float[] mVMatrix = new float[16];
//int[] vertexShader;
//int[] fragmentShader;
//int program;
//String vShaderSource = "";
//String fShaderSource = "";
public GameRenderer(Context context){
mContext = context;
//create objects/sprites
sprite = new Sprite(mContext);
sprite2 = new Sprite(mContext);
fps = new FPSCounter();
}
#Override
public void onDrawFrame(GL10 gl) {
GLES20.glClearColor(red, green, blue, 1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
if(x>3){
x=0;
}
if(x%2==0){
sprite.draw(gl);
}else{
sprite2.draw(gl);
}
x++;
fps.calculate();
//fps.draw(gl);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float)(width/height);
Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 0.5f, 10);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glClearDepthf(1.0f);
GLES20.glDepthFunc(GLES20.GL_LEQUAL);
GLES20.glDepthMask(true);
GLES20.glEnable(GLES20.GL_CULL_FACE);
GLES20.glCullFace(GLES20.GL_BACK);
GLES20.glClearColor(red, green, blue, 1.0f);
//load sprite/object textures (preferably loop through an array of all sprites).
sprite.loadGLTexture(gl, mContext, R.drawable.raw1);
sprite2.loadGLTexture(gl, mContext, R.drawable.raw2);
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -5.0f, 0.0f, 0f, 0f, 0f, 0.0f, 0.0f);
System.gc();
}
}
Shader class:
package com.detour.raw;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import android.content.Context;
import android.opengl.GLES20;
import android.util.Log;
public class Shader {
public static final String TAG = Shader.class.getSimpleName();
int program;
int vertexShader;
int fragmentShader;
String vShaderSource;
String fShaderSource;
public Shader(){
//blank constructor
//createProgram();
}
public Shader(String vs_source, String fs_source){
this.vShaderSource = vs_source;
this.fShaderSource = fs_source;
createProgram();
}
public Shader(int vs_source_id, int fs_source_id, Context context) {
StringBuffer vs = new StringBuffer();
StringBuffer fs = new StringBuffer();
try{
InputStream inputStream = context.getResources().openRawResource(vs_source_id);
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
String read = in.readLine();
while (read != null) {
vs.append(read + "\n");
read = in.readLine();
}
vs.deleteCharAt(vs.length() - 1);
inputStream = context.getResources().openRawResource(fs_source_id);
in = new BufferedReader(new InputStreamReader(inputStream));
read = in.readLine();
while (read != null) {
fs.append(read + "\n");
read = in.readLine();
}
fs.deleteCharAt(fs.length() - 1);
}catch (Exception e){
Log.d("ERROR-readingShader", "Could not read shader: " + e.getLocalizedMessage());
}
this.vShaderSource = vs.toString();
this.fShaderSource = fs.toString();
createProgram();
}
private void createProgram(){
program = GLES20.glCreateProgram();
if(program!=0){
vertexShader = createShader(GLES20.GL_VERTEX_SHADER, vShaderSource);
fragmentShader = createShader(GLES20.GL_FRAGMENT_SHADER, fShaderSource);
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
}else{
Log.e(TAG, "Couldn't create program.");
}
}
private int createShader(int type, String source){
int shader = GLES20.glCreateShader(type);
if(shader!=0){
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
}
return shader;
}
public int getProgram(){
return program;
}
Sprite class:
package com.detour.raw;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
public class Sprite {
//public static final int FRAME_WIDTH = 64;
//public static final int FRAME_HEIGHT = 64;
private static final String LOG_TAG = Sprite.class.getSimpleName();
Context mContext;
Bitmap bitmap;
private int textureLoc;
private int vertexLoc;
private int[] textures = new int[1];
//private int[] pixels;
/*private float textureCoordinates[] = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f};*/
private float vertices[] = {
-1.0f, 1.0f,// 0.0f,
-1.0f, -1.0f,// 0.0f,
1.0f, -1.0f,// 0.0f,
1.0f, 1.0f// 0.0f
};
private short[] indices = {
0, 1, 2,
0, 2, 3};
private FloatBuffer vertexBuffer;
//private IntBuffer textureBuffer;
private ShortBuffer indexBuffer;
Shader shader;
int program;
String vShaderSource = "";
String fShaderSource = "";
public Sprite(Context context){
mContext = context;
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(0);
}
public void draw(GL10 gl) {
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_FLOAT, indexBuffer);
}
public void loadGLTexture(GL10 gl, Context context, int id){
shader = new Shader(R.raw.sprite_vs, R.raw.sprite_fs, mContext);
program = shader.getProgram();
GLES20.glUseProgram(program);
vertexLoc = GLES20.glGetAttribLocation(program, "a_position");
textureLoc = GLES20.glGetUniformLocation(program, "u_texture"); //texture
InputStream is = context.getResources().openRawResource(id);
try {
bitmap = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
is = null;
} catch (IOException e) {
}
}
//pixels = new int[(bitmap.getWidth()*bitmap.getHeight())];
//bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
/*ByteBuffer byteBuf = ByteBuffer.allocateDirect(pixels.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
textureBuffer = byteBuf.asIntBuffer();
textureBuffer.put(pixels);
textureBuffer.position(0);*/
GLES20.glDeleteTextures(1, textures, 0);
GLES20.glGenTextures(1, textures, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glUniform1i(textureLoc, 0);
GLES20.glEnableVertexAttribArray(vertexLoc);
GLES20.glVertexAttribPointer(vertexLoc, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
//GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, FRAME_WIDTH, FRAME_HEIGHT, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, byteBuf);//(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
}
Vertex shader (sprite_vs.txt):
#version 110
attribute vec2 a_position;
varying vec2 v_texcoord;
void main()
{
gl_Position = vec4(a_position, 0.0, 1.0);
v_texcoord = a_position * vec2(0.5) + vec2(0.5);
}
Fragment (pixel) shader (sprite_fs.txt):
#version 110
uniform sampler2D u_texture;
varying vec2 v_texcoord;
void main()
{
gl_FragColor = texture2D(u_texture, v_texcoord);
}
Thank you so much if you actually took the time to look through this! Hopefully someone else can use this as a resource for themselves in the future, also.
A few observations/questions:
I don't know how you changed the fragment shader, but the version that is currently posted needs a precision specifier. Just add:
precision mediump float;
to the top, and it should work. Now regarding the black screen here are some questions:
When you change the glClearColor to something not black and comment out all the draw commands, does it still look black? If so, then you have a bigger problem than textures.
Second, if you ignore the texture output and try drawing each sprite as just a flat colored rectangle with no texture data, what do you get? You should be able to see some colored rectangle on the screen.
Finally, you need to bind the texture before you call glDrawElements. (Though this shouldn't matter in this example since you haven't changed the state yet.)

Categories

Resources