GL and function calls

Started by aeonios, December 20, 2015, 19:21:37

Previous topic - Next topic

aeonios

I've been having weird issues with GL11 calls not working properly, and although some of that was due to lack of knowledge and incorrect implementation some of the issues I've been having cannot be written off as mere programmer error. For some reason GL11 calls do not work properly when moved into separate function calls, causing random things to break. Taking the exact same code and moving it into a shallower single-class test magically causes it to work.

I've also seen a more extreme form of this, where GL calls made from so many levels down in a program's call graph throw a "no GL context present in this thread" error, which cannot be fixed even by calling glfwMakeContextCurrent in the same function directly before the GL calls. I can verify that the program was running entirely single-threaded and that no GL context problems occurred for other parts of the program that were called from shallower in the call graph.

Is there some special reason why it should matter where in a program GL calls are made from? Considering that my goal was to encapsulate the raw GL into a more usable OO format these issues are a major hinderance, and trying to use raw lwjgl in a real project would be a serious hinderance to maintainability (and I don't feel like doing that when there's a significant chance that it still won't work for no good reason).

spasi

From your posts so far, it sounds like you're misunderstanding how OpenGL and/or LWJGL works. In any case, you won't get an interesting reply to this post, unless you include a code sample that reproduces the issue you're having.

aeonios

Ok, I have something simple that shows breakage.

Here's a simple single file test that shows a blank white texture in the bottom left corner of the window, the rest in green.

import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLUtil;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.system.libffi.Closure;

import java.nio.ByteBuffer;

import static org.lwjgl.BufferUtils.createByteBuffer;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;

/**
 * Created by haplo on 12/20/2015.
 */
public class LWJGLTextureTest {
    long windowID;
    private GLFWErrorCallback errorCallback;
    Closure debugProc;
    int texID;
    int texWidth;
    int texHeight;
    final long NULL = MemoryUtil.NULL;

    public LWJGLTextureTest(){
        // init
        if (glfwInit() != GLFW_TRUE) {
            throw new RuntimeException("GLFW failed to init!");
        }

        glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
        this.windowID = glfwCreateWindow(640, 480, "LWJGLTextureTest", NULL, NULL);
        glfwMakeContextCurrent(windowID);
        glfwSwapInterval(1);
        GL.createCapabilities();

        glfwSetErrorCallback(errorCallback = GLFWErrorCallback.createPrint(System.err));
        debugProc = GLUtil.setupDebugMessageCallback();

        initTexture();
    }

    private void initTexture(){
        texWidth = getPow2(640);
        texHeight = getPow2(480);

        byte[] rawData = new byte[texWidth * texHeight * 4]; // here 4 is a colormodel constant for RGBA

        for (int i = 0; i < rawData.length; i++){
            rawData[i] = -1;
        }
        ByteBuffer imgData = createByteBuffer(rawData.length).put(rawData);
        imgData.flip();

        glEnable(GL_TEXTURE_2D);
        texID = glGenTextures();
        glBindTexture(GL_TEXTURE_2D, texID);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgData);
        glDisable(GL_TEXTURE_2D);
    }

    public void run(){
        glClearColor(0, 1, 0, 1); // green

        while (glfwWindowShouldClose(windowID) == GLFW_FALSE) {
            // clear the window buffer and then draw the texture to it.
            glClear(GL_COLOR_BUFFER_BIT);
            drawTex();

            // update the window
            glfwSwapBuffers(windowID);
            glfwPollEvents();
        }

        // clean up
        glDeleteTextures(texID);
        glfwDestroyWindow(windowID);
    }

    private void drawTex(){
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, texID);

        // Set Projection
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glViewport(0, 0, 640, 480);
        glOrtho(0, 640, 0, 480, -1.0, 1.0);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        // draw at half scale to show the background clear color
        int swidth = 320;
        int sheight = 240;

        glBegin(GL_QUADS);
        glTexCoord2f(0, 0);
        glVertex3f(0, 0, 0);
        glTexCoord2f(0, texHeight);
        glVertex3f(0, sheight, 0);
        glTexCoord2f(texWidth, texHeight);
        glVertex3f(swidth, sheight, 0);
        glTexCoord2f(texWidth, 0);
        glVertex3f(swidth, 0, 0);
        glEnd();

        glDisable(GL_TEXTURE_2D);
    }

    private int getPow2(int fold) {
        int ret = 2;
        while (ret < fold) {
            ret *= 2;
        }
        return ret;
    }

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


alright that test wasn't valid because I forgot to set up the projection. I'll have to keep hacking until I get something to actually break.

spasi

The two class test is missing these lines:

// Set Projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, 640, 480);
glOrtho(0, 640, 0, 480, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

i.e. it's using the default projection matrix (the identity matrix).

Unrelated advice: You should call glfwSetErrorCallback before glfwInit. If glfwInit fails, the callback will be invoked and you'll know the reason.

aeonios

I noticed. :P And somehow it works perfectly for this test, but breaks when using my library that uses the same image class (ie draws nothing at all even after glClear proved that the windowbuffer was currently bound). I'm trying to figure out what it actually takes to reproduce this. :|

aeonios

Aaand the offending code was:

glEnable(GL_BLEND);
glColorMask(true, true, true, false);
glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);

which baffles me. :|

EDIT: on closer inspection this is 'blend under' (or some facimile thereof) which I was using erroneously in place of 'blend over/mode normal'. It was only drawing properly otherwise because I was using mode-add!

spasi

There's also a problem with your glTexCoord2f calls. Texture coordinates for GL_TEXTURE_2D are in the range 0.0...1.0f, not 0...texWidth/texHeight.

aeonios

I fixed that too. :D I didn't mention it since I had already figured out that texcoord was messed up.

Hydroque

glEnable(GL_BLEND);
glColorMask(true, true, true, false);
glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);


Should be...

glEnable(GL_BLEND);
glColorMask(true, true, true, false);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);