From 9138b70a246a44c7fe465f0ac4f8e58cd1dfb05d Mon Sep 17 00:00:00 2001 From: Jeffrey Han Date: Fri, 6 Mar 2015 19:16:43 -0500 Subject: [PATCH] Minor GameContainer changes. Added copy of GameContainer.java: - updateAndRender() no longer calls Log.error(), and re-throws the original exception as a SlickException. This prevents errors from being logged twice, and now the relevant one is shown in the error popup (instead of a useless "failure" message). - getBuildVersion() no longer calls Log.error(), and removed slick build information from "version" file. Signed-off-by: Jeffrey Han --- pom.xml | 1 + res/version | 4 - src/itdelatrisu/opsu/Container.java | 33 +- src/org/newdawn/slick/GameContainer.java | 907 +++++++++++++++++++++++ 4 files changed, 931 insertions(+), 14 deletions(-) create mode 100644 src/org/newdawn/slick/GameContainer.java diff --git a/pom.xml b/pom.xml index 9ab36367..473658a8 100644 --- a/pom.xml +++ b/pom.xml @@ -112,6 +112,7 @@ org.slick2d:slick2d-core + org/newdawn/slick/GameContainer.* org/newdawn/slick/Image.* org/newdawn/slick/Music.* org/newdawn/slick/openal/AudioInputStream* diff --git a/res/version b/res/version index 11f63e48..006a1cd5 100644 --- a/res/version +++ b/res/version @@ -1,6 +1,2 @@ -# opsu! build info version=${pom.version} build.date=${timestamp} - -# slick build -build=237 diff --git a/src/itdelatrisu/opsu/Container.java b/src/itdelatrisu/opsu/Container.java index 8bb87adc..b56ae1e3 100644 --- a/src/itdelatrisu/opsu/Container.java +++ b/src/itdelatrisu/opsu/Container.java @@ -21,6 +21,7 @@ package itdelatrisu.opsu; import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.downloads.DownloadList; +import org.lwjgl.opengl.Display; import org.newdawn.slick.AppGameContainer; import org.newdawn.slick.Game; import org.newdawn.slick.SlickException; @@ -79,6 +80,28 @@ public class Container extends AppGameContainer { Opsu.exit(); } + @Override + protected void gameLoop() throws SlickException { + int delta = getDelta(); + if (!Display.isVisible() && updateOnlyOnVisible) { + try { Thread.sleep(100); } catch (Exception e) {} + } else { + try { + updateAndRender(delta); + } catch (SlickException e) { + this.e = e; // store exception to display later + running = false; + return; + } + } + updateFPS(); + Display.update(); + if (Display.isCloseRequested()) { + if (game.closeRequested()) + running = false; + } + } + /** * Actions to perform before destroying the game container. */ @@ -102,16 +125,6 @@ public class Container extends AppGameContainer { OsuGroupList.get().reset(); } - @Override - protected void updateAndRender(int delta) throws SlickException { - try { - super.updateAndRender(delta); - } catch (SlickException e) { - this.e = e; // store exception to display later - throw e; // re-throw exception - } - } - @Override public void exit() { // show confirmation dialog if any downloads are active diff --git a/src/org/newdawn/slick/GameContainer.java b/src/org/newdawn/slick/GameContainer.java new file mode 100644 index 00000000..3c6cff2d --- /dev/null +++ b/src/org/newdawn/slick/GameContainer.java @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2013, Slick2D + * 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 the Slick2D 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.newdawn.slick; + +import java.io.IOException; +import java.util.Properties; + +import org.lwjgl.LWJGLException; +import org.lwjgl.Sys; +import org.lwjgl.input.Cursor; +import org.lwjgl.opengl.Display; +import org.lwjgl.opengl.Drawable; +import org.lwjgl.opengl.Pbuffer; +import org.lwjgl.opengl.PixelFormat; +import org.newdawn.slick.gui.GUIContext; +import org.newdawn.slick.openal.SoundStore; +import org.newdawn.slick.opengl.CursorLoader; +import org.newdawn.slick.opengl.ImageData; +import org.newdawn.slick.opengl.renderer.Renderer; +import org.newdawn.slick.opengl.renderer.SGL; +import org.newdawn.slick.util.Log; +import org.newdawn.slick.util.ResourceLoader; + +/** + * A generic game container that handles the game loop, fps recording and + * managing the input system + * + * @author kevin + */ +public abstract class GameContainer implements GUIContext { + /** The renderer to use for all GL operations */ + protected static SGL GL = Renderer.get(); + /** The shared drawable if any */ + protected static Drawable SHARED_DRAWABLE; + + /** The time the last frame was rendered */ + protected long lastFrame; + /** The last time the FPS recorded */ + protected long lastFPS; + /** The last recorded FPS */ + protected int recordedFPS; + /** The current count of FPS */ + protected int fps; + /** True if we're currently running the game loop */ + protected boolean running = true; + + /** The width of the display */ + protected int width; + /** The height of the display */ + protected int height; + /** The game being managed */ + protected Game game; + + /** The default font to use in the graphics context */ + private Font defaultFont; + /** The graphics context to be passed to the game */ + private Graphics graphics; + + /** The input system to pass to the game */ + protected Input input; + /** The FPS we want to lock to */ + protected int targetFPS = -1; + /** True if we should show the fps */ + private boolean showFPS = true; + /** The minimum logic update interval */ + protected long minimumLogicInterval = 1; + /** The stored delta */ + protected long storedDelta; + /** The maximum logic update interval */ + protected long maximumLogicInterval = 0; + /** The last game started */ + protected Game lastGame; + /** True if we should clear the screen each frame */ + protected boolean clearEachFrame = true; + + /** True if the game is paused */ + protected boolean paused; + /** True if we should force exit */ + protected boolean forceExit = true; + /** True if vsync has been requested */ + protected boolean vsync; + /** Smoothed deltas requested */ + protected boolean smoothDeltas; + /** The number of samples we'll attempt through hardware */ + protected int samples; + + /** True if this context supports multisample */ + protected boolean supportsMultiSample; + + /** True if we should render when not focused */ + protected boolean alwaysRender; + /** True if we require stencil bits */ + protected static boolean stencil; + + /** + * Create a new game container wrapping a given game + * + * @param game The game to be wrapped + */ + protected GameContainer(Game game) { + this.game = game; + lastFrame = getTime(); + + getBuildVersion(); + Log.checkVerboseLogSetting(); + } + + public static void enableStencil() { + stencil = true; + } + + /** + * Set the default font that will be intialised in the graphics held in this container + * + * @param font The font to use as default + */ + public void setDefaultFont(Font font) { + if (font != null) { + this.defaultFont = font; + } else { + Log.warn("Please provide a non null font"); + } + } + + /** + * Indicate whether we want to try to use fullscreen multisampling. This will + * give antialiasing across the whole scene using a hardware feature. + * + * @param samples The number of samples to attempt (2 is safe) + */ + public void setMultiSample(int samples) { + this.samples = samples; + } + + /** + * Check if this hardware can support multi-sampling + * + * @return True if the hardware supports multi-sampling + */ + public boolean supportsMultiSample() { + return supportsMultiSample; + } + + /** + * The number of samples we're attempting to performing using + * hardware multisampling + * + * @return The number of samples requested + */ + public int getSamples() { + return samples; + } + + /** + * Indicate if we should force exitting the VM at the end + * of the game (default = true) + * + * @param forceExit True if we should force the VM exit + */ + public void setForceExit(boolean forceExit) { + this.forceExit = forceExit; + } + + /** + * Indicate if we want to smooth deltas. This feature will report + * a delta based on the FPS not the time passed. This works well with + * vsync. + * + * @param smoothDeltas True if we should report smooth deltas + */ + public void setSmoothDeltas(boolean smoothDeltas) { + this.smoothDeltas = smoothDeltas; + } + + /** + * Check if the display is in fullscreen mode + * + * @return True if the display is in fullscreen mode + */ + public boolean isFullscreen() { + return false; + } + + /** + * Get the aspect ratio of the screen + * + * @return The aspect ratio of the display + */ + public float getAspectRatio() { + return getWidth() / getHeight(); + } + + /** + * Indicate whether we want to be in fullscreen mode. Note that the current + * display mode must be valid as a fullscreen mode for this to work + * + * @param fullscreen True if we want to be in fullscreen mode + * @throws SlickException Indicates we failed to change the display mode + */ + public void setFullscreen(boolean fullscreen) throws SlickException { + } + + /** + * Enable shared OpenGL context. After calling this all containers created + * will shared a single parent context + * + * @throws SlickException Indicates a failure to create the shared drawable + */ + public static void enableSharedContext() throws SlickException { + try { + SHARED_DRAWABLE = new Pbuffer(64, 64, new PixelFormat(8, 0, 0), null); + } catch (LWJGLException e) { + throw new SlickException("Unable to create the pbuffer used for shard context, buffers not supported", e); + } + } + + /** + * Get the context shared by all containers + * + * @return The context shared by all the containers or null if shared context isn't enabled + */ + public static Drawable getSharedContext() { + return SHARED_DRAWABLE; + } + + /** + * Indicate if we should clear the screen at the beginning of each frame. If you're + * rendering to the whole screen each frame then setting this to false can give + * some performance improvements + * + * @param clear True if the the screen should be cleared each frame + */ + public void setClearEachFrame(boolean clear) { + this.clearEachFrame = clear; + } + + /** + * Renitialise the game and the context in which it's being rendered + * + * @throws SlickException Indicates a failure rerun initialisation routines + */ + public void reinit() throws SlickException { + } + + /** + * Pause the game - i.e. suspend updates + */ + public void pause() + { + setPaused(true); + } + + /** + * Resumt the game - i.e. continue updates + */ + public void resume() + { + setPaused(false); + } + + /** + * Check if the container is currently paused. + * + * @return True if the container is paused + */ + public boolean isPaused() { + return paused; + } + + /** + * Indicates if the game should be paused, i.e. if updates + * should be propogated through to the game. + * + * @param paused True if the game should be paused + */ + public void setPaused(boolean paused) + { + this.paused = paused; + } + + /** + * True if this container should render when it has focus + * + * @return True if this container should render when it has focus + */ + public boolean getAlwaysRender () { + return alwaysRender; + } + + /** + * Indicate whether we want this container to render when it has focus + * + * @param alwaysRender True if this container should render when it has focus + */ + public void setAlwaysRender (boolean alwaysRender) { + this.alwaysRender = alwaysRender; + } + + /** + * Get the build number of slick + * + * @return The build number of slick + */ + public static int getBuildVersion() { + try { + Properties props = new Properties(); + props.load(ResourceLoader.getResourceAsStream("version")); + + int build = Integer.parseInt(props.getProperty("build")); + Log.info("Slick Build #"+build); + + return build; + } catch (Exception e) { + Log.info("Unable to determine Slick build number"); + return -1; + } + } + + /** + * Get the default system font + * + * @return The default system font + */ + @Override + public Font getDefaultFont() { + return defaultFont; + } + + /** + * Check if sound effects are enabled + * + * @return True if sound effects are enabled + */ + public boolean isSoundOn() { + return SoundStore.get().soundsOn(); + } + + /** + * Check if music is enabled + * + * @return True if music is enabled + */ + public boolean isMusicOn() { + return SoundStore.get().musicOn(); + } + + /** + * Indicate whether music should be enabled + * + * @param on True if music should be enabled + */ + public void setMusicOn(boolean on) { + SoundStore.get().setMusicOn(on); + } + + /** + * Indicate whether sound effects should be enabled + * + * @param on True if sound effects should be enabled + */ + public void setSoundOn(boolean on) { + SoundStore.get().setSoundsOn(on); + } + + /** + * Retrieve the current default volume for music + * @return the current default volume for music + */ + public float getMusicVolume() { + return SoundStore.get().getMusicVolume(); + } + + /** + * Retrieve the current default volume for sound fx + * @return the current default volume for sound fx + */ + public float getSoundVolume() { + return SoundStore.get().getSoundVolume(); + } + + /** + * Set the default volume for sound fx + * @param volume the new default value for sound fx volume + */ + public void setSoundVolume(float volume) { + SoundStore.get().setSoundVolume(volume); + } + + /** + * Set the default volume for music + * @param volume the new default value for music volume + */ + public void setMusicVolume(float volume) { + SoundStore.get().setMusicVolume(volume); + } + + /** + * Get the width of the standard screen resolution + * + * @return The screen width + */ + @Override + public abstract int getScreenWidth(); + + /** + * Get the height of the standard screen resolution + * + * @return The screen height + */ + @Override + public abstract int getScreenHeight(); + + /** + * Get the width of the game canvas + * + * @return The width of the game canvas + */ + @Override + public int getWidth() { + return width; + } + + /** + * Get the height of the game canvas + * + * @return The height of the game canvas + */ + @Override + public int getHeight() { + return height; + } + + /** + * Set the icon to be displayed if possible in this type of + * container + * + * @param ref The reference to the icon to be displayed + * @throws SlickException Indicates a failure to load the icon + */ + public abstract void setIcon(String ref) throws SlickException; + + /** + * Set the icons to be used for this application. Note that the size of the icon + * defines how it will be used. Important ones to note + * + * Windows window icon must be 16x16 + * Windows alt-tab icon must be 24x24 or 32x32 depending on Windows version (XP=32) + * + * @param refs The reference to the icon to be displayed + * @throws SlickException Indicates a failure to load the icon + */ + public abstract void setIcons(String[] refs) throws SlickException; + + /** + * Get the accurate system time + * + * @return The system time in milliseconds + */ + @Override + public long getTime() { + return (Sys.getTime() * 1000) / Sys.getTimerResolution(); + } + + /** + * Sleep for a given period + * + * @param milliseconds The period to sleep for in milliseconds + */ + public void sleep(int milliseconds) { + long target = getTime()+milliseconds; + while (getTime() < target) { + try { Thread.sleep(1); } catch (Exception e) {} + } + } + + /** + * Set the mouse cursor to be displayed - this is a hardware cursor and hence + * shouldn't have any impact on FPS. + * + * @param ref The location of the image to be loaded for the cursor + * @param hotSpotX The x coordinate of the hotspot within the cursor image + * @param hotSpotY The y coordinate of the hotspot within the cursor image + * @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor + */ + @Override + public abstract void setMouseCursor(String ref, int hotSpotX, int hotSpotY) throws SlickException; + + /** + * Set the mouse cursor to be displayed - this is a hardware cursor and hence + * shouldn't have any impact on FPS. + * + * @param data The image data from which the cursor can be construted + * @param hotSpotX The x coordinate of the hotspot within the cursor image + * @param hotSpotY The y coordinate of the hotspot within the cursor image + * @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor + */ + @Override + public abstract void setMouseCursor(ImageData data, int hotSpotX, int hotSpotY) throws SlickException; + + /** + * Set the mouse cursor based on the contents of the image. Note that this will not take + * account of render state type changes to images (rotation and such). If these effects + * are required it is recommended that an offscreen buffer be used to produce an appropriate + * image. An offscreen buffer will always be used to produce the new cursor and as such + * this operation an be very expensive + * + * @param image The image to use as the cursor + * @param hotSpotX The x coordinate of the hotspot within the cursor image + * @param hotSpotY The y coordinate of the hotspot within the cursor image + * @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor + */ + public abstract void setMouseCursor(Image image, int hotSpotX, int hotSpotY) throws SlickException; + + /** + * Set the mouse cursor to be displayed - this is a hardware cursor and hence + * shouldn't have any impact on FPS. + * + * @param cursor The cursor to use + * @param hotSpotX The x coordinate of the hotspot within the cursor image + * @param hotSpotY The y coordinate of the hotspot within the cursor image + * @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor + */ + @Override + public abstract void setMouseCursor(Cursor cursor, int hotSpotX, int hotSpotY) throws SlickException; + + /** + * Get a cursor based on a image reference on the classpath. The image + * is assumed to be a set/strip of cursor animation frames running from top to + * bottom. + * + * @param ref The reference to the image to be loaded + * @param x The x-coordinate of the cursor hotspot (left -> right) + * @param y The y-coordinate of the cursor hotspot (bottom -> top) + * @param width The x width of the cursor + * @param height The y height of the cursor + * @param cursorDelays image delays between changing frames in animation + * + * @throws SlickException Indicates a failure to load the image or a failure to create the hardware cursor + */ + public void setAnimatedMouseCursor(String ref, int x, int y, int width, int height, int[] cursorDelays) throws SlickException + { + try { + Cursor cursor; + cursor = CursorLoader.get().getAnimatedCursor(ref, x, y, width, height, cursorDelays); + setMouseCursor(cursor, x, y); + } catch (IOException e) { + throw new SlickException("Failed to set mouse cursor", e); + } catch (LWJGLException e) { + throw new SlickException("Failed to set mouse cursor", e); + } + } + + /** + * Set the default mouse cursor - i.e. the original cursor before any native + * cursor was set + */ + @Override + public abstract void setDefaultMouseCursor(); + + /** + * Get the input system + * + * @return The input system available to this game container + */ + @Override + public Input getInput() { + return input; + } + + /** + * Get the current recorded FPS (frames per second) + * + * @return The current FPS + */ + public int getFPS() { + return recordedFPS; + } + + /** + * Indicate whether mouse cursor should be grabbed or not + * + * @param grabbed True if mouse cursor should be grabbed + */ + public abstract void setMouseGrabbed(boolean grabbed); + + /** + * Check if the mouse cursor is current grabbed. This will cause it not + * to be seen. + * + * @return True if the mouse is currently grabbed + */ + public abstract boolean isMouseGrabbed(); + + /** + * Retrieve the time taken to render the last frame, i.e. the change in time - delta. + * + * @return The time taken to render the last frame + */ + protected int getDelta() { + long time = getTime(); + int delta = (int) (time - lastFrame); + lastFrame = time; + + return delta; + } + + /** + * Updated the FPS counter + */ + protected void updateFPS() { + if (getTime() - lastFPS > 1000) { + lastFPS = getTime(); + recordedFPS = fps; + fps = 0; + } + fps++; + } + + /** + * Set the minimum amount of time in milliseonds that has to + * pass before update() is called on the container game. This gives + * a way to limit logic updates compared to renders. + * + * @param interval The minimum interval between logic updates + */ + public void setMinimumLogicUpdateInterval(int interval) { + minimumLogicInterval = interval; + } + + /** + * Set the maximum amount of time in milliseconds that can passed + * into the update method. Useful for collision detection without + * sweeping. + * + * @param interval The maximum interval between logic updates + */ + public void setMaximumLogicUpdateInterval(int interval) { + maximumLogicInterval = interval; + } + + /** + * Update and render the game + * + * @param delta The change in time since last update and render + * @throws SlickException Indicates an internal fault to the game. + */ + protected void updateAndRender(int delta) throws SlickException { + if (smoothDeltas) { + if (getFPS() != 0) { + delta = 1000 / getFPS(); + } + } + + input.poll(width, height); + + Music.poll(delta); + if (!paused) { + storedDelta += delta; + + if (storedDelta >= minimumLogicInterval) { + try { + if (maximumLogicInterval != 0) { + long cycles = storedDelta / maximumLogicInterval; + for (int i=0;i minimumLogicInterval) { + game.update(this, (int) (remainder % maximumLogicInterval)); + storedDelta = 0; + } else { + storedDelta = remainder; + } + } else { + game.update(this, (int) storedDelta); + storedDelta = 0; + } + + } catch (Throwable e) { +// Log.error(e); + throw new SlickException("Game.update() failure.", e); + } + } + } else { + game.update(this, 0); + } + + if (hasFocus() || getAlwaysRender()) { + if (clearEachFrame) { + GL.glClear(SGL.GL_COLOR_BUFFER_BIT | SGL.GL_DEPTH_BUFFER_BIT); + } + + GL.glLoadIdentity(); + + graphics.resetTransform(); + graphics.resetFont(); + graphics.resetLineWidth(); + graphics.setAntiAlias(false); + try { + game.render(this, graphics); + } catch (Throwable e) { +// Log.error(e); + throw new SlickException("Game.render() failure.", e); + } + graphics.resetTransform(); + + if (showFPS) { + defaultFont.drawString(10, 10, "FPS: "+recordedFPS); + } + + GL.flush(); + } + + if (targetFPS != -1) { + Display.sync(targetFPS); + } + } + + /** + * Indicate if the display should update only when the game is visible + * (the default is true) + * + * @param updateOnlyWhenVisible True if we should updated only when the display is visible + */ + public void setUpdateOnlyWhenVisible(boolean updateOnlyWhenVisible) { + } + + /** + * Check if this game is only updating when visible to the user (default = true) + * + * @return True if the game is only updated when the display is visible + */ + public boolean isUpdatingOnlyWhenVisible() { + return true; + } + + /** + * Initialise the GL context + */ + protected void initGL() { + Log.info("Starting display "+width+"x"+height); + GL.initDisplay(width, height); + + if (input == null) { + input = new Input(height); + } + input.init(height); + // no need to remove listeners? + //input.removeAllListeners(); + if (game instanceof InputListener) { + input.removeListener((InputListener) game); + input.addListener((InputListener) game); + } + + if (graphics != null) { + graphics.setDimensions(getWidth(), getHeight()); + } + lastGame = game; + } + + /** + * Initialise the system components, OpenGL and OpenAL. + * + * @throws SlickException Indicates a failure to create a native handler + */ + protected void initSystem() throws SlickException { + initGL(); + setMusicVolume(1.0f); + setSoundVolume(1.0f); + + graphics = new Graphics(width, height); + defaultFont = graphics.getFont(); + } + + /** + * Enter the orthographic mode + */ + protected void enterOrtho() { + enterOrtho(width, height); + } + + /** + * Indicate whether the container should show the FPS + * + * @param show True if the container should show the FPS + */ + public void setShowFPS(boolean show) { + showFPS = show; + } + + /** + * Check if the FPS is currently showing + * + * @return True if the FPS is showing + */ + public boolean isShowingFPS() { + return showFPS; + } + + /** + * Set the target fps we're hoping to get + * + * @param fps The target fps we're hoping to get + */ + public void setTargetFrameRate(int fps) { + targetFPS = fps; + } + + /** + * Indicate whether the display should be synced to the + * vertical refresh (stops tearing) + * + * @param vsync True if we want to sync to vertical refresh + */ + public void setVSync(boolean vsync) { + this.vsync = vsync; + Display.setVSyncEnabled(vsync); + } + + /** + * True if vsync is requested + * + * @return True if vsync is requested + */ + public boolean isVSyncRequested() { + return vsync; + } + + /** + * True if the game is running + * + * @return True if the game is running + */ + protected boolean running() { + return running; + } + + /** + * Inidcate we want verbose logging + * + * @param verbose True if we want verbose logging (INFO and DEBUG) + */ + public void setVerbose(boolean verbose) { + Log.setVerbose(verbose); + } + + /** + * Cause the game to exit and shutdown cleanly + */ + public void exit() { + running = false; + } + + /** + * Check if the game currently has focus + * + * @return True if the game currently has focus + */ + public abstract boolean hasFocus(); + + /** + * Get the graphics context used by this container. Note that this + * value may vary over the life time of the game. + * + * @return The graphics context used by this container + */ + public Graphics getGraphics() { + return graphics; + } + + /** + * Enter the orthographic mode + * + * @param xsize The size of the panel being used + * @param ysize The size of the panel being used + */ + protected void enterOrtho(int xsize, int ysize) { + GL.enterOrtho(xsize, ysize); + } +}