com.badlogic.gdx.backends.lwjgl3.Lwjgl3WindowController.java Source code

Java tutorial

Introduction

Here is the source code for com.badlogic.gdx.backends.lwjgl3.Lwjgl3WindowController.java

Source

/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package com.badlogic.gdx.backends.lwjgl3;

import static org.lwjgl.glfw.GLFW.glfwInit;
import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
import static org.lwjgl.glfw.GLFW.glfwPostEmptyEvent;
import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback;
import static org.lwjgl.glfw.GLFW.glfwShowWindow;
import static org.lwjgl.glfw.GLFW.glfwTerminate;
import static org.lwjgl.glfw.GLFW.glfwWaitEvents;

import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.utils.Array;

/** <B>EXPERIMENTAL</B> <BR>
 * <BR>
 * A simple controller that updates and control all GLFW window/Gdx Application. <br>
 * 
 * @author Natan Guilherme */
public class Lwjgl3WindowController {

    Object SYNC = new Object();

    private Runnable windowRunnablesWait;
    private Runnable executedWindowRunnablesWait;

    private final Array<Runnable> mainRunnables = new Array();
    private final Array<Runnable> executedMainRunnables = new Array();
    private final Array<Runnable> windowRunnables = new Array();
    private final Array<Runnable> executedWindowRunnables = new Array();

    private GLFWErrorCallback errorCallback;
    static long currentWindow;

    Array<Lwjgl3Application> windows;
    Array<Lwjgl3Application> queueWindows;

    Runnable runnable;

    int targetFPS = 60;

    boolean running = true;
    boolean shareContext;
    Thread windowThread;
    Thread mainThread;

    boolean jumpLoop;

    /** Sharecontext is for texture sharing with multiple windows (1 Texture for all windows for example). <br>
     * <br>
     * 
     * If parent context is destroyed you will need to reload the texture because it will be black. <br>
     * You can change the parent context with {@link Lwjgl3WindowController#changeParentWindow(long)} */
    public Lwjgl3WindowController(boolean shareContext) {
        Lwjgl3NativesLoader.load();

        if (glfwInit() != GL11.GL_TRUE)
            throw new IllegalStateException("Unable to initialize GLFW");

        glfwSetErrorCallback(errorCallback = GLFWErrorCallback.createPrint(System.err));
        windows = new Array<Lwjgl3Application>();
        queueWindows = new Array<Lwjgl3Application>();

        this.shareContext = shareContext;

        runnable = new Runnable() {

            @Override
            public void run() {

                while (running) {

                    executeWindowRunnablesAndWait();
                    executeWindowRunnables();
                    if (jumpLoop)
                        continue;
                    for (int i = 0; i < windows.size; i++) {
                        final Lwjgl3Application app = windows.get(i);

                        if (app.running) {

                            if (app.init)
                                app.loop(true);
                        } else {
                            app.setGlobals();
                            app.disposeListener();
                            windows.removeIndex(i);
                            i--;

                            Runnable run = new Runnable() {

                                @Override
                                public void run() {
                                    app.dispose();
                                }
                            };
                            postMainRunnable(run);

                            glfwPostEmptyEvent();
                        }
                    }

                    if (targetFPS != 0) {
                        if (targetFPS == -1)
                            Lwjgl3Application.sleep(100);
                        else
                            Sync.sync(targetFPS);
                    }

                }
            }
        };

        windowThread = new Thread(runnable, "Lwjgl3WindowController");
    }

    boolean tmpfirst;

