-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Lwjgl3 restart input handle #1268
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -176,7 +176,30 @@ private void onMouseButton(final long window, final int button, final int action | |
|
|
||
| @Override | ||
| public void initialize() { | ||
| initCallbacks(); | ||
|
|
||
| if (listener != null) { | ||
| sendFirstMouseEvent(); | ||
| } | ||
|
|
||
| setCursorVisible(cursorVisible); | ||
| logger.fine("Mouse created."); | ||
| initialized = true; | ||
|
Comment on lines
+181
to
+187
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't needed when restarting? What about sendFirstMouseEvent?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this all just mimics LWJGL 2. It doesn't seem to send either after restart. |
||
| } | ||
|
|
||
| /** | ||
| * 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 void invoke(final long window, final int width, final int height) { | |
| currentWidth = width; | ||
| } | ||
| }); | ||
|
|
||
| if(listener != null) { | ||
| sendFirstMouseEvent(); | ||
| } | ||
|
|
||
| setCursorVisible(cursorVisible); | ||
| logger.fine("Mouse created."); | ||
| initialized = true; | ||
| } | ||
|
|
||
| private void initCurrentMousePosition(long window) { | ||
|
|
@@ -295,9 +310,7 @@ public void destroy() { | |
| return; | ||
| } | ||
|
|
||
| cursorPosCallback.close(); | ||
| scrollCallback.close(); | ||
| mouseButtonCallback.close(); | ||
| closeCallbacks(); | ||
|
|
||
| currentCursor = null; | ||
| currentCursorDelays = null; | ||
|
|
@@ -313,6 +326,12 @@ public void destroy() { | |
| logger.fine("Mouse destroyed."); | ||
| } | ||
|
|
||
| private void closeCallbacks() { | ||
| cursorPosCallback.close(); | ||
| scrollCallback.close(); | ||
| mouseButtonCallback.close(); | ||
| } | ||
|
|
||
| @Override | ||
| public void setCursorVisible(boolean visible) { | ||
| cursorVisible = visible; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -145,6 +145,7 @@ public LwjglWindow(final JmeContext.Type type) { | |
| /** | ||
| * @return Type.Display or Type.Canvas | ||
| */ | ||
| @Override | ||
| public JmeContext.Type getType() { | ||
| return type; | ||
| } | ||
|
|
@@ -154,6 +155,7 @@ public JmeContext.Type getType() { | |
| * | ||
| * @param title the title to set | ||
| */ | ||
| @Override | ||
| public void setTitle(final String title) { | ||
| if (created.get() && window != NULL) { | ||
| glfwSetWindowTitle(window, title); | ||
|
|
@@ -163,6 +165,7 @@ public void setTitle(final String title) { | |
| /** | ||
| * Restart if it's a windowed or full-screen display. | ||
| */ | ||
| @Override | ||
| public void restart() { | ||
| if (created.get()) { | ||
| needRestart.set(true); | ||
|
|
@@ -295,6 +298,11 @@ public void invoke(final long window, final boolean focus) { | |
| showWindow(); | ||
|
|
||
| allowSwapBuffers = settings.isSwapBuffers(); | ||
|
|
||
| // Create OpenCL | ||
| if (settings.isOpenCLSupport()) { | ||
| initOpenCL(window); | ||
| } | ||
|
Comment on lines
+301
to
+305
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any specific reason why this should now only happen when restarting and not as part of the general init process? Wouldn't this prevent openCL init when regularly starting?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is part of the general init process. This is called in createContext which in turn is used by the restart and the initial context. |
||
| } | ||
|
|
||
| protected void showWindow() { | ||
|
|
@@ -303,6 +311,8 @@ protected void showWindow() { | |
|
|
||
| /** | ||
| * Set custom icons to the window of this application. | ||
| * | ||
| * @param settings settings for getting the icons | ||
| */ | ||
| protected void setWindowIcon(final AppSettings settings) { | ||
|
|
||
|
|
@@ -409,7 +419,6 @@ protected void destroyContext() { | |
| window = NULL; | ||
| } | ||
|
|
||
| glfwTerminate(); | ||
| } catch (final Exception ex) { | ||
| listener.handleError("Failed to destroy context", ex); | ||
| } | ||
|
|
@@ -429,6 +438,8 @@ public void create(boolean waitFor) { | |
|
|
||
| /** | ||
| * Does LWJGL display initialization in the OpenGL thread | ||
| * | ||
| * @return returns {@code true} if the context initialization was successful | ||
| */ | ||
| protected boolean initInThread() { | ||
| try { | ||
|
|
@@ -455,13 +466,6 @@ protected boolean initInThread() { | |
|
|
||
| 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 +490,7 @@ protected boolean initInThread() { | |
| 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 +546,25 @@ protected void runLoop() { | |
| 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 +578,7 @@ protected void deinitInThread() { | |
|
|
||
| destroyContext(); | ||
| super.internalDestroy(); | ||
| glfwTerminate(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just wonder here if we can't/shouldn't arrange it that the restart could call deinitInThread() and initInThread instead of manually re-creating the context. I think all that would be required is moving the glfwTerminate post deinitInThread, right?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, I tried it just now. Seems to actually fix #1013 . But also causes some side effects. Cursor is somehow gone as well as some other elements and all inputs... Need to investigate this a bit more... |
||
|
|
||
| LOGGER.fine("Display destroyed."); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't resetted when resetting the context.
Do you know about the special purpose of it?
Like I wonder if we should reset this value, like when initCallback fails and thus initialized is false after a restart.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use the flag to see if I need to re-create the callbacks. I'm unsure what the flag otherwise symbolizes, it was there already.