Lwjgl3: Getting started example throws error

Created on 14 Jan 2018  路  3Comments  路  Source: LWJGL/lwjgl3

Environment

  • LWJGL version: 3.1.5
  • LWJGL build #: 1
  • Java version: 1.8
  • Platform: macOS
  • Module: not sure

Description

I'm following this LWJGL Getting started guide which is supposed to show a window, but I'm getting this error which suggests running on the main thread and initialising AWT or JavaFX prior.
How does one do that?

I have set -XstartOnFirstThread in VM options. I'm on MacOS 10.13.2

I started the project by selecting a new Gradle project in IDEA, and then I used the LWJGL Gradle generator to generate build.gradle.

I followed the IDEA steps in the installation guide but I didn't understand what they meant by (I don't think it's too relevant to my error):

If you want to match the Maven/Gradle behavior exactly, you could create 2 separate libraries:
One with the class+source .jar files, make it a compile dependency of your module(s).
One with the natives .jar files, make it a runtime dependency of your module(s).
You can do this in the Project Structure > Modules > select a module > Dependencies tab, by changing the Scope of each dependency.

The error on gradle run:

Exception in thread "main" java.lang.ExceptionInInitializerError
at org.lwjgl.glfw.GLFW.glfwCreateWindow(GLFW.java:1694)
at com.javagame.kasha.HelloWorld.init(HelloWorld.java:51)
at com.javagame.kasha.HelloWorld.run(HelloWorld.java:24)
at com.javagame.kasha.HelloWorld.main(HelloWorld.java:114)
Caused by: java.lang.IllegalStateException: GLFW windows may only be created on the main thread and that thread must be the first thread in the process. Please run the JVM with -XstartOnFirstThread. For offscreen rendering, make sure another window toolkit (e.g. AWT or JavaFX) is initialized before GLFW.
at org.lwjgl.glfw.EventLoop$OffScreen.<clinit>(EventLoop.java:39)
... 4 more
:run FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':run'.
> Process 'command   '/Library/Java/JavaVirtualMachines/jdk1.8.0_141.jdk/Contents/Home/bin/java''   finished with non-zero exit value 1

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED in 0s

HelloWorld.java (copied from the guide, I added a package so I can start it with the Gradle application plugin):

package com.javagame.kasha;

import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.*;

import java.nio.*;

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

public class HelloWorld {

// The window handle
private long window;

public void run() {
    System.out.println("Hello LWJGL " + Version.getVersion() + "!");

    init();
    loop();

    // Free the window callbacks and destroy the window
    glfwFreeCallbacks(window);
    glfwDestroyWindow(window);

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

private void init() {
    // 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
    glfwDefaultWindowHints(); // optional, the current window hints are already the default
    glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
    glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable

    // 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, (window, key, scancode, action, mods) -> {
        if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
            glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
    });

    // 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
        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 visible
    glfwShowWindow(window);
}

private void loop() {
    // 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();

    // Set the clear color
    glClearColor(1.0f, 0.0f, 0.0f, 0.0f);

    // Run the rendering loop until the user has attempted to close
    // the window or has pressed the ESCAPE key.
    while ( !glfwWindowShouldClose(window) ) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer

        glfwSwapBuffers(window); // swap the color buffers

        // Poll for window events. The key callback above will only be
        // invoked during this call.
        glfwPollEvents();
    }
}

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

}

build.gradle:

group 'javagame'
version '1.0-SNAPSHOT'


import org.gradle.internal.os.OperatingSystem

switch ( OperatingSystem.current() ) {
    case OperatingSystem.WINDOWS:
        project.ext.lwjglNatives = "natives-windows"
        break
    case OperatingSystem.LINUX:
        project.ext.lwjglNatives = "natives-linux"
        break
    case OperatingSystem.MAC_OS:
        project.ext.lwjglNatives = "natives-macos"
        break
}


apply plugin: 'java'
apply plugin: 'application'

sourceCompatibility = 1.8
project.ext.lwjglVersion = "3.1.5"

repositories {
    mavenCentral()
}

mainClassName = "com.javagame.kasha.HelloWorld"

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
    compile "org.lwjgl:lwjgl:$lwjglVersion"
    compile "org.lwjgl:lwjgl-assimp:$lwjglVersion"
    compile "org.lwjgl:lwjgl-glfw:$lwjglVersion"
    compile "org.lwjgl:lwjgl-openal:$lwjglVersion"
    compile "org.lwjgl:lwjgl-opengl:$lwjglVersion"
    compile "org.lwjgl:lwjgl-stb:$lwjglVersion"
    compile "org.lwjgl:lwjgl:$lwjglVersion:$lwjglNatives"
    compile "org.lwjgl:lwjgl-assimp:$lwjglVersion:$lwjglNatives"
    compile "org.lwjgl:lwjgl-glfw:$lwjglVersion:$lwjglNatives"
    compile "org.lwjgl:lwjgl-openal:$lwjglVersion:$lwjglNatives"
    compile "org.lwjgl:lwjgl-opengl:$lwjglVersion:$lwjglNatives"
    compile "org.lwjgl:lwjgl-stb:$lwjglVersion:$lwjglNatives"
}

enter image description here

Question

Most helpful comment

You set the -XstartOnFirstThread property in IntelliJ but Gradle is not tied to the IDE an therefor does not know about it.

You can set the property in Gradle by adding the following line to your build script:
applicationDefaultJvmArgs = ["-XstartOnFirstThread"]

Gradle is a bit messy to get into but you can find the documentation of the application plugin here if you feel like it.

EDIT: I guess I was a bit late.

All 3 comments

It was a problem related to my configuration of Gradle and the application plugin. The solution is to put the arguments in the build.grade directly, instead of run configuration:

applicationDefaultJvmArgs = ["-XstartOnFirstThread"]

You set the -XstartOnFirstThread property in IntelliJ but Gradle is not tied to the IDE an therefor does not know about it.

You can set the property in Gradle by adding the following line to your build script:
applicationDefaultJvmArgs = ["-XstartOnFirstThread"]

Gradle is a bit messy to get into but you can find the documentation of the application plugin here if you feel like it.

EDIT: I guess I was a bit late.

@SauliusTheBlack That's a different error. You are mixing OSGI and "normal" dependencies (which might be fine, not really sure) but also different versions of LWJGL. The latter is the source of your problem.

If you are using OSGI on purpose use:

compile group: 'org.lwjgl.osgi', name: 'org.lwjgl.lwjgl', version: '3.2.1.1'
compile group: 'org.lwjgl.osgi', name: 'org.lwjgl.opengl', version: '3.2.1.1'
compile group: 'org.lwjgl.osgi', name: 'org.lwjgl.glfw', version: '3.2.1.1'

Otherwise use:

compile group: 'org.lwjgl', name: 'lwjgl', version: '3.2.2'
compile group: 'org.lwjgl', name: 'lwjgl-opengl', version: '3.2.2'
compile group: 'org.lwjgl', name: 'lwjgl-glfw', version: '3.2.2'

(OSGI artifacts for 3.2.2 are apparently not available.)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SpinyOwl picture SpinyOwl  路  3Comments

ChrisTrenkamp picture ChrisTrenkamp  路  6Comments

Marcono1234 picture Marcono1234  路  3Comments

EmpsThomy picture EmpsThomy  路  3Comments

dustContributor picture dustContributor  路  8Comments