Commits

Michael Ludwig committed c07c756

Remove location spec from OnscreenSurfaceOptions.
Significantly improve LWJGL static surface to use a native window instead of a parented window when possible.
Add logic to emulate vsync if necessary.

Comments (0)

Files changed (3)

ferox-renderer-jogl/src/main/java/com/ferox/renderer/impl/jogl/JoglNEWTSurface.java

         window.setDefaultCloseOperation(
                 WindowClosingProtocol.WindowClosingMode.DO_NOTHING_ON_CLOSE); // we manage this ourselves
         window.setTitle("");
-        window.setPosition(options.getX(), options.getY());
+        window.setPosition(0, 0);
         window.setVisible(true);
         window.requestFocus();
 

ferox-renderer-lwjgl/src/main/java/com/ferox/renderer/impl/lwjgl/LwjglStaticDisplaySurface.java

 import com.ferox.input.MouseKeyEventDispatcher;
 import com.ferox.input.MouseListener;
 import com.ferox.renderer.DisplayMode;
+import com.ferox.renderer.FrameworkException;
 import com.ferox.renderer.OnscreenSurfaceOptions;
 import com.ferox.renderer.SurfaceCreationException;
 import com.ferox.renderer.impl.AbstractOnscreenSurface;
 import com.ferox.renderer.impl.FrameworkImpl;
 import com.ferox.renderer.impl.OpenGLContext;
 import org.lwjgl.LWJGLException;
+import org.lwjgl.LWJGLUtil;
 import org.lwjgl.opengl.Display;
 import org.lwjgl.opengl.Drawable;
 import org.lwjgl.opengl.GL11;
     private final LwjglStaticDisplayDestructible impl;
 
     private final DisplayMode displayMode;
+    private final boolean emulateVSync;
+    private long lastSyncTime;
 
     private final int depthBits;
     private final int stencilBits;
     private boolean vsync;
     private boolean vsyncNeedsUpdate;
 
-    public LwjglStaticDisplaySurface(FrameworkImpl framework, LwjglSurfaceFactory factory,
+    public LwjglStaticDisplaySurface(final FrameworkImpl framework, final LwjglSurfaceFactory factory,
                                      final OnscreenSurfaceOptions options, LwjglContext shareWith) {
         if (Display.isCreated()) {
             throw new SurfaceCreationException(
                     "Static LWJGL Display is already in use, cannot create another surface");
         }
 
-        org.lwjgl.opengl.PixelFormat format = choosePixelFormat(options, factory);
-        Drawable realShare = (shareWith == null ? null : shareWith.getDrawable());
+        final org.lwjgl.opengl.PixelFormat format = choosePixelFormat(options, factory);
+        final Drawable realShare = (shareWith == null ? null : shareWith.getDrawable());
 
         Canvas glCanvas = null;
         Frame parentFrame = null;
             displayMode = options.getFullscreenMode();
         } else {
             // not a fullscreen window
-            final Frame innerFrame = new Frame();
-            final Canvas innerCanvas = new Canvas(); //new PaintDisabledCanvas();
+            boolean needCanvasParent = options.isResizable() || options.isUndecorated();
+            if (needCanvasParent) {
+                parentFrame = new Frame();
+                glCanvas = new PaintDisabledCanvas();
 
-            Utils.invokeOnAWTThread(new Runnable() {
-                @Override
-                public void run() {
-                    innerFrame.setResizable(options.isResizable());
-                    innerFrame.setUndecorated(options.isUndecorated());
-                    innerFrame.setBounds(options.getX(), options.getY(), options.getWidth(),
-                                         options.getHeight());
-                    innerFrame.add(innerCanvas);
+                parentFrame.setResizable(options.isResizable());
+                parentFrame.setUndecorated(options.isUndecorated());
+                parentFrame.setBounds(0, 0, options.getWidth(), options.getHeight());
+                parentFrame.add(glCanvas);
 
-                    innerCanvas.setSize(options.getWidth(), options.getHeight());
+                parentFrame.setVisible(true);
+                glCanvas.requestFocusInWindow(); // We use LWJGL's input system, but just in case
 
-                    innerFrame.setVisible(true);
-                    innerFrame.pack();
-                    innerCanvas.requestFocusInWindow(); // We use LWJGL's input system, but just in case
-
-                    innerFrame.setIgnoreRepaint(true);
-                    innerCanvas.setIgnoreRepaint(true);
-                }
-            }, true);
+                parentFrame.setIgnoreRepaint(true);
+                glCanvas.setIgnoreRepaint(true);
+            }
 
             try {
-                Display.setParent(innerCanvas);
+                if (glCanvas != null) {
+                    Display.setParent(glCanvas);
+                } else {
+                    Display.setDisplayMode(
+                            new org.lwjgl.opengl.DisplayMode(options.getWidth(), options.getHeight()));
+                }
+
                 Display.create(format, realShare, factory.getContextAttribs());
+                if (glCanvas == null) {
+                    Display.setLocation(0, 0);
+                    Display.setTitle("");
+                }
             } catch (LWJGLException e) {
                 if (Display.isCreated()) {
                     Display.destroy();
                 }
                 throw new SurfaceCreationException("Unable to create static display", e);
             }
-
-            parentFrame = innerFrame;
-            glCanvas = innerCanvas;
             displayMode = factory.getDefaultDisplayMode();
         }
 
 
         vsync = false;
         vsyncNeedsUpdate = true;
+        // TODO test if other platforms support vsync with a parented window
+        emulateVSync = LWJGLUtil.getPlatform() == LWJGLUtil.PLATFORM_MACOSX && parentFrame != null;
+        lastSyncTime = -1L;
 
         impl = new LwjglStaticDisplayDestructible(framework, this, context, parentFrame, glCanvas);
     }
         super.onSurfaceActivate(context);
 
         synchronized (impl) {
-            if (vsyncNeedsUpdate) {
+            if (vsyncNeedsUpdate && !emulateVSync) {
                 Display.setSwapInterval(vsync ? 1 : 0);
                 vsyncNeedsUpdate = false;
             }
 
     @Override
     public boolean isFullscreen() {
-        return impl.parentFrame == null;
+        return impl.parentFrame == null && Display.isFullscreen();
     }
 
     @Override
     @Override
     public void setTitle(final String title) {
         if (impl.parentFrame != null) {
-            Utils.invokeOnAWTThread(new Runnable() {
-                @Override
-                public void run() {
-                    synchronized (impl) {
-                        impl.parentFrame.setTitle(title);
-                    }
-                }
-            }, false);
+            synchronized (impl) {
+                impl.parentFrame.setTitle(title);
+            }
         } else {
             synchronized (impl) {
                 // Display.setTitle() does not require the display to be current.
             if (impl.parentFrame != null) {
                 return impl.parentFrame.getX();
             } else {
-                return 0; // fullscreen
+                return Display.getX();
             }
         }
     }
             if (impl.parentFrame != null) {
                 return impl.parentFrame.getY();
             } else {
-                return 0; // fullscreen
+                return Display.getY();
             }
         }
     }
             throw new IllegalArgumentException("Dimensions must be at least 1");
         }
 
