diff --git a/jme3-examples/src/main/java/jme3test/renderer/TestContextRestart.java b/jme3-examples/src/main/java/jme3test/renderer/TestContextRestart.java new file mode 100644 index 0000000000..d0ebb73889 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/renderer/TestContextRestart.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2009-2021 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.renderer; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.control.AbstractControl; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; + +/** + * Tests whether gamma correction works after a context restart. This test + * generates a series of boxes, each one with a slightly different shade from + * the other. If the boxes look the same before and after the restart, that + * means that gamma correction is working properly. + *
+ * Note that for testing, it may be helpful to bypass the test chooser and run + * this class directly, since it can be easier to define your own settings + * beforehand. Of course, it should still workif all you need to test is the + * gamma correction, as long as you enable it in the settings dialog. + *
+ * + * @author Markil 3 + */ +public class TestContextRestart extends SimpleApplication +{ + public static final String INPUT_RESTART_CONTEXT = "SIMPLEAPP_Restart"; + + public static void main(String[] args) + { + TestContextRestart app = new TestContextRestart(); + AppSettings settings = new AppSettings(true); + settings.setGammaCorrection(true); +// settings.setRenderer(AppSettings.LWJGL_OPENGL32); + app.setSettings(settings); + app.start(); + } + + @Override + public void simpleInitApp() + { + for (int i = 0, l = 256; i < l; i += 8) + { + Geometry box = new Geometry("Box" + i, new Box(10, 200, 10)); + Material mat = new Material(this.assetManager, + "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", new ColorRGBA((float) i / 255F, 0, 0, 1)); + box.setMaterial(mat); + box.setLocalTranslation(-2.5F * (l / 2 - i), 0, -700); + box.addControl(new AbstractControl() + { + @Override + protected void controlUpdate(float tpf) + { + float[] angles = this.getSpatial() + .getLocalRotation() + .toAngles(new float[3]); + angles[0] = angles[0] + (FastMath.PI / 500F); + this.getSpatial() + .setLocalRotation(new Quaternion().fromAngles(angles)); + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) + { + + } + }); + this.rootNode.attachChild(box); + } + + this.viewPort.setBackgroundColor(ColorRGBA.Yellow); + + this.flyCam.setEnabled(false); + this.inputManager.setCursorVisible(true); + + inputManager.addMapping(INPUT_RESTART_CONTEXT, new KeyTrigger( + KeyInput.KEY_TAB)); + this.inputManager.addListener(new ActionListener() + { + @Override + public void onAction(String name, boolean isPressed, float tpf) + { + if (name.equals(INPUT_RESTART_CONTEXT)) + { + restart(); + } + } + }, INPUT_RESTART_CONTEXT); + } +} diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index f8aabc9497..5f440cd33a 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -251,42 +251,65 @@ protected int getNumSamplesToUse() { return samples; } + /** + * Reinitializes the relevent details of the context. For internal use only. + */ + protected void reinitContext() { + initContext(false); + } + + /** + * Initializes the LWJGL renderer and input for the first time. For internal + * use only. + */ protected void initContextFirstTime() { + initContext(true); + } + + /** + * Initializes the LWJGL renderer and input. + * @param first - Whether this is the first time we are initializing and we + * need to create the renderer or not. Otherwise, we'll just reset the + * renderer as needed. + */ + private void initContext(boolean first) { if (!GLContext.getCapabilities().OpenGL20) { throw new RendererException("OpenGL 2.0 or higher is " + "required for jMonkeyEngine"); } - + int vers[] = getGLVersion(settings.getRenderer()); if (vers != null) { - GL gl = new LwjglGL(); - GLExt glext = new LwjglGLExt(); - GLFbo glfbo; - - if (GLContext.getCapabilities().OpenGL30) { - glfbo = new LwjglGLFboGL3(); - } else { - glfbo = new LwjglGLFboEXT(); - } - - if (settings.getBoolean("GraphicsDebug")) { - gl = (GL) GLDebug.createProxy(gl, gl, GL.class, GL2.class, GL3.class, GL4.class); - glext = (GLExt) GLDebug.createProxy(gl, glext, GLExt.class); - glfbo = (GLFbo) GLDebug.createProxy(gl, glfbo, GLFbo.class); - } - if (settings.getBoolean("GraphicsTiming")) { - GLTimingState timingState = new GLTimingState(); - gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class); - glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class); - glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class); - } - if (settings.getBoolean("GraphicsTrace")) { - gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class); - glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class); - glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class); + if (first) { + GL gl = new LwjglGL(); + GLExt glext = new LwjglGLExt(); + GLFbo glfbo; + + if (GLContext.getCapabilities().OpenGL30) { + glfbo = new LwjglGLFboGL3(); + } else { + glfbo = new LwjglGLFboEXT(); + } + + if (settings.getBoolean("GraphicsDebug")) { + gl = (GL) GLDebug.createProxy(gl, gl, GL.class, GL2.class, GL3.class, GL4.class); + glext = (GLExt) GLDebug.createProxy(gl, glext, GLExt.class); + glfbo = (GLFbo) GLDebug.createProxy(gl, glfbo, GLFbo.class); + } + if (settings.getBoolean("GraphicsTiming")) { + GLTimingState timingState = new GLTimingState(); + gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class); + glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class); + glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class); + } + if (settings.getBoolean("GraphicsTrace")) { + gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class); + glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class); + glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class); + } + renderer = new GLRenderer(gl, glext, glfbo); + renderer.initialize(); } - renderer = new GLRenderer(gl, glext, glfbo); - renderer.initialize(); } else { throw new UnsupportedOperationException("Unsupported renderer: " + settings.getRenderer()); } @@ -296,19 +319,20 @@ protected void initContextFirstTime() { renderer.setMainFrameBufferSrgb(settings.isGammaCorrection()); renderer.setLinearizeSrgbImages(settings.isGammaCorrection()); - // Init input - if (keyInput != null) { - keyInput.initialize(); - } + if (first) { + // Init input + if (keyInput != null) { + keyInput.initialize(); + } - if (mouseInput != null) { - mouseInput.initialize(); - } + if (mouseInput != null) { + mouseInput.initialize(); + } - if (joyInput != null) { - joyInput.initialize(); + if (joyInput != null) { + joyInput.initialize(); + } } - } @SuppressWarnings("unchecked") diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java index bbf02adacd..f7c455728c 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java @@ -185,6 +185,11 @@ public void runLoop(){ logger.log(Level.SEVERE, "Failed to set display settings!", ex); } listener.reshape(settings.getWidth(), settings.getHeight()); + if (renderable.get()) { + reinitContext(); + } else { + assert getType() == Type.Canvas; + } logger.fine("Display restarted."); } else if (Display.wasResized()) { int newWidth = Display.getWidth(); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 536c2a18a5..df73583754 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -174,7 +174,28 @@ protected int getNumSamplesToUse() { return samples; } + /** + * Reinitializes the relevant details of the context. For internal use only. + */ + protected void reinitContext() { + initContext(false); + } + + /** + * Initializes the LWJGL renderer and input for the first time. For internal + * use only. + */ protected void initContextFirstTime() { + initContext(true); + } + + /** + * Initializes the LWJGL renderer and input. + * @param first - Whether this is the first time we are initializing and we + * need to create the renderer or not. Otherwise, we'll just reset the + * renderer as needed. + */ + private void initContext(boolean first) { final String renderer = settings.getRenderer(); final GLCapabilities capabilities = createCapabilities(!renderer.equals(AppSettings.LWJGL_OPENGL2)); @@ -185,36 +206,38 @@ protected void initContextFirstTime() { throw new UnsupportedOperationException("Unsupported renderer: " + renderer); } - GL gl = new LwjglGL(); - GLExt glext = new LwjglGLExt(); - GLFbo glfbo; + if (first) { + GL gl = new LwjglGL(); + GLExt glext = new LwjglGLExt(); + GLFbo glfbo; - if (capabilities.OpenGL30) { - glfbo = new LwjglGLFboGL3(); - } else { - glfbo = new LwjglGLFboEXT(); - } + if (capabilities.OpenGL30) { + glfbo = new LwjglGLFboGL3(); + } else { + glfbo = new LwjglGLFboEXT(); + } - if (settings.getBoolean("GraphicsDebug")) { - gl = (GL) GLDebug.createProxy(gl, gl, GL.class, GL2.class, GL3.class, GL4.class); - glext = (GLExt) GLDebug.createProxy(gl, glext, GLExt.class); - glfbo = (GLFbo) GLDebug.createProxy(gl, glfbo, GLFbo.class); - } + if (settings.getBoolean("GraphicsDebug")) { + gl = (GL) GLDebug.createProxy(gl, gl, GL.class, GL2.class, GL3.class, GL4.class); + glext = (GLExt) GLDebug.createProxy(gl, glext, GLExt.class); + glfbo = (GLFbo) GLDebug.createProxy(gl, glfbo, GLFbo.class); + } - if (settings.getBoolean("GraphicsTiming")) { - GLTimingState timingState = new GLTimingState(); - gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class); - glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class); - glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class); - } + if (settings.getBoolean("GraphicsTiming")) { + GLTimingState timingState = new GLTimingState(); + gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class); + glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class); + glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class); + } - if (settings.getBoolean("GraphicsTrace")) { - gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class); - glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class); - glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class); - } + if (settings.getBoolean("GraphicsTrace")) { + gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class); + glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class); + glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class); + } - this.renderer = new GLRenderer(gl, glext, glfbo); + this.renderer = new GLRenderer(gl, glext, glfbo); + } this.renderer.initialize(); if (capabilities.GL_ARB_debug_output && settings.getBoolean("GraphicsDebug")) { @@ -224,36 +247,38 @@ protected void initContextFirstTime() { this.renderer.setMainFrameBufferSrgb(settings.isGammaCorrection()); this.renderer.setLinearizeSrgbImages(settings.isGammaCorrection()); - // Init input - if (keyInput != null) { - keyInput.initialize(); - } - - if (mouseInput != null) { - mouseInput.initialize(); - } - - if (joyInput != null) { - joyInput.initialize(); - } + if (first) { + // Init input + if (keyInput != null) { + keyInput.initialize(); + } - GLFW.glfwSetJoystickCallback(new GLFWJoystickCallback() { - @Override - public void invoke(int jid, int event) { + if (mouseInput != null) { + mouseInput.initialize(); + } - // Invoke the disconnected event before we reload the joysticks or we lose the reference to it. - // Invoke the connected event after we reload the joysticks to obtain the reference to it. + if (joyInput != null) { + joyInput.initialize(); + } - if ( event == GLFW.GLFW_CONNECTED ) { - joyInput.reloadJoysticks(); - joyInput.fireJoystickConnectedEvent(jid); + GLFW.glfwSetJoystickCallback(new GLFWJoystickCallback() { + @Override + public void invoke(int jid, int event) { + + // Invoke the disconnected event before we reload the joysticks or we lose the reference to it. + // Invoke the connected event after we reload the joysticks to obtain the reference to it. + + if ( event == GLFW.GLFW_CONNECTED ) { + joyInput.reloadJoysticks(); + joyInput.fireJoystickConnectedEvent(jid); + } + else { + joyInput.fireJoystickDisconnectedEvent(jid); + joyInput.reloadJoysticks(); + } } - else { - joyInput.fireJoystickDisconnectedEvent(jid); - joyInput.reloadJoysticks(); - } - } - }); + }); + } renderable.set(true); } 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 66515e9b78..d04ca57cbc 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 @@ -576,6 +576,8 @@ private void restartContext() { } catch (Exception ex) { LOGGER.log(Level.SEVERE, "Failed to set display settings!", ex); } + // Reinitialize context flags and such + reinitContext(); // We need to reinit the mouse and keyboard input as they are tied to a window handle if (keyInput != null && keyInput.isInitialized()) {