Related
I began to try to draw VBO using JOGL. Prior to that, I drew with the help of glBegin and glEnd, and everything worked. And then I see only a black screen. What could be the problem? I read somewhere that using VBO for drawing requires shaders. Is it so?
Code:
public class Main implements GLEventListener {
public static DisplayMode dm, dm_old;
private GLU glu = new GLU();
private float xrot,yrot,zrot;
private int texture;
Texture t;
#Override
public void display(GLAutoDrawable drawable) {
final GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity(); // Reset The View
gl.glTranslatef(0f, 0f, -5.0f);
gl.glBindTexture(GL2.GL_TEXTURE_2D, texture);
final float[] coordData = {
0, 0, //
1, 0, //
0, 1, //
};
final float[] vertices = {
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
};
// Setup the vertices into the buffer
FloatBuffer verts = Buffers.newDirectFloatBuffer(vertices.length);
verts.put(vertices).position(0);
// Setup the texture coordinates
FloatBuffer coords = Buffers.newDirectFloatBuffer(coordData.length);
coords.put(coordData).position(0);
gl.glVertexPointer(3, GL2.GL_FLOAT, 0, verts);
gl.glTexCoordPointer(2, GL2.GL_FLOAT, 0, coords);
gl.glDrawArrays(GL2.GL_TRIANGLES, 0, 3);
//change the speeds here
xrot += 5f;
}
#Override
public void init(GLAutoDrawable drawable) {
final GL2 gl = drawable.getGL().getGL2();
gl.glShadeModel(GL2.GL_SMOOTH);
gl.glClearColor(0f, 0f, 0f, 0f);
gl.glClearDepth(1.0f);
gl.glEnable(GL2.GL_DEPTH_TEST);
gl.glDepthFunc(GL2.GL_LEQUAL);
gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST);
gl.glEnable(GL2.GL_TEXTURE_2D);
try {
File im = new File("/home/congard/pic/t.jpeg");
t = TextureIO.newTexture(im, true);
texture= t.getTextureObject(gl);
}catch(IOException e){
e.printStackTrace();
}
}
#Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
// some code
}
}
You didn't enable the client-side capabilities for vertex and texture coordinates. See Client-Side Vertex Arrays
and glEnableClientState.
Add the following to your code:
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
gl.glVertexPointer(3, GL2.GL_FLOAT, 0, verts);
gl.glTexCoordPointer(2, GL2.GL_FLOAT, 0, coords);
so I've been following a fair amount of tutorials on the internet and I tried to create my own graphics engine with OpenGL. The problem is that I can't make the texture work. I can render a square on the screen and change the color but I can't show a texture.
This is the Main Method:
public class Main implements Runnable{
public int HEIGHT = 400;
public int WIDTH = 400;
private boolean running;
private Thread thread;
private long window;
Level level;
public Main(){
}
public void start(){
running = true;
thread = new Thread(this, "Game");
thread.start();
}
public void stop(){
try {
thread.join();
running = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void init(){
if(glfwInit() != GL_TRUE){
System.err.println("Couldn't load the window");
return;
}
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
window = glfwCreateWindow(WIDTH, HEIGHT, "Game!!", NULL, NULL);
if(window == NULL){
System.err.println("Couldn't create the window");
return;
}
ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, (GLFWvidmode.width(vidmode) - WIDTH) / 2, (GLFWvidmode.height(vidmode) - HEIGHT) / 2);
glfwMakeContextCurrent(window);
glfwShowWindow(window);
GLContext.createFromCurrent();
Input input = new Input();
glfwSetKeyCallback(window, input);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
System.out.println("OpenGL: " + glGetString(GL_VERSION));
Shader.loadAll();
Matrix4f pr_matrix = Matrix4f.orthographic(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
Shader.BG.setUniformMat4f("pr_matrix", pr_matrix);
Shader.BG.setUniform1i("tex", 1);
level = new Level();
}
public void run() {
init();
long lastTime = System.nanoTime();
double delta = 0.0;
double ns = 1000000000.0 / 60.0;
long timer = System.currentTimeMillis();
int updates = 0;
int frames = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
if (delta >= 1.0) {
update();
updates++;
delta--;
}
render();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println(updates + " ups, " + frames + " fps");
updates = 0;
frames = 0;
}
if (glfwWindowShouldClose(window) == GL_TRUE)
running = false;
}
}
private void update(){
glfwPollEvents();
if(Input.isKeyDown(GLFW_KEY_ESCAPE)){
running = false;
}
}
private void render(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int error = glGetError();
if (error != GL_NO_ERROR)
System.out.println(error);
glfwSwapBuffers(window);
level.render();
}
public static void main(String arg[]){
new Main().start();
}
}
This is the Level Method:
public class Level {
private VertexArray background;
private Texture bgTexture;
public Level() {
float[] vertices = new float[] {
-0.5f, 0.5f, 0f,
-0.5f, -0.5f, 0f,
0.5f, -0.5f, 0f,
0.5f, 0.5f, 0f
};
byte[] indices = new byte[] { 0, 1, 3, 3, 1, 2 };
float[] tcs = new float[] {
0f, 0f,
0, 1.0f,
1.0f, 1.0f,
1.0f, 0
};
background = new VertexArray(vertices, indices, tcs);
bgTexture = new Texture("res/bird.png");
}
public void render() {
Shader.BG.enable();
bgTexture.bind();
background.bind();
background.draw();
bgTexture.unbind();
Shader.BG.disable();
}
Here the Texture Class:
public class Texture {
private int width, height;
private int texture;
public Texture(String path) {
texture = load(path);
}
private int load(String path) {
int[] pixels = null;
try {
BufferedImage image = ImageIO.read(new FileInputStream(path));
width = image.getWidth();
height = image.getHeight();
pixels = new int[width * height];
image.getRGB(0, 0, width, height, pixels, 0, width);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
int[] data = new int[width * height];
for (int i = 0; i < width * height; i++) {
int a = (pixels[i] & 0xff000000) >> 24;
int r = (pixels[i] & 0xff0000) >> 16;
int g = (pixels[i] & 0xff00) >> 8;
int b = (pixels[i] & 0xff);
data[i] = a << 24 | b << 16 | g << 8 | r;
}
int result = glGenTextures();
glBindTexture(GL_TEXTURE_2D, result);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, BufferUtils.createIntBuffer(data));
glBindTexture(GL_TEXTURE_2D, 0);
return result;
}
public void bind() {
glBindTexture(GL_TEXTURE_2D, texture);
}
public void unbind() {
glBindTexture(GL_TEXTURE_2D, 0);
}
}
Here the Vertex Class:
public class VertexArray {
private int vao, vbo, ibo, tbo;
private int count;
public VertexArray(int count) {
this.count = count;
vao = glGenVertexArrays();
}
public VertexArray(float[] vertices, byte[] indices, float[] textureCoordinates) {
count = indices.length;
vao = glGenVertexArrays();
glBindVertexArray(vao);
vbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(vertices), GL_STATIC_DRAW);
glVertexAttribPointer(Shader.VERTEX_ATTRIB, 3, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(Shader.VERTEX_ATTRIB);
tbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, tbo);
glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(textureCoordinates), GL_STATIC_DRAW);
glVertexAttribPointer(Shader.TCOORD_ATTRIB, 2, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(Shader.TCOORD_ATTRIB);
ibo = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, BufferUtils.createByteBuffer(indices), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
public void bind() {
glBindVertexArray(vao);
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
if (ibo > 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
}
public void unbind() {
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
if (ibo > 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
public void draw() {
if (ibo > 0)
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, 0);
else
glDrawArrays(GL_TRIANGLES, 0, count);
}
public void render() {
bind();
draw();
}
}
And here the Shaders:
Vertex:
#version 400 core
in vec4 position;
layout (location = 1) in vec2 tc;
uniform mat4 pr_matrix;
out vec2 tc_vr;
void main(void)
{
gl_Position = pr_matrix * position;
tc_vr = tc;
}
Fragment:
#version 400 core
out vec4 color;
in vec2 tc_vr;
uniform sampler2D tex;
void main(void)
{
color = texture(tex, tc_vr);
}
Thanks a lot for the help!
I am trying to write a basic Quad-renderer, using VBO, VAO, IBO and shaders.
I am trying to use mainly only one VBO, VAO, IBO and rebuffer the data when an element is added/removed.
Mostly everything worked fine, until I decided to implement textures, instead of color gradings.
It just doesn't draw anyhting, no matter what I try, because I want to avoid using deprecated functions like ClientStates and maybe use the textures inside the shaders.
Next to the problem, that nothing is being drawn, I have the problem that the Textures are saved inside the BRectangle class, and now I don't know, how to access them while using DrawElements.
And can I reuse my IBO, so I don't have to add the additional indices?
My current approach:
The Renderer, you can add a Rectangle atm and it will buffer the needed data.
public class ShaderRenderer {
public static final int POSITION_INDEX = 0; // index of vertex attribute "in_Position"
public static final int TEXTURE_INDEX = 1; // index of vertex attribute "in_Texture"
public static final int FLOAT_NUM_BYTES; // sizeof(float) in bytes
public static final int INT_NUM_BYTES; // sizeof(int) in bytes
public static final int VEC4_BYTES; // sizeof(vec4) in bytes
static {
FLOAT_NUM_BYTES = Float.SIZE / Byte.SIZE;
INT_NUM_BYTES = Integer.SIZE / Byte.SIZE;
VEC4_BYTES = 4 * FLOAT_NUM_BYTES;
}
private VAO vao = new VAO();
private VBO vbo = new VBO();
private IBO ibo = new IBO();
private int elements = 0;
public ShaderRenderer() {
try {
ShaderUtilities.compileShader("shaders/screen.vert", "shaders/screen.frag", POSITION_INDEX, TEXTURE_INDEX);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void add( BRectangle rect ) {
// Bind the VAO
// This OpenGL-object groups the "in_Position" and "in_Color"
// vertex attributes.
vao.bind();
// Bind the VBO and add the FloatBuffer from the Rect
vbo.bind();
vbo.addBuffer(rect.vertexData);
ibo.bind();
ibo.addIndices(generateIndices());
ibo.buffer();
//==============================================================
// Now we tell OpenGL that we will use POSITION_INDEX and COLOR_INDEX
// to communicate respectively the vertex positions and vertex colors
// to our shaders.
{
// First we enable the indices. This will affect the vertex
// array object from above.
glEnableVertexAttribArray(POSITION_INDEX);
Util.checkGLError();
// Then we tell OpenGL how it should read the GL_ARRAY_BUFFER
// (to which we have bound our vertex data, see above).
// The position data starts at the beginning of the vertex data
glVertexAttribPointer(POSITION_INDEX, 4, GL_FLOAT, false,
2 * VEC4_BYTES, 0);
Util.checkGLError();
// The color data starts after the first 4 floats of position data
glVertexAttribPointer(TEXTURE_INDEX, 2, GL_FLOAT, false,
0, VEC4_BYTES);
Util.checkGLError();
}
vbo.bufferData();
// Just to be VERY clean, we will unbind the vertex attribute object
// and only bind it when we render. This way we cannot accidentally modify
// it anymore.
vao.unbind();
// Only after the vertex array is disabled, we unbind the buffers
// to the GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER targets, because
// otherwise the vertex array object would become invalid again.
vbo.unbind();
ibo.unbind();
}
void DestroyVBO() {
glDisableVertexAttribArray(POSITION_INDEX);
Util.checkGLError();
glDisableVertexAttribArray(TEXTURE_INDEX);
Util.checkGLError();
glBindBuffer(GL_ARRAY_BUFFER, 0);
Util.checkGLError();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Util.checkGLError();
glDeleteBuffers(ibo.id);
Util.checkGLError();
glDeleteBuffers(vbo.id);
Util.checkGLError();
glBindVertexArray(0);
Util.checkGLError();
glDeleteVertexArrays(vao.id);
Util.checkGLError();
}
private int[] generateIndices() {
int c = elements * 3;
int v[] = { c, c+1, c+2,
c, c+3, c+2};
elements++;
return v;
}
public void render () {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Util.checkGLError();
vao.bind();
glDrawElements(
GL_TRIANGLES,
ibo.size,
GL_UNSIGNED_INT,
0);
Util.checkGLError();
vao.unbind();
}
}
My basic Rectangle class
public class BRectangle {
final int amountOfVertices = 8;
final int vertexSize = 3;
final int textureSize = 2;
public FloatBuffer vertexData;
Texture texture;
public BRectangle(float x, float y ) {
float[] VerticesArray = new float[]{
-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.1f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
-0.1f, 0.4f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.4f, 0.0f, 1.0f, 0.0f, 1.0f
};
vertexData = BufferUtils.createFloatBuffer(24);
vertexData.put(VerticesArray);
try {
texture = Textures.loadTexture("data/floor.jpg");
} catch (IOException e) {
e.printStackTrace();
}
glBindTexture(GL_TEXTURE_2D, texture.getTextureID());
}
}
The test with main[]
public class ShaderTest {
ShaderRenderer sr;
FpsCounter c;
public ShaderTest() {
}
public void create() throws LWJGLException, Exception {
new SimpleDisplay(800, 600, "test", false, false);
glOrtho(0, 800, 0, 600, 1, -1);
//Keyboard
Keyboard.create();
c = new FpsCounter();
Textures.setUpTextureLoader();
//Mouse
Mouse.setGrabbed(false);
Mouse.create();
sr = new ShaderRenderer();
//OpenGL
initGL();
}
public void destroy() {
Mouse.destroy();
Keyboard.destroy();
Display.destroy();
}
public void initGL() throws IOException {
ShaderUtilities.compileShader("shaders/screen.vert", "shaders/screen.frag", ShaderRenderer.POSITION_INDEX, ShaderRenderer.TEXTURE_INDEX);
sr.add(new BRectangle(0f, 0f));
}
public void processKeyboard() {
}
public void processMouse() {
}
public void render() throws LWJGLException {
sr.render();
}
public void run() throws LWJGLException {
while (!Display.isCloseRequested() && !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
if (Display.isVisible()) {
processKeyboard();
processMouse();
update();
render();
} else {
if (Display.isDirty()) {
render();
}
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
}
Display.update();
//Display.sync(60);
}
}
public void update() {
c.updateFPS();
}
public static void main(String[] args) {
ShaderTest main = null;
try {
main = new ShaderTest();
main.create();
main.run();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (main != null) {
main.destroy();
}
}
}
}
and the openglinit
public static void initGLSlim() {
glClearColor(0, 0, 0, 0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL11.GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 800, 600, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
vertex shader
#version 140
in vec4 in_Position;
in vec2 in_Texture;
out vec2 out_Texture;
void main(void)
{
gl_Position = vec4(in_Position.x *0.75 ,in_Position.y, in_Position.z, in_Position.w);
out_Texture = in_Texture;
}
fragment shader
#version 140
in vec2 out_Texture;
uniform sampler2D mytexture;
out vec4 fragColor;
void main(void)
{
fragColor = texture2D(mytexture, out_Texture);
}
Your stride parameters are not correct.
Here's what you have:
glVertexAttribPointer(POSITION_INDEX, 4, GL_FLOAT, false, 2 * VEC4_BYTES, 0);
glVertexAttribPointer(TEXTURE_INDEX, 2, GL_FLOAT, false, 0, VEC4_BYTES);
You're telling the position index that it has 8 float stride, which is not correct. As far as I can tell you're uploading 4 vertices, with 6 floats per vertex (4x position + 2x texture). That means your POSITION stride should be 6 * FLOAT_NUM_BYTES.
Your texture stride should be the same, as it's packed into the same array. Here you're telling it that the texcoords are tightly packed, but in reality theres only one pair of texcoords per 6 floats. So again you need 6 * FLOAT_NUM_BYTES here.
And can I reuse my IBO, so I don't have to add the additional indices?
Yes, you can use an IBO to draw as many objects as you want, provided that they all want the same indices.
Other less serious comments:
You don't need to clearColor to zero in initialization, it's zero by
default.
You don't need to disable depth_test/lighting in
initialization, they are off by default.
Don't call glEnable(GL_TEXTURE_2D) when you're using shaders. This
switch only enables texturing for the fixed pipeline, and it has no effect on shader programs. This will generate an error if you ever move to a core profile, so just get rid of it.
I have an application written in Java with JOGL that works fine on nvidia cards, but when I run it on an ati card, it works perfect until I add textures on 1 or more faces. Eventually, the java vm crashes hard, and it either says it is a crash in the ati driver thread or in the kernel system thread. I managed to recreate it in a simpler bit of code, but it takes a couple minutes to get the crash. up/ down rotates the image, return toggles the textures. keep doing that for a couple of minutes with an ati card and it will crash. I've tried it on about 10 or 15 machines.
package org.yourorghere;
import com.sun.opengl.util.Animator;
import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureIO;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
/**
* SimpleJOGL.java <BR>
* author: Brian Paul (converted to Java by Ron Cemer and Sven Goethel) <P>
*
* This version is equal to Brian Paul's version 1.2 1999/10/21
*/
public class SimpleJOGL implements GLEventListener, KeyListener {
GLCanvas canvas;
int lists;
float angle = 0.f;
boolean needsRotate = false;
boolean needsTexture = false;
Texture texture1;
Texture texture2;
Color c1 = Color.red;
Color c2 = Color.green;
public SimpleJOGL(GLCanvas canvas) {
this.canvas = canvas;
}
public static void main(String[] args) {
Frame frame = new Frame("Simple JOGL Application");
GLCanvas canvas = new GLCanvas();
SimpleJOGL sjogl = new SimpleJOGL(canvas);
canvas.addKeyListener(sjogl);
canvas.addGLEventListener(sjogl);
frame.add(canvas);
frame.setSize(640, 480);
final Animator animator = new Animator(canvas);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
// Run this on another thread than the AWT event queue to
// make sure the call to Animator.stop() completes before
// exiting
new Thread(new Runnable() {
public void run() {
animator.stop();
System.exit(0);
}
}).start();
}
});
// Center frame
frame.setLocationRelativeTo(null);
frame.setVisible(true);
animator.start();
}
public void init(GLAutoDrawable drawable) {
// Use debug pipeline
// drawable.setGL(new DebugGL(drawable.getGL()));
GL gl = drawable.getGL();
System.err.println("INIT GL IS: " + gl.getClass().getName());
// Enable VSync
gl.setSwapInterval(1);
// double buffer
gl.glEnable(GL.GL_DOUBLEBUFFER);
drawable.setAutoSwapBufferMode(false);
// Enable VSync
gl.setSwapInterval(1);
// Setup the drawing area and shading mode
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glShadeModel(GL.GL_SMOOTH); // try setting this to GL_FLAT and see what happens.
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glDisable(GL.GL_BLEND);
// -- lighting --
gl.glEnable(GL.GL_COLOR_MATERIAL);
gl.glLightModelf(GL.GL_LIGHT_MODEL_TWO_SIDE, 1.0f);
gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE);
gl.glEnable(GL.GL_MAP1_VERTEX_3);
gl.glHint(GL.GL_POLYGON_SMOOTH_HINT, GL.GL_NICEST);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, new float[]{.3f,.3f,.3f,1.f},0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, new float[]{.55f,.55f,.55f,1.f},0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, new float[]{.05f,.05f,.05f,1.f}, 0);
gl.glFrontFace(GL.GL_CCW);
gl.glEnable(GL.GL_LIGHT0);
gl.glEnable(GL.GL_LIGHTING);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE, new float[]{.5f,.5f,.5f,1.0f}, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR, new float[]{.05f, .05f, .05f, 1.0f}, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_EMISSION, new float[]{0.01f, 0.01f, 0.01f, 1.f}, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_SHININESS, new float[]{30}, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_COLOR_INDEXES, new float[]{1.0f, 0.0f, 0.0f, 1.0f}, 0);
gl.glCullFace(GL.GL_BACK);
gl.glDisable(GL.GL_BLEND);
gl.glEnable(GL.GL_RESCALE_NORMAL);
lists = gl.glGenLists(3);
this.needsRotate = true;
this.needsTexture = true;
}
private void reTexture(GL gl) {
BufferedImage image1 = makeImage(c1);
BufferedImage image2 = makeImage(c2);
makeShape(gl, image1, image2);
}
private BufferedImage makeImage(Color c) {
int y = 1200;
int x = 1024;
BufferedImage image = new BufferedImage(y, y, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
g.setBackground(Color.white);
g.clearRect(0, 0, y,y);
Rectangle2D r = new Rectangle2D.Float(128,128,x-256,x-256);
g.setColor(c);
g.fill(r);
g.dispose();
return image;
}
private void makeShape(GL gl, BufferedImage image1, BufferedImage image2) {
float x = 1024.f/1200.f;
texture1 = TextureIO.newTexture(image1, false) ;
texture2 = TextureIO.newTexture(image2, false) ;
gl.glNewList(lists+1, GL.GL_COMPILE);
gl.glColor3f(0f, .8f, .4f);
// Drawing Using Triangles
gl.glBegin(GL.GL_POLYGON);
gl.glTexCoord2f(0, 0);
gl.glVertex3f(0.0f, 0.0f, 0.0f); // Top
gl.glNormal3f(0, 0, 1);
gl.glTexCoord2f(x, 0);
gl.glVertex3f(1.0f, 0.0f, 0.0f); // Bottom Left
gl.glNormal3f(0, 0, 1);
gl.glTexCoord2f(x, x);
gl.glVertex3f(1.0f, 1.0f, 0.0f); // Bottom Right
gl.glNormal3f(0, 0, 1);
gl.glTexCoord2f(0, x);
gl.glVertex3f(0f, 1.0f, 0.0f); // Bottom Right
gl.glNormal3f(0, 0, 1);
gl.glEnd();
texture1.disable();
gl.glEndList();
gl.glNewList(lists+2, GL.GL_COMPILE);
texture2.enable();
texture2.bind();
gl.glBegin(GL.GL_POLYGON);
gl.glTexCoord2f(0, 0);
gl.glVertex3f(0.0f, 0.0f, 0.0f); // Top
gl.glNormal3f(0, 0, 1);
gl.glTexCoord2f(x, 0);
gl.glVertex3f(1.0f, 0.0f, 0.0f); // Bottom Left
gl.glNormal3f(0, 0, 1);
gl.glTexCoord2f(x, x);
gl.glVertex3f(1.0f, -1.0f, 0.0f); // Bottom Right
gl.glNormal3f(0, 0, 1);
gl.glTexCoord2f(0, x);
gl.glVertex3f(0f, -1.0f, 0.0f); // Bottom Right
gl.glNormal3f(0, 0, 1);
gl.glEnd();
texture2.disable();
gl.glEndList();
}
public void rotate(GL gl) {
gl.glNewList(lists, GL.GL_COMPILE);
gl.glLoadIdentity();
gl.glTranslatef(-2.f, 0.f, -6.f);
gl.glRotatef(angle, 1.0f, 0.f, 0.f);
gl.glCallList(lists+1);
gl.glRotatef(-45, 1.f, 0.f, 0.f);
gl.glCallList(lists+2);
gl.glEndList();
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
GL gl = drawable.getGL();
GLU glu = new GLU();
if (height <= 0) { // avoid a divide by zero error!
height = 1;
}
final float h = (float) width / (float) height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45.0f, h, 1.0, 20.0);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
}
public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
if (needsTexture) {
reTexture(gl);
needsTexture = false;
}
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, new float[]{1.f, 1.f, 1.f, 0.f}, 0);
gl.glLoadIdentity();
gl.glTranslatef(-2.f, 0.f, -6.f);
gl.glRotatef(angle, 1.0f, 0.f, 0.f);
texture1.enable();
texture1.bind();
gl.glCallList(lists+1);
texture1.disable();
gl.glRotatef(-45, 1.f, 0.f, 0.f);
gl.glCallList(lists+2);
// Flush all drawing operations to the graphics card
drawable.swapBuffers();
}
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
angle -= 5;
needsRotate = true;
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
angle += 5;
needsRotate = true;
}
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
Color c = c1;
c1 = c2;
c2 = c;
needsTexture = true;
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
canvas.repaint();
}
}
thank you!
You need to dispose of the textures when you have finished with them, e.g.
private void makeShape(GL gl, BufferedImage image1, BufferedImage image2) {
if (texture1 != null) {
texture1.dispose();
}
texture1 = TextureIO.newTexture(image1, false) ;
if (texture2 != null) {
texture2.dispose();
}
texture2 = TextureIO.newTexture(image2, false) ;
// ...
}
otherwise you will eventually run out of texture names.
Note: Texture does not have a finalizer.
I'm working on a 2D game in LWJGL. I have successfully rendered QUADS with textures using glBegin but moving to VBOs turned out to be a big undertaking. At the moment I can switch between the vbo and non-vbo rendering with a boolean, both using the same vertex- and texture coordinates. The VBO-implementation won't draw anything onto the screen. Can anyone point me in the right direction?
This is my initialization:
public void init() {
VBOID = VBOHandler.createVBOID();
TBOID = VBOHandler.createVBOID();
float[] vdata = {0, 0,
width, 0,
width, height,
0, height};
float[] tdata = {sx, sy,
ex, sy,
ex, ey,
sx, ey};
//Texture coordinates: (0,0)(1,0)(1,1) and (0,1)
FloatBuffer fb = BufferUtils.createFloatBuffer(8);
fb.put(vdata);
VBOHandler.bufferData(VBOID, fb);
fb = BufferUtils.createFloatBuffer(8);
fb.put(tdata);
VBOHandler.bufferData(TBOID, fb);
}
And here is my rendering code:
private void render() {
texture.bind();
if(vbo) {
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
VBOHandler.bindBuffer(VBOID);
GL11.glVertexPointer(2, GL11.GL_FLOAT, 0, 0);
VBOHandler.bindBuffer(TBOID);
GL11.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
VBOHandler.bindElementBuffer(VBOHandler.getDefaultIBOID());
// I figured why not use a standard IBO for all my sprite drawing
// The default IBO ID is initialized earlier in the program, not shown in this code
GL12.glDrawRangeElements(GL11.GL_TRIANGLE_FAN, 0, 3, 4, GL11.GL_UNSIGNED_SHORT, 0);
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
} else {
GL11.glBegin(GL11.GL_TRIANGLE_FAN);
GL11.glTexCoord2f(sx, sy);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(ex, sy);
GL11.glVertex2f(width,0);
GL11.glTexCoord2f(ex, ey);
GL11.glVertex2f(width, height);
GL11.glTexCoord2f(sx, ey);
GL11.glVertex2f(0, height);
GL11.glEnd();
}
}
And the VBOHandler class, for those interested
public class VBOHandler {
private static int IBOID;
public static void initDefaultIBO() {
IBOID = createVBOID();
short[] indexdata = {0, 1, 2, 3};
ShortBuffer shortBuffer = BufferUtils.createShortBuffer(4);
shortBuffer.put(indexdata);
VBOHandler.bufferElementData(IBOID, shortBuffer);
}
public static int getDefaultIBOID() {
return IBOID;
}
public static int createVBOID() {
if(GLContext.getCapabilities().GL_ARB_vertex_buffer_object) {
return ARBVertexBufferObject.glGenBuffersARB();
}
return 0;
}
public static void bufferData(int id, FloatBuffer buffer) {
if (GLContext.getCapabilities().GL_ARB_vertex_buffer_object) {
ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, id);
ARBVertexBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, buffer, ARBVertexBufferObject.GL_STATIC_DRAW_ARB);
}
}
public static void bufferElementData(int id, ShortBuffer buffer) {
if (GLContext.getCapabilities().GL_ARB_vertex_buffer_object) {
ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, id);
ARBVertexBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, buffer, ARBVertexBufferObject.GL_STATIC_DRAW_ARB);
}
}
public static void bindBuffer(int id) {
ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, id);
}
public static void bindElementBuffer(int id) {
ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, id);
}
}
The above render-function lies within my Sprite class. It is called by my GameView every frame as so:
public void renderGame() {
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glLoadIdentity();
sprite.render();
}
The GameView is initialized with the following code:
Display.setDisplayMode(new DisplayMode(1024, 768));
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GL11.glEnable(GL11.GL_BLEND); // enable alpha blending
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(x - width/2, x + width/2, y + height / 2, y - height / 2, -1, 1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
You did not call 'flip' on the FloatBuffers before passing them to OpenGL. You need to call 'flip()' on FloatBuffers before you pass them to OpenGL, or it will not be able to read them. It is worth noting that you cannot read the FloatBuffers after you call 'flip()' yourself.