    /** Main Loop for GLFW. This call will block <br> */
    public void start() {
        mainThread = Thread.currentThread();
        windowThread.start();
        running = true;
        while (running) {
            executeMainRunnables();

            for (int i = 0; i < queueWindows.size;) {
                final Lwjgl3Application app = queueWindows.removeIndex(i);
                i--;

                Runnable run = new Runnable() {
                    @Override
                    public void run() {
                        glfwMakeContextCurrent(0);
                        jumpLoop = true;
                    }
                };
                postWindowRunnableAndWait(run);

                initWindow(app);
                glfwShowWindow(app.graphics.window);

                Runnable run2 = new Runnable() {
                    @Override
                    public void run() {
                        initContext(app);
                        windows.add(app);
                        tmpfirst = true;
                    }
                };
                postWindowRunnable(run2);
                jumpLoop = false;
                break;
            }

            if (tmpfirst && windows.size == 0) {
                running = false;
            }

            glfwWaitEvents();
        }
        try {
            windowThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        glfwTerminate();
        if (errorCallback != null)
            errorCallback.release();
    }

    void initWindow(Lwjgl3Application app) {

        app.graphics.initWindow();
        if (shareContext == true && Lwjgl3Graphics.contextShare == 0) {
            Lwjgl3Graphics.contextShare = app.graphics.window;
        }
        app.initStaticVariables();

        app.input.addCallBacks();
        app.addCallBacks();
        app.windowListener = listener;
    }

    void initContext(Lwjgl3Application app) {
        if (app.init == false) {

            glfwMakeContextCurrent(app.graphics.window);
            GL.createCapabilities();
            app.graphics.initGL();
            app.graphics.show();
            app.init = true;
        }
    }

    public void addWindow(String id, ApplicationListener listener, final Lwjgl3ApplicationConfiguration config) {
        addWindow(id, new Lwjgl3Application(listener, config, false));
    }

    public void addWindow(final String id, final Lwjgl3Application app) {
        if (!app.useController) // cannot have a running loop
            return;

        Thread thisThread = Thread.currentThread();

        if (thisThread == mainThread) {
            if (getWindow(id) == null) {
                app.id = id;
                queueWindows.add(app);
            }
        } else {
            Runnable run = new Runnable() {

                @Override
                public void run() {
                    if (getWindow(id) == null) {
                        app.id = id;
                        queueWindows.add(app);
                    }
                }
            };
            postMainRunnable(run);
        }
    }

    public boolean removeWindow(String id) {
        for (int i = 0; i < windows.size; i++) {
            Lwjgl3Application app = windows.get(i);
            if (app.id.equals(id)) {
                app.exit();
                return true;
            }
        }
        return false;
    }

    public Lwjgl3Application getWindow(String id) {
        for (int i = 0; i < windows.size; i++) {
            Lwjgl3Application app = windows.get(i);
            if (app.id.equals(id)) {
                return app;
            }
        }
        return null;
    }

    /** Set a new window to share its context. Default is 0. Only for new windows. */
    public void changeParentWindow(long firstWindow) {
        Lwjgl3Graphics.contextShare = firstWindow;
    }

    /** The last focus window so you can use GLFW calls to manipulate it. */
    public static long getCurrentWindow() {
        return currentWindow;
    }

    public void postMainRunnable(Runnable runnable) {
        synchronized (mainRunnables) {
            mainRunnables.add(runnable);
        }
    }

    public void postWindowRunnable(Runnable runnable) {
        synchronized (windowRunnables) {
            windowRunnables.add(runnable);
        }
    }

    public void postWindowRunnableAndWait(Runnable runnable) {
        synchronized (SYNC) {
            windowRunnablesWait = runnable;
        }

        while (windowRunnablesWait != null) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void executeMainRunnables() {
        synchronized (mainRunnables) {
            for (int i = mainRunnables.size - 1; i >= 0; i--)
                executedMainRunnables.addAll(mainRunnables.get(i));
            mainRunnables.clear();
        }

        if (executedMainRunnables.size == 0)
            return;
        for (int i = executedMainRunnables.size - 1; i >= 0; i--)
            executedMainRunnables.removeIndex(i).run();
    }

    void executeWindowRunnables() {
        synchronized (windowRunnables) {
            for (int i = windowRunnables.size - 1; i >= 0; i--)
                executedWindowRunnables.addAll(windowRunnables.get(i));
            windowRunnables.clear();
        }

        if (executedWindowRunnables.size == 0)
            return;
        for (int i = executedWindowRunnables.size - 1; i >= 0; i--)
            executedWindowRunnables.removeIndex(i).run();
    }

    void executeWindowRunnablesAndWait() {

        if (windowRunnablesWait == null)
            return;

        synchronized (SYNC) {
            executedWindowRunnablesWait = windowRunnablesWait;
        }
        executedWindowRunnablesWait.run();
        executedWindowRunnablesWait = null;
        windowRunnablesWait = null;
    }

    Lwjgl3WindowListener listener = new Lwjgl3WindowListener() {

        @Override
        public void size(Lwjgl3Application app, int width, int height) {
        }

        @Override
        public void refresh(final Lwjgl3Application app) {
        }

        @Override
        public void position(Lwjgl3Application app, int x, int y) {
        }

        @Override
        public void focus(Lwjgl3Application app, boolean focused) {
        }

        @Override
        public void exit(Lwjgl3Application app) {
        }
    };
}