All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.mathiewz.slick.AppletGameContainer Maven / Gradle / Ivy

Go to download

The main purpose of this libraryis to modernize and maintain the slick2D library.

The newest version!
package com.github.mathiewz.slick;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextArea;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.ByteBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Cursor;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.PixelFormat;

import com.github.mathiewz.slick.openal.SoundStore;
import com.github.mathiewz.slick.opengl.CursorLoader;
import com.github.mathiewz.slick.opengl.ImageData;
import com.github.mathiewz.slick.opengl.InternalTextureLoader;
import com.github.mathiewz.slick.util.Log;

/**
 * A game container that displays the game as an applet. Note however that the
 * actual game container implementation is an internal class which can be
 * obtained with the getContainer() method - this is due to the Applet being a
 * class wrap than an interface.
 *
 * @author kevin
 */
public class AppletGameContainer extends Applet {
    /** The GL Canvas used for this container */
    protected transient ContainerPanel canvas;
    /** The actual container implementation */
    protected transient Container container;
    /** The parent of the display */
    protected Canvas displayParent;
    /** The thread that is looping for the game */
    protected transient Thread gameThread;
    /** Alpha background supported */
    protected boolean alphaSupport = true;

    /**
     * @see java.applet.Applet#destroy()
     */
    @Override
    public void destroy() {
        if (displayParent != null) {
            remove(displayParent);
        }
        super.destroy();
        Log.info("Clear up");
    }

    /**
     * Clean up the LWJGL resources
     */
    private void destroyLWJGL() {
        container.stopApplet();

        try {
            gameThread.join();
        } catch (InterruptedException e) {
            Log.error(e);
        }
    }

    /**
     * Start a thread to run LWJGL in
     */
    public void startLWJGL() {
        if (gameThread != null) {
            return;
        }

        gameThread = new Thread() {
            @Override
            public void run() {
                try {
                    canvas.start();
                } catch (Exception e) {
                    Log.error(e);
                    if (Display.isCreated()) {
                        Display.destroy();
                    }
                    displayParent.setVisible(false);
                    add(new ConsolePanel(e));
                    validate();
                }
            }
        };

        gameThread.start();
    }

    /**
     * @see java.applet.Applet#init()
     */
    @Override
    public void init() {
        removeAll();
        setLayout(new BorderLayout());
        setIgnoreRepaint(true);

        try {
            Game game = (Game) Class.forName(getParameter("game")).newInstance();

            container = new Container(game);
            canvas = new ContainerPanel(container);
            displayParent = new Canvas() {
                @Override
                public final void addNotify() {
                    super.addNotify();
                    startLWJGL();
                }

                @Override
                public final void removeNotify() {
                    destroyLWJGL();
                    super.removeNotify();
                }

            };

            displayParent.setSize(getWidth(), getHeight());
            add(displayParent);
            displayParent.setFocusable(true);
            displayParent.requestFocus();
            displayParent.setIgnoreRepaint(true);
            setVisible(true);
        } catch (Exception e) {
            Log.error(e);
            throw new SlickException("Unable to create game container");
        }
    }

    /**
     * Create a new panel to display the GL context
     *
     * @author kevin
     */
    public class ContainerPanel {
        /** The container being displayed on this canvas */
        private final Container container;

        /**
         * Create a new panel
         *
         * @param container
         *            The container we're running
         */
        public ContainerPanel(Container container) {
            this.container = container;
        }

        /**
         * Create the LWJGL display
         *
         * @throws LWJGLException
         *
         * @throws Exception
         *             Failure to create display
         */
        private void createDisplay() throws LWJGLException {
            try {
                // create display with alpha
                Display.create(new PixelFormat(8, 8, GameContainer.stencil ? 8 : 0));
                alphaSupport = true;
            } catch (Exception e) {
                // if we couldn't get alpha, let us know
                alphaSupport = false;
                Display.destroy();
                // create display without alpha
                Display.create();
            }
        }

        /**
         * Start the game container
         */
        public void start() {

            try {
                Display.setParent(displayParent);
                Display.setVSyncEnabled(true);
                createDisplay();
            } catch (LWJGLException e) {
                Log.error(e);
                try {
                    Thread.sleep(1000);
                    createDisplay();
                } catch (InterruptedException | LWJGLException nestedEx) {
                    throw new SlickException("Failed to create display", nestedEx);
                }
            }

            initGL();
            displayParent.requestFocus();
            container.runloop();
        }

        /**
         * Initialise GL state
         */
        protected void initGL() {
            try {
                InternalTextureLoader.get().clear();
                SoundStore.get().clear();

                container.initApplet();
            } catch (Exception e) {
                Log.error(e);
                container.stopApplet();
            }
        }
    }

