From e123997fc2cc2b4caca809ab0967a033aa066b98 Mon Sep 17 00:00:00 2001 From: Caspian Rychlik-Prince Date: Wed, 21 Apr 2004 20:47:08 +0000 Subject: [PATCH] Rendery stuff --- .../renderer/AnimationEventListener.java | 47 ++++++ .../util/model/renderer/FrameProcessor.java | 55 ++++++ .../{Renderer.java => ModelRenderer.java} | 158 +++++++++++++++--- .../lwjgl/util/model/renderer/Sprite3D.java | 93 +++++++++++ 4 files changed, 327 insertions(+), 26 deletions(-) create mode 100644 src/java/org/lwjgl/util/model/renderer/AnimationEventListener.java create mode 100644 src/java/org/lwjgl/util/model/renderer/FrameProcessor.java rename src/java/org/lwjgl/util/model/renderer/{Renderer.java => ModelRenderer.java} (61%) create mode 100644 src/java/org/lwjgl/util/model/renderer/Sprite3D.java diff --git a/src/java/org/lwjgl/util/model/renderer/AnimationEventListener.java b/src/java/org/lwjgl/util/model/renderer/AnimationEventListener.java new file mode 100644 index 00000000..02f7d855 --- /dev/null +++ b/src/java/org/lwjgl/util/model/renderer/AnimationEventListener.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2003 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.model.renderer; + +/** + * $Id$ + * Listens out for events that occur in animations and takes appropriate actions + * @author $Author$ + * @version $Revision$ + */ +public interface AnimationEventListener { + /** + * Fired when a frame with an action associated with it is rendered + * @param src The source Renderer + * @param action The action + */ + public void receiveAnimationEvent(ModelRenderer src, String action); +} diff --git a/src/java/org/lwjgl/util/model/renderer/FrameProcessor.java b/src/java/org/lwjgl/util/model/renderer/FrameProcessor.java new file mode 100644 index 00000000..0b1ce239 --- /dev/null +++ b/src/java/org/lwjgl/util/model/renderer/FrameProcessor.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003 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.model.renderer; + +import org.lwjgl.util.Renderable; +import org.lwjgl.util.model.Frame; +import org.lwjgl.util.model.Model; + +/** + * $Id$ + * The interface for processing individual frames of rendered models. + * Typically the processor will process the frame of animation, and store + * the processed results in some data structure that make it easy to render. + * @author $Author$ + * @version $Revision$ + */ +public interface FrameProcessor extends Renderable { + + /** + * Process a frame. + * @param model The model + * @param frame The frame to process + */ + public void process(Model model, Frame frame); + +} diff --git a/src/java/org/lwjgl/util/model/renderer/Renderer.java b/src/java/org/lwjgl/util/model/renderer/ModelRenderer.java similarity index 61% rename from src/java/org/lwjgl/util/model/renderer/Renderer.java rename to src/java/org/lwjgl/util/model/renderer/ModelRenderer.java index 99418cae..9055f3a4 100644 --- a/src/java/org/lwjgl/util/model/renderer/Renderer.java +++ b/src/java/org/lwjgl/util/model/renderer/ModelRenderer.java @@ -31,9 +31,9 @@ */ package org.lwjgl.util.model.renderer; -import java.util.Arrays; -import java.util.Collections; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.lwjgl.util.Renderable; @@ -44,8 +44,7 @@ import org.lwjgl.util.model.Model; /** * $Id$ * - * A simple (and very inefficient) Model renderer. This calculates the model vertices on the fly - * and uses GL immediate mode to render the result. This is of course very slow. + * Pluggable model renderer *

* 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 @@ -57,7 +56,7 @@ import org.lwjgl.util.model.Model; * @author $Author$ * @version $Revision$ */ -public class Renderer implements Renderable { +public class ModelRenderer implements Renderable { /** Material map: String name->Renderable */ private static final Map materials = new HashMap(); @@ -65,6 +64,12 @@ public class Renderer implements Renderable { /** The model we're rendering */ private Model model; + /** The frame processor */ + private FrameProcessor processor; + + /** Animation event listeners */ + private List listeners; + /** The current material */ private Renderable material; @@ -75,15 +80,15 @@ public class Renderer implements Renderable { private final Timer timer = new Timer(); /** Last frame rendered */ - private Frame lastFrame; + private Frame currentFrame; /** Visibility */ - private boolean visible; + private boolean visible = true; /** * C'tor */ - public Renderer() { + public ModelRenderer() { } /** @@ -115,32 +120,47 @@ public class Renderer implements Renderable { } frame = model.getAnimation(animation); timer.reset(); - lastFrame = null; } /** - * Render a Model + * Update the model */ - public void render() { - - // Don't do anything if there's no model or no animation - if (model == null || frame == null) { + public void update() { + + // Don't do anything if there's no model or no animation or no processor + if (model == null || frame == null || processor == null) { return; } - // 1. Set up GL state from the Model's material + // Work out what frame to show + Frame frame = findFrame(); + if (frame != currentFrame) { + currentFrame = frame; + processFrame(); + if (currentFrame.getAction() != null) { + fireAnimationEvent(currentFrame.getAction()); + } + } + + } + + /** + * Render things + */ + public void render() { + + // Don't do anything if there's no model or no animation or no processor + if (model == null || frame == null || processor == null || !visible) { + return; + } + + // Set up GL state from the Model's material if (material != null) { material.render(); } - // 2. Work out what frame to show - Frame frame = findFrame(); - if (frame != lastFrame) { - lastFrame = frame; - processFrame(); - } - - // 3. Render the processed frame + // Render the current frame + renderFrame(); } @@ -152,13 +172,43 @@ public class Renderer implements Renderable { float time = timer.getTime(); // Use a binary search to find the frame - int a = 0, b = + int i = 0; + for (int j = frame.length - 1; i <= j;) { + int k = i + j >> 1; + Frame f = frame[k]; + if (f.getTime() == time) { + return f; + } else if (f.getTime() < time) { + i = k + 1; + } else { + j = k - 1; + } + } + + return frame[i + 1]; + } + + /** + * Process the current frame of animation + */ + protected void processFrame() { + processor.process(model, currentFrame); + } + + /** + * Render the current frame + */ + protected void renderFrame() { + processor.render(); } /** * Add a material - * @param name The material's name - * @param renderable The renderable object + * + * @param name + * The material's name + * @param renderable + * The renderable object */ public static void putMaterial(String name, Renderable renderable) { materials.put(name, renderable); @@ -218,4 +268,60 @@ public class Renderer implements Renderable { timer.resume(); } + /** + * @return Returns the processor. + */ + public FrameProcessor getProcessor() { + return processor; + } + + /** + * Sets the processor. The processor is the clever bit that actually does the + * vertex twiddling and rendering. + * @param processor The processor to set. + */ + public void setProcessor(FrameProcessor processor) { + this.processor = processor; + } + + /** + * Add an animation listener + * @param listener + */ + public void addAnimationEventListener(AnimationEventListener listener) { + if (listeners == null) { + listeners = new ArrayList(1); + } + listeners.remove(listener); + listeners.add(listener); + } + + /** + * Remove an animation listener + * @param listener + */ + public void removeAnimationEventListener(AnimationEventListener listener) { + if (listeners == null) { + return; + } + listeners.remove(listener); + if (listeners.size() == 0) { + listeners = null; + } + } + + /** + * Fire an animation event + * @param action + */ + protected void fireAnimationEvent(String action) { + if (listeners == null) { + return; + } + int n = listeners.size(); + for (int i = 0; i < n; i ++) { + AnimationEventListener listener = (AnimationEventListener) listeners.get(i); + listener.receiveAnimationEvent(this, action); + } + } } diff --git a/src/java/org/lwjgl/util/model/renderer/Sprite3D.java b/src/java/org/lwjgl/util/model/renderer/Sprite3D.java new file mode 100644 index 00000000..8b6ff535 --- /dev/null +++ b/src/java/org/lwjgl/util/model/renderer/Sprite3D.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2003 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.model.renderer; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.vector.Vector3f; + +/** + * $Id$ + * A 3D sprite! + * @author $Author$ + * @version $Revision$ + */ +public class Sprite3D extends ModelRenderer { + + /** Current position */ + private final Vector3f position = new Vector3f(); + + /** Current orientation (axis/angle) */ + private final Vector3f axis = new Vector3f(); + private float angle; + + /* + * Recognised animation actions + */ + private static final String ANIM_HIDE = "hide"; + private static final String ANIM_REWIND = "rewind"; + private static final String ANIM_GOTO = "goto "; + + /** + * C'tor + */ + public Sprite3D() { + addAnimationEventListener(new AnimationEventListener() { + public void receiveAnimationEvent(ModelRenderer src, String action) { + if (action.equals(ANIM_HIDE)) { + setVisible(false); + } else if (action.equals(ANIM_REWIND)) { + rewind(); + } else if (action.startsWith(ANIM_GOTO)) { + setAnimation(action.substring(ANIM_GOTO.length())); + } + } + }); + } + + /* (non-Javadoc) + * @see org.lwjgl.util.model.renderer.ModelRenderer#renderFrame() + */ + protected void renderFrame() { + // TODO: rotation + GL11.glPushMatrix(); + GL11.glTranslatef(position.getX(), position.getY(), position.getY()); + super.renderFrame(); + GL11.glPopMatrix(); + } + + /** + * @return Returns the position. + */ + public Vector3f getPosition() { + return position; + } +}