Explorar o código

Lwjgl3 restart input handle (#1268)

* Reinit inputs on context restart

* Added test issue from issue #1013

* Verify that the inputs are already initialized
Toni Helenius %!s(int64=5) %!d(string=hai) anos
pai
achega
1198908555

+ 127 - 0
jme3-examples/src/main/java/jme3test/niftygui/TestIssue1013.java

@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2009-2020 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.niftygui;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.niftygui.NiftyJmeDisplay;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+import de.lessvoid.nifty.Nifty;
+import de.lessvoid.nifty.builder.LayerBuilder;
+import de.lessvoid.nifty.builder.PanelBuilder;
+import de.lessvoid.nifty.builder.ScreenBuilder;
+import de.lessvoid.nifty.controls.button.builder.ButtonBuilder;
+import de.lessvoid.nifty.screen.Screen;
+import de.lessvoid.nifty.screen.ScreenController;
+
+public class TestIssue1013 extends SimpleApplication implements ScreenController {
+
+    public static void main(String[] args) {
+        new TestIssue1013().start();
+    }
+
+    private NiftyJmeDisplay niftyDisplay;
+
+    @Override
+    public void simpleInitApp() {
+
+        // this box here always renders
+        Box b = new Box(1, 1, 1);
+        Geometry geom = new Geometry("Box", b);
+        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+        mat.setTexture("ColorMap", assetManager.loadTexture("/com/jme3/app/Monkey.png"));
+        geom.setMaterial(mat);
+        rootNode.attachChild(geom);
+
+        niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);
+
+        Nifty nifty = niftyDisplay.getNifty();
+        nifty.loadStyleFile("nifty-default-styles.xml");
+        nifty.loadControlFile("nifty-default-controls.xml");
+
+        ScreenController ctrl = this;
+
+        new ScreenBuilder("start") {
+            {
+                controller(ctrl);
+                layer(new LayerBuilder() {
+                    {
+                        childLayoutVertical();
+                        panel(new PanelBuilder() {
+                            {
+                                childLayoutCenter();
+                                width("100%");
+                                height("50%");
+                                backgroundColor("#ff0000");
+                            }
+                        });
+                        control(new ButtonBuilder("RestartButton", "Restart Context") {
+                            {
+                                alignCenter();
+                                valignCenter();
+                                height("32px");
+                                width("480px");
+                                interactOnClick("restartContext()");
+                            }
+                        });
+                    }
+                });
+            }
+        }.build(nifty);
+
+        guiViewPort.addProcessor(niftyDisplay);
+        nifty.gotoScreen("start");
+
+        flyCam.setDragToRotate(true);
+    }
+
+    @Override
+    public void bind(Nifty nifty, Screen screen) {
+    }
+
+    @Override
+    public void onStartScreen() {
+    }
+
+    @Override
+    public void onEndScreen() {
+    }
+
+    public void restartContext() {
+        // even without changing settings, stuff breaks!
+        restart();
+        // ...and re-adding the processor doesn't help at all
+        guiViewPort.addProcessor(niftyDisplay);
+    }
+
+}

+ 23 - 5
jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java

