mirror of
https://github.com/shadowfacts/lwjgl2-arm64.git
synced 2026-01-06 08:49:56 +01:00
space invaders example
This commit is contained in:
parent
7c20070bf8
commit
5aedbe9c7f
157
src/java/org/lwjgl/examples/spaceinvaders/AlienEntity.java
Normal file
157
src/java/org/lwjgl/examples/spaceinvaders/AlienEntity.java
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2004 LWJGL Project
|
||||
* 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 'LWJGL' 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.lwjgl.examples.spaceinvaders;
|
||||
|
||||
/**
|
||||
* An entity which represents one of our space invader aliens.
|
||||
*
|
||||
* @author Kevin Glass
|
||||
* @author Brian Matzon
|
||||
*/
|
||||
public class AlienEntity extends Entity {
|
||||
|
||||
/** Movement made downwards when a border is hit */
|
||||
private static final int DOWNWARD_MOVEMENT = 10;
|
||||
|
||||
/** Border at which player dies */
|
||||
private static final int BOTTOM_BORDER = 570;
|
||||
|
||||
/** Right border at which to shift direction */
|
||||
private static final int RIGHT_BORDER = 750;
|
||||
|
||||
/** Left border at which to shift direction */
|
||||
private static final int LEFT_BORDER = 10;
|
||||
|
||||
/** The speed at which the alient moves horizontally */
|
||||
private float moveSpeed = 75;
|
||||
|
||||
/** The game in which the entity exists */
|
||||
private Game game;
|
||||
|
||||
/** The animation frames */
|
||||
private Sprite[] frames = new Sprite[4];
|
||||
|
||||
/** The time since the last frame change took place */
|
||||
private long lastFrameChange;
|
||||
|
||||
/** The frame duration in milliseconds, i.e. how long any given frame of animation lasts */
|
||||
private long frameDuration = 250;
|
||||
|
||||
/** The current frame of animation being displayed */
|
||||
private int frameNumber;
|
||||
|
||||
/**
|
||||
* Create a new alien entity
|
||||
*
|
||||
* @param game The game in which this entity is being created
|
||||
* @param x The intial x location of this alien
|
||||
* @param y The intial y location of this alient
|
||||
*/
|
||||
public AlienEntity(Game game, int x, int y) {
|
||||
super(game.getSprite("alien.gif"), x, y);
|
||||
|
||||
// setup the animatin frames
|
||||
frames[0] = sprite;
|
||||
frames[1] = game.getSprite("alien2.gif");
|
||||
frames[2] = sprite;
|
||||
frames[3] = game.getSprite("alien3.gif");
|
||||
|
||||
this.game = game;
|
||||
dx = -moveSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that this alien moved based on time elapsed
|
||||
*
|
||||
* @param delta The time that has elapsed since last move
|
||||
*/
|
||||
public void move(long delta) {
|
||||
// since the move tells us how much time has passed
|
||||
// by we can use it to drive the animation, however
|
||||
// its the not the prettiest solution
|
||||
lastFrameChange += delta;
|
||||
|
||||
// if we need to change the frame, update the frame number
|
||||
// and flip over the sprite in use
|
||||
if (lastFrameChange > frameDuration) {
|
||||
// reset our frame change time counter
|
||||
lastFrameChange = 0;
|
||||
|
||||
// update the frame
|
||||
frameNumber++;
|
||||
if (frameNumber >= frames.length) {
|
||||
frameNumber = 0;
|
||||
}
|
||||
|
||||
sprite = frames[frameNumber];
|
||||
}
|
||||
|
||||
// if we have reached the left hand side of the screen and
|
||||
// are moving left then request a logic update
|
||||
if ((dx < 0) && (x < LEFT_BORDER)) {
|
||||
game.updateLogic();
|
||||
}
|
||||
// and vice vesa, if we have reached the right hand side of
|
||||
// the screen and are moving right, request a logic update
|
||||
if ((dx > 0) && (x > RIGHT_BORDER)) {
|
||||
game.updateLogic();
|
||||
}
|
||||
|
||||
// proceed with normal move
|
||||
super.move(delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the game logic related to aliens
|
||||
*/
|
||||
public void doLogic() {
|
||||
// swap over horizontal movement and move down the
|
||||
// screen a bit
|
||||
dx = -dx;
|
||||
y += DOWNWARD_MOVEMENT;
|
||||
|
||||
// if we've reached the bottom of the screen then the player
|
||||
// dies
|
||||
if (y > BOTTOM_BORDER) {
|
||||
game.notifyDeath();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that this alien has collided with another entity
|
||||
*
|
||||
* @param other The other entity
|
||||
*/
|
||||
public void collidedWith(Entity other) {
|
||||
// collisions with aliens are handled elsewhere
|
||||
}
|
||||
}
|
||||
184
src/java/org/lwjgl/examples/spaceinvaders/Entity.java
Normal file
184
src/java/org/lwjgl/examples/spaceinvaders/Entity.java
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2004 LWJGL Project
|
||||
* 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 'LWJGL' 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.lwjgl.examples.spaceinvaders;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
|
||||
/**
|
||||
* An entity represents any element that appears in the game. The
|
||||
* entity is responsible for resolving collisions and movement
|
||||
* based on a set of properties defined either by subclass or externally.
|
||||
*
|
||||
* Note that doubles are used for positions. This may seem strange
|
||||
* given that pixels locations are integers. However, using double means
|
||||
* that an entity can move a partial pixel. It doesn't of course mean that
|
||||
* they will be display half way through a pixel but allows us not lose
|
||||
* accuracy as we move.
|
||||
*
|
||||
* @author Kevin Glass
|
||||
*/
|
||||
public abstract class Entity {
|
||||
|
||||
/** The current x location of this entity */
|
||||
protected float x;
|
||||
|
||||
/** The current y location of this entity */
|
||||
protected float y;
|
||||
|
||||
/** The sprite that represents this entity */
|
||||
protected Sprite sprite;
|
||||
|
||||
/** The current speed of this entity horizontally (pixels/sec) */
|
||||
protected float dx;
|
||||
|
||||
/** The current speed of this entity vertically (pixels/sec) */
|
||||
protected float dy;
|
||||
|
||||
/** The rectangle used for this entity during collisions resolution */
|
||||
private Rectangle me = new Rectangle();
|
||||
|
||||
/** The rectangle used for other entities during collision resolution */
|
||||
private Rectangle him = new Rectangle();
|
||||
|
||||
/**
|
||||
* Construct a entity based on a sprite image and a location.
|
||||
*
|
||||
* @param ref The reference to the image to be displayed for this entity
|
||||
* @param x The initial x location of this entity
|
||||
* @param y The initial y location of this entity
|
||||
*/
|
||||
public Entity(Sprite sprite, int x, int y) {
|
||||
this.sprite = sprite;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that this entity move itself based on a certain ammount
|
||||
* of time passing.
|
||||
*
|
||||
* @param delta The ammount of time that has passed in milliseconds
|
||||
*/
|
||||
public void move(long delta) {
|
||||
// update the location of the entity based on move speeds
|
||||
x += (delta * dx) / 1000;
|
||||
y += (delta * dy) / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the horizontal speed of this entity
|
||||
*
|
||||
* @param dx The horizontal speed of this entity (pixels/sec)
|
||||
*/
|
||||
public void setHorizontalMovement(float dx) {
|
||||
this.dx = dx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the vertical speed of this entity
|
||||
*
|
||||
* @param dy The vertical speed of this entity (pixels/sec)
|
||||
*/
|
||||
public void setVerticalMovement(float dy) {
|
||||
this.dy = dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the horizontal speed of this entity
|
||||
*
|
||||
* @return The horizontal speed of this entity (pixels/sec)
|
||||
*/
|
||||
public float getHorizontalMovement() {
|
||||
return dx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the vertical speed of this entity
|
||||
*
|
||||
* @return The vertical speed of this entity (pixels/sec)
|
||||
*/
|
||||
public float getVerticalMovement() {
|
||||
return dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw this entity to the graphics context provided
|
||||
*/
|
||||
public void draw() {
|
||||
sprite.draw((int) x, (int) y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the logic associated with this entity. This method
|
||||
* will be called periodically based on game events
|
||||
*/
|
||||
public void doLogic() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the x location of this entity
|
||||
*
|
||||
* @return The x location of this entity
|
||||
*/
|
||||
public int getX() {
|
||||
return (int) x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the y location of this entity
|
||||
*
|
||||
* @return The y location of this entity
|
||||
*/
|
||||
public int getY() {
|
||||
return (int) y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this entity collised with another.
|
||||
*
|
||||
* @param other The other entity to check collision against
|
||||
* @return True if the entities collide with each other
|
||||
*/
|
||||
public boolean collidesWith(Entity other) {
|
||||
me.setBounds((int) x, (int) y, sprite.getWidth(), sprite.getHeight());
|
||||
him.setBounds((int) other.x, (int) other.y, other.sprite.getWidth(), other.sprite.getHeight());
|
||||
|
||||
return me.intersects(him);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that this entity collided with another.
|
||||
*
|
||||
* @param other The entity with which this entity collided.
|
||||
*/
|
||||
public abstract void collidedWith(Entity other);
|
||||
}
|
||||
607
src/java/org/lwjgl/examples/spaceinvaders/Game.java
Normal file
607
src/java/org/lwjgl/examples/spaceinvaders/Game.java
Normal file
|
|
@ -0,0 +1,607 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2004 LWJGL Project
|
||||
* 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 'LWJGL' 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.lwjgl.examples.spaceinvaders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.lwjgl.Display;
|
||||
import org.lwjgl.DisplayMode;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.Sys;
|
||||
import org.lwjgl.input.Controller;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.Window;
|
||||
|
||||
/**
|
||||
* The main hook of our game. This class with both act as a manager
|
||||
* for the display and central mediator for the game logic.
|
||||
*
|
||||
* Display management will consist of a loop that cycles round all
|
||||
* entities in the game asking them to move and then drawing them
|
||||
* in the appropriate place. With the help of an inner class it
|
||||
* will also allow the player to control the main ship.
|
||||
*
|
||||
* As a mediator it will be informed when entities within our game
|
||||
* detect events (e.g. alient killed, played died) and will take
|
||||
* appropriate game actions.
|
||||
*
|
||||
* <p>
|
||||
* NOTE:<br>
|
||||
* This game is a LWJGLized implementation of the Space Invaders game by Kevin
|
||||
* Glass. The original implementation is renderer agnostic and supports other
|
||||
* OpenGL implementations as well as Java2D. This version has been made specific
|
||||
* for LWJGL, and has added input control as well as sound (which the original doesn't,
|
||||
* at the time of writing).
|
||||
* You can find the original article here:<br>
|
||||
* <a href="http://www.cokeandcode.com/" target="_blank">http://www.cokeandcode.com</a>
|
||||
* </p>
|
||||
*
|
||||
* @author Kevin Glass
|
||||
* @author Brian Matzon
|
||||
*/
|
||||
public class Game {
|
||||
|
||||
/** The normal title of the window */
|
||||
private String WINDOW_TITLE = "Space Invaders 104 (for LWJGL)";
|
||||
|
||||
/** The width of the game display area */
|
||||
private int width = 800;
|
||||
|
||||
/** The height of the game display area */
|
||||
private int height = 600;
|
||||
|
||||
/** The loader responsible for converting images into OpenGL textures */
|
||||
private TextureLoader textureLoader;
|
||||
|
||||
/** The list of all the entities that exist in our game */
|
||||
private ArrayList entities = new ArrayList();
|
||||
|
||||
/** The list of entities that need to be removed from the game this loop */
|
||||
private ArrayList removeList = new ArrayList();
|
||||
|
||||
/** The entity representing the player */
|
||||
private ShipEntity ship;
|
||||
|
||||
/** List of shots */
|
||||
private ShotEntity[] shots;
|
||||
|
||||
/** The message to display which waiting for a key press */
|
||||
private Sprite message;
|
||||
|
||||
/** The sprite containing the "Press Any Key" message */
|
||||
private Sprite pressAnyKey;
|
||||
|
||||
/** The sprite containing the "You win!" message */
|
||||
private Sprite youWin;
|
||||
|
||||
/** The sprite containing the "You lose!" message */
|
||||
private Sprite gotYou;
|
||||
|
||||
/** Last shot index */
|
||||
private int shotIndex;
|
||||
|
||||
/** The speed at which the player's ship should move (pixels/sec) */
|
||||
private float moveSpeed = 300;
|
||||
|
||||
/** The time at which last fired a shot */
|
||||
private long lastFire = 0;
|
||||
|
||||
/** The interval between our players shot (ms) */
|
||||
private long firingInterval = 500;
|
||||
|
||||
/** The number of aliens left on the screen */
|
||||
private int alienCount;
|
||||
|
||||
/** True if we're holding up game play until a key has been pressed */
|
||||
private boolean waitingForKeyPress = true;
|
||||
|
||||
/** True if game logic needs to be applied this loop, normally as a result of a game event */
|
||||
private boolean logicRequiredThisLoop = false;
|
||||
|
||||
/** The time at which the last rendering looped started from the point of view of the game logic */
|
||||
private long lastLoopTime = getTime();
|
||||
|
||||
/** True if the fire key has been released */
|
||||
private boolean fireHasBeenReleased = false;
|
||||
|
||||
/** The time since the last record of fps */
|
||||
private long lastFpsTime = 0;
|
||||
|
||||
/** The recorded fps */
|
||||
private int fps;
|
||||
|
||||
private static long timerTicksPerSecond = Sys.getTimerResolution();
|
||||
|
||||
/** True if the game is currently "running", i.e. the game loop is looping */
|
||||
public static boolean gameRunning = true;
|
||||
|
||||
/** SoundManager to make sound with */
|
||||
private SoundManager soundManager;
|
||||
|
||||
/** Whether we're running in fullscreen mode */
|
||||
private boolean fullscreen;
|
||||
|
||||
/** ID of shot effect */
|
||||
private int SOUND_SHOT;
|
||||
|
||||
/** ID of hit effect */
|
||||
private int SOUND_HIT;
|
||||
|
||||
/** ID of start sound */
|
||||
private int SOUND_START;
|
||||
|
||||
/** ID of win sound */
|
||||
private int SOUND_WIN;
|
||||
|
||||
/** ID of loose sound */
|
||||
private int SOUND_LOOSE;
|
||||
|
||||
/** Mouse movement on x axis */
|
||||
private int mouseX;
|
||||
|
||||
/**
|
||||
* Construct our game and set it running.
|
||||
* @param fullscreen
|
||||
*
|
||||
* @param renderingType The type of rendering to use (should be one of the contansts from ResourceFactory)
|
||||
*/
|
||||
public Game(boolean fullscreen) {
|
||||
this.fullscreen = fullscreen;
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the high resolution time in milliseconds
|
||||
*
|
||||
* @return The high resolution time in milliseconds
|
||||
*/
|
||||
public static long getTime() {
|
||||
// we get the "timer ticks" from the high resolution timer
|
||||
// multiply by 1000 so our end result is in milliseconds
|
||||
// then divide by the number of ticks in a second giving
|
||||
// us a nice clear time in milliseconds
|
||||
return (Sys.getTime() * 1000) / timerTicksPerSecond;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleep for a fixed number of milliseconds.
|
||||
*
|
||||
* @param duration The amount of time in milliseconds to sleep for
|
||||
*/
|
||||
public static void sleep(long duration) {
|
||||
try {
|
||||
Thread.sleep((duration * timerTicksPerSecond) / 1000);
|
||||
} catch (InterruptedException inte) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Intialise the common elements for the game
|
||||
*/
|
||||
public void initialize() {
|
||||
// initialize the window beforehand
|
||||
try {
|
||||
if (fullscreen && setDisplayMode()) {
|
||||
Window.create(WINDOW_TITLE, Display.getDepth(), 0, 8, 0, 0);
|
||||
} else {
|
||||
Window.create(WINDOW_TITLE, 100, 100, width, height, Display.getDepth(), 0, 8, 0, 0);
|
||||
}
|
||||
|
||||
// grab the mouse, dont want that hideous cursor when we're playing!
|
||||
Mouse.setGrabbed(true);
|
||||
|
||||
// enable textures since we're going to use these for our sprites
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
|
||||
// disable the OpenGL depth test since we're rendering 2D graphics
|
||||
GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||
|
||||
GL11.glMatrixMode(GL11.GL_PROJECTION);
|
||||
GL11.glLoadIdentity();
|
||||
|
||||
GL11.glOrtho(0, width, height, 0, -1, 1);
|
||||
|
||||
textureLoader = new TextureLoader();
|
||||
|
||||
// create our sound manager, and initialize it with 7 channels
|
||||
// 1 channel for sounds, 6 for effects - this should be enough
|
||||
// since we have a most 4 shots on screen at any one time, which leaves
|
||||
// us with 2 channels for explosions.
|
||||
soundManager = new SoundManager();
|
||||
soundManager.initialize(8);
|
||||
|
||||
// load our sound data
|
||||
SOUND_SHOT = soundManager.addSound("shot.wav");
|
||||
SOUND_HIT = soundManager.addSound("hit.wav");
|
||||
SOUND_START = soundManager.addSound("start.wav");
|
||||
SOUND_WIN = soundManager.addSound("win.wav");
|
||||
SOUND_LOOSE = soundManager.addSound("loose.wav");
|
||||
} catch (LWJGLException le) {
|
||||
System.out.println("Game exiting - exception in initialization:");
|
||||
le.printStackTrace();
|
||||
Game.gameRunning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// get our sprites
|
||||
gotYou = getSprite("gotyou.gif");
|
||||
pressAnyKey = getSprite("pressanykey.gif");
|
||||
youWin = getSprite("youwin.gif");
|
||||
|
||||
message = pressAnyKey;
|
||||
|
||||
// setup 5 shots
|
||||
shots = new ShotEntity[5];
|
||||
for (int i = 0; i < shots.length; i++) {
|
||||
shots[i] = new ShotEntity(this, "shot.gif", 0, 0);
|
||||
}
|
||||
|
||||
// setup the initial game state
|
||||
startGame();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display mode for fullscreen mode
|
||||
*/
|
||||
private boolean setDisplayMode() {
|
||||
// get modes
|
||||
DisplayMode[] dm = Display.getAvailableDisplayModes();
|
||||
|
||||
// locate the first one that has 800*600*32
|
||||
for (int i = 0; i < dm.length; i++) {
|
||||
if (dm[i].width == 800 && dm[i].height == 600 && dm[i].bpp == 32) {
|
||||
try {
|
||||
Display.setDisplayMode(dm[i]);
|
||||
return true;
|
||||
} catch (LWJGLException le) {
|
||||
le.printStackTrace();
|
||||
System.out.println("Unable to enter fullscreen, continuing in windowed mode");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a fresh game, this should clear out any old data and
|
||||
* create a new set.
|
||||
*/
|
||||
private void startGame() {
|
||||
// clear out any existing entities and intialise a new set
|
||||
entities.clear();
|
||||
initEntities();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the starting state of the entities (ship and aliens). Each
|
||||
* entitiy will be added to the overall list of entities in the game.
|
||||
*/
|
||||
private void initEntities() {
|
||||
// create the player ship and place it roughly in the center of the screen
|
||||
ship = new ShipEntity(this, "ship.gif", 370, 550);
|
||||
entities.add(ship);
|
||||
|
||||
// create a block of aliens (5 rows, by 12 aliens, spaced evenly)
|
||||
alienCount = 0;
|
||||
for (int row = 0; row < 5; row++) {
|
||||
for (int x = 0; x < 12; x++) {
|
||||
Entity alien = new AlienEntity(this, 100 + (x * 50), (50) + row * 30);
|
||||
entities.add(alien);
|
||||
alienCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification from a game entity that the logic of the game
|
||||
* should be run at the next opportunity (normally as a result of some
|
||||
* game event)
|
||||
*/
|
||||
public void updateLogic() {
|
||||
logicRequiredThisLoop = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an entity from the game. The entity removed will
|
||||
* no longer move or be drawn.
|
||||
*
|
||||
* @param entity The entity that should be removed
|
||||
*/
|
||||
public void removeEntity(Entity entity) {
|
||||
removeList.add(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that the player has died.
|
||||
*/
|
||||
public void notifyDeath() {
|
||||
if (!waitingForKeyPress) {
|
||||
soundManager.playSound(SOUND_LOOSE);
|
||||
}
|
||||
message = gotYou;
|
||||
waitingForKeyPress = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that the player has won since all the aliens
|
||||
* are dead.
|
||||
*/
|
||||
public void notifyWin() {
|
||||
message = youWin;
|
||||
waitingForKeyPress = true;
|
||||
soundManager.playSound(SOUND_WIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that an alien has been killed
|
||||
*/
|
||||
public void notifyAlienKilled() {
|
||||
// reduce the alient count, if there are none left, the player has won!
|
||||
alienCount--;
|
||||
|
||||
if (alienCount == 0) {
|
||||
notifyWin();
|
||||
}
|
||||
|
||||
// if there are still some aliens left then they all need to get faster, so
|
||||
// speed up all the existing aliens
|
||||
for (int i = 0; i < entities.size(); i++) {
|
||||
Entity entity = (Entity) entities.get(i);
|
||||
|
||||
if (entity instanceof AlienEntity) {
|
||||
// speed up by 2%
|
||||
entity.setHorizontalMovement(entity.getHorizontalMovement() * 1.02f);
|
||||
}
|
||||
}
|
||||
|
||||
soundManager.playEffect(SOUND_HIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to fire a shot from the player. Its called "try"
|
||||
* since we must first check that the player can fire at this
|
||||
* point, i.e. has he/she waited long enough between shots
|
||||
*/
|
||||
public void tryToFire() {
|
||||
// check that we have waiting long enough to fire
|
||||
if (System.currentTimeMillis() - lastFire < firingInterval) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if we waited long enough, create the shot entity, and record the time.
|
||||
lastFire = System.currentTimeMillis();
|
||||
ShotEntity shot = shots[shotIndex++ % shots.length];
|
||||
shot.reinitialize(ship.getX() + 10, ship.getY() - 30);
|
||||
entities.add(shot);
|
||||
|
||||
soundManager.playEffect(SOUND_SHOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the main game loop. This method keeps rendering the scene
|
||||
* and requesting that the callback update its screen.
|
||||
*/
|
||||
private void gameLoop() {
|
||||
while (Game.gameRunning) {
|
||||
// clear screen
|
||||
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||
GL11.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
GL11.glLoadIdentity();
|
||||
|
||||
// let subsystem paint
|
||||
frameRendering();
|
||||
|
||||
// update window contents
|
||||
Window.update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that a frame is being rendered. Responsible for
|
||||
* running game logic and rendering the scene.
|
||||
*/
|
||||
public void frameRendering() {
|
||||
//SystemTimer.sleep(lastLoopTime+10-SystemTimer.getTime());
|
||||
Display.sync(60);
|
||||
|
||||
// work out how long its been since the last update, this
|
||||
// will be used to calculate how far the entities should
|
||||
// move this loop
|
||||
long delta = getTime() - lastLoopTime;
|
||||
lastLoopTime = getTime();
|
||||
lastFpsTime += delta;
|
||||
fps++;
|
||||
|
||||
// update our FPS counter if a second has passed
|
||||
if (lastFpsTime >= 1000) {
|
||||
Window.setTitle(WINDOW_TITLE + " (FPS: " + fps + ")");
|
||||
lastFpsTime = 0;
|
||||
fps = 0;
|
||||
}
|
||||
|
||||
// cycle round asking each entity to move itself
|
||||
if (!waitingForKeyPress && !soundManager.isPlayingSound()) {
|
||||
for (int i = 0; i < entities.size(); i++) {
|
||||
Entity entity = (Entity) entities.get(i);
|
||||
entity.move(delta);
|
||||
}
|
||||
}
|
||||
|
||||
// cycle round drawing all the entities we have in the game
|
||||
for (int i = 0; i < entities.size(); i++) {
|
||||
Entity entity = (Entity) entities.get(i);
|
||||
entity.draw();
|
||||
}
|
||||
|
||||
// brute force collisions, compare every entity against
|
||||
// every other entity. If any of them collide notify
|
||||
// both entities that the collision has occured
|
||||
for (int p = 0; p < entities.size(); p++) {
|
||||
for (int s = p + 1; s < entities.size(); s++) {
|
||||
Entity me = (Entity) entities.get(p);
|
||||
Entity him = (Entity) entities.get(s);
|
||||
|
||||
if (me.collidesWith(him)) {
|
||||
me.collidedWith(him);
|
||||
him.collidedWith(me);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove any entity that has been marked for clear up
|
||||
entities.removeAll(removeList);
|
||||
removeList.clear();
|
||||
|
||||
// if a game event has indicated that game logic should
|
||||
// be resolved, cycle round every entity requesting that
|
||||
// their personal logic should be considered.
|
||||
if (logicRequiredThisLoop) {
|
||||
for (int i = 0; i < entities.size(); i++) {
|
||||
Entity entity = (Entity) entities.get(i);
|
||||
entity.doLogic();
|
||||
}
|
||||
|
||||
logicRequiredThisLoop = false;
|
||||
}
|
||||
|
||||
// if we're waiting for an "any key" press then draw the
|
||||
// current message
|
||||
if (waitingForKeyPress) {
|
||||
message.draw(325, 250);
|
||||
}
|
||||
|
||||
// resolve the movemfent of the ship. First assume the ship
|
||||
// isn't moving. If either cursor key is pressed then
|
||||
// update the movement appropraitely
|
||||
ship.setHorizontalMovement(0);
|
||||
|
||||
// get mouse movement on x axis. We need to get it now, since
|
||||
// we can only call getDX ONCE! - secondary calls will yield 0, since
|
||||
// there haven't been any movement since last call.
|
||||
mouseX = Mouse.getDX();
|
||||
|
||||
// we delegate input checking to submethod since we want to check
|
||||
// for keyboard, mouse & controller
|
||||
boolean leftPressed = hasInput(Keyboard.KEY_LEFT);
|
||||
boolean rightPressed = hasInput(Keyboard.KEY_RIGHT);
|
||||
boolean firePressed = hasInput(Keyboard.KEY_SPACE);
|
||||
|
||||
if (!waitingForKeyPress && !soundManager.isPlayingSound()) {
|
||||
if ((leftPressed) && (!rightPressed)) {
|
||||
ship.setHorizontalMovement(-moveSpeed);
|
||||
} else if ((rightPressed) && (!leftPressed)) {
|
||||
ship.setHorizontalMovement(moveSpeed);
|
||||
}
|
||||
|
||||
// if we're pressing fire, attempt to fire
|
||||
if (firePressed) {
|
||||
tryToFire();
|
||||
}
|
||||
} else {
|
||||
if (!firePressed) {
|
||||
fireHasBeenReleased = true;
|
||||
}
|
||||
if ((firePressed) && (fireHasBeenReleased) && !soundManager.isPlayingSound()) {
|
||||
waitingForKeyPress = false;
|
||||
fireHasBeenReleased = false;
|
||||
startGame();
|
||||
soundManager.playSound(SOUND_START);
|
||||
}
|
||||
}
|
||||
|
||||
// if escape has been pressed, stop the game
|
||||
if (Window.isCloseRequested() || Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
|
||||
Game.gameRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key_left
|
||||
* @return
|
||||
*/
|
||||
private boolean hasInput(int direction) {
|
||||
switch(direction) {
|
||||
case Keyboard.KEY_LEFT:
|
||||
return
|
||||
Keyboard.isKeyDown(Keyboard.KEY_LEFT) ||
|
||||
mouseX < 0 ||
|
||||
(Controller.isCreated() && Controller.getX() < 0);
|
||||
|
||||
case Keyboard.KEY_RIGHT:
|
||||
return
|
||||
Keyboard.isKeyDown(Keyboard.KEY_RIGHT) ||
|
||||
mouseX > 0 ||
|
||||
(Controller.isCreated() && Controller.getX() > 0);
|
||||
|
||||
case Keyboard.KEY_SPACE:
|
||||
return
|
||||
Keyboard.isKeyDown(Keyboard.KEY_SPACE) ||
|
||||
Mouse.isButtonDown(0) ||
|
||||
(Controller.isCreated() && Controller.isButtonDown(0));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point into the game. We'll simply create an
|
||||
* instance of class which will start the display and game
|
||||
* loop.
|
||||
*
|
||||
* @param argv The arguments that are passed into our game
|
||||
*/
|
||||
public static void main(String argv[]) {
|
||||
new Game((argv.length > 0 && argv[0].equalsIgnoreCase("-fullscreen"))).execute();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void execute() {
|
||||
gameLoop();
|
||||
soundManager.destroy();
|
||||
Window.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or get a sprite which displays the image that is pointed
|
||||
* to in the classpath by "ref"
|
||||
*
|
||||
* @param ref A reference to the image to load
|
||||
* @return A sprite that can be drawn onto the current graphics context.
|
||||
*/
|
||||
public Sprite getSprite(String ref) {
|
||||
return new Sprite(textureLoader, ref);
|
||||
}
|
||||
}
|
||||
98
src/java/org/lwjgl/examples/spaceinvaders/ShipEntity.java
Normal file
98
src/java/org/lwjgl/examples/spaceinvaders/ShipEntity.java
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2004 LWJGL Project
|
||||
* 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 'LWJGL' 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.lwjgl.examples.spaceinvaders;
|
||||
|
||||
/**
|
||||
* The entity that represents the players ship
|
||||
*
|
||||
* @author Kevin Glass
|
||||
* @author Brian Matzon
|
||||
*/
|
||||
public class ShipEntity extends Entity {
|
||||
|
||||
/** Right border at which to disallow further movement */
|
||||
private static final int RIGHT_BORDER = 750;
|
||||
|
||||
/** Left border at which to disallow further movement */
|
||||
private static final int LEFT_BORDER = 10;
|
||||
|
||||
/** The game in which the ship exists */
|
||||
private Game game;
|
||||
|
||||
/**
|
||||
* Create a new entity to represent the players ship
|
||||
*
|
||||
* @param game The game in which the ship is being created
|
||||
* @param ref The reference to the sprite to show for the ship
|
||||
* @param x The initial x location of the player's ship
|
||||
* @param y The initial y location of the player's ship
|
||||
*/
|
||||
public ShipEntity(Game game,String ref,int x,int y) {
|
||||
super(game.getSprite(ref), x, y);
|
||||
|
||||
this.game = game;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that the ship move itself based on an elapsed ammount of
|
||||
* time
|
||||
*
|
||||
* @param delta The time that has elapsed since last move (ms)
|
||||
*/
|
||||
public void move(long delta) {
|
||||
// if we're moving left and have reached the left hand side
|
||||
// of the screen, don't move
|
||||
if ((dx < 0) && (x < LEFT_BORDER)) {
|
||||
return;
|
||||
}
|
||||
// if we're moving right and have reached the right hand side
|
||||
// of the screen, don't move
|
||||
if ((dx > 0) && (x > RIGHT_BORDER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.move(delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that the player's ship has collided with something
|
||||
*
|
||||
* @param other The entity with which the ship has collided
|
||||
*/
|
||||
public void collidedWith(Entity other) {
|
||||
// if its an alien, notify the game that the player
|
||||
// is dead
|
||||
if (other instanceof AlienEntity) {
|
||||
game.notifyDeath();
|
||||
}
|
||||
}
|
||||
}
|
||||
120
src/java/org/lwjgl/examples/spaceinvaders/ShotEntity.java
Normal file
120
src/java/org/lwjgl/examples/spaceinvaders/ShotEntity.java
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2004 LWJGL Project
|
||||
* 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 'LWJGL' 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.lwjgl.examples.spaceinvaders;
|
||||
|
||||
/**
|
||||
* An entity representing a shot fired by the player's ship
|
||||
*
|
||||
* @author Kevin Glass
|
||||
* @author Brian Matzon
|
||||
*/
|
||||
public class ShotEntity extends Entity {
|
||||
|
||||
/** Top border at which shots are outside */
|
||||
private static final int TOP_BORDER = -100;
|
||||
|
||||
/** The vertical speed at which the players shot moves */
|
||||
private float moveSpeed = -300;
|
||||
|
||||
/** The game in which this entity exists */
|
||||
private Game game;
|
||||
|
||||
/** True if this shot has been "used", i.e. its hit something */
|
||||
private boolean used = false;
|
||||
|
||||
/**
|
||||
* Create a new shot from the player
|
||||
*
|
||||
* @param game The game in which the shot has been created
|
||||
* @param sprite The sprite representing this shot
|
||||
* @param x The initial x location of the shot
|
||||
* @param y The initial y location of the shot
|
||||
*/
|
||||
public ShotEntity(Game game, String sprite, int x, int y) {
|
||||
super(game.getSprite(sprite), x, y);
|
||||
|
||||
this.game = game;
|
||||
dy = moveSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinitializes this entity, for reuse
|
||||
*
|
||||
* @param x new x coordinate
|
||||
* @param y new y coordinate
|
||||
*/
|
||||
public void reinitialize(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
used = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that this shot moved based on time elapsed
|
||||
*
|
||||
* @param delta The time that has elapsed since last move
|
||||
*/
|
||||
public void move(long delta) {
|
||||
// proceed with normal move
|
||||
super.move(delta);
|
||||
|
||||
// if we shot off the screen, remove ourselfs
|
||||
if (y < TOP_BORDER) {
|
||||
game.removeEntity(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that this shot has collided with another
|
||||
* entity
|
||||
*
|
||||
* @param other The other entity with which we've collided
|
||||
*/
|
||||
public void collidedWith(Entity other) {
|
||||
// prevents double kills, if we've already hit something,
|
||||
// don't collide
|
||||
if (used) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if we've hit an alien, kill it!
|
||||
if (other instanceof AlienEntity) {
|
||||
// remove the affected entities
|
||||
game.removeEntity(this);
|
||||
game.removeEntity(other);
|
||||
|
||||
// notify the game that the alien has been killed
|
||||
game.notifyAlienKilled();
|
||||
used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
189
src/java/org/lwjgl/examples/spaceinvaders/SoundManager.java
Normal file
189
src/java/org/lwjgl/examples/spaceinvaders/SoundManager.java
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2004 LWJGL Project
|
||||
* 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 'LWJGL' 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.lwjgl.examples.spaceinvaders;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.openal.AL;
|
||||
import org.lwjgl.openal.AL10;
|
||||
import org.lwjgl.test.openal.WaveData;
|
||||
|
||||
|
||||
/**
|
||||
* $Id$
|
||||
* <p>
|
||||
* Simple sound manager for OpenAL using n sources accessed in
|
||||
* a round robin schedule. Source n is reserved for a single buffer and checking for
|
||||
* whether it's playing.
|
||||
* </p>
|
||||
* @author Brian Matzon <brian@matzon.dk>
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class SoundManager {
|
||||
|
||||
/** We support at most 256 buffers*/
|
||||
private int[] buffers = new int[256];
|
||||
|
||||
/** Number of sources is limited tby user (and hardware) */
|
||||
private int[] sources;
|
||||
|
||||
/** Our internal scratch buffer */
|
||||
private IntBuffer scratchBuffer = BufferUtils.createIntBuffer(256);
|
||||
|
||||
/** Whether we're running in no sound mode */
|
||||
private boolean soundOutput;
|
||||
|
||||
/** Current index in our buffers */
|
||||
private int bufferIndex;
|
||||
|
||||
/** Current index in our source list */
|
||||
private int sourceIndex;
|
||||
|
||||
/**
|
||||
* Creates a new SoundManager
|
||||
*/
|
||||
public SoundManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays a sound effect
|
||||
* @param buffer Buffer index to play gotten from addSound
|
||||
*/
|
||||
public void playEffect(int buffer) {
|
||||
if(soundOutput) {
|
||||
// make sure we never choose last channel, since it is used for special sounds
|
||||
int channel = sources[(sourceIndex++ % (sources.length-1))];
|
||||
|
||||
// link buffer and source, and play it
|
||||
AL10.alSourcei(channel, AL10.AL_BUFFER, buffers[buffer]);
|
||||
AL10.alSourcePlay(channel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays a sound on last source
|
||||
* @param buffer Buffer index to play gotten from addSound
|
||||
*/
|
||||
public void playSound(int buffer) {
|
||||
if(soundOutput) {
|
||||
AL10.alSourcei(sources[sources.length-1], AL10.AL_BUFFER, buffers[buffer]);
|
||||
AL10.alSourcePlay(sources[sources.length-1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a sound is playing on last source
|
||||
* @return true if a source is playing right now on source n
|
||||
*/
|
||||
public boolean isPlayingSound() {
|
||||
return AL10.alGetSourcei(sources[sources.length-1], AL10.AL_SOURCE_STATE) == AL10.AL_PLAYING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the SoundManager
|
||||
*
|
||||
* @param sources Number of sources to create
|
||||
*/
|
||||
public void initialize(int channels) {
|
||||
try {
|
||||
AL.create();
|
||||
|
||||
// allocate sources
|
||||
scratchBuffer.limit(channels);
|
||||
AL10.alGenSources(scratchBuffer);
|
||||
scratchBuffer.rewind();
|
||||
scratchBuffer.get(sources = new int[channels]);
|
||||
|
||||
// could we allocate all channels?
|
||||
if(AL10.alGetError() != AL10.AL_NO_ERROR) {
|
||||
throw new LWJGLException("Unable to allocate " + channels + " sources");
|
||||
}
|
||||
|
||||
// we have sound
|
||||
soundOutput = true;
|
||||
} catch (LWJGLException le) {
|
||||
le.printStackTrace();
|
||||
System.out.println("Sound disabled");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a sound to the Sound Managers pool
|
||||
*
|
||||
* @param path Path to file to load
|
||||
* @return index into SoundManagers buffer list
|
||||
*/
|
||||
public int addSound(String path) {
|
||||
// Generate 1 buffer entry
|
||||
scratchBuffer.rewind().position(0).limit(1);
|
||||
AL10.alGenBuffers(scratchBuffer);
|
||||
buffers[bufferIndex] = scratchBuffer.get(0);
|
||||
|
||||
// load wave data from buffer
|
||||
WaveData wavefile = WaveData.create("spaceinvaders/" + path);
|
||||
|
||||
// copy to buffers
|
||||
AL10.alBufferData(buffers[bufferIndex], wavefile.format, wavefile.data, wavefile.samplerate);
|
||||
|
||||
// unload file again
|
||||
wavefile.dispose();
|
||||
|
||||
// return index for this sound
|
||||
return bufferIndex++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy this SoundManager
|
||||
*/
|
||||
public void destroy() {
|
||||
if(soundOutput) {
|
||||
|
||||
// stop playing sounds
|
||||
scratchBuffer.position(0).limit(sources.length);
|
||||
scratchBuffer.put(sources).flip();
|
||||
AL10.alSourceStop(scratchBuffer);
|
||||
|
||||
// destroy sources
|
||||
AL10.alDeleteSources(scratchBuffer);
|
||||
|
||||
// destroy buffers
|
||||
scratchBuffer.position(0).limit(bufferIndex);
|
||||
scratchBuffer.put(buffers, 0, bufferIndex).flip();
|
||||
AL10.alDeleteBuffers(scratchBuffer);
|
||||
|
||||
// destory OpenAL
|
||||
AL.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
127
src/java/org/lwjgl/examples/spaceinvaders/Sprite.java
Normal file
127
src/java/org/lwjgl/examples/spaceinvaders/Sprite.java
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2004 LWJGL Project
|
||||
* 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 'LWJGL' 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.lwjgl.examples.spaceinvaders;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* Implementation of sprite that uses an OpenGL quad and a texture
|
||||
* to render a given image to the screen.
|
||||
*
|
||||
* @author Kevin Glass
|
||||
* @author Brian Matzon
|
||||
*/
|
||||
public class Sprite {
|
||||
|
||||
/** The texture that stores the image for this sprite */
|
||||
private Texture texture;
|
||||
|
||||
/** The width in pixels of this sprite */
|
||||
private int width;
|
||||
|
||||
/** The height in pixels of this sprite */
|
||||
private int height;
|
||||
|
||||
/**
|
||||
* Create a new sprite from a specified image.
|
||||
*
|
||||
* @param window The window in which the sprite will be displayed
|
||||
* @param ref A reference to the image on which this sprite should be based
|
||||
*/
|
||||
public Sprite(TextureLoader loader, String ref) {
|
||||
try {
|
||||
texture = loader.getTexture("spaceinvaders/" + ref);
|
||||
width = texture.getImageWidth();
|
||||
height = texture.getImageHeight();
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of this sprite in pixels
|
||||
*
|
||||
* @return The width of this sprite in pixels
|
||||
*/
|
||||
public int getWidth() {
|
||||
return texture.getImageWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of this sprite in pixels
|
||||
*
|
||||
* @return The height of this sprite in pixels
|
||||
*/
|
||||
public int getHeight() {
|
||||
return texture.getImageHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the sprite at the specified location
|
||||
*
|
||||
* @param x The x location at which to draw this sprite
|
||||
* @param y The y location at which to draw this sprite
|
||||
*/
|
||||
public void draw(int x, int y) {
|
||||
// store the current model matrix
|
||||
GL11.glPushMatrix();
|
||||
|
||||
// bind to the appropriate texture for this sprite
|
||||
texture.bind();
|
||||
|
||||
// translate to the right location and prepare to draw
|
||||
GL11.glTranslatef(x, y, 0);
|
||||
|
||||
// draw a quad textured to match the sprite
|
||||
GL11.glBegin(GL11.GL_QUADS);
|
||||
{
|
||||
GL11.glTexCoord2f(0, 0);
|
||||
GL11.glVertex2f(0, 0);
|
||||
|
||||
GL11.glTexCoord2f(0, texture.getHeight());
|
||||
GL11.glVertex2f(0, height);
|
||||
|
||||
GL11.glTexCoord2f(texture.getWidth(), texture.getHeight());
|
||||
GL11.glVertex2f(width, height);
|
||||
|
||||
GL11.glTexCoord2f(texture.getWidth(), 0);
|
||||
GL11.glVertex2f(width, 0);
|
||||
}
|
||||
GL11.glEnd();
|
||||
|
||||
// restore the model view matrix to prevent contamination
|
||||
GL11.glPopMatrix();
|
||||
}
|
||||
}
|
||||
190
src/java/org/lwjgl/examples/spaceinvaders/Texture.java
Normal file
190
src/java/org/lwjgl/examples/spaceinvaders/Texture.java
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2004 LWJGL Project
|
||||
* 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 'LWJGL' 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.lwjgl.examples.spaceinvaders;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* A texture to be bound within OpenGL. This object is responsible for
|
||||
* keeping track of a given OpenGL texture and for calculating the
|
||||
* texturing mapping coordinates of the full image.
|
||||
*
|
||||
* Since textures need to be powers of 2 the actual texture may be
|
||||
* considerably bigged that the source image and hence the texture
|
||||
* mapping coordinates need to be adjusted to matchup drawing the
|
||||
* sprite against the texture.
|
||||
*
|
||||
* @author Kevin Glass
|
||||
* @author Brian Matzon
|
||||
*/
|
||||
public class Texture {
|
||||
|
||||
/** The GL target type */
|
||||
private int target;
|
||||
|
||||
/** The GL texture ID */
|
||||
private int textureID;
|
||||
|
||||
/** The height of the image */
|
||||
private int height;
|
||||
|
||||
/** The width of the image */
|
||||
private int width;
|
||||
|
||||
/** The width of the texture */
|
||||
private int texWidth;
|
||||
|
||||
/** The height of the texture */
|
||||
private int texHeight;
|
||||
|
||||
/** The ratio of the width of the image to the texture */
|
||||
private float widthRatio;
|
||||
|
||||
/** The ratio of the height of the image to the texture */
|
||||
private float heightRatio;
|
||||
|
||||
/**
|
||||
* Create a new texture
|
||||
*
|
||||
* @param target The GL target
|
||||
* @param textureID The GL texture ID
|
||||
*/
|
||||
public Texture(int target, int textureID) {
|
||||
this.target = target;
|
||||
this.textureID = textureID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the specified GL context to a texture
|
||||
*
|
||||
* @param gl The GL context to bind to
|
||||
*/
|
||||
public void bind() {
|
||||
GL11.glBindTexture(target, textureID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the height of the image
|
||||
*
|
||||
* @param height The height of the image
|
||||
*/
|
||||
public void setHeight(int height) {
|
||||
this.height = height;
|
||||
setHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width of the image
|
||||
*
|
||||
* @param width The width of the image
|
||||
*/
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
setWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of the original image
|
||||
*
|
||||
* @return The height of the original image
|
||||
*/
|
||||
public int getImageHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of the original image
|
||||
*
|
||||
* @return The width of the original image
|
||||
*/
|
||||
public int getImageWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of the physical texture
|
||||
*
|
||||
* @return The height of physical texture
|
||||
*/
|
||||
public float getHeight() {
|
||||
return heightRatio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of the physical texture
|
||||
*
|
||||
* @return The width of physical texture
|
||||
*/
|
||||
public float getWidth() {
|
||||
return widthRatio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the height of this texture
|
||||
*
|
||||
* @param texHeight The height of the texture
|
||||
*/
|
||||
public void setTextureHeight(int texHeight) {
|
||||
this.texHeight = texHeight;
|
||||
setHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width of this texture
|
||||
*
|
||||
* @param texWidth The width of the texture
|
||||
*/
|
||||
public void setTextureWidth(int texWidth) {
|
||||
this.texWidth = texWidth;
|
||||
setWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the height of the texture. This will update the
|
||||
* ratio also.
|
||||
*/
|
||||
private void setHeight() {
|
||||
if (texHeight != 0) {
|
||||
heightRatio = ((float) height) / texHeight;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width of the texture. This will update the
|
||||
* ratio also.
|
||||
*/
|
||||
private void setWidth() {
|
||||
if (texWidth != 0) {
|
||||
widthRatio = ((float) width) / texWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
285
src/java/org/lwjgl/examples/spaceinvaders/TextureLoader.java
Normal file
285
src/java/org/lwjgl/examples/spaceinvaders/TextureLoader.java
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2004 LWJGL Project
|
||||
* 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 'LWJGL' 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.lwjgl.examples.spaceinvaders;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ComponentColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.DataBufferByte;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* A utility class to load textures for OpenGL. This source is based
|
||||
* on a texture that can be found in the Java Gaming (www.javagaming.org)
|
||||
* Wiki. It has been simplified slightly for explicit 2D graphics use.
|
||||
*
|
||||
* OpenGL uses a particular image format. Since the images that are
|
||||
* loaded from disk may not match this format this loader introduces
|
||||
* a intermediate image which the source image is copied into. In turn,
|
||||
* this image is used as source for the OpenGL texture.
|
||||
*
|
||||
* @author Kevin Glass
|
||||
* @author Brian Matzon
|
||||
*/
|
||||
public class TextureLoader {
|
||||
/** The table of textures that have been loaded in this loader */
|
||||
private HashMap table = new HashMap();
|
||||
|
||||
/** The colour model including alpha for the GL image */
|
||||
private ColorModel glAlphaColorModel;
|
||||
|
||||
/** The colour model for the GL image */
|
||||
private ColorModel glColorModel;
|
||||
|
||||
/** Scratch buffer for texture ID's */
|
||||
private IntBuffer textureIDBuffer = BufferUtils.createIntBuffer(1);
|
||||
|
||||
/**
|
||||
* Create a new texture loader based on the game panel
|
||||
*
|
||||
* @param gl The GL content in which the textures should be loaded
|
||||
*/
|
||||
public TextureLoader() {
|
||||
glAlphaColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||
new int[] {8,8,8,8},
|
||||
true,
|
||||
false,
|
||||
ComponentColorModel.TRANSLUCENT,
|
||||
DataBuffer.TYPE_BYTE);
|
||||
|
||||
glColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||
new int[] {8,8,8,0},
|
||||
false,
|
||||
false,
|
||||
ComponentColorModel.OPAQUE,
|
||||
DataBuffer.TYPE_BYTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new texture ID
|
||||
*
|
||||
* @return A new texture ID
|
||||
*/
|
||||
private int createTextureID() {
|
||||
GL11.glGenTextures(textureIDBuffer);
|
||||
return textureIDBuffer.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a texture
|
||||
*
|
||||
* @param resourceName The location of the resource to load
|
||||
* @return The loaded texture
|
||||
* @throws IOException Indicates a failure to access the resource
|
||||
*/
|
||||
public Texture getTexture(String resourceName) throws IOException {
|
||||
Texture tex = (Texture) table.get(resourceName);
|
||||
|
||||
if (tex != null) {
|
||||
return tex;
|
||||
}
|
||||
|
||||
tex = getTexture(resourceName,
|
||||
GL11.GL_TEXTURE_2D, // target
|
||||
GL11.GL_RGBA, // dst pixel format
|
||||
GL11.GL_LINEAR, // min filter (unused)
|
||||
GL11.GL_LINEAR);
|
||||
|
||||
table.put(resourceName,tex);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a texture into OpenGL from a image reference on
|
||||
* disk.
|
||||
*
|
||||
* @param resourceName The location of the resource to load
|
||||
* @param target The GL target to load the texture against
|
||||
* @param dstPixelFormat The pixel format of the screen
|
||||
* @param minFilter The minimising filter
|
||||
* @param magFilter The magnification filter
|
||||
* @return The loaded texture
|
||||
* @throws IOException Indicates a failure to access the resource
|
||||
*/
|
||||
public Texture getTexture(String resourceName,
|
||||
int target,
|
||||
int dstPixelFormat,
|
||||
int minFilter,
|
||||
int magFilter) throws IOException {
|
||||
int srcPixelFormat = 0;
|
||||
|
||||
// create the texture ID for this texture
|
||||
int textureID = createTextureID();
|
||||
Texture texture = new Texture(target,textureID);
|
||||
|
||||
// bind this texture
|
||||
GL11.glBindTexture(target, textureID);
|
||||
|
||||
BufferedImage bufferedImage = loadImage(resourceName);
|
||||
texture.setWidth(bufferedImage.getWidth());
|
||||
texture.setHeight(bufferedImage.getHeight());
|
||||
|
||||
if (bufferedImage.getColorModel().hasAlpha()) {
|
||||
srcPixelFormat = GL11.GL_RGBA;
|
||||
} else {
|
||||
srcPixelFormat = GL11.GL_RGB;
|
||||
}
|
||||
|
||||
// convert that image into a byte buffer of texture data
|
||||
ByteBuffer textureBuffer = convertImageData(bufferedImage,texture);
|
||||
|
||||
if (target == GL11.GL_TEXTURE_2D) {
|
||||
GL11.glTexParameteri(target, GL11.GL_TEXTURE_MIN_FILTER, minFilter);
|
||||
GL11.glTexParameteri(target, GL11.GL_TEXTURE_MAG_FILTER, magFilter);
|
||||
}
|
||||
|
||||
// produce a texture from the byte buffer
|
||||
GL11.glTexImage2D(target,
|
||||
0,
|
||||
dstPixelFormat,
|
||||
get2Fold(bufferedImage.getWidth()),
|
||||
get2Fold(bufferedImage.getHeight()),
|
||||
0,
|
||||
srcPixelFormat,
|
||||
GL11.GL_UNSIGNED_BYTE,
|
||||
textureBuffer );
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the buffered image to a texture
|
||||
*
|
||||
* @param bufferedImage The image to convert to a texture
|
||||
* @param texture The texture to store the data into
|
||||
* @return A buffer containing the data
|
||||
*/
|
||||
private ByteBuffer convertImageData(BufferedImage bufferedImage,Texture texture) {
|
||||
ByteBuffer imageBuffer = null;
|
||||
WritableRaster raster;
|
||||
BufferedImage texImage;
|
||||
|
||||
int texWidth = 2;
|
||||
int texHeight = 2;
|
||||
|
||||
// find the closest power of 2 for the width and height
|
||||
// of the produced texture
|
||||
while (texWidth < bufferedImage.getWidth()) {
|
||||
texWidth *= 2;
|
||||
}
|
||||
while (texHeight < bufferedImage.getHeight()) {
|
||||
texHeight *= 2;
|
||||
}
|
||||
|
||||
texture.setTextureHeight(texHeight);
|
||||
texture.setTextureWidth(texWidth);
|
||||
|
||||
// create a raster that can be used by OpenGL as a source
|
||||
// for a texture
|
||||
if (bufferedImage.getColorModel().hasAlpha()) {
|
||||
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,texWidth,texHeight,4,null);
|
||||
texImage = new BufferedImage(glAlphaColorModel,raster,false,new Hashtable());
|
||||
} else {
|
||||
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,texWidth,texHeight,3,null);
|
||||
texImage = new BufferedImage(glColorModel,raster,false,new Hashtable());
|
||||
}
|
||||
|
||||
// copy the source image into the produced image
|
||||
Graphics g = texImage.getGraphics();
|
||||
g.setColor(new Color(0f,0f,0f,0f));
|
||||
g.fillRect(0,0,texWidth,texHeight);
|
||||
g.drawImage(bufferedImage,0,0,null);
|
||||
|
||||
// build a byte buffer from the temporary image
|
||||
// that be used by OpenGL to produce a texture.
|
||||
byte[] data = ((DataBufferByte) texImage.getRaster().getDataBuffer()).getData();
|
||||
|
||||
imageBuffer = ByteBuffer.allocateDirect(data.length);
|
||||
imageBuffer.order(ByteOrder.nativeOrder());
|
||||
imageBuffer.put(data, 0, data.length);
|
||||
imageBuffer.flip();
|
||||
|
||||
return imageBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a given resource as a buffered image
|
||||
*
|
||||
* @param ref The location of the resource to load
|
||||
* @return The loaded buffered image
|
||||
* @throws IOException Indicates a failure to find a resource
|
||||
*/
|
||||
private BufferedImage loadImage(String ref) throws IOException {
|
||||
URL url = TextureLoader.class.getClassLoader().getResource(ref);
|
||||
|
||||
if (url == null) {
|
||||
throw new IOException("Cannot find: " + ref);
|
||||
}
|
||||
|
||||
BufferedImage bufferedImage = ImageIO.read(new BufferedInputStream(getClass().getClassLoader().getResourceAsStream(ref)));
|
||||
|
||||
return bufferedImage;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue