changed Vector2D to Vector2f insted and added sound but the sound is not finnishd yet.

and added a update method to entity for ex the sound entity to update its position in the 
world. Added loging support to whit MultiPrintStream.java
This commit is contained in:
Ziver Koc 2007-03-15 19:52:28 +00:00
parent b2cf5d543b
commit 9d4810d38e
37 changed files with 1262 additions and 39 deletions

View file

@ -5,5 +5,7 @@
<classpathentry kind="lib" path="lib/lwjgl.jar"/>
<classpathentry kind="lib" path="lib/jinput.jar"/>
<classpathentry kind="lib" path="lib/lwjgl_util.jar"/>
<classpathentry kind="lib" path="lib/jogg-0.0.7.jar"/>
<classpathentry kind="lib" path="lib/jorbis-0.0.15.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

BIN
OpenAL32.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

BIN
bin/data/sounds/test.ogg Normal file

Binary file not shown.

BIN
bin/data/sounds/test.wav Normal file

Binary file not shown.

BIN
bin/data/units/Thumbs.db Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/jogg-0.0.7.jar Normal file

Binary file not shown.

BIN
lib/jorbis-0.0.15.jar Normal file

Binary file not shown.

1
log.txt Normal file
View file

@ -0,0 +1 @@
Loading: data/sounds/test.wav

View file

