more utils
This commit is contained in:
parent
c08c972bce
commit
e871fefb02
|
@ -29,7 +29,7 @@
|
|||
* 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.util.model.renderer;
|
||||
package org.lwjgl.util;
|
||||
|
||||
/**
|
||||
* $Id$
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (c) 2002 Shaven Puppy Ltd
|
||||
* 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 'Shaven Puppy' 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.util;
|
||||
|
||||
import org.lwjgl.Sys;
|
||||
|
||||
/**
|
||||
* $Id$
|
||||
*
|
||||
* A hires timer. This measures time in seconds as floating point values.
|
||||
* All Timers created are updated simultaneously by calling the static method
|
||||
* tick(). This ensures that within a single iteration of a game loop that
|
||||
* all timers are updated consistently with each other.
|
||||
*
|
||||
* @author cix_foo <cix_foo@users.sourceforge.net>
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class Timer {
|
||||
|
||||
// Record the timer resolution on classload
|
||||
private static final long resolution = Sys.getTimerResolution();
|
||||
|
||||
// Globally keeps track of time for all instances of Timer
|
||||
private static long currentTime;
|
||||
|
||||
// When the timer was started
|
||||
private long startTime;
|
||||
|
||||
// The last time recorded by getTime()
|
||||
private long lastTime;
|
||||
|
||||
// Whether the timer is paused
|
||||
private boolean paused;
|
||||
|
||||
/**
|
||||
* Constructs a timer. The timer will be reset to 0.0 and resumed immediately.
|
||||
*/
|
||||
public Timer() {
|
||||
reset();
|
||||
resume();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the time in seconds, as a float
|
||||
*/
|
||||
public float getTime() {
|
||||
if (!paused)
|
||||
lastTime = currentTime - startTime;
|
||||
|
||||
return (float) ((double) lastTime / (double) resolution);
|
||||
}
|
||||
/**
|
||||
* @return whether this timer is paused
|
||||
*/
|
||||
public boolean isPaused() {
|
||||
return paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause the timer. Whilst paused the time will not change for this timer
|
||||
* when tick() is called.
|
||||
*
|
||||
* @see #resume()
|
||||
*/
|
||||
public void pause() {
|
||||
paused = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the timer. Equivalent to set(0.0f);
|
||||
* @see #set()
|
||||
*/
|
||||
public void reset() {
|
||||
set(0.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume the timer.
|
||||
* @see #pause()
|
||||
*/
|
||||
public void resume() {
|
||||
paused = false;
|
||||
startTime = currentTime - lastTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time of this timer
|
||||
* @param newTime the new time, in seconds
|
||||
*/
|
||||
public void set(float newTime) {
|
||||
long newTimeInTicks = (long) ((double) newTime * (double) resolution);
|
||||
startTime = currentTime - newTimeInTicks;
|
||||
lastTime = newTimeInTicks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next time update from the system's hires timer. This method should
|
||||
* be called once per main loop iteration; all timers are updated simultaneously
|
||||
* from it.
|
||||
*/
|
||||
public static void tick() {
|
||||
currentTime = Sys.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug output.
|
||||
*/
|
||||
public String toString() {
|
||||
return "Timer[Time=" + getTime() + ", Paused=" + paused + "]";
|
||||
}
|
||||
}
|
|
@ -49,10 +49,11 @@ public class BoneFrame extends Frame {
|
|||
/**
|
||||
* C'tor
|
||||
* @param time
|
||||
* @param action
|
||||
* @param bone[]
|
||||
*/
|
||||
public BoneFrame(float time, Matrix4f[] bone) {
|
||||
super(time);
|
||||
public BoneFrame(float time, String action, Matrix4f[] bone) {
|
||||
super(time, action);
|
||||
this.bone = bone;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,8 +65,8 @@ public class BonedModel extends Model {
|
|||
* @param animation
|
||||
* @param vertex
|
||||
*/
|
||||
public BonedModel(String material, Triangle[] triangle, Vector2f[] skin, Color[] color, Map animation, BonedVertex[] vertex) {
|
||||
super(material, triangle, skin, color, animation);
|
||||
public BonedModel(String name, String material, Triangle[] triangle, Vector2f[] skin, Color[] color, Map animation, BonedVertex[] vertex) {
|
||||
super(name, material, triangle, skin, color, animation);
|
||||
this.vertex = vertex;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,19 +39,24 @@ import java.io.Serializable;
|
|||
* @author $Author$
|
||||
* @version $Revision$
|
||||
*/
|
||||
public abstract class Frame implements Serializable {
|
||||
public abstract class Frame implements Serializable, Comparable {
|
||||
|
||||
public static final long serialVersionUID = 1L;
|
||||
|
||||
/** Frame time */
|
||||
private final float time;
|
||||
|
||||
/** User-defined action to occur after this frame has been used. May be null */
|
||||
private final String action;
|
||||
|
||||
/**
|
||||
* C'tor
|
||||
* @param time
|
||||
* @param action
|
||||
*/
|
||||
public Frame(float time) {
|
||||
public Frame(float time, String action) {
|
||||
this.time = time;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,4 +65,35 @@ public abstract class Frame implements Serializable {
|
|||
public final float getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
public int compareTo(Object o) {
|
||||
if (o == null) {
|
||||
return 0;
|
||||
}
|
||||
if (! (o instanceof Frame)) {
|
||||
return 0;
|
||||
}
|
||||
Frame f = (Frame) o;
|
||||
if (f.time == time) {
|
||||
return 0;
|
||||
} else if (f.time > time) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user-defined animation action. This can be processed by whatever
|
||||
* is animating the model to perform some special action after the frame is
|
||||
* used. For example, you could use "stop" to stop the animation, or "rewind"
|
||||
* to repeat the animation ad infinitum.
|
||||
* @return String, or null, for no action
|
||||
*/
|
||||
public final String getAction() {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,10 +48,11 @@ public class MeshFrame extends Frame {
|
|||
/**
|
||||
* C'tor
|
||||
* @param time
|
||||
* @param action
|
||||
* @param bone[]
|
||||
*/
|
||||
public MeshFrame(float time, Vertex[] vertex) {
|
||||
super(time);
|
||||
public MeshFrame(float time, String action, Vertex[] vertex) {
|
||||
super(time, action);
|
||||
this.vertex = vertex;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,8 +61,8 @@ public class MeshedModel extends Model {
|
|||
* @param color[]
|
||||
* @param animation
|
||||
*/
|
||||
public MeshedModel(String material, Triangle[] triangle, Vector2f[] skin, Color[] color, Map animation) {
|
||||
super(material, triangle, skin, color, animation);
|
||||
public MeshedModel(String name, String material, Triangle[] triangle, Vector2f[] skin, Color[] color, Map animation) {
|
||||
super(name, material, triangle, skin, color, animation);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -52,6 +52,9 @@ public abstract class Model implements Serializable {
|
|||
|
||||
public static final long serialVersionUID = 1L;
|
||||
|
||||
/** Model name */
|
||||
private final String name;
|
||||
|
||||
/** Material */
|
||||
private final String material;
|
||||
|
||||
|
@ -69,13 +72,15 @@ public abstract class Model implements Serializable {
|
|||
|
||||
/**
|
||||
* C'tor
|
||||
* @param name
|
||||
* @param material
|
||||
* @param triangle
|
||||
* @param skin[]
|
||||
* @param color[]
|
||||
* @param animation
|
||||
*/
|
||||
public Model(String material, Triangle[] triangle, Vector2f[] skin, Color[] color, Map animation) {
|
||||
public Model(String name, String material, Triangle[] triangle, Vector2f[] skin, Color[] color, Map animation) {
|
||||
this.name = name;
|
||||
this.material = material;
|
||||
this.triangle = triangle;
|
||||
this.skin = skin;
|
||||
|
@ -88,8 +93,8 @@ public abstract class Model implements Serializable {
|
|||
* @param name The name of the animation
|
||||
* @return the Frames of an animation (or null, if no such animation exists)
|
||||
*/
|
||||
public final BoneFrame[] getAnimation(String name) {
|
||||
return (BoneFrame[]) animation.get(name);
|
||||
public final Frame[] getAnimation(String name) {
|
||||
return (Frame[]) animation.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,5 +125,17 @@ public abstract class Model implements Serializable {
|
|||
return color;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
return "Model["+name+"]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the name.
|
||||
*/
|
||||
public final String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,9 @@
|
|||
* 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.util.model.loader;
|
||||
package org.lwjgl.util.model.loaders;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -60,7 +61,7 @@ import org.w3c.dom.Element;
|
|||
* @author $Author$
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class Loader {
|
||||
public class XMLLoader {
|
||||
|
||||
/** The source document */
|
||||
private final Document src;
|
||||
|
@ -74,7 +75,7 @@ public class Loader {
|
|||
/**
|
||||
* C'tor
|
||||
*/
|
||||
public Loader(Document src) {
|
||||
public XMLLoader(Document src) {
|
||||
this.src = src;
|
||||
}
|
||||
|
||||
|
@ -84,12 +85,14 @@ public class Loader {
|
|||
* @throws Exception
|
||||
*/
|
||||
public Model load() throws Exception {
|
||||
String name = XMLUtil.getString(src.getDocumentElement(), "name");
|
||||
String material = XMLUtil.getString(src.getDocumentElement(), "material");
|
||||
numVertices = XMLUtil.getInt(src.getDocumentElement(), "vertices");
|
||||
if (XMLUtil.getString(src.getDocumentElement(), "type").equals("boned")) {
|
||||
// It's a boned model
|
||||
numBones = XMLUtil.getInt(src.getDocumentElement(), "bones", 0);
|
||||
return new BonedModel(
|
||||
name,
|
||||
material,
|
||||
loadTriangles(),
|
||||
loadSkin(),
|
||||
|
@ -100,6 +103,7 @@ public class Loader {
|
|||
} else if (XMLUtil.getString(src.getDocumentElement(), "type").equals("meshed")) {
|
||||
// It's a mesh keyframe model
|
||||
return new MeshedModel(
|
||||
name,
|
||||
material,
|
||||
loadTriangles(),
|
||||
loadSkin(),
|
||||
|
@ -371,6 +375,7 @@ public class Loader {
|
|||
Element frameElement = (Element) i.next();
|
||||
frames[frameCount++] = loadBoneFrame(frameElement);
|
||||
}
|
||||
Arrays.sort(frames);
|
||||
return frames;
|
||||
}
|
||||
|
||||
|
@ -388,6 +393,7 @@ public class Loader {
|
|||
Element frameElement = (Element) i.next();
|
||||
frames[frameCount++] = loadMeshFrame(frameElement);
|
||||
}
|
||||
Arrays.sort(frames);
|
||||
return frames;
|
||||
}
|
||||
|
||||
|
@ -409,7 +415,8 @@ public class Loader {
|
|||
bones[boneCount++] = loadBone(boneElement);
|
||||
}
|
||||
return new BoneFrame(
|
||||
XMLUtil.getFloat(element, "time", 0.0f),
|
||||
XMLUtil.getFloat(element, "time"),
|
||||
XMLUtil.getString(element, "action", null),
|
||||
bones
|
||||
);
|
||||
}
|
||||
|
@ -432,7 +439,8 @@ public class Loader {
|
|||
vertices[vertexCount++] = loadMeshVertex(vertexElement);
|
||||
}
|
||||
return new MeshFrame(
|
||||
XMLUtil.getFloat(element, "time", 0.0f),
|
||||
XMLUtil.getFloat(element, "time"),
|
||||
XMLUtil.getString(element, "action", null),
|
||||
vertices
|
||||
);
|
||||
}
|
|
@ -29,7 +29,7 @@
|
|||
* 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.util.model.loader;
|
||||
package org.lwjgl.util.model.loaders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
|
@ -31,11 +31,15 @@
|
|||
*/
|
||||
package org.lwjgl.util.model.renderer;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.lwjgl.util.model.BoneFrame;
|
||||
import org.lwjgl.util.model.BonedModel;
|
||||
import org.lwjgl.util.Renderable;
|
||||
import org.lwjgl.util.Timer;
|
||||
import org.lwjgl.util.model.Frame;
|
||||
import org.lwjgl.util.model.Model;
|
||||
|
||||
/**
|
||||
* $Id$
|
||||
|
@ -46,14 +50,35 @@ import org.lwjgl.util.model.BonedModel;
|
|||
* Material lookups are performed by mapping the material name to a Renderable thing. You must
|
||||
* suppy appropriate Renderables - typically something that binds a 2D texture and sets up some
|
||||
* GL state.
|
||||
* <p>
|
||||
* To animate things, you will need to call Timer.tick() every frame to update the timers in your
|
||||
* Renderables. Then they'll just animate themselves. Hurrah!
|
||||
*
|
||||
* @author $Author$
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class Renderer {
|
||||
public class Renderer implements Renderable {
|
||||
|
||||
/** Material map: String name->Renderable */
|
||||
private final Map materials = new HashMap();
|
||||
private static final Map materials = new HashMap();
|
||||
|
||||
/** The model we're rendering */
|
||||
private Model model;
|
||||
|
||||
/** The current material */
|
||||
private Renderable material;
|
||||
|
||||
/** The animation currently being animated */
|
||||
private Frame[] frame;
|
||||
|
||||
/** The current time */
|
||||
private final Timer timer = new Timer();
|
||||
|
||||
/** Last frame rendered */
|
||||
private Frame lastFrame;
|
||||
|
||||
/** Visibility */
|
||||
private boolean visible;
|
||||
|
||||
/**
|
||||
* C'tor
|
||||
|
@ -62,36 +87,135 @@ public class Renderer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Render a Model
|
||||
* @param model The model to render
|
||||
* @param animation The name of the animation
|
||||
* @param time The time for the animation
|
||||
* @param model The model to set.
|
||||
*/
|
||||
public void render(BonedModel model, String animation, float time) {
|
||||
public void setModel(Model model) {
|
||||
if (this.model == model) {
|
||||
return;
|
||||
}
|
||||
this.model = model;
|
||||
material = (Renderable) materials.get(model.getMaterial());
|
||||
frame = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Model we're rendering with this Renderer
|
||||
*/
|
||||
public Model getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the animation
|
||||
* @param animation
|
||||
*/
|
||||
public void setAnimation(String animation) {
|
||||
if (model == null) {
|
||||
return;
|
||||
}
|
||||
frame = model.getAnimation(animation);
|
||||
timer.reset();
|
||||
lastFrame = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Model
|
||||
*/
|
||||
public void render() {
|
||||
|
||||
// Don't do anything if there's no model or no animation
|
||||
if (model == null || frame == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Set up GL state from the Model's material
|
||||
Renderable material = (Renderable) materials.get(model.getMaterial());
|
||||
if (material != null) {
|
||||
material.render();
|
||||
}
|
||||
|
||||
// 2. Get the animation
|
||||
BoneFrame[] frame = model.getAnimation(animation);
|
||||
if (frame == null) {
|
||||
return;
|
||||
// 2. Work out what frame to show
|
||||
Frame frame = findFrame();
|
||||
if (frame != lastFrame) {
|
||||
lastFrame = frame;
|
||||
processFrame();
|
||||
}
|
||||
|
||||
// 3. Work out what the nearest frame is to the specified time
|
||||
// 3. Render the processed frame
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the nearest frame to the current time
|
||||
* @return the Frame nearest the current time
|
||||
*/
|
||||
private Frame findFrame() {
|
||||
float time = timer.getTime();
|
||||
|
||||
// Use a binary search to find the frame
|
||||
int a = 0, b =
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a material
|
||||
* @param name The material's name
|
||||
* @param renderable The renderable object
|
||||
*/
|
||||
public void putMaterial(String name, Renderable renderable) {
|
||||
public static void putMaterial(String name, Renderable renderable) {
|
||||
materials.put(name, renderable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a material
|
||||
* @param name The material's name
|
||||
* @return a Renderable
|
||||
*/
|
||||
public static Renderable removeMaterial(String name) {
|
||||
return (Renderable) materials.remove(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this Renderer is visible
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visibility of this Renderer
|
||||
* @param visible
|
||||
*/
|
||||
public void setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the animation is paused
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isPaused() {
|
||||
return timer.isPaused();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause the animation
|
||||
*/
|
||||
public void pause() {
|
||||
timer.pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewind the animation
|
||||
*/
|
||||
public void rewind() {
|
||||
timer.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume a paused animation
|
||||
*/
|
||||
public void resume() {
|
||||
timer.resume();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue