Hello Guest

[FIXED] Yet more VBO silent failure

  • 4 Replies
  • 10093 Views
[FIXED] Yet more VBO silent failure
« on: January 17, 2012, 22:05:32 »
I'm reasonably familar with vertex buffer objects. I've checked this over and over, rewritten it multiple times and can't find a thing wrong with it. Still, no output from glDrawElements.

Code: [Select]
package shaders0.shaders3;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.util.glu.GLU;

public final class Main implements Runnable
{
  private static final int  SCREEN_WIDTH  = 640;
  private static final int  SCREEN_HEIGHT = 480;

  private final FloatBuffer vertices;
  private final int         vertices_name;
  private int               indices_name;
  private ShortBuffer       indices;

  /**
   * Abort if an OpenGL error occurred.
   */

  private static void checkGL()
  {
    final int code = GL11.glGetError();
    if (code != 0) {
      final String x = GLU.gluErrorString(code);
      final String message = "OpenGL error (" + code + "): " + x;
      System.err.println(message);
      System.exit(1);
    }
  }

  public Main()
  {
    // Initialize a vertex buffer object with vertex data.
    {
      // Allocate buffer name.
      this.vertices_name = GL15.glGenBuffers();

      // Bind buffer name.
      GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.vertices_name);

      // Create and upload vertex data.
      final ByteBuffer vertices_bytes =
        ByteBuffer.allocateDirect(3 * 3 * 4).order(ByteOrder.nativeOrder());
      this.vertices = vertices_bytes.asFloatBuffer();
      this.vertices.put(new float[] { 0.0f, 0.0f, 0.0f });
      this.vertices.put(new float[] { 200.0f, 0.0f, 0.0f });
      this.vertices.put(new float[] { 200.0f, 200.0f, 0.0f });
      assert this.vertices.remaining() == 0;
      assert this.vertices.order() == ByteOrder.LITTLE_ENDIAN;

      GL15.glBufferData(
        GL15.GL_ARRAY_BUFFER,
        this.vertices,
        GL15.GL_STATIC_DRAW);

      // Unbind buffer name.
      GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
      Main.checkGL();
    }

    // Initialize an index buffer to reference the above vertices.
    {
      // Allocate buffer name.
      this.indices_name = GL15.glGenBuffers();

      // Bind buffer name.
      GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, this.indices_name);

      // Allocate and upload indices.
      final ByteBuffer indices_bytes =
        ByteBuffer.allocateDirect(3 * 2).order(ByteOrder.nativeOrder());
      this.indices = indices_bytes.asShortBuffer();
      this.indices.put(new short[] { 0, 1, 2 });
      assert this.indices.remaining() == 0;
      assert this.indices.order() == ByteOrder.LITTLE_ENDIAN;

      GL15.glBufferData(
        GL15.GL_ELEMENT_ARRAY_BUFFER,
        this.indices,
        GL15.GL_STATIC_DRAW);

      // Unbind buffer name.
      GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
      Main.checkGL();
    }
  }

  private static void setupCamera()
  {
    GL11.glViewport(0, 0, Main.SCREEN_WIDTH, Main.SCREEN_HEIGHT);
    GL11.glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);

    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glLoadIdentity();
    GL11.glOrtho(0, Main.SCREEN_WIDTH, 0, Main.SCREEN_HEIGHT, -1.0, 100.0);

    GL11.glMatrixMode(GL11.GL_MODELVIEW);
    GL11.glLoadIdentity();
  }

  private void draw()
  {
    // Draw a blue triangle that should be completely overwritten
    // by the triangle drawn by the VBO.

    GL11.glColor3d(0.0, 0.0, 1.0);
    GL11.glBegin(GL11.GL_TRIANGLES);
    {
      GL11.glVertex3f(0.0f, 0.0f, 0.0f);
      GL11.glVertex3f(200.0f, 0.0f, 0.0f);
      GL11.glVertex3f(200.0f, 200.0f, 0.0f);
    }
    GL11.glEnd();

    // Reset colour to white.
    GL11.glColor3d(1.0, 1.0, 1.0);

    // Bind vertex array and index buffer.
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.vertices_name);
    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, this.indices_name);

    // Enable vertex array.
    GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);

    // Tell GL where vertex data can be found.
    GL11.glVertexPointer(3, GL11.GL_FLOAT, 0, 0L);

    // Draw triangle.
    GL11.glDrawElements(GL11.GL_TRIANGLES, 3, GL11.GL_UNSIGNED_SHORT, 0L);

    // Disable vertex array.
    GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);

    // Unbind buffers.
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);

    Main.checkGL();
  }

  private void render()
  {
    Main.setupCamera();
    this.draw();
  }

  @Override public void run()
  {
    while (!Display.isCloseRequested()) {
      this.render();
      Display.update();
      Display.sync(60);
    }
    Display.destroy();
  }

  public static void main(
    final String args[])
  {
    try {
      Display.setDisplayMode(new DisplayMode(
        Main.SCREEN_WIDTH,
        Main.SCREEN_HEIGHT));
      Display.setTitle("shaders0");
      Display.create();
    } catch (final LWJGLException e) {
      e.printStackTrace();
      System.exit(0);
    }

    final Main m = new Main();
    m.run();
  }
}

Re: Yet more VBO silent failure
« Reply #1 on: January 18, 2012, 11:17:34 »
For future reference: buffers need rewinding before passing to OpenGL. I wish the lwjgl bindings had raised an error, as this would've saved an entire day.

Code: [Select]
      this.vertices.put(new float[] { 200.0f, 200.0f, 0.0f });
      assert this.vertices.remaining() == 0;
      assert this.vertices.order() == ByteOrder.LITTLE_ENDIAN;
      this.vertices.rewind();

Code: [Select]
      this.indices.put(new short[] { 0, 1, 2 });
      assert this.indices.remaining() == 0;
      assert this.indices.order() == ByteOrder.LITTLE_ENDIAN;
      this.indices.rewind();

*

Offline spasi

  • *****
  • 2261
    • WebHotelier
Re: Yet more VBO silent failure
« Reply #2 on: January 18, 2012, 12:21:27 »
The next nightly build will be checking all buffer object data parameters, to make sure that .remaining() is greater than zero.

Re: [FIXED] Yet more VBO silent failure
« Reply #3 on: January 18, 2012, 13:26:27 »
Nice. Thank you!

I recommend checking endianness, too (buffer.order() == ByteOrder.nativeOrder()). I've forgotten to set the byte order for buffers more than once (also manifests as silent failure on the OpenGL side).

*

Offline spasi

  • *****
  • 2261
    • WebHotelier
Re: [FIXED] Yet more VBO silent failure
« Reply #4 on: January 18, 2012, 14:00:15 »
The best way to avoid that is to always use the org.lwjgl.BufferUtils class to allocate buffers. Then you only have to be careful when .slice() is used, you need to set the order again on the resulting buffer.