@ -8,6 +8,7 @@ import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import ei.engine.state.GameStateManager;
import ei.engine.util.MultiPrintStream;
public class LWJGLGameWindow {
private boolean exit = false;
@ -28,6 +29,8 @@ public class LWJGLGameWindow {
this.fullscreen = fullscreen;
this.title = title;
MultiPrintStream.makeInstance(new MultiPrintStream("log.txt"));
try {
initDisplay();
run();

View file

@ -0,0 +1,42 @@
package ei.engine.math;
public class Vector2f {
private float x;
private float y;
public Vector2f(float x, float y){
this.x = x;
this.y = y;
}
/**
* Get the X value
*
* @return the x value in the vector
*/
public float getX(){
return x;
}
/**
* Get the Y value
*
* @return the y value in the vector
*/
public float getY(){
return y;
}
/**
* Add to the vectro
* @param i The amount to add
*/
public void add(float i){
x += i;
y += i;
}
public String toString(){
return "Vector2f["+x+","+y+"]";
}
}

View file

@ -0,0 +1,42 @@
package ei.engine.math;
public class Vector2i {
private int x;
private int y;
public Vector2i(int x, int y){
this.x = x;
this.y = y;
}
/**
* Get the X value
*
* @return the x value in the vector
*/
public int getX(){
return x;
}
/**
* Get the Y value
*
* @return the y value in the vector
*/
public int getY(){
return y;
}
/**
* Add to the vectro
* @param i The amount to add
*/
public void add(int i){
x += i;
y += i;
}
public String toString(){
return "Vector2i["+x+","+y+"]";
}
}

View file

@ -3,8 +3,7 @@
*/
package ei.engine.scene;
import ei.engine.math.Vector2D;
import ei.engine.math.Vector2I;
import ei.engine.math.Vector2f;
/**
* This class is the root class of all the objects that
@ -17,13 +16,13 @@ public abstract class Entity {
private String name;
/** The location of this entity in pixels*/
private Vector2D location;
private Vector2f location;
/** The rotation of this entity in pixels*/
private Vector2D rotation;
private Vector2f rotation;
/** The size of this entity in pixels*/
private Vector2I size;
private Vector2f size;
/**
* creates a new entity
@ -32,7 +31,7 @@ public abstract class Entity {
*/
public Entity(String name){
this.name = name;
location = new Vector2D(0,0);
location = new Vector2f(0,0);
}
/**
@ -47,7 +46,7 @@ public abstract class Entity {
*
* @return The Location of the entity
*/
public Vector2D getLocation() {
public Vector2f getLocation() {
return location;
}
@ -56,7 +55,7 @@ public abstract class Entity {
*
* @param l The location of the entity
*/
public void setLocation(Vector2D l) {
public void setLocation(Vector2f l) {
location = l;
}
@ -65,7 +64,7 @@ public abstract class Entity {
*
* @return The Location of the entity
*/
public Vector2D getRotation() {
public Vector2f getRotation() {
return rotation;
}
@ -74,7 +73,7 @@ public abstract class Entity {
*
* @param r The rotation of the entity
*/
public void setRotation(Vector2D r) {
public void setRotation(Vector2f r) {
rotation = r;
}
@ -83,7 +82,7 @@ public abstract class Entity {
*
* @return The Location of the entity
*/
public Vector2I getSize() {
public Vector2f getSize() {
return size;
}
@ -92,12 +91,17 @@ public abstract class Entity {
*
* @param s The size of the entity
*/
public void setSize(Vector2I s) {
public void setSize(Vector2f s) {
size = s;
}
/**
* the render method shuold beimplemented for every entity
* the render method should be implemented for every entity
*/
public abstract void render();
/**
* the update method can be implemented for every entity
*/
public void update(){}
}

View file

@ -4,70 +4,79 @@ import java.util.ArrayList;
public class Node extends Sprite {
/** the sprites of this node */
protected ArrayList<Sprite> sprites;
protected ArrayList<Entity> entities;
public Node(String name) {
super(name);
sprites = new ArrayList<Sprite>();
entities = new ArrayList<Entity>();
}
/**
* Add a Sprite
* Add a Entity
* @param s the Sprite to add
* @return false if the Sprite alredy exist else true
* @return false if the Entity alredy exist else true
*/
public boolean add(Sprite s){
if(!sprites.contains(s)){
sprites.add(s);
public boolean add(Entity s){
if(!entities.contains(s)){
entities.add(s);
return true;
}
return false;
}
/**
* get a Sprite
* @param name the name of Sprite to get
* @return null if the Sprite wasnt found
* get a Entity
* @param name the name of Entity to get
* @return null if the Entity wasnt found
*/
public Sprite get(String name){
public Entity get(String name){
int i = getId(name);
if(i >= 0){
return sprites.get(i);
return entities.get(i);
}
return null;
}
/**
* remove a Sprite
* @param name the name of Sprite to remove
* @return false if the Sprite alredy exist else true
* remove a Entity
* @param name the name of Entity to remove
* @return false if the Entity alredy exist else true
*/
public boolean remove(String name){
int i = getId(name);
if(i >= 0){
sprites.remove(i);
entities.remove(i);
return true;
}
return false;
}
/**
* Draw all the sprites in the node
* Draw all the Entities in the node
*/
public void render() {
for(int i=0; i<sprites.size() ;i++){
sprites.get(i).render();
for(int i=0; i<entities.size() ;i++){
entities.get(i).render();
}
}
/**
* Searches for the given name of a sprite
* @param name The name of the sprite
* @return The index of the sprite
* update all the Entities in the node
*/
public void update() {
for(int i=0; i<entities.size() ;i++){
entities.get(i).update();
}
}
/**
* Searches for the given name of a Entity
* @param name The name of the Entity
* @return The index of the Entity
*/
private int getId(String name){
for(int i=0; i<sprites.size() ;i++){
if(sprites.get(i).getName().equals(name)){
for(int i=0; i<entities.size() ;i++){
if(entities.get(i).getName().equals(name)){
return i;
}
}

View file

@ -4,8 +4,8 @@ import java.io.IOException;
import org.lwjgl.opengl.GL11;
import ei.engine.util.Texture;
import ei.engine.util.TextureLoader;
import ei.engine.texture.Texture;
import ei.engine.texture.TextureLoader;
/**
* Implementation of sprite that uses an OpenGL quad and a texture

View file

@ -0,0 +1,53 @@
package ei.engine.sound;
import java.io.IOException;
import org.lwjgl.openal.AL10;
import ei.engine.scene.Entity;
import ei.engine.util.MultiPrintStream;
/**
* A sound that can be played through OpenAL
*
* @author Kevin Glass
*/
public class Sound extends Entity{
/** The buffer containing the sound */
private int buffer;
/**
* Create a new sound
*
* @param name The name of the sound
* @param ref the path to the sound file
*/
public Sound(String name, String ref) {
super(name);
try {
this.buffer = SoundLoader.getInstnace().loadSound(ref);
} catch (IOException e) {
MultiPrintStream.out.println("Unable to load sound: "+ref+" - "+e.getMessage());
e.printStackTrace();
}
}
/**
* Play this sound as a sound effect
*
* @param pitch The pitch of the play back
* @param gain The gain of the play back
*/
public void play(float pitch, float gain) {
SoundLoader.getInstnace().playSound(buffer, pitch, gain, getLocation());
}
public void update() {
//AL10.alSource(source.get(0), AL10.AL_POSITION, sourcePos);
}
/**
* unimplamented method
*/
public void render() {}
}

View file

@ -0,0 +1,200 @@
package ei.engine.sound;
import java.io.IOException;
import java.io.InputStream;
import java.nio.IntBuffer;
import java.util.HashMap;
import org.lwjgl.BufferUtils;
import org.lwjgl.Sys;
import org.lwjgl.openal.AL;
import org.lwjgl.openal.AL10;
import org.lwjgl.util.WaveData;
import ei.engine.math.Vector2f;
import ei.engine.sound.decoders.OggData;
import ei.engine.sound.decoders.OggDecoder;
import ei.engine.util.MultiPrintStream;
/**
* Responsible for holding and playing the sounds used in the game.
*
* @author Kevin Glass
* @author Ziver Koc
*/
public class SoundLoader {
/** The single instance of this class */
private static SoundLoader instance = new SoundLoader();
/** True if sound effects are turned on */
private boolean soundsEnabled;
/** The number of sound sources enabled - default 8 */
private int sourceCount;
/** The map of references to IDs of previously loaded sounds */
private HashMap<String, Integer> loaded = new HashMap<String, Integer>();
/** The OpenGL AL sound sources in use */
private IntBuffer sources;
/** The next source to be used for sound effects */
private int nextSource;
/**
* Create a new sound store
*/
private SoundLoader() {
init();
}
/**
* Indicate whether sound effects should be played
*
* @param sounds True if sound effects should be played
*/
public void setEnabled(boolean enabled) {
this.soundsEnabled = enabled;
}
/**
* Check if sound effects are currently enabled
*
* @return True if sound effects are currently enabled
*/
public boolean isEnabled() {
return soundsEnabled;
}
/**
* Initialise the sound effects stored. This must be called
* before anything else will work
*/
private void init() {
try {
AL.create();
soundsEnabled = true;
} catch (Exception e) {
e.printStackTrace();
soundsEnabled = false;
}
if (soundsEnabled) {
sourceCount = 8;
sources = BufferUtils.createIntBuffer(sourceCount);
AL10.alGenSources(sources);
if (AL10.alGetError() != AL10.AL_NO_ERROR) {
soundsEnabled = false;
}
}
}
/**
* Play the specified buffer as a sound effect with the specified
* pitch and gain.
*
* @param buffer The ID of the buffer to play
* @param pitch The pitch to play at
* @param gain The gain to play at
*/
void playSound(int buffer,float pitch,float gain, Vector2f pos) {
if (soundsEnabled) {
nextSource++;
if (nextSource >= sourceCount) {
nextSource = 1;
}
AL10.alSourceStop(sources.get(nextSource));
AL10.alSourcei(sources.get(nextSource), AL10.AL_BUFFER, buffer);
AL10.alSourcef(sources.get(nextSource), AL10.AL_PITCH, pitch);
AL10.alSourcef(sources.get(nextSource), AL10.AL_GAIN, gain);
//specify where the sound is comming from by tree axes x,y and z
AL10.alSource3f(sources.get(nextSource), AL10.AL_POSITION,
pos.getX(), pos.getY(), 0);
//AL10.alSource(sources.get(nextSource), AL10.AL_VELOCITY, sourceVel);
//AL10.alSourcei(sources.get(nextSource), AL10.AL_LOOPING, AL10.AL_TRUE );
AL10.alSourcePlay(sources.get(nextSource));
}
}
/**
* Get the Sound based on a specified file path in the classpath
*
* @param ref The reference to the file in the classpath
* @return An integer value that represents the buffer -1 if sound is disabled
* @throws IOException Indicates a failure to load the sound file
*/
public int loadSound(String ref) throws IOException {
if (!soundsEnabled) {
return -1;
}
int buffer = -1;
if (loaded.get(ref) != null) {
buffer = ((Integer) loaded.get(ref)).intValue();
}
else {
MultiPrintStream.out.println("Loading: "+ref);
try {
IntBuffer buf = BufferUtils.createIntBuffer(1);
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(ref);
String extension = getFileExtension(ref);
AL10.alGenBuffers(buf);
if(extension.equals("ogg")){
OggDecoder decoder = new OggDecoder();
OggData ogg = decoder.getData(in);
AL10.alBufferData(buf.get(0), ogg.channels > 1 ? AL10.AL_FORMAT_STEREO16 : AL10.AL_FORMAT_MONO16, ogg.data, ogg.rate);
}
else if(extension.equals("wav")){
//
WaveData wav = WaveData.create(in);
AL10.alBufferData(buf.get(0), wav.format, wav.data, wav.samplerate);
wav.dispose();
}
else{
MultiPrintStream.out.println("Unknown file format: "+ref);
return -1;
}
loaded.put(ref,new Integer(buf.get(0)));
buffer = buf.get(0);
} catch (Exception e) {
e.printStackTrace();
Sys.alert("Error","Failed to load: "+ref+" - "+e.getMessage());
MultiPrintStream.out.println("Failed to load: "+ref+" - "+e.getMessage());
soundsEnabled = false;
return -1;
//System.exit(0);
}
}
if (buffer == -1) {
throw new IOException("Unable to load: "+ref);
}
return buffer;
}
private String getFileExtension(String file){
int dotPlace = file.lastIndexOf ( '.' );
if ( dotPlace >= 0 ){
return file.substring(dotPlace + 1, file.length());
}
else{
return "";
}
}
/**
* Get the single instance of this class
*
* @return The single instnace of this class
*/
public static SoundLoader getInstnace() {
if(instance == null){
instance = new SoundLoader();
}
return instance;
}
}

View file

@ -0,0 +1,17 @@
package ei.engine.sound.decoders;
import java.nio.ByteBuffer;
/**
* Data describing the sounds in a OGG file
*
* @author Kevin Glass
*/
public class OggData {
/** The data that has been read from the OGG file */
public ByteBuffer data;
/** The sampling rate */
public int rate;
/** The number of channels in the sound file */
public int channels;
}

View file

@ -0,0 +1,329 @@
package ei.engine.sound.decoders;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import com.jcraft.jogg.Packet;
import com.jcraft.jogg.Page;
import com.jcraft.jogg.StreamState;
import com.jcraft.jogg.SyncState;
import com.jcraft.jorbis.Block;
import com.jcraft.jorbis.Comment;
import com.jcraft.jorbis.DspState;
import com.jcraft.jorbis.Info;
import ei.engine.util.MultiPrintStream;
/**
* Decode an OGG file to PCM data
*
* @author Kevin Glass
*/
public class OggDecoder {
/** The conversion buffer size */
private int convsize = 4096 * 4;
/** The buffer used to read OGG file */
private byte[] convbuffer = new byte[convsize]; // take 8k out of the data segment, not the stack
/**
* Create a new OGG decoder
*/
public OggDecoder() {
}
/**
* Get the data out of an OGG file
*
* @param input The input stream from which to read the OGG file
* @return The data describing the OGG thats been read
*/
public OggData getData(InputStream input) {
ByteArrayOutputStream dataout = new ByteArrayOutputStream();
SyncState oy = new SyncState(); // sync and verify incoming physical bitstream
StreamState os = new StreamState(); // take physical pages, weld into a logical stream of packets
Page og = new Page(); // one Ogg bitstream page. Vorbis packets are inside
Packet op = new Packet(); // one raw packet of data for decode
Info vi = new Info(); // struct that stores all the static vorbis bitstream settings
Comment vc = new Comment(); // struct that stores all the bitstream user comments
DspState vd = new DspState(); // central working state for the packet->PCM decoder
Block vb = new Block(vd); // local working space for packet->PCM decode
byte[] buffer;
int bytes = 0;
boolean bigEndian = ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN);
// Decode setup
oy.init(); // Now we can read pages
while (true) { // we repeat if the bitstream is chained
int eos = 0;
// grab some data at the head of the stream. We want the first page
// (which is guaranteed to be small and only contain the Vorbis
// stream initial header) We need the first page to get the stream
// serialno.
// submit a 4k block to libvorbis' Ogg layer
int index = oy.buffer(4096);
buffer = oy.data;
try {
bytes = input.read(buffer, index, 4096);
} catch (Exception e) {
MultiPrintStream.out.println("Failure reading in vorbis");
MultiPrintStream.out.println(e);
System.exit(0);
}
oy.wrote(bytes);
// Get the first page.
if (oy.pageout(og) != 1) {
// have we simply run out of data? If so, we're done.
if (bytes < 4096)
break;
// error case. Must not be Vorbis data
MultiPrintStream.out.println("Input does not appear to be an Ogg bitstream.");
System.exit(0);
}
// Get the serial number and set up the rest of decode.
// serialno first; use it to set up a logical stream
os.init(og.serialno());
// extract the initial header from the first page and verify that the
// Ogg bitstream is in fact Vorbis data
// I handle the initial header first instead of just having the code
// read all three Vorbis headers at once because reading the initial
// header is an easy way to identify a Vorbis bitstream and it's
// useful to see that functionality seperated out.
vi.init();
vc.init();
if (os.pagein(og) < 0) {
// error; stream version mismatch perhaps
MultiPrintStream.out.println("Error reading first page of Ogg bitstream data.");
System.exit(0);
}
if (os.packetout(op) != 1) {
// no page? must not be vorbis
MultiPrintStream.out.println("Error reading initial header packet.");
System.exit(0);
}
if (vi.synthesis_headerin(vc, op) < 0) {
// error case; not a vorbis header
MultiPrintStream.out.println("This Ogg bitstream does not contain Vorbis audio data.");
System.exit(0);
}
// At this point, we're sure we're Vorbis. We've set up the logical
// (Ogg) bitstream decoder. Get the comment and codebook headers and
// set up the Vorbis decoder
// The next two packets in order are the comment and codebook headers.
// They're likely large and may span multiple pages. Thus we reead
// and submit data until we get our two pacakets, watching that no
// pages are missing. If a page is missing, error out; losing a
// header page is the only place where missing data is fatal. */
int i = 0;
while (i < 2) {
while (i < 2) {
int result = oy.pageout(og);
if (result == 0)
break; // Need more data
// Don't complain about missing or corrupt data yet. We'll
// catch it at the packet output phase
if (result == 1) {
os.pagein(og); // we can ignore any errors here
// as they'll also become apparent
// at packetout
while (i < 2) {
result = os.packetout(op);
if (result == 0)
break;
if (result == -1) {
// Uh oh; data at some point was corrupted or missing!
// We can't tolerate that in a header. Die.
MultiPrintStream.out.println("Corrupt secondary header. Exiting.");
System.exit(0);
}
vi.synthesis_headerin(vc, op);
i++;
}
}
}
// no harm in not checking before adding more
index = oy.buffer(4096);
buffer = oy.data;
try {
bytes = input.read(buffer, index, 4096);
} catch (Exception e) {
MultiPrintStream.out.println("Failed to read Vorbis: ");
MultiPrintStream.out.println(e);
System.exit(0);
}
if (bytes == 0 && i < 2) {
MultiPrintStream.out.println("End of file before finding all Vorbis headers!");
System.exit(0);
}
oy.wrote(bytes);
}
// Throw the comments plus a few lines about the bitstream we're
// decoding
{
MultiPrintStream.out.println("Bitstream is " + vi.channels + " channel, " + vi.rate + "Hz");
MultiPrintStream.out.println("Encoded by: "+ new String(vc.vendor, 0, vc.vendor.length - 1));
}
convsize = 4096 / vi.channels;
// OK, got and parsed all three headers. Initialize the Vorbis
// packet->PCM decoder.
vd.synthesis_init(vi); // central decode state
vb.init(vd); // local state for most of the decode
// so multiple block decodes can
// proceed in parallel. We could init
// multiple vorbis_block structures
// for vd here
float[][][] _pcm = new float[1][][];
int[] _index = new int[vi.channels];
// The rest is just a straight decode loop until end of stream
while (eos == 0) {
while (eos == 0) {
int result = oy.pageout(og);
if (result == 0)
break; // need more data
if (result == -1) { // missing or corrupt data at this page position
MultiPrintStream.out.println("Corrupt or missing data in bitstream; continuing...");
} else {
os.pagein(og); // can safely ignore errors at
// this point
while (true) {
result = os.packetout(op);
if (result == 0)
break; // need more data
if (result == -1) { // missing or corrupt data at this page position
// no reason to complain; already complained above
} else {
// we have a packet. Decode it
int samples;
if (vb.synthesis(op) == 0) { // test for success!
vd.synthesis_blockin(vb);
}
// **pcm is a multichannel float vector. In stereo, for
// example, pcm[0] is left, and pcm[1] is right. samples is
// the size of each channel. Convert the float values
// (-1.<=range<=1.) to whatever PCM format and write it out
while ((samples = vd.synthesis_pcmout(_pcm,
_index)) > 0) {
float[][] pcm = _pcm[0];
int bout = (samples < convsize ? samples
: convsize);
// convert floats to 16 bit signed ints (host order) and
// interleave
for (i = 0; i < vi.channels; i++) {
int ptr = i * 2;
//int ptr=i;
int mono = _index[i];
for (int j = 0; j < bout; j++) {
int val = (int) (pcm[i][mono + j] * 32767.);
// short val=(short)(pcm[i][mono+j]*32767.);
// int val=(int)Math.round(pcm[i][mono+j]*32767.);
// might as well guard against clipping
if (val > 32767) {
val = 32767;
}
if (val < -32768) {
val = -32768;
}
if (val < 0)
val = val | 0x8000;
if (bigEndian) {
convbuffer[ptr] = (byte) (val >>> 8);
convbuffer[ptr + 1] = (byte) (val);
} else {
convbuffer[ptr] = (byte) (val);
convbuffer[ptr + 1] = (byte) (val >>> 8);
}
ptr += 2 * (vi.channels);
}
}
dataout.write(convbuffer, 0, 2 * vi.channels * bout);
vd.synthesis_read(bout); // tell libvorbis how
// many samples we
// actually consumed
}
}
}
if (og.eos() != 0)
eos = 1;
}
}
if (eos == 0) {
index = oy.buffer(4096);
if (index >= 0) {
buffer = oy.data;
try {
bytes = input.read(buffer, index, 4096);
} catch (Exception e) {
MultiPrintStream.out.println("Failure during vorbis decoding");
MultiPrintStream.out.println(e);
System.exit(0);
}
} else {
bytes = 0;
}
oy.wrote(bytes);
if (bytes == 0)
eos = 1;
}
}
// clean up this logical bitstream; before exit we see if we're
// followed by another [chained]
os.clear();
// ogg_page and ogg_packet structs always point to storage in
// libvorbis. They're never freed or manipulated directly
vb.clear();
vd.clear();
vi.clear(); // must be called last
}
// OK, clean up the framer
oy.clear();
OggData ogg = new OggData();
ogg.channels = vi.channels;
ogg.rate = vi.rate;
byte[] data = dataout.toByteArray();
ogg.data = ByteBuffer.allocateDirect(data.length);
ogg.data.put(data);
ogg.data.rewind();
return ogg;
}
}

View file

@ -0,0 +1,151 @@
package ei.engine.texture;
import org.lwjgl.opengl.GL11;
/**
* A texture to be bound within JOGL. 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;
}
}
}

View file

@ -0,0 +1,277 @@
package ei.engine.texture;
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.opengl.GL11;
/**
* A utility class to load textures for lwjgl. 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
* @author Ziver koc
*/
public class TextureLoader {
private static TextureLoader instace;
/** The table of textures that have been loaded in this loader */
private static HashMap<String, Texture> table = new HashMap<String, Texture>();
/** The colour model including alpha for the GL image */
private ColorModel glAlphaColorModel;
/** The colour model for the GL image */
private ColorModel glColorModel;
/**
* 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(){
IntBuffer tmp = createIntBuffer(1);
GL11.glGenTextures(tmp);
return tmp.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;
}
/**
* Creates an integer buffer to hold specified ints
* - strictly a utility method
*
* @param size how many int to contain
* @return created IntBuffer
*/
protected IntBuffer createIntBuffer(int size) {
ByteBuffer temp = ByteBuffer.allocateDirect(4 * size);
temp.order(ByteOrder.nativeOrder());
return temp.asIntBuffer();
}
public static TextureLoader getTextureLoaderInstance(){
if(instace == null){
instace = new TextureLoader();
}
return instace;
}
}

View file

@ -0,0 +1,93 @@
package ei.engine.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
/**
* @author Ziver
* this class kan print strings to multiple PrintStreams
*/
public class MultiPrintStream extends PrintStream {
//the printstreams that will print
private PrintStream[] streams;
//a instance of this class
public static MultiPrintStream out;
/**
* this constructor makes a simple PrintStream that prints to the console and to a file
* @param file the file name to outpu to
*/
public MultiPrintStream(String file){
super(new PrintStream(System.out));
try {
streams = new PrintStream[2];
streams[0] = new PrintStream(System.out);
streams[1] = new PrintStream(new File(file));
} catch (FileNotFoundException e) {
System.out.println("Error when declaring PrintStream!!");
e.printStackTrace();
}
}
/**
* this constructor takes a array of PrintStreams to be used
* @param streams a array of the streams that will be used
*/
public MultiPrintStream(PrintStream[] streams){
super(streams[0]);
this.streams = streams;
}
/**
* this constructor takes a array of PrintStreams to be used
* @param streams a array of the streams that will be used
*/
public static void makeInstance(MultiPrintStream instanceStream){
out = instanceStream;
}
public boolean checkError(){
for(int i=0; i<streams.length ;i++)
if(streams[i].checkError())
return true;
return false;
}
/**
* closes all the PrintStreams
*/
public void close(){
for(int i=0; i<streams.length ;i++)
streams[i].close();
}
/**
* prints whit a new line to all the PrintStreams
*/
public void println(String s){
s = getTime() + s;
for(int i=0; i<streams.length ;i++)
streams[i].println(s);
}
/**
* prints to all the PrintStreams
*/
public void print(String s){
for(int i=0; i<streams.length ;i++)
streams[i].print(s);
}
private String getTime(){
try {
return "" + (new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")).parse(""+(new java.util.Date()));
} catch (ParseException e) {
return "";
}
}
}