Path: blob/master/SLICK_HOME/src/org/newdawn/slick/AppletGameContainer.java
1456 views
package org.newdawn.slick;12import java.applet.Applet;3import java.awt.BorderLayout;4import java.awt.Canvas;5import java.awt.Color;6import java.awt.Font;7import java.awt.GridLayout;8import java.awt.Label;9import java.awt.Panel;10import java.awt.TextArea;11import java.io.PrintWriter;12import java.io.StringWriter;13import java.nio.ByteBuffer;1415import org.lwjgl.BufferUtils;16import org.lwjgl.LWJGLException;17import org.lwjgl.input.Cursor;18import org.lwjgl.input.Mouse;19import org.lwjgl.opengl.Display;20import org.lwjgl.opengl.GL11;21import org.lwjgl.opengl.PixelFormat;22import org.newdawn.slick.openal.SoundStore;23import org.newdawn.slick.opengl.CursorLoader;24import org.newdawn.slick.opengl.ImageData;25import org.newdawn.slick.opengl.InternalTextureLoader;26import org.newdawn.slick.util.Log;2728/**29* A game container that displays the game as an applet. Note however that the30* actual game container implementation is an internal class which can be31* obtained with the getContainer() method - this is due to the Applet being a32* class wrap than an interface.33*34* @author kevin35*/36public class AppletGameContainer extends Applet {37/** The GL Canvas used for this container */38protected ContainerPanel canvas;39/** The actual container implementation */40protected Container container;41/** The parent of the display */42protected Canvas displayParent;43/** The thread that is looping for the game */44protected Thread gameThread;45/** Alpha background supported */46protected boolean alphaSupport = true;4748/**49* @see java.applet.Applet#destroy()50*/51public void destroy() {52if (displayParent != null) {53remove(displayParent);54}55super.destroy();5657Log.info("Clear up");58}5960/**61* Clean up the LWJGL resources62*/63private void destroyLWJGL() {64container.stopApplet();6566try {67gameThread.join();68} catch (InterruptedException e) {69Log.error(e);70}71}7273/**74* @see java.applet.Applet#start()75*/76public void start() {7778}7980/**81* Start a thread to run LWJGL in82*/83public void startLWJGL() {84if (gameThread != null) {85return;86}8788gameThread = new Thread() {89public void run() {90try {91canvas.start();92}93catch (Exception e) {94e.printStackTrace();95if (Display.isCreated()) {96Display.destroy();97}98displayParent.setVisible(false);//removeAll();99add(new ConsolePanel(e));100validate();101}102}103};104105gameThread.start();106}107108/**109* @see java.applet.Applet#stop()110*/111public void stop() {112}113114/**115* @see java.applet.Applet#init()116*/117public void init() {118removeAll();119setLayout(new BorderLayout());120setIgnoreRepaint(true);121122try {123Game game = (Game) Class.forName(getParameter("game")).newInstance();124125container = new Container(game);126canvas = new ContainerPanel(container);127displayParent = new Canvas() {128public final void addNotify() {129super.addNotify();130startLWJGL();131}132public final void removeNotify() {133destroyLWJGL();134super.removeNotify();135}136137};138139displayParent.setSize(getWidth(), getHeight());140add(displayParent);141displayParent.setFocusable(true);142displayParent.requestFocus();143displayParent.setIgnoreRepaint(true);144setVisible(true);145} catch (Exception e) {146Log.error(e);147throw new RuntimeException("Unable to create game container");148}149}150151/**152* Get the GameContainer providing this applet153*154* @return The game container providing this applet155*/156public GameContainer getContainer() {157return container;158}159160/**161* Create a new panel to display the GL context162*163* @author kevin164*/165public class ContainerPanel {166/** The container being displayed on this canvas */167private Container container;168169/**170* Create a new panel171*172* @param container The container we're running173*/174public ContainerPanel(Container container) {175this.container = container;176}177178/**179* Create the LWJGL display180*181* @throws Exception Failure to create display182*/183private void createDisplay() throws Exception {184try {185// create display with alpha186Display.create(new PixelFormat(8,8,0));187alphaSupport = true;188} catch (Exception e) {189// if we couldn't get alpha, let us know190alphaSupport = false;191Display.destroy();192// create display without alpha193Display.create();194}195}196197/**198* Start the game container199*200* @throws Exception Failure to create display201*/202public void start() throws Exception {203Display.setParent(displayParent);204Display.setVSyncEnabled(true);205206try {207createDisplay();208} catch (LWJGLException e) {209e.printStackTrace();210// failed to create Display, apply workaround (sleep for 1 second) and try again211Thread.sleep(1000);212createDisplay();213}214215initGL();216displayParent.requestFocus();217container.runloop();218}219220/**221* Initialise GL state222*/223protected void initGL() {224try {225InternalTextureLoader.get().clear();226SoundStore.get().clear();227228container.initApplet();229} catch (Exception e) {230Log.error(e);231container.stopApplet();232}233}234}235236/**237* A game container to provide the applet context238*239* @author kevin240*/241public class Container extends GameContainer {242/**243* Create a new container wrapped round the game244*245* @param game The game to be held in this container246*/247public Container(Game game) {248super(game);249250width = AppletGameContainer.this.getWidth();251height = AppletGameContainer.this.getHeight();252}253254/**255* Initiliase based on Applet init256*257* @throws SlickException Indicates a failure to inialise the basic framework258*/259public void initApplet() throws SlickException {260initSystem();261enterOrtho();262263try {264getInput().initControllers();265} catch (SlickException e) {266Log.info("Controllers not available");267} catch (Throwable e) {268Log.info("Controllers not available");269}270271game.init(this);272getDelta();273}274275/**276* Check if the applet is currently running277*278* @return True if the applet is running279*/280public boolean isRunning() {281return running;282}283284/**285* Stop the applet play back286*/287public void stopApplet() {288running = false;289}290291/**292* @see org.newdawn.slick.GameContainer#getScreenHeight()293*/294public int getScreenHeight() {295return 0;296}297298/**299* @see org.newdawn.slick.GameContainer#getScreenWidth()300*/301public int getScreenWidth() {302return 0;303}304305/**306* Check if the display created supported alpha in the back buffer307*308* @return True if the back buffer supported alpha309*/310public boolean supportsAlphaInBackBuffer() {311return alphaSupport;312}313314/**315* @see org.newdawn.slick.GameContainer#hasFocus()316*/317public boolean hasFocus() {318return true;319}320321/**322* Returns the Applet Object323* @return Applet Object324*/325public Applet getApplet() {326return AppletGameContainer.this;327}328329/**330* @see org.newdawn.slick.GameContainer#setIcon(java.lang.String)331*/332public void setIcon(String ref) throws SlickException {333// unsupported in an applet334}335336/**337* @see org.newdawn.slick.GameContainer#setMouseGrabbed(boolean)338*/339public void setMouseGrabbed(boolean grabbed) {340Mouse.setGrabbed(grabbed);341}342343/**344* @see org.newdawn.slick.GameContainer#isMouseGrabbed()345*/346public boolean isMouseGrabbed() {347return Mouse.isGrabbed();348}349350/**351* @see org.newdawn.slick.GameContainer#setMouseCursor(java.lang.String,352* int, int)353*/354public void setMouseCursor(String ref, int hotSpotX, int hotSpotY) throws SlickException {355try {356Cursor cursor = CursorLoader.get().getCursor(ref, hotSpotX, hotSpotY);357Mouse.setNativeCursor(cursor);358} catch (Exception e) {359Log.error("Failed to load and apply cursor.", e);360}361}362363/**364* Get the closest greater power of 2 to the fold number365*366* @param fold The target number367* @return The power of 2368*/369private int get2Fold(int fold) {370int ret = 2;371while (ret < fold) {372ret *= 2;373}374return ret;375}376377/**378* {@inheritDoc}379*/380public void setMouseCursor(Image image, int hotSpotX, int hotSpotY) throws SlickException {381try {382Image temp = new Image(get2Fold(image.getWidth()), get2Fold(image.getHeight()));383Graphics g = temp.getGraphics();384385ByteBuffer buffer = BufferUtils.createByteBuffer(temp.getWidth() * temp.getHeight() * 4);386g.drawImage(image.getFlippedCopy(false, true), 0, 0);387g.flush();388g.getArea(0,0,temp.getWidth(),temp.getHeight(),buffer);389390Cursor cursor = CursorLoader.get().getCursor(buffer, hotSpotX, hotSpotY,temp.getWidth(),temp.getHeight());391Mouse.setNativeCursor(cursor);392} catch (Exception e) {393Log.error("Failed to load and apply cursor.", e);394}395}396397/**398* @see org.newdawn.slick.GameContainer#setIcons(java.lang.String[])399*/400public void setIcons(String[] refs) throws SlickException {401// unsupported in an applet402}403404/**405* @see org.newdawn.slick.GameContainer#setMouseCursor(org.newdawn.slick.opengl.ImageData, int, int)406*/407public void setMouseCursor(ImageData data, int hotSpotX, int hotSpotY) throws SlickException {408try {409Cursor cursor = CursorLoader.get().getCursor(data, hotSpotX, hotSpotY);410Mouse.setNativeCursor(cursor);411} catch (Exception e) {412Log.error("Failed to load and apply cursor.", e);413}414}415416/**417* @see org.newdawn.slick.GameContainer#setMouseCursor(org.lwjgl.input.Cursor, int, int)418*/419public void setMouseCursor(Cursor cursor, int hotSpotX, int hotSpotY) throws SlickException {420try {421Mouse.setNativeCursor(cursor);422} catch (Exception e) {423Log.error("Failed to load and apply cursor.", e);424}425}426427/**428* @see org.newdawn.slick.GameContainer#setDefaultMouseCursor()429*/430public void setDefaultMouseCursor() {431}432433public boolean isFullscreen() {434return Display.isFullscreen();435}436437public void setFullscreen(boolean fullscreen) throws SlickException {438if (fullscreen == isFullscreen()) {439return;440}441442try {443if (fullscreen) {444// get current screen resolution445int screenWidth = Display.getDisplayMode().getWidth();446int screenHeight = Display.getDisplayMode().getHeight();447448// calculate aspect ratio449float gameAspectRatio = (float) width / height;450float screenAspectRatio = (float) screenWidth451/ screenHeight;452453int newWidth;454int newHeight;455456// get new screen resolution to match aspect ratio457458if (gameAspectRatio >= screenAspectRatio) {459newWidth = screenWidth;460newHeight = (int) (height / ((float) width / screenWidth));461} else {462newWidth = (int) (width / ((float) height / screenHeight));463newHeight = screenHeight;464}465466// center new screen467int xoffset = (screenWidth - newWidth) / 2;468int yoffset = (screenHeight - newHeight) / 2;469470// scale game to match new resolution471GL11.glViewport(xoffset, yoffset, newWidth, newHeight);472473enterOrtho();474475// fix input to match new resolution476this.getInput().setOffset(477-xoffset * (float) width / newWidth,478-yoffset * (float) height / newHeight);479480this.getInput().setScale((float) width / newWidth,481(float) height / newHeight);482483width = screenWidth;484height = screenHeight;485Display.setFullscreen(true);486} else {487// restore input488this.getInput().setOffset(0, 0);489this.getInput().setScale(1, 1);490width = AppletGameContainer.this.getWidth();491height = AppletGameContainer.this.getHeight();492GL11.glViewport(0, 0, width, height);493494enterOrtho();495496Display.setFullscreen(false);497}498} catch (LWJGLException e) {499Log.error(e);500}501502}503504/**505* The running game loop506*507* @throws Exception Indicates a failure within the game's loop rather than the framework508*/509public void runloop() throws Exception {510while (running) {511int delta = getDelta();512513updateAndRender(delta);514515updateFPS();516Display.update();517}518519Display.destroy();520}521}522523/**524* A basic console to display an error message if the applet crashes.525* This will prevent the applet from just freezing in the browser526* and give the end user an a nice gui where the error message can easily527* be viewed and copied.528*/529public class ConsolePanel extends Panel {530/** The area display the console output */531TextArea textArea = new TextArea();532533/**534* Create a new panel to display the console output535*536* @param e The exception causing the console to be displayed537*/538public ConsolePanel(Exception e) {539setLayout(new BorderLayout());540setBackground(Color.black);541setForeground(Color.white);542543Font consoleFont = new Font("Arial", Font.BOLD, 14);544545Label slickLabel = new Label("SLICK CONSOLE", Label.CENTER);546slickLabel.setFont(consoleFont);547add(slickLabel, BorderLayout.PAGE_START);548549StringWriter sw = new StringWriter();550e.printStackTrace(new PrintWriter(sw));551552textArea.setText(sw.toString());553textArea.setEditable(false);554add(textArea, BorderLayout.CENTER);555556// add a border on both sides of the console557add(new Panel(), BorderLayout.LINE_START);558add(new Panel(), BorderLayout.LINE_END);559560Panel bottomPanel = new Panel();561bottomPanel.setLayout(new GridLayout(0, 1));562Label infoLabel1 = new Label("An error occured while running the applet.", Label.CENTER);563Label infoLabel2 = new Label("Plese contact support to resolve this issue.", Label.CENTER);564infoLabel1.setFont(consoleFont);565infoLabel2.setFont(consoleFont);566bottomPanel.add(infoLabel1);567bottomPanel.add(infoLabel2);568add(bottomPanel, BorderLayout.PAGE_END);569}570}571}572573