diff --git a/src/java/com/threerings/jme/sprite/LineSegmentPath.java b/src/java/com/threerings/jme/sprite/LineSegmentPath.java index 4cef01211..810b24129 100644 --- a/src/java/com/threerings/jme/sprite/LineSegmentPath.java +++ b/src/java/com/threerings/jme/sprite/LineSegmentPath.java @@ -21,6 +21,7 @@ package com.threerings.jme.sprite; +import com.jme.math.Quaternion; import com.jme.math.Vector3f; /** @@ -39,11 +40,15 @@ public class LineSegmentPath extends Path * traversal. This will as a result be shorter by one element than the * points array. */ - public LineSegmentPath (Sprite sprite, Vector3f[] points, float[] durations) + public LineSegmentPath (Sprite sprite, Vector3f up, Vector3f orient, + Vector3f[] points, float[] durations) { super(sprite); + _up = up; + _orient = orient; _points = points; _durations = durations; + updateRotation(); } // documentation inherited @@ -57,6 +62,9 @@ public class LineSegmentPath extends Path if (_accum > _durations[_current]) { _accum -= _durations[_current]; _current++; + if (_current < _points.length-1) { + updateRotation(); + } } // if we have completed our path, move the sprite to the final @@ -73,9 +81,18 @@ public class LineSegmentPath extends Path _sprite.setLocalTranslation(_temp); } + protected void updateRotation () + { + _points[_current+1].subtract(_points[_current], _temp); + PathUtil.computeRotation(_up, _orient, _temp, _rotate); + _sprite.getLocalRotation().set(_rotate); + } + + protected Vector3f _up, _orient; protected Vector3f[] _points; protected float[] _durations; protected float _accum; protected int _current; protected Vector3f _temp = new Vector3f(0, 0, 0); + protected Quaternion _rotate = new Quaternion(); } diff --git a/src/java/com/threerings/jme/sprite/OrientingBallisticPath.java b/src/java/com/threerings/jme/sprite/OrientingBallisticPath.java index da5d6526b..7f85b38df 100644 --- a/src/java/com/threerings/jme/sprite/OrientingBallisticPath.java +++ b/src/java/com/threerings/jme/sprite/OrientingBallisticPath.java @@ -50,8 +50,8 @@ public class OrientingBallisticPath extends BallisticPath _up = accel.negate(); _up.normalizeLocal(); - computeRotation(velocity); - _sprite.getLocalRotation().set(_rotate); + _sprite.setLocalRotation( + PathUtil.computeAxisRotation(_up, velocity, _rotate)); } // documentation inherited @@ -60,24 +60,11 @@ public class OrientingBallisticPath extends BallisticPath // do the normal update super.update(time); - computeRotation(_velocity); - _sprite.getLocalRotation().set(_rotate); - } - - protected void computeRotation (Vector3f velocity) - { - _axes[0].set(velocity); - _axes[0].normalizeLocal(); - _axes[0].cross(_up, _axes[1]); - _axes[1].normalizeLocal(); - _axes[1].cross(_axes[0], _axes[2]); - _axes[2].cross(_axes[0], _axes[1]); - _rotate.fromAxes(_axes); + _sprite.setLocalRotation( + PathUtil.computeAxisRotation(_up, _velocity, _rotate)); } protected Vector3f _orient; protected Vector3f _up; - protected Vector3f[] _axes = { - new Vector3f(), new Vector3f(), new Vector3f() }; protected Quaternion _rotate = new Quaternion(); } diff --git a/src/java/com/threerings/jme/sprite/PathUtil.java b/src/java/com/threerings/jme/sprite/PathUtil.java new file mode 100644 index 000000000..20f3b24b8 --- /dev/null +++ b/src/java/com/threerings/jme/sprite/PathUtil.java @@ -0,0 +1,96 @@ +// +// $Id$ +// +// Narya library - tools for developing networked games +// Copyright (C) 2002-2005 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/narya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.threerings.jme.sprite; + +import com.jme.math.FastMath; +import com.jme.math.Quaternion; +import com.jme.math.Vector3f; + +/** + * Path related utility functions. + */ +public class PathUtil +{ + /** + * Computes a rotation to align the X axis with the specified + * orientation and stores it in the provided target. The provided up + * vector is crossed with the new orientation to find the left vector + * and the left vector is recrossed with the orientation to find the + * correct up vector. + * + * @return the supplied target quaternion. + */ + public static Quaternion computeAxisRotation ( + Vector3f up, Vector3f orient, Quaternion target) + { + _axes[0].set(orient); + _axes[0].normalizeLocal(); + _axes[0].cross(up, _axes[1]); + _axes[1].normalizeLocal(); + _axes[1].cross(_axes[0], _axes[2]); + _axes[2].cross(_axes[0], _axes[1]); + target.fromAxes(_axes); + return target; + } + + /** + * Computes a rotation from the one vector to another. + * + * @param axis will be used as the axis of rotation if the two vectors + * are parallel. + */ + public static Quaternion computeRotation ( + Vector3f axis, Vector3f from, Vector3f to, Quaternion target) + { + float angle = computeAngle(from, to); + if (angle == FastMath.PI) { // opposite + target.fromAngleAxis(angle, axis); + } else if (angle == 0) { // coincident + target.x = target.y = target.z = 0; + target.w = 1; + } else { + from.cross(to, _axis); + target.fromAngleAxis(angle, _axis); + } + return target; + } + + /** + * Computes the angle between two arbitrary vectors. + */ + public static float computeAngle (Vector3f one, Vector3f two) + { + return FastMath.acos(one.dot(two) / (one.length() * two.length())); + } + + /** + * Computes the angle between two normalized vectors. + */ + public static float computeAngleNormal (Vector3f one, Vector3f two) + { + return FastMath.acos(one.dot(two)); + } + + protected static Vector3f[] _axes = { + new Vector3f(), new Vector3f(), new Vector3f() }; + protected static Vector3f _axis = new Vector3f(); +} diff --git a/tests/src/java/com/threerings/jme/sprite/PathTest.java b/tests/src/java/com/threerings/jme/sprite/PathTest.java index ecb320012..6cc3a1daf 100644 --- a/tests/src/java/com/threerings/jme/sprite/PathTest.java +++ b/tests/src/java/com/threerings/jme/sprite/PathTest.java @@ -3,6 +3,7 @@ package com.threerings.jme.sprite; +import java.util.Arrays; import java.util.logging.Level; import com.jme.math.FastMath; @@ -11,12 +12,14 @@ import com.jme.math.Quaternion; import com.jme.math.Vector3f; import com.jme.renderer.ColorRGBA; import com.jme.scene.shape.Box; +import com.jme.scene.shape.Disk; import com.jme.scene.shape.Quad; import com.jme.scene.shape.Sphere; import com.jme.scene.state.LightState; import com.jme.util.LoggingSystem; import com.threerings.jme.JmeApp; +import com.threerings.jme.sprite.LineSegmentPath; /** * Used for testing paths. @@ -51,24 +54,30 @@ public class PathTest extends JmeApp } } + Box target = new Box("target", new Vector3f(-.1f, -.1f, -.1f), + new Vector3f(.1f, .1f, .1f)); + target.setLocalTranslation(new Vector3f(dist, dist, 0)); + _geom.attachChild(target); + Box box = new Box("box", new Vector3f(-1, -0.5f, -0.25f), new Vector3f(1, 0.5f, 0.25f)); - _geom.attachChild(box); - - Box box2 = new Box("box2", new Vector3f(-.1f, -.1f, -.1f), - new Vector3f(.1f, .1f, .1f)); - box2.setLocalTranslation(new Vector3f(dist, dist, 0)); - _geom.attachChild(box2); - + Disk disk = new Disk("dot", 10, 10, 0.5f); + disk.setLightCombineMode(LightState.OFF); + disk.setLocalTranslation(new Vector3f(0.5f, 0f, 0.3f)); Sprite shot = new Sprite(); shot.attachChild(box); + shot.attachChild(disk); _geom.attachChild(shot); - Vector3f start = new Vector3f(0, 0, 0); +// testBallistic(shot, target); + testLineSegment(shot); + } + protected void testBallistic (Sprite shot, Box target) + { // start with the "cannon" pointed along the x axis - Vector3f diff = box2.getLocalTranslation().subtract( - box.getLocalTranslation()); + Vector3f diff = target.getLocalTranslation().subtract( + shot.getLocalTranslation()); Vector3f vel = diff.normalize(); float range = diff.length(), angle = -FastMath.PI/4; @@ -85,6 +94,7 @@ public class PathTest extends JmeApp FastMath.sin(2*angle)); vel.multLocal(muzvel); + Vector3f start = new Vector3f(0, 0, 0); float time = BallisticPath.computeFlightTime(range, muzvel, angle); shot.move(new OrientingBallisticPath( shot, new Vector3f(1, 0, 0), start, vel, GRAVITY, time)); @@ -98,6 +108,20 @@ public class PathTest extends JmeApp System.out.println("Velocity: " + vel); } + protected void testLineSegment (Sprite shot) + { + Vector3f[] points = new Vector3f[] { + new Vector3f(0, 0, 0), new Vector3f(2, 0, 0), new Vector3f(3, 0, 0), + new Vector3f(3, 2, 0), new Vector3f(5, 2, 0), new Vector3f(5, -2, 0), + new Vector3f(-4, -2, 0) + }; + float[] durations = new float[points.length]; + Arrays.fill(durations, 1f); + Vector3f up = new Vector3f(0, 0, 1); + Vector3f orient = new Vector3f(1, 0, 0); + shot.move(new LineSegmentPath(shot, up, orient, points, durations)); + } + public static void main (String[] args) { LoggingSystem.getLogger().setLevel(Level.OFF);