-        if (impl.parentFrame != null) {
-            Utils.invokeOnAWTThread(new Runnable() {
-                @Override
-                public void run() {
-                    synchronized (impl) {
-                        impl.parentFrame.setSize(width, height);
-                    }
+        synchronized (impl) {
+            if (impl.parentFrame != null) {
+                impl.parentFrame.setSize(width, height);
+            } else if (!Display.isFullscreen()) {
+                try {
+                    Display.setDisplayMode(new org.lwjgl.opengl.DisplayMode(width, height));
+                } catch (LWJGLException e) {
+                    throw new FrameworkException("Unexpected error changing window size", e);
                 }
-            }, false);
-        } else {
-            throw new IllegalStateException("Surface is fullscreen");
+            } else {
+                throw new IllegalStateException("Surface is fullscreen");
+            }
         }
     }
 
     @Override
     public void setLocation(final int x, final int y) {
-        if (impl.parentFrame != null) {
-            Utils.invokeOnAWTThread(new Runnable() {
-                @Override
-                public void run() {
-                    synchronized (impl) {
-                        impl.parentFrame.setLocation(x, y);
-                    }
-                }
-            }, false);
-        } else {
-            throw new IllegalStateException("Surface is fullscreen");
+        synchronized (impl) {
+            if (impl.parentFrame != null) {
+                impl.parentFrame.setLocation(x, y);
+            } else if (!Display.isFullscreen()) {
+                Display.setLocation(x, y);
+            } else {
+                throw new IllegalStateException("Surface is fullscreen");
+            }
         }
     }
 
             if (impl.parentFrame != null) {
                 return impl.glCanvas.getWidth();
             } else {
+                // FIXME insets
                 return Display.getWidth();
             }
         }
             if (impl.parentFrame != null) {
                 return impl.glCanvas.getHeight();
             } else {
+                // FIXME insets
                 return Display.getHeight();
             }
         }
     public void flush(OpenGLContext context) {
         // Just swap the buffers during flush(), we'll process messages
         // in another queued task
-        //            Display.swapBuffers();
         Display.update(false);
+
+        if (emulateVSync) {
+            boolean vsync;
+            synchronized (impl) {
+                vsync = this.vsync;
+            }
+
+            if (vsync && lastSyncTime >= 0) {
+                int freq = Display.getDisplayMode().getFrequency();
+                if (freq <= 0) {
+                    freq = 60; // default
+                }
+
+                long totalFrameTime = 1000 / freq;
+                long renderedTime = System.currentTimeMillis() - lastSyncTime;
+                while (totalFrameTime < renderedTime) {
+                    totalFrameTime *= 2; // double the interval if we've missed it
+                }
+
+                try {
+                    Thread.sleep(totalFrameTime - renderedTime);
+                } catch (InterruptedException e) {
+                    // ignore
+                }
+            }
+        }
+        lastSyncTime = System.currentTimeMillis();
     }
 
     private static class LwjglStaticDisplayDestructible extends SurfaceDestructible
         }
 
         /*
-     * Internal class that queues tasks to the gpu thread to periodically check
-     * OS state to push input events, or close the window.
-     */
+         * Internal class that queues tasks to the gpu thread to periodically check
+         * OS state to push input events, or close the window.
+         */
         private class EventMonitor implements Runnable {
             @Override
             public void run() {

ferox-renderer/src/main/java/com/ferox/renderer/OnscreenSurfaceOptions.java

     private final int width;
     private final int height;
 
-    private final int x;
-    private final int y;
-
     private final DisplayMode fullMode;
 
     private final int depthBits;
      * a decorated, resizable window at (0, 0) with dimensions 600 x 600.
      */
     public OnscreenSurfaceOptions() {
-        this(24, 0, 0, false, true, 0, 0, 600, 600, null);
+        this(24, 0, 0, false, true, 600, 600, null);
     }
 
     private OnscreenSurfaceOptions(int depthBits, int msaa, int stencilBits, boolean undecorated,
-                                   boolean resizable, int x, int y, int width, int height,
-                                   DisplayMode fullMode) {
+                                   boolean resizable, int width, int height, DisplayMode fullMode) {
         this.undecorated = undecorated;
         this.resizable = resizable;
         this.width = width;
         this.height = height;
-        this.x = x;
-        this.y = y;
 
         this.fullMode = fullMode;
         this.depthBits = depthBits;
      * @return New options configured for the given dimensions
      */
     public OnscreenSurfaceOptions windowed(int width, int height) {
-        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, undecorated, resizable, x, y, width,
-                                          height, null);
-    }
-
-    /**
-     * Create a new options that is updated to set the location of the of a windowed OnscreenSurface. The
-     * options are coerced to a windowed surface if there was a non-null fullscreen display mode.
-     *
-     * @param x The x location of the window in pixels from the left edge of the monitor
-     * @param y The y location of the window in pixels from the top of the monitor
-     *
-     * @return New options configured for the given location
-     */
-    public OnscreenSurfaceOptions locatedAt(int x, int y) {
-        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, undecorated, resizable, x, y, width,
-                                          height, null);
+        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, undecorated, resizable, width, height,
+                                          null);
     }
 
     /**
      * @return New options configured for a fullscreen surface
      */
     public OnscreenSurfaceOptions fullScreen(DisplayMode mode) {
-        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, true, false, 0, 0, mode.getWidth(),
+        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, true, false, mode.getWidth(),
                                           mode.getHeight(), mode);
     }
 
      * @return New options with the new depth buffer configuration
      */
     public OnscreenSurfaceOptions withDepthBuffer(int depthBits) {
-        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, undecorated, resizable, x, y, width,
-                                          height, fullMode);
+        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, undecorated, resizable, width, height,
+                                          fullMode);
     }
 
     /**
      * @return New options with the new depth stencil configuration
      */
     public OnscreenSurfaceOptions withStencilBuffer(int stencilBits) {
-        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, undecorated, resizable, x, y, width,
-                                          height, fullMode);
+        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, undecorated, resizable, width, height,
+                                          fullMode);
     }
 
     /**
      * @return New options with the new MSAA configuration
      */
     public OnscreenSurfaceOptions withMSAA(int samples) {
-        return new OnscreenSurfaceOptions(depthBits, samples, stencilBits, undecorated, resizable, x, y,
-                                          width, height, fullMode);
+        return new OnscreenSurfaceOptions(depthBits, samples, stencilBits, undecorated, resizable, width,
+                                          height, fullMode);
     }
 
     /**
      * @return New options marking the surface as undecorated
      */
     public OnscreenSurfaceOptions undecorated() {
-        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, true, resizable, x, y, width, height,
+        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, true, resizable, width, height,
                                           fullMode);
     }
 
      * @return New options marking the surface as not resizable
      */
     public OnscreenSurfaceOptions fixedSize() {
-        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, undecorated, false, x, y, width,
-                                          height, fullMode);
-    }
-
-    /**
-     * @return The initial x coordinate of the OnscreenSurface when windowed
-     */
-    public int getX() {
-        return x;
-    }
-
-    /**
-     * @return The initial y coordinate of the OnscreenSurface when windowed
-     */
-    public int getY() {
-        return y;
+        return new OnscreenSurfaceOptions(depthBits, msaa, stencilBits, undecorated, false, width, height,
+                                          fullMode);
     }
 
     /**
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.