Path: blob/master/SLICK_HOME/src/org/newdawn/slick/AppGameContainer.java
1456 views
package org.newdawn.slick;12import java.io.IOException;3import java.io.OutputStream;4import java.nio.ByteBuffer;5import java.security.AccessController;6import java.security.PrivilegedAction;78import org.lwjgl.BufferUtils;9import org.lwjgl.LWJGLException;10import org.lwjgl.Sys;11import org.lwjgl.input.Cursor;12import org.lwjgl.input.Mouse;13import org.lwjgl.openal.AL;14import org.lwjgl.opengl.Display;15import org.lwjgl.opengl.DisplayMode;16import org.lwjgl.opengl.PixelFormat;17import org.newdawn.slick.openal.SoundStore;18import org.newdawn.slick.opengl.CursorLoader;19import org.newdawn.slick.opengl.ImageData;20import org.newdawn.slick.opengl.ImageIOImageData;21import org.newdawn.slick.opengl.InternalTextureLoader;22import org.newdawn.slick.opengl.LoadableImageData;23import org.newdawn.slick.opengl.TGAImageData;24import org.newdawn.slick.util.Log;25import org.newdawn.slick.util.ResourceLoader;2627/**28* A game container that will display the game as an stand alone29* application.30*31* @author kevin32*/33public class AppGameContainer extends GameContainer {34static {35AccessController.doPrivileged(new PrivilegedAction() {36public Object run() {37try {38Display.getDisplayMode();39} catch (Exception e) {40Log.error(e);41}42return null;43}});44}4546/** The original display mode before we tampered with things */47protected DisplayMode originalDisplayMode;48/** The display mode we're going to try and use */49protected DisplayMode targetDisplayMode;50/** True if we should update the game only when the display is visible */51protected boolean updateOnlyOnVisible = true;52/** Alpha background supported */53protected boolean alphaSupport = false;5455/**56* Create a new container wrapping a game57*58* @param game The game to be wrapped59* @throws SlickException Indicates a failure to initialise the display60*/61public AppGameContainer(Game game) throws SlickException {62this(game,640,480,false);63}6465/**66* Create a new container wrapping a game67*68* @param game The game to be wrapped69* @param width The width of the display required70* @param height The height of the display required71* @param fullscreen True if we want fullscreen mode72* @throws SlickException Indicates a failure to initialise the display73*/74public AppGameContainer(Game game,int width,int height,boolean fullscreen) throws SlickException {75super(game);7677originalDisplayMode = Display.getDisplayMode();7879setDisplayMode(width,height,fullscreen);80}8182/**83* Check if the display created supported alpha in the back buffer84*85* @return True if the back buffer supported alpha86*/87public boolean supportsAlphaInBackBuffer() {88return alphaSupport;89}9091/**92* Set the title of the window93*94* @param title The title to set on the window95*/96public void setTitle(String title) {97Display.setTitle(title);98}99100/**101* Set the display mode to be used102*103* @param width The width of the display required104* @param height The height of the display required105* @param fullscreen True if we want fullscreen mode106* @throws SlickException Indicates a failure to initialise the display107*/108public void setDisplayMode(int width, int height, boolean fullscreen) throws SlickException {109if ((this.width == width) && (this.height == height) && (isFullscreen() == fullscreen)) {110return;111}112113try {114targetDisplayMode = null;115if (fullscreen) {116DisplayMode[] modes = Display.getAvailableDisplayModes();117int freq = 0;118119for (int i=0;i<modes.length;i++) {120DisplayMode current = modes[i];121122if ((current.getWidth() == width) && (current.getHeight() == height)) {123if ((targetDisplayMode == null) || (current.getFrequency() >= freq)) {124if ((targetDisplayMode == null) || (current.getBitsPerPixel() > targetDisplayMode.getBitsPerPixel())) {125targetDisplayMode = current;126freq = targetDisplayMode.getFrequency();127}128}129130// if we've found a match for bpp and frequence against the131// original display mode then it's probably best to go for this one132// since it's most likely compatible with the monitor133if ((current.getBitsPerPixel() == originalDisplayMode.getBitsPerPixel()) &&134(current.getFrequency() == originalDisplayMode.getFrequency())) {135targetDisplayMode = current;136break;137}138}139}140} else {141targetDisplayMode = new DisplayMode(width,height);142}143144if (targetDisplayMode == null) {145throw new SlickException("Failed to find value mode: "+width+"x"+height+" fs="+fullscreen);146}147148this.width = width;149this.height = height;150151Display.setDisplayMode(targetDisplayMode);152Display.setFullscreen(fullscreen);153154if (Display.isCreated()) {155initGL();156enterOrtho();157}158159if (targetDisplayMode.getBitsPerPixel() == 16) {160InternalTextureLoader.get().set16BitMode();161}162} catch (LWJGLException e) {163throw new SlickException("Unable to setup mode "+width+"x"+height+" fullscreen="+fullscreen, e);164}165166getDelta();167}168169/**170* Check if the display is in fullscreen mode171*172* @return True if the display is in fullscreen mode173*/174public boolean isFullscreen() {175return Display.isFullscreen();176}177178/**179* Indicate whether we want to be in fullscreen mode. Note that the current180* display mode must be valid as a fullscreen mode for this to work181*182* @param fullscreen True if we want to be in fullscreen mode183* @throws SlickException Indicates we failed to change the display mode184*/185public void setFullscreen(boolean fullscreen) throws SlickException {186if (isFullscreen() == fullscreen) {187return;188}189190if (!fullscreen) {191try {192Display.setFullscreen(fullscreen);193} catch (LWJGLException e) {194throw new SlickException("Unable to set fullscreen="+fullscreen, e);195}196} else {197setDisplayMode(width, height, fullscreen);198}199getDelta();200}201202/**203* @see org.newdawn.slick.GameContainer#setMouseCursor(java.lang.String, int, int)204*/205public void setMouseCursor(String ref, int hotSpotX, int hotSpotY) throws SlickException {206try {207Cursor cursor = CursorLoader.get().getCursor(ref, hotSpotX, hotSpotY);208Mouse.setNativeCursor(cursor);209} catch (Exception e) {210Log.error("Failed to load and apply cursor.", e);211}212}213214/**215* @see org.newdawn.slick.GameContainer#setMouseCursor(org.newdawn.slick.opengl.ImageData, int, int)216*/217public void setMouseCursor(ImageData data, int hotSpotX, int hotSpotY) throws SlickException {218try {219Cursor cursor = CursorLoader.get().getCursor(data, hotSpotX, hotSpotY);220Mouse.setNativeCursor(cursor);221} catch (Exception e) {222Log.error("Failed to load and apply cursor.", e);223}224}225226/**227* @see org.newdawn.slick.GameContainer#setMouseCursor(org.lwjgl.input.Cursor, int, int)228*/229public void setMouseCursor(Cursor cursor, int hotSpotX, int hotSpotY) throws SlickException {230try {231Mouse.setNativeCursor(cursor);232} catch (Exception e) {233Log.error("Failed to load and apply cursor.", e);234}235}236237/**238* Get the closest greater power of 2 to the fold number239*240* @param fold The target number241* @return The power of 2242*/243private int get2Fold(int fold) {244int ret = 2;245while (ret < fold) {246ret *= 2;247}248return ret;249}250251/**252* @see org.newdawn.slick.GameContainer#setMouseCursor(org.newdawn.slick.Image, int, int)253*/254public void setMouseCursor(Image image, int hotSpotX, int hotSpotY) throws SlickException {255try {256Image temp = new Image(get2Fold(image.getWidth()), get2Fold(image.getHeight()));257Graphics g = temp.getGraphics();258259ByteBuffer buffer = BufferUtils.createByteBuffer(temp.getWidth() * temp.getHeight() * 4);260g.drawImage(image.getFlippedCopy(false, true), 0, 0);261g.flush();262g.getArea(0,0,temp.getWidth(),temp.getHeight(),buffer);263264Cursor cursor = CursorLoader.get().getCursor(buffer, hotSpotX, hotSpotY,temp.getWidth(),image.getHeight());265Mouse.setNativeCursor(cursor);266} catch (Exception e) {267Log.error("Failed to load and apply cursor.", e);268}269}270271/**272* @see org.newdawn.slick.GameContainer#reinit()273*/274public void reinit() throws SlickException {275InternalTextureLoader.get().clear();276SoundStore.get().clear();277initSystem();278enterOrtho();279280try {281game.init(this);282} catch (SlickException e) {283Log.error(e);284running = false;285}286}287288/**289* Try creating a display with the given format290*291* @param format The format to attempt292* @throws LWJGLException Indicates a failure to support the given format293*/294private void tryCreateDisplay(PixelFormat format) throws LWJGLException {295296if (SHARED_DRAWABLE == null)297{298Display.create(format);299}300else301{302Display.create(format, SHARED_DRAWABLE);303}304}305306/**307* Start running the game308*309* @throws SlickException Indicates a failure to initialise the system310*/311public void start() throws SlickException {312try {313setup();314315getDelta();316while (running()) {317gameLoop();318}319} finally {320destroy();321}322323if (forceExit) {324System.exit(0);325}326}327328/**329* Setup the environment330*331* @throws SlickException Indicates a failure332*/333protected void setup() throws SlickException {334if (targetDisplayMode == null) {335setDisplayMode(640,480,false);336}337338Display.setTitle(game.getTitle());339340Log.info("LWJGL Version: "+Sys.getVersion());341Log.info("OriginalDisplayMode: "+originalDisplayMode);342Log.info("TargetDisplayMode: "+targetDisplayMode);343344AccessController.doPrivileged(new PrivilegedAction() {345public Object run() {346try {347PixelFormat format = new PixelFormat(8,8,0,samples);348349tryCreateDisplay(format);350supportsMultiSample = true;351} catch (Exception e) {352Display.destroy();353354try {355PixelFormat format = new PixelFormat(8,8,0);356357tryCreateDisplay(format);358alphaSupport = false;359} catch (Exception e2) {360Display.destroy();361// if we couldn't get alpha, let us know362try {363tryCreateDisplay(new PixelFormat());364} catch (Exception e3) {365Log.error(e3);366}367}368}369370return null;371}});372373if (!Display.isCreated()) {374throw new SlickException("Failed to initialise the LWJGL display");375}376377initSystem();378enterOrtho();379380try {381getInput().initControllers();382} catch (SlickException e) {383Log.info("Controllers not available");384} catch (Throwable e) {385Log.info("Controllers not available");386}387388try {389game.init(this);390} catch (SlickException e) {391Log.error(e);392running = false;393}394}395396/**397* Strategy for overloading game loop context handling398*399* @throws SlickException Indicates a game failure400*/401protected void gameLoop() throws SlickException {402int delta = getDelta();403if (!Display.isVisible() && updateOnlyOnVisible) {404try { Thread.sleep(100); } catch (Exception e) {}405} else {406try {407updateAndRender(delta);408} catch (SlickException e) {409Log.error(e);410running = false;411return;412}413}414415updateFPS();416417Display.update();418419if (Display.isCloseRequested()) {420if (game.closeRequested()) {421running = false;422}423}424}425426/**427* @see org.newdawn.slick.GameContainer#setUpdateOnlyWhenVisible(boolean)428*/429public void setUpdateOnlyWhenVisible(boolean updateOnlyWhenVisible) {430updateOnlyOnVisible = updateOnlyWhenVisible;431}432433/**434* @see org.newdawn.slick.GameContainer#isUpdatingOnlyWhenVisible()435*/436public boolean isUpdatingOnlyWhenVisible() {437return updateOnlyOnVisible;438}439440/**441* @see org.newdawn.slick.GameContainer#setIcon(java.lang.String)442*/443public void setIcon(String ref) throws SlickException {444setIcons(new String[] {ref});445}446447/**448* @see org.newdawn.slick.GameContainer#setMouseGrabbed(boolean)449*/450public void setMouseGrabbed(boolean grabbed) {451Mouse.setGrabbed(grabbed);452}453454/**455* @see org.newdawn.slick.GameContainer#isMouseGrabbed()456*/457public boolean isMouseGrabbed() {458return Mouse.isGrabbed();459}460461/**462* @see org.newdawn.slick.GameContainer#hasFocus()463*/464public boolean hasFocus() {465// hmm, not really the right thing, talk to the LWJGL guys466return Display.isActive();467}468469/**470* @see org.newdawn.slick.GameContainer#getScreenHeight()471*/472public int getScreenHeight() {473return originalDisplayMode.getHeight();474}475476/**477* @see org.newdawn.slick.GameContainer#getScreenWidth()478*/479public int getScreenWidth() {480return originalDisplayMode.getWidth();481}482483/**484* Destroy the app game container485*/486public void destroy() {487Display.destroy();488AL.destroy();489}490491/**492* A null stream to clear out those horrid errors493*494* @author kevin495*/496private class NullOutputStream extends OutputStream {497/**498* @see java.io.OutputStream#write(int)499*/500public void write(int b) throws IOException {501// null implemetnation502}503504}505506/**507* @see org.newdawn.slick.GameContainer#setIcons(java.lang.String[])508*/509public void setIcons(String[] refs) throws SlickException {510ByteBuffer[] bufs = new ByteBuffer[refs.length];511for (int i=0;i<refs.length;i++) {512LoadableImageData data;513boolean flip = true;514515if (refs[i].endsWith(".tga")) {516data = new TGAImageData();517} else {518flip = false;519data = new ImageIOImageData();520}521522try {523bufs[i] = data.loadImage(ResourceLoader.getResourceAsStream(refs[i]), flip, false, null);524} catch (Exception e) {525Log.error(e);526throw new SlickException("Failed to set the icon");527}528}529530Display.setIcon(bufs);531}532533/**534* @see org.newdawn.slick.GameContainer#setDefaultMouseCursor()535*/536public void setDefaultMouseCursor() {537try {538Mouse.setNativeCursor(null);539} catch (LWJGLException e) {540Log.error("Failed to reset mouse cursor", e);541}542}543}544545546