Skip to main content
2 of 2
Added minimal not working example
piegames
  • 297
  • 1
  • 9

LWJGL/OpenGL render textured quad

So this should be easy and simple, but I still can't get it to work. All I need is a small example program that:

  • Takes in a BufferedImage (TYPE_INT_ARGB)
  • Renders that BufferedImage on a textured quad
  • Using a VBO
  • Without additional shader declaration
  • Using LWJGL3

Here's what I have got so far:

package togos.minecraft.maprend.guistandalone;

import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.system.MemoryUtil.NULL;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWKeyCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.glfw.GLFWWindowSizeCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLUtil;
import org.lwjgl.system.Callback;

public class GuiMain2 {

    // We need to strongly reference callback instances.
    private GLFWErrorCallback       errorCallback;
    private GLFWKeyCallback         keyCallback;
    private GLFWWindowSizeCallback  wsCallback;
    private Callback                debugProc;

    // The window handle
    private long                    window;
    private int                     width, height;

    public void run() {
        try {
            init();
            loop();

            // Release window and window callbacks
            glfwDestroyWindow(window);
            keyCallback.free();
            wsCallback.free();
            if (debugProc != null)
                debugProc.free();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            glfwTerminate();
            errorCallback.free();
        }
    }

    private void init() {
        glfwSetErrorCallback(errorCallback = GLFWErrorCallback.createPrint(System.err));
        if (!glfwInit())
            throw new IllegalStateException("Unable to initialize GLFW");

        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);

        // Create the window
        window = glfwCreateWindow(300, 300, "Hello World!", NULL, NULL);
        if (window == NULL)
            throw new RuntimeException("Failed to create the GLFW window");

        // Setup a key callback. It will be called every time a key is pressed, repeated or released.
        glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {

            @Override
            public void invoke(long window, int key, int scancode, int action, int mods) {
                if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
                    glfwSetWindowShouldClose(window, true); // We will detect this in our rendering loop
            }
        });
        glfwSetWindowSizeCallback(window, wsCallback = new GLFWWindowSizeCallback() {

            @Override
            public void invoke(long window, int w, int h) {
                if (w > 0 && h > 0) {
                    width = w;
                    height = h;
                }
            }
        });

        GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
        glfwSetWindowPos(window, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);
        glfwMakeContextCurrent(window);
        glfwShowWindow(window);
    }

    private void loop() throws IOException {
        GL.createCapabilities();
        debugProc = GLUtil.setupDebugMessageCallback();

        glEnable(GL_TEXTURE_2D);
        glEnable(GL_COLOR_MATERIAL);
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

        float[] vertices = {
                -0.5f, -0.5f, 0, 0,
                0.5f, -0.5f, 1, 0,
                0.5f, 0.5f, 1, 1,
                -0.5f, 0.5f, 0, 1 };
        int vbo = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, (FloatBuffer) BufferUtils.createFloatBuffer(vertices.length).put(vertices).flip(), GL_STATIC_DRAW);

        int id = genTexture();
        while (!glfwWindowShouldClose(window)) {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glViewport(0, 0, width, height);
            glMatrixMode(GL_PROJECTION);
            float aspect = (float) width / height;
            glLoadIdentity();
            glOrtho(-aspect, aspect, -1, 1, -1, 1);

            {// Rendering
                glBindTexture(GL_TEXTURE_2D, id);
                glVertexPointer(2, GL_FLOAT, 4 * 4, 0L);
                glTexCoordPointer(2, GL_FLOAT, 4 * 4, 4 * 2);
                glDrawArrays(GL_QUADS, 0, 4);
            }

            glfwSwapBuffers(window);
            glfwPollEvents();
        }
    }

    public int genTexture() {
        int id = glGenTextures();
        glBindTexture(GL_TEXTURE_2D, id);
        ByteBuffer pixels = BufferUtils.createByteBuffer(512 * 512 * 4);

        for (int y = 0; y < 512; y++) {
            for (int x = 0; x < 512; x++) {
                pixels.put((byte) 255);
                pixels.put((byte) 0);
                pixels.put((byte) 0);
                pixels.put((byte) 255);
            }
        }
        pixels.flip();

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
        return id;
    }

    public static void main(String[] args) {
        new GuiMain2().run();
    }
}

When starting, it displays a white quad in the center of the screen. If textures were working, that quad would be red. And I can't get textures to work.

piegames
  • 297
  • 1
  • 9