    /**
     * A game container to provide the applet context
     *
     * @author kevin
     */
    public class Container extends GameContainer {
        
        private static final String MOUSE_CURSOR_ERROR = "Failed to set mouse cursor";
        
        /**
         * Create a new container wrapped round the game
         *
         * @param game
         *            The game to be held in this container
         */
        public Container(Game game) {
            super(game);

            width = AppletGameContainer.this.getWidth();
            height = AppletGameContainer.this.getHeight();
        }

        /**
         * Initiliase based on Applet init
         *
         */
        public void initApplet() {
            initSystem();
            enterOrtho();

            try {
                getInput().initControllers();
            } catch (Exception e) {
                Log.info("Controllers not available");
            }
            
            game.init(this);
            getDelta();
        }

        /**
         * Check if the applet is currently running
         *
         * @return True if the applet is running
         */
        public boolean isRunning() {
            return running;
        }

        /**
         * Stop the applet play back
         */
        public void stopApplet() {
            running = false;
        }

        /**
         * @see com.github.mathiewz.slick.GameContainer#getScreenHeight()
         */
        @Override
        public int getScreenHeight() {
            return 0;
        }

        /**
         * @see com.github.mathiewz.slick.GameContainer#getScreenWidth()
         */
        @Override
        public int getScreenWidth() {
            return 0;
        }

        /**
         * Check if the display created supported alpha in the back buffer
         *
         * @return True if the back buffer supported alpha
         */
        public boolean supportsAlphaInBackBuffer() {
            return alphaSupport;
        }

        /**
         * @see com.github.mathiewz.slick.GameContainer#hasFocus()
         */
        @Override
        public boolean hasFocus() {
            return true;
        }

        /**
         * Returns the Applet Object
         *
         * @return Applet Object
         */
        public Applet getApplet() {
            return AppletGameContainer.this;
        }

        /**
         * @see com.github.mathiewz.slick.GameContainer#setIcon(java.lang.String)
         */
        @Override
        public void setIcon(String ref) {
            // unsupported in an applet
        }

        /**
         * @see com.github.mathiewz.slick.GameContainer#setMouseGrabbed(boolean)
         */
        @Override
        public void setMouseGrabbed(boolean grabbed) {
            Mouse.setGrabbed(grabbed);
        }

        /**
         * @see com.github.mathiewz.slick.GameContainer#isMouseGrabbed()
         */
        @Override
        public boolean isMouseGrabbed() {
            return Mouse.isGrabbed();
        }

        /**
         * @see com.github.mathiewz.slick.GameContainer#setMouseCursor(java.lang.String,
         *      int, int)
         */
        @Override
        public void setMouseCursor(String ref, int hotSpotX, int hotSpotY) {
            try {
                Cursor cursor = CursorLoader.get().getCursor(ref, hotSpotX, hotSpotY);
                Mouse.setNativeCursor(cursor);
            } catch (Exception e) {
                throw new SlickException(MOUSE_CURSOR_ERROR, e);
            }
        }

