LWJGL3-加载屏幕后,窗口显示为空白,为什么?

时间:2018-06-27 01:55:55

标签: java multithreading lwjgl glfw

我即将为程序实现一个加载屏幕,但是在完成加载屏幕并加载所有资源之后,主窗口出现了问题。

我正在为加载屏幕生成一个新线程,并从主线程为它提供了OpenGL上下文。在对LoadingScreen类进行编码时,我看了this示例。

import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWFramebufferSizeCallback;
import org.lwjgl.glfw.GLFWKeyCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;

import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.NULL;

public class LoadingScreen {
    private GLFWErrorCallback errorCallback;
    private GLFWKeyCallback keyCallback;
    private GLFWFramebufferSizeCallback fsCallback;

    private long window;
    private int width = 768;
    private int height = 384;
    private final Object lock = new Object();
    private boolean destroyed;

    public void stop() {
        synchronized (lock) {
            destroyed = true;
            glfwDestroyWindow(window);
            keyCallback.free();
            fsCallback.free();
            errorCallback.free();
        }
    }

    public void run() {
        init();
        winProcLoop();
    }

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

        // set window hints
        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
        glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);

        // create window and set event callbacks
        window = glfwCreateWindow(width, height, "Hello World!", NULL, NULL);
        if (window == NULL)
            throw new RuntimeException("Failed to create the GLFW window");

        glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
            public void invoke(long window, int key, int scancode, int action, int mods) {
                if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
                     glfwSetWindowShouldClose(window, true);
            }
         });
        glfwSetFramebufferSizeCallback(window, fsCallback = new GLFWFramebufferSizeCallback() {
            public void invoke(long window, int w, int h) {
                if (w > 0 && h > 0) {
                    width = w;
                    height = h;
                }
            }
        });

        // set window position and show
        GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
        glfwSetWindowPos(window, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);
        glfwShowWindow(window);
    }

    private void renderLoop() {
        // get OpenGLContext
        glfwMakeContextCurrent(window);
        // make OpenGL work
        GL.createCapabilities();

        glClearColor(0, 0, 0, 1);

        while (!destroyed) {
            // prepare rendering
            glClear(GL_COLOR_BUFFER_BIT);
            glViewport(0, 0, width, height);

            // renderer something

            synchronized (lock) {
                if (!destroyed) {
                    glfwSwapBuffers(window);
                }
             }
         }
     }

    private void winProcLoop() {
       /*
         * Start new thread to have the OpenGL context current in and which does
         * the rendering.
         */
         new Thread(this::renderLoop).start();
    }
}

Main类只是首先实例化并运行LoadingScreen,然后在实例化并运行Loader类之后再启动主窗口,该类正在加载程序的所有资源(纹理,objs等)。 比执行主循环还要渲染和更新显示。

import static org.lwjgl.glfw.GLFW.*;

public class Main {

    public static void main(String[] args) {

        // init loading screen
        System.out.println("starting loading screen");
        LoadingScreen loadingScreen = new LoadingScreen();
        loadingScreen.run();

        // init display
        System.out.println("initializing display...");
        DisplayManager displayManager = new DisplayManager(Configs.TITLE, Configs.WIDTH, Configs.HEIGHT, 8);

        // load resources
        Loader loader = Loader.load();
        RenderingEngine renderingEngine = new RenderingEngine(DisplayManager.getWidth(), DisplayManager.getHeight());

        System.out.println("stopping loading screen...");
        loadingScreen.stop();

        // only now after loading show the screen
        glfwShowWindow(displayManager.getWindow());

        System.out.println("starting main loop...");
        while (!glfwWindowShouldClose(displayManager.getWindow())) {
            // prepare in a nut shell
            GL11.glClearColor(1f, 1f, 1f, 1f);
            GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
            GL32.glProvokingVertex(GL32.GL_FIRST_VERTEX_CONVENTION);
            OpenGlUtils.cullBackFaces(true);
            OpenGlUtils.enableDepthTesting(true);
            OpenGlUtils.antialias(true);
            GL11.glHint(GL11.GL_POLYGON_SMOOTH_HINT, GL11.GL_NICEST);

            renderingEngine.render();
            displayManager.update();
        }

        renderingEngine.close();
        loader.cleanUp();
        displayManager.closeDisplay();
        System.out.println("done.");
    }

}

