我即将为程序实现一个加载屏幕,但是在完成加载屏幕并加载所有资源之后,主窗口出现了问题。
我正在为加载屏幕生成一个新线程,并从主线程为它提供了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即可。我不知道为什么它现在能正常工作,它是完全相同的代码,但是来自工件。
由于这里没有任何答案,我只想提一下问题正在解决。嗯,这带来了一个新问题……