        /**
         * Get the closest greater power of 2 to the fold number
         *
         * @param fold
         *            The target number
         * @return The power of 2
         */
        private int get2Fold(int fold) {
            int ret = 2;
            while (ret < fold) {
                ret *= 2;
            }
            return ret;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void setMouseCursor(Image image, int hotSpotX, int hotSpotY) {
            try {
                Image temp = new Image(get2Fold(image.getWidth()), get2Fold(image.getHeight()));
                Graphics g = temp.getGraphics();

                ByteBuffer buffer = BufferUtils.createByteBuffer(temp.getWidth() * temp.getHeight() * 4);
                g.drawImage(image.getFlippedCopy(false, true), 0, 0);
                g.flush();
                g.getArea(0, 0, temp.getWidth(), temp.getHeight(), buffer);

                Cursor cursor = CursorLoader.get().getCursor(buffer, hotSpotX, hotSpotY, temp.getWidth(), temp.getHeight());
                Mouse.setNativeCursor(cursor);
            } catch (Exception e) {
                throw new SlickException(MOUSE_CURSOR_ERROR, e);
            }
        }

        /**
         * @see com.github.mathiewz.slick.GameContainer#setIcons(java.lang.String[])
         */
        @Override
        public void setIcons(String[] refs) {
            // unsupported in an applet
        }

        /**
         * @see com.github.mathiewz.slick.GameContainer#setMouseCursor(com.github.mathiewz.slick.opengl.ImageData, int, int)
         */
        @Override
        public void setMouseCursor(ImageData data, int hotSpotX, int hotSpotY) {
            try {
                Cursor cursor = CursorLoader.get().getCursor(data, hotSpotX, hotSpotY);
                Mouse.setNativeCursor(cursor);
            } catch (Exception e) {
                throw new SlickException(MOUSE_CURSOR_ERROR, e);
            }
        }

        /**
         * @see com.github.mathiewz.slick.GameContainer#setMouseCursor(org.lwjgl.input.Cursor, int, int)
         */
        @Override
        public void setMouseCursor(Cursor cursor, int hotSpotX, int hotSpotY) {
            try {
                Mouse.setNativeCursor(cursor);
            } catch (Exception e) {
                throw new SlickException(MOUSE_CURSOR_ERROR, e);
            }
        }

        /**
         * @see com.github.mathiewz.slick.GameContainer#setDefaultMouseCursor()
         */
        @Override
        public void setDefaultMouseCursor() {
            // Nothing to do here
        }

        @Override
        public boolean isFullscreen() {
            return Display.isFullscreen();
        }

        @Override
        public void setFullscreen(boolean fullscreen) {
            if (fullscreen == isFullscreen()) {
                return;
            }

            try {
                if (fullscreen) {
                    // get current screen resolution
                    int screenWidth = Display.getDisplayMode().getWidth();
                    int screenHeight = Display.getDisplayMode().getHeight();

                    // calculate aspect ratio
                    float gameAspectRatio = (float) width / height;
                    float screenAspectRatio = (float) screenWidth / screenHeight;

                    int newWidth;
                    int newHeight;

                    // get new screen resolution to match aspect ratio

                    if (gameAspectRatio >= screenAspectRatio) {
                        newWidth = screenWidth;
                        newHeight = (int) (height / ((float) width / screenWidth));
                    } else {
                        newWidth = (int) (width / ((float) height / screenHeight));
                        newHeight = screenHeight;
                    }

                    // center new screen
                    int xoffset = (screenWidth - newWidth) / 2;
                    int yoffset = (screenHeight - newHeight) / 2;

                    // scale game to match new resolution
                    GL11.glViewport(xoffset, yoffset, newWidth, newHeight);

                    enterOrtho();

                    // fix input to match new resolution
                    getInput().setOffset(-xoffset * (float) width / newWidth, -yoffset * (float) height / newHeight);

                    getInput().setScale((float) width / newWidth, (float) height / newHeight);

                    width = screenWidth;
                    height = screenHeight;
                    Display.setFullscreen(true);
                } else {
                    // restore input
                    getInput().setOffset(0, 0);
                    getInput().setScale(1, 1);
                    width = AppletGameContainer.this.getWidth();
                    height = AppletGameContainer.this.getHeight();
                    GL11.glViewport(0, 0, width, height);

                    enterOrtho();

                    Display.setFullscreen(false);
                }
            } catch (LWJGLException e) {
                Log.error(e);
            }

        }

        /**
         * The running game loop
         *
         */
        public void runloop() {
            while (running) {
                int delta = getDelta();

                updateAndRender(delta);

                updateFPS();
                Display.update();
            }

            Display.destroy();
        }
    }

    /**
     * A basic console to display an error message if the applet crashes.
     * This will prevent the applet from just freezing in the browser
     * and give the end user an a nice gui where the error message can easily
     * be viewed and copied.
     */
    public class ConsolePanel extends Panel {
        /** The area display the console output */
        TextArea textArea = new TextArea();

        /**
         * Create a new panel to display the console output
         *
         * @param e
         *            The exception causing the console to be displayed
         */
        public ConsolePanel(Exception e) {
            setLayout(new BorderLayout());
            setBackground(Color.black);
            setForeground(Color.white);

            Font consoleFont = new Font("Arial", Font.BOLD, 14);

            Label slickLabel = new Label("SLICK CONSOLE", Label.CENTER);
            slickLabel.setFont(consoleFont);
            add(slickLabel, BorderLayout.PAGE_START);

            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));

            textArea.setText(sw.toString());
            textArea.setEditable(false);
            add(textArea, BorderLayout.CENTER);

            // add a border on both sides of the console
            add(new Panel(), BorderLayout.LINE_START);
            add(new Panel(), BorderLayout.LINE_END);

            Panel bottomPanel = new Panel();
            bottomPanel.setLayout(new GridLayout(0, 1));
            Label infoLabel1 = new Label("An error occured while running the applet.", Label.CENTER);
            Label infoLabel2 = new Label("Plese contact support to resolve this issue.", Label.CENTER);
            infoLabel1.setFont(consoleFont);
            infoLabel2.setFont(consoleFont);
            bottomPanel.add(infoLabel1);
            bottomPanel.add(infoLabel2);
            add(bottomPanel, BorderLayout.PAGE_END);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy