/* * Copyright (c) 2002-2008 LWJGL Project * 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 'LWJGL' 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 org.lwjgl.opengl; /** * This is the abstract class for a Display in LWJGL. LWJGL displays have some * peculiar characteristics: * * - the display may be closeable by the user or operating system, and may be minimized * by the user or operating system * - only one display may ever be open at once * - the operating system may or may not be able to do fullscreen or windowed displays. * * @author foo */ import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; import java.util.HashSet; import java.awt.Canvas; import java.awt.event.ComponentListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import org.lwjgl.BufferUtils; import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLUtil; import org.lwjgl.Sys; import org.lwjgl.input.Controllers; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; public final class Display { private static final Thread shutdown_hook = new Thread() { public void run() { reset(); } }; /** The display implementor */ private static final DisplayImplementation display_impl; /** The initial display mode */ private static final DisplayMode initial_mode; /** The parent, if any */ private static Canvas parent; /** The current display mode, if created */ private static DisplayMode current_mode; /** Timer for sync() */ private static long timeThen; /** X coordinate of the window */ private static int x = -1; /** Cached window icons, for when Display is recreated */ private static ByteBuffer[] cached_icons; /** * Y coordinate of the window. Y in window coordinates is from the top of the display down, * unlike GL, where it is typically at the bottom of the display. */ private static int y = -1; /** Title of the window (never null) */ private static String title = "Game"; /** Fullscreen */ private static boolean fullscreen; /** Swap interval */ private static int swap_interval; /** A unique context object, so we can track different contexts between creates() and destroys() */ private static PeerInfo peer_info; private static Context context; /** The Drawable instance that tracks the current Display context */ private final static Drawable drawable; private static boolean window_created = false; private static boolean parent_resized; private static ComponentListener component_listener = new ComponentAdapter() { public final void componentResized(ComponentEvent e) { synchronized (GlobalLock.lock) { parent_resized = true; } } }; static { Sys.initialize(); display_impl = createDisplayImplementation(); try { current_mode = initial_mode = display_impl.init(); LWJGLUtil.log("Initial mode: " + initial_mode); } catch (LWJGLException e) { throw new RuntimeException(e); } drawable = new Drawable() { public Context getContext() { synchronized (GlobalLock.lock) { return isCreated() ? context : null; } } }; } /** * Fetch the Drawable from the Display. * * @return the Drawable corresponding to the Display context */ public static Drawable getDrawable() { return drawable; } private static DisplayImplementation createDisplayImplementation() { switch (LWJGLUtil.getPlatform()) { case LWJGLUtil.PLATFORM_LINUX: return new LinuxDisplay(); case LWJGLUtil.PLATFORM_WINDOWS: return new WindowsDisplay(); case LWJGLUtil.PLATFORM_MACOSX: return new MacOSXDisplay(); default: throw new IllegalStateException("Unsupported platform"); } } /** * Only constructed by ourselves */ private Display() { } /** * Returns the entire list of possible fullscreen display modes as an array, in no * particular order. Although best attempts to filter out invalid modes are done, any * given mode is not guaranteed to be available nor is it guaranteed to be within the * current monitor specs (this is especially a problem with the frequency parameter). * Furthermore, it is not guaranteed that create() will detect an illegal display mode. * * The only certain way to check * is to call create() and make sure it works. * Only non-palette-indexed modes are returned (ie. bpp will be 16, 24, or 32). * Only DisplayModes from this call can be used when the Display is in fullscreen * mode. * * @return an array of all display modes the system reckons it can handle. */ public static DisplayMode[] getAvailableDisplayModes() throws LWJGLException { synchronized (GlobalLock.lock) { DisplayMode[] unfilteredModes = display_impl.getAvailableDisplayModes(); if (unfilteredModes == null) { return new DisplayMode[0]; } // We'll use a HashSet to filter out the duplicated modes HashSet modes = new HashSet(unfilteredModes.length); modes.addAll(Arrays.asList(unfilteredModes)); DisplayMode[] filteredModes = new DisplayMode[modes.size()]; modes.toArray(filteredModes); LWJGLUtil.log("Removed " + (unfilteredModes.length - filteredModes.length) + " duplicate displaymodes"); return filteredModes; } } /** * Return the current display mode, as set by setDisplayMode(). * @return The current display mode */ public static DisplayMode getDisplayMode() { synchronized (GlobalLock.lock) { return current_mode; } } /** * Set the current display mode. If no OpenGL context has been created, the given mode will apply to * the context when create() is called, and no immediate mode switching will happen. If there is a * context already, it will be resized according to the given mode. If the context is also a * fullscreen context, the mode will also be switched immediately. The native cursor position * is also reset. * * @param mode The new display mode to set * @throws LWJGLException if the display mode could not be set */ public static void setDisplayMode(DisplayMode mode) throws LWJGLException { synchronized (GlobalLock.lock) { if (mode == null) throw new NullPointerException("mode must be non-null"); current_mode = mode; if (isCreated()) { destroyWindow(); // If mode is not fullscreen capable, make sure we are in windowed mode if (!mode.isFullscreen()) resetFullscreen(); try { if (fullscreen) switchDisplayMode(); createWindow(); makeCurrentAndSetSwapInterval(); } catch (LWJGLException e) { destroyContext(); destroyPeerInfo(); display_impl.resetDisplayMode(); throw e; } } } } private static DisplayMode getEffectiveMode() { return !fullscreen && parent != null ? new DisplayMode(parent.getWidth(), parent.getHeight()) : current_mode; } private static int getWindowX() { if (!fullscreen && parent == null) { // if no display location set, center window if (x == -1) { return Math.max(0, (initial_mode.getWidth() - current_mode.getWidth()) / 2); } else { return x; } } else { return 0; } } private static int getWindowY() { if (!fullscreen && parent == null) { // if no display location set, center window if (y == -1) { return Math.max(0, (initial_mode.getHeight() - current_mode.getHeight()) / 2); } else { return y; } } else { return 0; } } /** * Create the native window peer from the given mode and fullscreen flag. * A native context must exist, and it will be attached to the window. */ private static void createWindow() throws LWJGLException { if (window_created) { return; } Canvas tmp_parent = fullscreen ? null : parent; if (tmp_parent != null && !tmp_parent.isDisplayable()) // Only a best effort check, since the parent can turn undisplayable hereafter throw new LWJGLException("Parent.isDisplayable() must be true"); if (tmp_parent != null) { tmp_parent.addComponentListener(component_listener); } DisplayMode mode = getEffectiveMode(); display_impl.createWindow(mode, fullscreen, tmp_parent, getWindowX(), getWindowY()); window_created = true; setTitle(title); initControls(); // set cached window icon if exists if(cached_icons != null) { setIcon(cached_icons); } else { setIcon(new ByteBuffer[] { LWJGLUtil.LWJGLIcon32x32, LWJGLUtil.LWJGLIcon16x16 }); } } private static void destroyWindow() { if (!window_created) { return; } if (parent != null) { parent.removeComponentListener(component_listener); } try { if (context != null && context.isCurrent()) { Context.releaseCurrentContext(); context.releaseDrawable(); } } catch (LWJGLException e) { LWJGLUtil.log("Exception occurred while trying to release context: " + e); } // Automatically destroy keyboard & mouse if (Mouse.isCreated()) { Mouse.destroy(); } if (Keyboard.isCreated()) { Keyboard.destroy(); } display_impl.destroyWindow(); window_created = false; } private static void switchDisplayMode() throws LWJGLException { if (!current_mode.isFullscreen()) { throw new IllegalStateException("Only modes acquired from getAvailableDisplayModes() can be used for fullscreen display"); } display_impl.switchDisplayMode(current_mode); } /** * Set the display configuration to the specified gamma, brightness and contrast. * The configuration changes will be reset when destroy() is called. * * @param gamma The gamma value * @param brightness The brightness value between -1.0 and 1.0, inclusive * @param contrast The contrast, larger than 0.0. */ public static void setDisplayConfiguration(float gamma, float brightness, float contrast) throws LWJGLException { synchronized (GlobalLock.lock) { if (!isCreated()) { throw new LWJGLException("Display not yet created."); } if (brightness < -1.0f || brightness > 1.0f) throw new IllegalArgumentException("Invalid brightness value"); if (contrast < 0.0f) throw new IllegalArgumentException("Invalid contrast value"); int rampSize = display_impl.getGammaRampLength(); if (rampSize == 0) { throw new LWJGLException("Display configuration not supported"); } FloatBuffer gammaRamp = BufferUtils.createFloatBuffer(rampSize); for (int i = 0; i < rampSize; i++) { float intensity = (float)i/(rampSize - 1); // apply gamma float rampEntry = (float)java.lang.Math.pow(intensity, gamma); // apply brightness rampEntry += brightness; // apply contrast rampEntry = (rampEntry - 0.5f)*contrast + 0.5f; // Clamp entry to [0, 1] if (rampEntry > 1.0f) rampEntry = 1.0f; else if (rampEntry < 0.0f) rampEntry = 0.0f; gammaRamp.put(i, rampEntry); } display_impl.setGammaRamp(gammaRamp); LWJGLUtil.log("Gamma set, gamma = " + gamma + ", brightness = " + brightness + ", contrast = " + contrast); } } /** * Synchronize the display to a capped frame rate. Note that we are being "smart" about the * desired results in our implementation; we automatically subtract 1 from the desired framerate * to prevent just missing the frame time if vsync is set. * @param fps The desired frame rate, in frames per second */ public static void sync3(int fps) { long savedTimeThen; long timeNow; synchronized (GlobalLock.lock) { timeNow = Sys.getTime(); savedTimeThen = timeThen; timeThen = timeNow; } float frameTime = 1.0f / (fps > 1 ? fps - 1 : 1); while (timeNow > savedTimeThen && (float) (timeNow - savedTimeThen) / (float) Sys.getTimerResolution() < frameTime) { // This is a system-friendly way of allowing other stuff to use CPU if it wants to Thread.yield(); timeNow = Sys.getTime(); } } private static long timeLate; /** * Alternative sync method which works better on triple-buffered GL displays. * * @param fps The desired frame rate, in frames per second */ public static void sync2(int fps) { long timeNow; long gapTo; long savedTimeLate; synchronized (GlobalLock.lock) { gapTo = Sys.getTimerResolution() / fps + timeThen; timeNow = Sys.getTime(); savedTimeLate = timeLate; } while (gapTo > timeNow + savedTimeLate) { Thread.yield(); timeNow = Sys.getTime(); } synchronized (GlobalLock.lock) { if (gapTo < timeNow) timeLate = timeNow - gapTo; else timeLate = 0; timeThen = timeNow; } } /** * Best sync method that works reliably. * * @param fps The desired frame rate, in frames per second */ public static void sync(int fps) { long timeNow; long gapTo; long savedTimeLate; synchronized (GlobalLock.lock) { gapTo = Sys.getTimerResolution() / fps + timeThen; timeNow = Sys.getTime(); savedTimeLate = timeLate; } while (gapTo > timeNow + savedTimeLate) { try { Thread.sleep(1); } catch (InterruptedException e) { } timeNow = Sys.getTime(); } synchronized (GlobalLock.lock) { if (gapTo < timeNow) timeLate = timeNow - gapTo; else timeLate = 0; timeThen = timeNow; } } /** * @return the X coordinate of the window (always 0 for fullscreen) */ /*public static int getX() { return (fullscreen) ? 0 : x; }*/ /** * @return the Y coordinate of the window (always 0 for fullscreen) */ /*public static int getY() { return (fullscreen) ? 0 : y; }*/ /** * @return the title of the window */ public static String getTitle() { synchronized (GlobalLock.lock) { return title; } } private static void resetFullscreen() { synchronized (GlobalLock.lock) { if (Display.fullscreen) { Display.fullscreen = false; display_impl.resetDisplayMode(); } } } /** * Return the last parent set with setParent(). */ public static Canvas getParent() { synchronized (GlobalLock.lock) { return parent; } } /** * Set the parent of the Display. If parent is null, the Display will appear as a top level window. * If parent is not null, the Display is made a child of the parent. A parent's isDisplayable() must be true when * setParent() is called and remain true until setParent() is called again with * null or a different parent. This generally means that the parent component must remain added to it's parent container.

* It is not advisable to call this method from an AWT thread, since the context will be made current on the thread * and it is difficult to predict which AWT thread will process any given AWT event.

* If the Display is in fullscreen mode, the current parent will be ignored. * */ public static void setParent(Canvas parent) throws LWJGLException { synchronized (GlobalLock.lock) { if (Display.parent != parent) { Display.parent = parent; if (!isCreated()) return; destroyWindow(); try { if (fullscreen) { switchDisplayMode(); } else { display_impl.resetDisplayMode(); } createWindow(); makeCurrentAndSetSwapInterval(); } catch (LWJGLException e) { destroyContext(); destroyPeerInfo(); display_impl.resetDisplayMode(); throw e; } } } } /** * Set the fullscreen mode of the context. If no context has been created through create(), * the mode will apply when create() is called. If fullscreen is true, the context will become * a fullscreen context and the display mode is switched to the mode given by getDisplayMode(). If * fullscreen is false, the context will become a windowed context with the dimensions given in the * mode returned by getDisplayMode(). The native cursor position is also reset. * * @param fullscreen Specify the fullscreen mode of the context. * @throws LWJGLException If fullscreen is true, and the current DisplayMode instance is not * from getAvailableDisplayModes() or if the mode switch fails. */ public static void setFullscreen(boolean fullscreen) throws LWJGLException { synchronized (GlobalLock.lock) { if (Display.fullscreen != fullscreen) { Display.fullscreen = fullscreen; if (!isCreated()) return; destroyWindow(); try { if (fullscreen) { switchDisplayMode(); } else { display_impl.resetDisplayMode(); } createWindow(); makeCurrentAndSetSwapInterval(); } catch (LWJGLException e) { destroyContext(); destroyPeerInfo(); display_impl.resetDisplayMode(); throw e; } } } } /** * @return whether the Display is in fullscreen mode */ public static boolean isFullscreen() { synchronized (GlobalLock.lock) { return fullscreen; } } /** * Set the title of the window. This may be ignored by the underlying OS. * @param newTitle The new window title */ public static void setTitle(String newTitle) { synchronized (GlobalLock.lock) { if (newTitle == null) { newTitle = ""; } title = newTitle; if (isCreated()) display_impl.setTitle(title); } } /** * @return true if the user or operating system has asked the window to close */ public static boolean isCloseRequested() { synchronized (GlobalLock.lock) { if (!isCreated()) throw new IllegalStateException("Cannot determine close requested state of uncreated window"); return display_impl.isCloseRequested(); } } /** * @return true if the window is visible, false if not */ public static boolean isVisible() { synchronized (GlobalLock.lock) { if (!isCreated()) throw new IllegalStateException("Cannot determine minimized state of uncreated window"); return display_impl.isVisible(); } } /** * @return true if window is active, that is, the foreground display of the operating system. */ public static boolean isActive() { synchronized (GlobalLock.lock) { if (!isCreated()) throw new IllegalStateException("Cannot determine focused state of uncreated window"); return display_impl.isActive(); } } /** * Determine if the window's contents have been damaged by external events. * If you are writing a straightforward game rendering loop and simply paint * every frame regardless, you can ignore this flag altogether. If you are * trying to be kind to other processes you can check this flag and only * redraw when it returns true. The flag is cleared when update() or isDirty() is called. * * @return true if the window has been damaged by external changes * and needs to repaint itself */ public static boolean isDirty() { synchronized (GlobalLock.lock) { if (!isCreated()) throw new IllegalStateException("Cannot determine dirty state of uncreated window"); return display_impl.isDirty(); } } /** * Process operating system events. Call this to update the Display's state and to receive new * input device events. This method is called from update(), so it is not necessary to call * this method if update() is called periodically. */ public static void processMessages() { synchronized (GlobalLock.lock) { if (!isCreated()) throw new IllegalStateException("Display not created"); display_impl.update(); } } /** * Swap the display buffers. This method is called from update(), and should normally not be called by * the application. * @throws OpenGLException if an OpenGL error has occured since the last call to GL11.glGetError() */ public static void swapBuffers() throws LWJGLException { synchronized (GlobalLock.lock) { if (!isCreated()) throw new IllegalStateException("Display not created"); Util.checkGLError(); Context.swapBuffers(); } } /** * Update the window. This calls processMessages(), and if the window is visible * clears the dirty flag and calls swapBuffers() and finally polls the input devices. * @throws OpenGLException if an OpenGL error has occured since the last call to GL11.glGetError() */ public static void update() { synchronized (GlobalLock.lock) { if (!isCreated()) throw new IllegalStateException("Display not created"); processMessages(); // We paint only when the window is visible or dirty if (display_impl.isVisible() || display_impl.isDirty()) { try { swapBuffers(); } catch (LWJGLException e) { throw new RuntimeException(e); } } pollDevices(); if (parent_resized) { reshape(); parent_resized = false; } } } static void pollDevices() { // Poll the input devices while we're here if (Mouse.isCreated()) { Mouse.poll(); Mouse.updateCursor(); } if (Keyboard.isCreated()) { Keyboard.poll(); } if(Controllers.isCreated()) { Controllers.poll(); } } /** * Release the Display context. * * @throws LWJGLException If the context could not be released */ public static void releaseContext() throws LWJGLException { synchronized (GlobalLock.lock) { if (!isCreated()) throw new IllegalStateException("Display is not created"); if (context.isCurrent()) Context.releaseCurrentContext(); } } /** * Make the Display the current rendering context for GL calls. * * @throws LWJGLException If the context could not be made current */ public static void makeCurrent() throws LWJGLException { synchronized (GlobalLock.lock) { if (!isCreated()) throw new IllegalStateException("Display is not created"); context.makeCurrent(); } } /** * Create the OpenGL context. If isFullscreen() is true or if windowed * context are not supported on the platform, the display mode will be switched to the mode returned by * getDisplayMode(), and a fullscreen context will be created. If isFullscreen() is false, a windowed context * will be created with the dimensions given in the mode returned by getDisplayMode(). If a context can't be * created with the given parameters, a LWJGLException will be thrown. * *

The window created will be set up in orthographic 2D projection, with 1:1 pixel ratio with GL coordinates. * * @throws LWJGLException */ public static void create() throws LWJGLException { synchronized (GlobalLock.lock) { create(new PixelFormat()); } } /** * Create the OpenGL context with the given minimum parameters. If isFullscreen() is true or if windowed * context are not supported on the platform, the display mode will be switched to the mode returned by * getDisplayMode(), and a fullscreen context will be created. If isFullscreen() is false, a windowed context * will be created with the dimensions given in the mode returned by getDisplayMode(). If a context can't be * created with the given parameters, a LWJGLException will be thrown. * *

The window created will be set up in orthographic 2D projection, with 1:1 pixel ratio with GL coordinates. * * @param pixel_format Describes the minimum specifications the context must fulfill. * @throws LWJGLException */ public static void create(PixelFormat pixel_format) throws LWJGLException { synchronized (GlobalLock.lock) { create(pixel_format, null); } } private static void removeShutdownHook() { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { Runtime.getRuntime().removeShutdownHook(shutdown_hook); return null; } }); } private static void registerShutdownHook() { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { Runtime.getRuntime().addShutdownHook(shutdown_hook); return null; } }); } /** * Create the OpenGL context with the given minimum parameters. If isFullscreen() is true or if windowed * context are not supported on the platform, the display mode will be switched to the mode returned by * getDisplayMode(), and a fullscreen context will be created. If isFullscreen() is false, a windowed context * will be created with the dimensions given in the mode returned by getDisplayMode(). If a context can't be * created with the given parameters, a LWJGLException will be thrown. * *

The window created will be set up in orthographic 2D projection, with 1:1 pixel ratio with GL coordinates. * * @param pixel_format Describes the minimum specifications the context must fulfill. * @param shared_drawable The Drawable to share context with or null. * @throws LWJGLException */ public static void create(PixelFormat pixel_format, Drawable shared_drawable) throws LWJGLException { synchronized (GlobalLock.lock) { if (isCreated()) throw new IllegalStateException("Only one LWJGL context may be instantiated at any one time."); if (pixel_format == null) throw new NullPointerException("pixel_format cannot be null"); removeShutdownHook(); registerShutdownHook(); if (fullscreen) switchDisplayMode(); try { peer_info = display_impl.createPeerInfo(pixel_format); try { createWindow(); try { context = new Context(peer_info, shared_drawable != null ? shared_drawable.getContext() : null); try { makeCurrentAndSetSwapInterval(); initContext(); } catch (LWJGLException e) { destroyContext(); throw e; } } catch (LWJGLException e) { destroyWindow(); throw e; } } catch (LWJGLException e) { destroyPeerInfo(); throw e; } } catch (LWJGLException e) { display_impl.resetDisplayMode(); throw e; } } } private static void makeCurrentAndSetSwapInterval() throws LWJGLException { makeCurrent(); Util.checkGLError(); setSwapInterval(swap_interval); } private static void initContext() { // Clear window to avoid the desktop "showing through" GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); update(); } static DisplayImplementation getImplementation() { return display_impl; } /** * Gets a boolean property as a privileged action. */ static boolean getPrivilegedBoolean(final String property_name) { Boolean value = (Boolean)AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return new Boolean(Boolean.getBoolean(property_name)); } }); return value.booleanValue(); } private static void initControls() { // Automatically create mouse, keyboard and controller if (!getPrivilegedBoolean("org.lwjgl.opengl.Display.noinput")) { if (!Mouse.isCreated() && !getPrivilegedBoolean("org.lwjgl.opengl.Display.nomouse")) { try { Mouse.create(); } catch (LWJGLException e) { if (LWJGLUtil.DEBUG) { e.printStackTrace(System.err); } else { LWJGLUtil.log("Failed to create Mouse: "+e); } } } if (!Keyboard.isCreated() && !getPrivilegedBoolean("org.lwjgl.opengl.Display.nokeyboard")) { try { Keyboard.create(); } catch (LWJGLException e) { if (LWJGLUtil.DEBUG) { e.printStackTrace(System.err); } else { LWJGLUtil.log("Failed to create Keyboard: "+e); } } } } } /** * Destroy the Display. After this call, there will be no current GL rendering context, * regardless of whether the Display was the current rendering context. */ public static void destroy() { synchronized (GlobalLock.lock) { if (!isCreated()) { return; } destroyWindow(); destroyContext(); destroyPeerInfo(); x = y = -1; cached_icons = null; reset(); removeShutdownHook(); } } private static void destroyPeerInfo() { peer_info.destroy(); peer_info = null; } private static void destroyContext() { try { context.forceDestroy(); } catch (LWJGLException e) { throw new RuntimeException(e); } finally { context = null; } } /* * Reset display mode if fullscreen. This method is also called from the shutdown hook added * in the static constructor */ private static void reset() { display_impl.resetDisplayMode(); current_mode = initial_mode; } /** * @return true if the window's native peer has been created */ public static boolean isCreated() { synchronized (GlobalLock.lock) { return window_created; } } /** * Set the buffer swap interval. This call is a best-attempt at changing * the monitor swap interval, which is the minimum periodicity of color buffer swaps, * measured in video frame periods, and is not guaranteed to be successful. * * A video frame period is the time required to display a full frame of video data. * * @param value The swap interval in frames, 0 to disable */ public static void setSwapInterval(int value) { synchronized (GlobalLock.lock) { swap_interval = value; if (isCreated()) Context.setSwapInterval(swap_interval); } } /** * Enable or disable vertical monitor synchronization. This call is a best-attempt at changing * the vertical refresh synchronization of the monitor, and is not guaranteed to be successful. * @param sync true to synchronize; false to ignore synchronization */ public static void setVSyncEnabled(boolean sync) { synchronized (GlobalLock.lock) { setSwapInterval(sync ? 1 : 0); } } /** * Set the window's location. This is a no-op on fullscreen windows or when getParent() != null. * The window is clamped to remain entirely on the screen. If you attempt * to position the window such that it would extend off the screen, the window * is simply placed as close to the edge as possible. *
noteIf no location has been specified (or x == y == -1) the window will be centered * @param new_x The new window location on the x axis * @param new_y The new window location on the y axis */ public static void setLocation(int new_x, int new_y) { synchronized (GlobalLock.lock) { if (fullscreen) { return; } // cache position x = new_x; y = new_y; // offset if already created if(isCreated()) { reshape(); } } } private static void reshape() { DisplayMode mode = getEffectiveMode(); display_impl.reshape(getWindowX(), getWindowY(), mode.getWidth(), mode.getHeight()); } /** * Get the driver adapter string. This is a unique string describing the actual card's hardware, eg. "Geforce2", "PS2", * "Radeon9700". If the adapter cannot be determined, this function returns null. * @return a String */ public static String getAdapter() { synchronized (GlobalLock.lock) { return display_impl.getAdapter(); } } /** * Get the driver version. This is a vendor/adapter specific version string. If the version cannot be determined, * this function returns null. * @return a String */ public static String getVersion() { synchronized (GlobalLock.lock) { return display_impl.getVersion(); } } /** * Sets one or more icons for the Display. *

* The implementation will use the supplied ByteBuffers with image data in RGBA and perform any conversions nescesarry for the specific platform. *

* NOTE: The display will make a deep copy of the supplied byte buffer array, for the purpose * of recreating the icons when you go back and forth fullscreen mode. You therefore only need to * set the icon once per instance. * * @param icons Array of icons in RGBA mode. Pass the icons in order of preference. * @return number of icons used, or 0 if display hasn't been created */ public static int setIcon(ByteBuffer[] icons) { synchronized (GlobalLock.lock) { // make deep copy so we dont rely on the supplied buffers later on // don't recache! if(cached_icons != icons) { cached_icons = new ByteBuffer[icons.length]; for(int i=0;i