diff --git a/jme3-examples/src/main/java/jme3test/niftygui/TestIssue1013.java b/jme3-examples/src/main/java/jme3test/niftygui/TestIssue1013.java new file mode 100644 index 000000000..b40311f62 --- /dev/null +++ b/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); + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java index b8049a8f8..97580ee80 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java +++ b/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."); } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java index fea4ee7c1..8b1563bfb 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java +++ b/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; diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java index 74e442840..ab82bbc05 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -302,6 +302,11 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { showWindow(); allowSwapBuffers = settings.isSwapBuffers(); + + // Create OpenCL + if (settings.isOpenCLSupport()) { + initOpenCL(window); + } } protected void showWindow() { @@ -310,6 +315,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) { @@ -416,7 +423,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { window = NULL; } - glfwTerminate(); } catch (final Exception ex) { listener.handleError("Failed to destroy context", ex); } @@ -436,6 +442,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 { @@ -462,13 +470,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) { @@ -493,14 +494,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()) { @@ -556,6 +550,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; @@ -569,6 +582,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { destroyContext(); super.internalDestroy(); + glfwTerminate(); LOGGER.fine("Display destroyed."); }