@@ -83,11 +83,33 @@ public class GlfwKeyInput implements KeyInput {
 
     @Override
     public void initialize() {
+        if (!context.isRenderable()) {
+            return;
+        }
+        initCallbacks();
+
+        initialized = true;
+        logger.fine("Keyboard created.");
+    }
 
+    /**
+     * Re-initializes the key input context window specific callbacks
+     */
+    public void resetContext() {
         if (!context.isRenderable()) {
             return;
         }
 
+        closeCallbacks();
+        initCallbacks();
+    }
+
+    private void closeCallbacks() {
+        keyCallback.close();
+        charCallback.close();
+    }
+
+    private void initCallbacks() {
         glfwSetKeyCallback(context.getWindowHandle(), keyCallback = new GLFWKeyCallback() {
             @Override
             public void invoke(final long window, final int key, final int scancode, final int action, final int mods) {
@@ -122,9 +144,6 @@ public class GlfwKeyInput implements KeyInput {
                 keyInputEvents.add(released);
             }
         });
-
-        initialized = true;
-        logger.fine("Keyboard created.");
     }
 
     public int getKeyCount() {
@@ -149,8 +168,7 @@ public class GlfwKeyInput implements KeyInput {
             return;
         }
 
-        keyCallback.close();
-        charCallback.close();
+        closeCallbacks();
         logger.fine("Keyboard destroyed.");
     }
 

+ 30 - 11
jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java

@@ -176,7 +176,30 @@ public class GlfwMouseInput implements MouseInput {
 
     @Override
     public void initialize() {
+        initCallbacks();
 
+        if (listener != null) {
+            sendFirstMouseEvent();
+        }
+
+        setCursorVisible(cursorVisible);
+        logger.fine("Mouse created.");
+        initialized = true;
+    }
+
+    /**
+     * Re-initializes the mouse input context window specific callbacks
+     */
+    public void resetContext() {
+        if (!context.isRenderable()) {
+            return;
+        }
+
+        closeCallbacks();
+        initCallbacks();
+    }
+
+    private void initCallbacks() {
         final long window = context.getWindowHandle();
 
         try (MemoryStack stack = MemoryStack.stackPush()) {
@@ -219,14 +242,6 @@ public class GlfwMouseInput implements MouseInput {
                 currentWidth = width;
             }
         });
-
-        if(listener != null) {
-            sendFirstMouseEvent();
-        }
-
-        setCursorVisible(cursorVisible);
-        logger.fine("Mouse created.");
-        initialized = true;
     }
 
     private void initCurrentMousePosition(long window) {
@@ -295,9 +310,7 @@ public class GlfwMouseInput implements MouseInput {
             return;
         }
 
-        cursorPosCallback.close();
-        scrollCallback.close();
-        mouseButtonCallback.close();
+        closeCallbacks();
 
         currentCursor = null;
         currentCursorDelays = null;
@@ -313,6 +326,12 @@ public class GlfwMouseInput implements MouseInput {
         logger.fine("Mouse destroyed.");
     }
 
+    private void closeCallbacks() {
+        cursorPosCallback.close();
+        scrollCallback.close();
+        mouseButtonCallback.close();
+    }
+
     @Override
     public void setCursorVisible(boolean visible) {
         cursorVisible = visible;

+ 30 - 16
jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java

@@ -295,6 +295,11 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
         showWindow();
 
         allowSwapBuffers = settings.isSwapBuffers();
+
+        // Create OpenCL
+        if (settings.isOpenCLSupport()) {
+            initOpenCL(window);
+        }
     }
 
     protected void showWindow() {
@@ -303,6 +308,8 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
 
     /**
      * Set custom icons to the window of this application.
+     *
+     * @param settings settings for getting the icons
      */
     protected void setWindowIcon(final AppSettings settings) {
 
@@ -409,7 +416,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
                 window = NULL;
             }
 
-            glfwTerminate();
         } catch (final Exception ex) {
             listener.handleError("Failed to destroy context", ex);
         }
@@ -429,6 +435,8 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
 
     /**
      * Does LWJGL display initialization in the OpenGL thread
+     *
+     * @return returns {@code true} if the context initialization was successful
      */
     protected boolean initInThread() {
         try {
@@ -455,13 +463,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
 
             created.set(true);
             super.internalCreate();
-
-            //create OpenCL
-            //Must be done here because the window handle is needed
-            if (settings.isOpenCLSupport()) {
-                initOpenCL(window);
-            }
-
         } catch (Exception ex) {
             try {
                 if (window != NULL) {
@@ -486,14 +487,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
     protected void runLoop() {
         // If a restart is required, lets recreate the context.
         if (needRestart.getAndSet(false)) {
-            try {
-                destroyContext();
-                createContext(settings);
-            } catch (Exception ex) {
-                LOGGER.log(Level.SEVERE, "Failed to set display settings!", ex);
-            }
-
-            LOGGER.fine("Display restarted.");
+            restartContext();
         }
 
         if (!created.get()) {
@@ -549,6 +543,25 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
         glfwPollEvents();
     }
 
+    private void restartContext() {
+        try {
+            destroyContext();
+            createContext(settings);
+        } catch (Exception ex) {
+            LOGGER.log(Level.SEVERE, "Failed to set display settings!", ex);
+        }
+
+        // We need to reinit the mouse and keyboard input as they are tied to a window handle
+        if (keyInput != null && keyInput.isInitialized()) {
+            keyInput.resetContext();
+        }
+        if (mouseInput != null && mouseInput.isInitialized()) {
+            mouseInput.resetContext();
+        }
+
+        LOGGER.fine("Display restarted.");
+    }
+
     private void setFrameRateLimit(int frameRateLimit) {
         this.frameRateLimit = frameRateLimit;
         frameSleepTime = 1000.0 / this.frameRateLimit;
@@ -562,6 +575,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
 
         destroyContext();
         super.internalDestroy();
+        glfwTerminate();
 
         LOGGER.fine("Display destroyed.");
     }