package org.newdawn.slick;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Cursor;
import org.lwjgl.input.Mouse;
import org.lwjgl.openal.AL;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;
import org.newdawn.slick.openal.SoundStore;
import org.newdawn.slick.opengl.CursorLoader;
import org.newdawn.slick.opengl.ImageData;
import org.newdawn.slick.opengl.ImageIOImageData;
import org.newdawn.slick.opengl.InternalTextureLoader;
import org.newdawn.slick.opengl.LoadableImageData;
import org.newdawn.slick.opengl.TGAImageData;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
/**
* A game container that will display the game as an stand alone application.
*
* @author kevin
*/
public class AppGameContainer extends GameContainer {
static {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
Display.getDisplayMode();
} catch (Exception e) {
Log.error(e);
}
return null;
}
});
}
/** The original display mode before we tampered with things */
protected DisplayMode originalDisplayMode;
/** The display mode we're going to try and use */
protected DisplayMode targetDisplayMode;
/** True if we should update the game only when the display is visible */
protected boolean updateOnlyOnVisible = true;
/** Alpha background supported */
protected boolean alphaSupport = true;
/**
* Create a new container wrapping a game
*
* @param game
* The game to be wrapped
* @throws SlickException
* Indicates a failure to initialise the display
*/
public AppGameContainer(Game game) throws SlickException {
this(game, 640, 480, false);
}
/**
* Create a new container wrapping a game
*
* @param game
* The game to be wrapped
* @param width
* The width of the display required
* @param height
* The height of the display required
* @param fullscreen
* True if we want fullscreen mode
* @throws SlickException
* Indicates a failure to initialise the display
*/
public AppGameContainer(Game game, int width, int height, boolean fullscreen)
throws SlickException {
super(game);
originalDisplayMode = Display.getDisplayMode();
setDisplayMode(width, height, fullscreen);
}
/**
* Check if the display created supported alpha in the back buffer
*
* @return True if the back buffer supported alpha
*/
public boolean supportsAlphaInBackBuffer() {
return alphaSupport;
}
/**
* Set the title of the window
*
* @param title
* The title to set on the window
*/
public void setTitle(String title) {
Display.setTitle(title);
}
/**
* Set the display mode to be used
*
* @param width
* The width of the display required
* @param height
* The height of the display required
* @param fullscreen
* True if we want fullscreen mode
* @throws SlickException
* Indicates a failure to initialise the display
*/
public void setDisplayMode(int width, int height, boolean fullscreen)
throws SlickException {
if ((this.width == width) && (this.height == height)
&& (isFullscreen() == fullscreen)) {
return;
}
try {
targetDisplayMode = null;
if (fullscreen) {
DisplayMode[] modes = Display.getAvailableDisplayModes();
int freq = 0;
for (int i = 0; i < modes.length; i++) {
DisplayMode current = modes[i];
if ((current.getWidth() == width)
&& (current.getHeight() == height)) {
if ((targetDisplayMode == null)
|| (current.getFrequency() >= freq)) {
if ((targetDisplayMode == null)
|| (current.getBitsPerPixel() > targetDisplayMode
.getBitsPerPixel())) {
targetDisplayMode = current;
freq = targetDisplayMode.getFrequency();
}
}
// if we've found a match for bpp and frequence against
// the
// original display mode then it's probably best to go
// for this one
// since it's most likely compatible with the monitor
if ((current.getBitsPerPixel() == originalDisplayMode
.getBitsPerPixel())
&& (current.getFrequency() == originalDisplayMode
.getFrequency())) {
targetDisplayMode = current;
break;
}
}
}
} else {
targetDisplayMode = new DisplayMode(width, height);
}
if (targetDisplayMode == null) {
throw new SlickException("Failed to find value mode: " + width
+ "x" + height + " fs=" + fullscreen);
}
this.width = width;
this.height = height;
Display.setDisplayMode(targetDisplayMode);
Display.setFullscreen(fullscreen);
if (Display.isCreated()) {
initGL();
enterOrtho();
}
if (targetDisplayMode.getBitsPerPixel() == 16) {
InternalTextureLoader.get().set16BitMode();
}
} catch (LWJGLException e) {
throw new SlickException("Unable to setup mode " + width + "x"
+ height + " fullscreen=" + fullscreen, e);
}
getDelta();
}
/**
* Check if the display is in fullscreen mode
*
* @return True if the display is in fullscreen mode
*/
public boolean isFullscreen() {
return Display.isFullscreen();
}
/**
* 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 {
if (isFullscreen() == fullscreen) {
return;
}
if (!fullscreen) {
try {
Display.setFullscreen(fullscreen);
} catch (LWJGLException e) {
throw new SlickException("Unable to set fullscreen="
+ fullscreen, e);
}
} else {
setDisplayMode(width, height, fullscreen);
}
getDelta();
}
/**
* @see org.newdawn.slick.GameContainer#setMouseCursor(java.lang.String,
* int, int)
*/
public void setMouseCursor(String ref, int hotSpotX, int hotSpotY)
throws SlickException {
try {
Cursor cursor = CursorLoader.get().getCursor(ref, hotSpotX,
hotSpotY);
Mouse.setNativeCursor(cursor);
} catch (Exception e) {
Log.error("Failed to load and apply cursor.", e);
}
}
/**
* @see org.newdawn.slick.GameContainer#setMouseCursor(org.newdawn.slick.opengl.ImageData,
* int, int)
*/
public void setMouseCursor(ImageData data, int hotSpotX, int hotSpotY)
throws SlickException {
try {
Cursor cursor = CursorLoader.get().getCursor(data, hotSpotX,
hotSpotY);
Mouse.setNativeCursor(cursor);
} catch (Exception e) {
Log.error("Failed to load and apply cursor.", e);
}
}
/**
* @see org.newdawn.slick.GameContainer#setMouseCursor(org.lwjgl.input.Cursor,
* int, int)
*/
public void setMouseCursor(Cursor cursor, int hotSpotX, int hotSpotY)
throws SlickException {
try {
Mouse.setNativeCursor(cursor);
} catch (Exception e) {
Log.error("Failed to load and apply cursor.", e);
}
}
/**
* @see org.newdawn.slick.GameContainer#setMouseCursor(org.newdawn.slick.Image,
* int, int)
*/
public void setMouseCursor(Image image, int hotSpotX, int hotSpotY)
throws SlickException {
try {
ByteBuffer buffer = ByteBuffer.allocate(image.getWidth()
* image.getHeight() * 4);
image.getGraphics().getArea(0, 0, image.getWidth(),
image.getHeight(), buffer);
Cursor cursor = CursorLoader.get().getCursor(buffer, hotSpotX,
hotSpotY, image.getWidth(), image.getHeight());
Mouse.setNativeCursor(cursor);
} catch (Exception e) {
Log.error("Failed to load and apply cursor.", e);
}
}
/**
* @see org.newdawn.slick.GameContainer#reinit()
*/
public void reinit() throws SlickException {
InternalTextureLoader.get().clear();
SoundStore.get().clear();
initSystem();
enterOrtho();
try {
game.init(this);
} catch (SlickException e) {
Log.error(e);
running = false;
}
}
/**
* Start running the game
*
* @throws SlickException
* Indicates a failure to initialise the system
*/
public void start() throws SlickException {
try {
if (targetDisplayMode == null) {
setDisplayMode(640, 480, false);
}
Display.setTitle(game.getTitle());
Log.info("LWJGL Version: " + Sys.getVersion());
Log.info("OriginalDisplayMode: " + originalDisplayMode);
Log.info("TargetDisplayMode: " + targetDisplayMode);
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
int sample=8;
PixelFormat format;
while (!Display.isCreated()) {
try {
format = new PixelFormat(8, 8, 0,sample);
if (SHARED_DRAWABLE == null) {
Display.create(format);
} else {
Display.create(format, SHARED_DRAWABLE);
}
//System.out.println("Samples:"+sample);
} catch (Exception e) {
if(sample%2!=0)
sample--;
else
sample-=2;
if(sample<0) break;
//Log.error(e);
}
}
if (!Display.isCreated()) {
alphaSupport = false;
Display.destroy();
try {
if (SHARED_DRAWABLE == null) {
Display.create();
} else {
Display.create(new PixelFormat(),SHARED_DRAWABLE);
}
} catch (Exception x) {
Log.error(x);
}
}
return null;
}
});
if (!Display.isCreated()) {
throw new SlickException(
"Failed to initialise the LWJGL display");
}
initSystem();
enterOrtho();
try {
getInput().initControllers();
} catch (SlickException e) {
Log.info("Controllers not available");
} catch (Throwable e) {
Log.info("Controllers not available");
}
try {
game.init(this);
} catch (SlickException e) {
Log.error(e);
running = false;
}
getDelta();
while (running()) {
int delta = getDelta();
if(delta>60)delta = 60;
if (!Display.isVisible() && updateOnlyOnVisible) {
try {
Thread.sleep(100);
} catch (Exception e) {
}
} else {
try {
updateAndRender(delta);
} catch (SlickException e) {
Log.error(e);
showError(e);
running = false;
break;
}
}
updateFPS();
Display.update();
if (Display.isCloseRequested()) {
if (game.closeRequested()) {
running = false;
}
}
}
} finally {
AL.destroy();
Display.destroy();
}
if (forceExit) {
System.exit(0);
}
}
/**
* @see org.newdawn.slick.GameContainer#setUpdateOnlyWhenVisible(boolean)
*/
public void setUpdateOnlyWhenVisible(boolean updateOnlyWhenVisible) {
updateOnlyOnVisible = updateOnlyWhenVisible;
}
/**
* @see org.newdawn.slick.GameContainer#isUpdatingOnlyWhenVisible()
*/
public boolean isUpdatingOnlyWhenVisible() {
return updateOnlyOnVisible;
}
/**
* @see org.newdawn.slick.GameContainer#setIcon(java.lang.String)
*/
public void setIcon(String ref) throws SlickException {
setIcons(new String[] { ref });
}
/**
* @see org.newdawn.slick.GameContainer#setMouseGrabbed(boolean)
*/
public void setMouseGrabbed(boolean grabbed) {
Mouse.setGrabbed(grabbed);
}
/**
* @see org.newdawn.slick.GameContainer#hasFocus()
*/
public boolean hasFocus() {
// hmm, not really the right thing, talk to the LWJGL guys
return Display.isVisible();
}
/**
* @see org.newdawn.slick.GameContainer#getScreenHeight()
*/
public int getScreenHeight() {
return originalDisplayMode.getHeight();
}
/**
* @see org.newdawn.slick.GameContainer#getScreenWidth()
*/
public int getScreenWidth() {
return originalDisplayMode.getWidth();
}
/**
* Destroy the app game container
*/
public void destroy() {
Display.destroy();
AL.destroy();
}
/**
* A null stream to clear out those horrid errors
*
* @author kevin
*/
private class NullOutputStream extends OutputStream {
/**
* @see java.io.OutputStream#write(int)
*/
public void write(int b) throws IOException {
// null implemetnation
}
}
/**
* @see org.newdawn.slick.GameContainer#setIcons(java.lang.String[])
*/
public void setIcons(String[] refs) throws SlickException {
ByteBuffer[] bufs = new ByteBuffer[refs.length];
for (int i = 0; i < refs.length; i++) {
LoadableImageData data;
boolean flip = true;
if (refs[i].endsWith(".tga")) {
data = new TGAImageData();
} else {
flip = false;
data = new ImageIOImageData();
}
try {
bufs[i] = data.loadImage(ResourceLoader
.getResourceAsStream(refs[i]), flip, false, null);
} catch (Exception e) {
Log.error(e);
throw new SlickException("Failed to set the icon");
}
}
Display.setIcon(bufs);
}
/**
* @see org.newdawn.slick.GameContainer#setDefaultMouseCursor()
*/
public void setDefaultMouseCursor() {
try {
Mouse.setNativeCursor(null);
} catch (LWJGLException e) {
Log.error("Failed to reset mouse cursor", e);
}
}
public void showError(Exception e){
StringWriter w = new StringWriter();
PrintWriter out = new PrintWriter(w);
e.printStackTrace(out);
JTextPane txt = new JTextPane();
txt.setText(w.toString());
javax.swing.JOptionPane.showMessageDialog(null,new JScrollPane(txt),e.getMessage(),javax.swing.JOptionPane.ERROR_MESSAGE);
}
}