DisplayManager类非常简单,就像许多示例代码一样。

import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.NULL;

public class DisplayManager {
    private static int width;
    private static int height;
    private static long lastFrameTime;
    private static float delta;
    private long window;
    private String title;

    public DisplayManager(String title, int width, int height, int aa) {
        this.title = title;
        DisplayManager.width = width;
        DisplayManager.height = height;
        createDisplay(aa);
        lastFrameTime = getCurrentTime();
    }

    public void createDisplay(int aa) {
        // Setup an error callback. The default implementation
        // will print the error message in System.err.
        GLFWErrorCallback.createPrint(System.err).set();

        // Initialize GLFW. Most GLFW functions will not work before doing this.
        if (!glfwInit())
             throw new IllegalStateException("Unable to initialize GLFW");

        // Configure GLFW
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); 
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); 
        glfwWindowHint(GLFW_STENCIL_BITS, aa);
        glfwWindowHint(GLFW_SAMPLES, aa);
        // this is needed because glfw somehow remembers the hint of the loading screen window
        glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); 

        // Create the window
        window = glfwCreateWindow(width, height, title, 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, new KeyboardHandler());
        glfwSetMouseButtonCallback(window, new MouseHandler());
        glfwSetCursorPosCallback(window, new CursorHandler());
        glfwSetScrollCallback(window, new ScrollHandler());

        // Get the thread stack and push a new frame
        try (MemoryStack stack = stackPush()) {
            IntBuffer pWidth = stack.mallocInt(1); // int*
            IntBuffer pHeight = stack.mallocInt(1); // int*

             // Get the window size passed to glfwCreateWindow
            glfwGetWindowSize(window, pWidth, pHeight);

            // Get the resolution of the primary monitor
            GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());

            // Center the window
            assert vidmode != null;
            glfwSetWindowPos(
                    window,
                    (vidmode.width() - pWidth.get(0)) / 2,
                    (vidmode.height() - pHeight.get(0)) / 2
            );
         } // the stack frame is popped automatically

         // Make the OpenGL context current
         glfwMakeContextCurrent(window);
         // Enable v-sync
         glfwSwapInterval(1);

         // Make the window NOT visible
         // glfwShowWindow(window);

         // This line is critical for LWJGL's interoperation with GLFW's
         // OpenGL context, or any context that is managed externally.
         // LWJGL detects the context that is current in the current thread,
         // creates the GLCapabilities instance and makes the OpenGL
         // bindings available for use.
         GL.createCapabilities();
    }

    public void update() {
         glfwSwapBuffers(window); // swap the color buffers
         // Poll for window events. The key callback above will only be
         // invoked during this call.
         glfwPollEvents();

         long currentFrameTime = getCurrentTime();
         delta = (currentFrameTime - lastFrameTime) / 1e3f;
         lastFrameTime = currentFrameTime;
    }

     public void closeDisplay() {
         // Free the window callbacks and destroy the window
         glfwFreeCallbacks(window);
         glfwDestroyWindow(window);

         // Terminate GLFW and free the error callback
         glfwTerminate();
         Objects.requireNonNull(glfwSetErrorCallback(null)).free();
    }
}

预期的输出将是一个加载屏幕,加载完成后,加载屏幕将停止并显示主窗口。

正在发生什么,是我没有收到任何错误消息,加载屏幕显示正确,加载后主窗口也显示了,但是它完全空白(可能来自glClearColor(1、1、1、1, ))并没有呈现任何内容(物理程序正在打印正确的内容,所以我认为,render方法中没有任何内容。)

如果在窗口初始化后在DisplayManager类中设置glShowWindow(window),一切都会起作用。但这使窗口可见,而在加载过程中,我不希望看到该窗口。

感谢阅读,对此有何建议?

编辑
DisplayManager类实际上来自一个自写的OpenGL包装器,我将其导入为.jar。为了实现加载屏幕,我在该项目中创建了一个副本,该副本无法按所述方式工作。但是在包装器项目中调整DisplayManager并再次导入其.jar即可。我不知道为什么它现在能正常工作,它是完全相同的代码,但是来自工件。 由于这里没有任何答案,我只想提一下问题正在解决。嗯,这带来了一个新问题……

0 个答案:

没有答案