diff --git a/jme3-core/src/main/java/com/jme3/system/AppSettings.java b/jme3-core/src/main/java/com/jme3/system/AppSettings.java index 0c8f56bd9..73b036f2f 100644 --- a/jme3-core/src/main/java/com/jme3/system/AppSettings.java +++ b/jme3-core/src/main/java/com/jme3/system/AppSettings.java @@ -129,6 +129,8 @@ public final class AppSettings extends HashMap { defaults.put("MinHeight", 0); defaults.put("MinWidth", 0); defaults.put("GammaCorrection", false); + defaults.put("Resizable", false); + defaults.put("SwapBuffers", true); // defaults.put("Icons", null); } @@ -935,4 +937,57 @@ public final class AppSettings extends HashMap { public boolean getGammaCorrection() { return getBoolean("GammaCorrection"); } + + /** + * Allows the display window to be resized by dragging its edges. + * + * Only supported for {@link JmeContext.Type#Display} contexts which + * are in windowed mode, ignored for other types. + * The default value is false. + * + * @param resizable True to make a resizable window, false to make a fixed + * size window. + */ + public void setResizable(boolean resizable) { + putBoolean("Resizable", true); + } + + /** + * Determine if the display window can be resized by dragging its edges. + * + * @return True if the window is resizable, false if it is fixed size. + * + * @see #setResizable(boolean) + */ + public boolean isResizable() { + return getBoolean("Resizable"); + } + + /** + * When enabled the display context will swap buffers every frame. + * + * This may need to be disabled when integrating with an external + * library that handles buffer swapping on its own, e.g. Oculus Rift. + * When disabled, the engine will process window messages + * after each frame but it will not swap buffers - note that this + * will cause 100% CPU usage normally as there's no VSync or any framerate + * caps (unless set via {@link #setFrameRate(int) }. + * The default is true. + * + * @param swapBuffers True to enable buffer swapping, false to disable it. + */ + public void setSwapBuffers(boolean swapBuffers) { + putBoolean("SwapBuffers", swapBuffers); + } + + /** + * Determine if the the display context will swap buffers every frame. + * + * @return True if buffer swapping is enabled, false otherwise. + * + * @see #setSwapBuffers(boolean) + */ + public boolean isSwapBuffers() { + return getBoolean("SwapBuffers"); + } } diff --git a/jme3-examples/src/main/java/jme3test/app/TestResizableApp.java b/jme3-examples/src/main/java/jme3test/app/TestResizableApp.java new file mode 100644 index 000000000..ad493ab44 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/app/TestResizableApp.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009-2015 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.app; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.font.Rectangle; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; +import jme3test.model.shape.TestBox; + +/** + * Tests the capability to resize the application window. + * + * @author Kirill Vainer + */ +public class TestResizableApp extends SimpleApplication { + + private BitmapText txt; + + public static void main(String[] args){ + TestResizableApp app = new TestResizableApp(); + AppSettings settings = new AppSettings(true); + settings.setResizable(true); + app.setSettings(settings); + app.setShowSettings(false); + app.start(); + } + + public void reshape(int width, int height) { + super.reshape(width, height); + + // Need to move text relative to app height + txt.setLocalTranslation(0, settings.getHeight(), 0); + txt.setText("Drag the corners of the application to resize it.\n" + + "Current Size: " + settings.getWidth() + "x" + settings.getHeight()); + } + + public void simpleInitApp() { + flyCam.setDragToRotate(true); + + 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("Interface/Logo/Monkey.jpg")); + geom.setMaterial(mat); + rootNode.attachChild(geom); + + txt = new BitmapText(loadGuiFont(), false); + txt.setText("Drag the corners of the application to resize it.\n" + + "Current Size: " + settings.getWidth() + "x" + settings.getHeight()); + txt.setLocalTranslation(0, settings.getHeight(), 0); + guiNode.attachChild(txt); + } + +} diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java index f0a157196..ee6a81c53 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java @@ -59,6 +59,7 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna protected boolean wasActive = false; protected int frameRate = 0; protected boolean autoFlush = true; + protected boolean allowSwapBuffers = false; /** * @return Type.Display or Type.Canvas @@ -149,7 +150,7 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna throw new IllegalStateException(); listener.update(); - + // All this does is call swap buffers // If the canvas is not active, there's no need to waste time // doing that .. @@ -158,30 +159,30 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna // calls swap buffers, etc. try { - if (autoFlush){ + if (allowSwapBuffers && autoFlush) { Display.update(false); - }else{ - Display.processMessages(); - Thread.sleep(50); - // add a small wait - // to reduce CPU usage - } + } } catch (Throwable ex){ listener.handleError("Error while swapping buffers", ex); } } - if (frameRate > 0) - Display.sync(frameRate); - - if (renderable.get()){ - if (autoFlush){ - // check input after we synchronize with framerate. - // this reduces input lag. - Display.processMessages(); - } + int frameRateCap; + if (autoFlush) { + frameRateCap = frameRate; + } else { + frameRateCap = 20; } - + + if (frameRateCap > 0) { + // Cap framerate + Display.sync(frameRateCap); + } + + // check input after we synchronize with framerate. + // this reduces input lag. + Display.processMessages(); + // Subclasses just call GLObjectManager clean up objects here // it is safe .. for now. renderer.postFrame(); diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java index f51fc7b35..f1fcc34a2 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java @@ -435,6 +435,7 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex // In case canvas is not visible, we still take framerate // from settings to prevent "100% CPU usage" frameRate = settings.getFrameRate(); + allowSwapBuffers = settings.isSwapBuffers(); try { if (renderable.get()){ 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 f74076c2c..4ecfc9a49 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 @@ -94,6 +94,7 @@ public class LwjglDisplay extends LwjglAbstractDisplay { settings.useStereo3D()); frameRate = settings.getFrameRate(); + allowSwapBuffers = settings.isSwapBuffers(); logger.log(Level.FINE, "Selected display mode: {0}", displayMode); boolean pixelFormatChanged = false; @@ -108,6 +109,7 @@ public class LwjglDisplay extends LwjglAbstractDisplay { pixelFormat = pf; Display.setTitle(settings.getTitle()); + Display.setResizable(settings.isResizable()); if (displayMode != null) { if (settings.isFullscreen()) { @@ -172,14 +174,19 @@ public class LwjglDisplay extends LwjglAbstractDisplay { @Override public void runLoop(){ // This method is overriden to do restart - if (needRestart.getAndSet(false)){ - try{ + if (needRestart.getAndSet(false)) { + try { createContext(settings); - }catch (LWJGLException ex){ + } catch (LWJGLException ex) { logger.log(Level.SEVERE, "Failed to set display settings!", ex); } listener.reshape(settings.getWidth(), settings.getHeight()); logger.fine("Display restarted."); + } else if (Display.wasResized()) { + int newWidth = Display.getWidth(); + int newHeight = Display.getHeight(); + settings.setResolution(newWidth, newHeight); + listener.reshape(newWidth, newHeight); } super.runLoop();