Behold, Nenya, Ring of Water and repository for our media and animation related

goodies, both Java 2D and LWJGL/JME 3D.


git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@1 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
Michael Bayne
2006-06-23 18:07:28 +00:00
commit c2117ee86d
570 changed files with 61913 additions and 0 deletions
@@ -0,0 +1,412 @@
//
// $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.camera;
import com.jme.math.FastMath;
import com.jme.math.Matrix3f;
import com.jme.math.Plane;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.samskivert.util.ObserverList;
/**
* Provides various useful mechanisms for manipulating the camera.
*/
public class CameraHandler
{
/**
* Creates a new camera handler. The camera begins life at the origin,
* facing in the negative z direction (pointing at the ground).
*/
public CameraHandler (Camera camera)
{
_camera = camera;
resetAxes();
}
/**
* Resets the camera orientation to its initial state.
*/
public void resetAxes ()
{
_camera.getDirection().set(0, 0, -1);
_camera.getLeft().set(-1, 0, 0);
_camera.getUp().set(0, 1, 0);
_camera.update();
_rxdir.set(1, 0, 0);
_rydir.set(0, 1, 0);
}
/**
* Configures limits on the camera tilt.
*/
public void setTiltLimits (float minAngle, float maxAngle)
{
_minTilt = minAngle;
_maxTilt = maxAngle;
}
/**
* Configures limits on the distance the camera can be panned.
*
* @param boundViaFrustum if true instead of bounding the camera's
* position, we will compute the intersections of the view frustum with the
* ground plan and bound that rectangle into the specified bounds.
* <em>Note:</em> the camera must generally be pointing down at the ground
* (up to perhaps 45 degrees or so) for this to work. At higher angles the
* back of the view frustum will intersect the ground plane at or near
* infinity.
*/
public void setPanLimits (float minX, float minY, float maxX, float maxY,
boolean boundViaFrustum)
{
_minX = minX;
_minY = minY;
_maxX = maxX;
_maxY = maxY;
_boundViaFrustum = boundViaFrustum;
}
/**
* Configures the minimum and maximum zoom values allowed for the
* camera.
*/
public void setZoomLimits (float minZoom, float maxZoom)
{
_minZoom = minZoom;
_maxZoom = maxZoom;
}
/**
* Enables or disables the current set of limits.
*/
public void setLimitsEnabled (boolean enabled)
{
_limitsEnabled = enabled;
}
/**
* Sets the camera zoom level to a value between zero (zoomed in maximally)
* and 1 (zoomed out maximally). Zoom limits must have already been set up
* via a call to {@link #setZoomLimits}.
*/
public void setZoomLevel (float level)
{
// Log.info("Zoom " + level + " " + _camera.getLocation());
level = Math.max(0f, Math.min(level, 1f));
_camera.getLocation().z = _minZ + (_maxZ - _minZ) * level;
_camera.update();
}
/**
* Returns the current camera zoom level.
*/
public float getZoomLevel ()
{
return (_camera.getLocation().z - _minZ) / (_maxZ - _minZ);
}
/**
* Adds a camera path observer.
*/
public void addCameraObserver (CameraPath.Observer camobs)
{
_campathobs.add(camobs);
}
/**
* Removes a camera path observer.
*/
public void removeCameraObserver (CameraPath.Observer camobs)
{
_campathobs.remove(camobs);
}
/**
* Starts the camera moving along a path which will be updated every tick
* until it is complete.
*/
public void moveCamera (CameraPath path)
{
if (_campath != null) {
_campath.abort();
_campathobs.apply(new CompletedOp(_campath));
}
_campath = path;
}
/**
* Returns true if the camera is currently animating along a path, false if
* it is not.
*/
public boolean cameraIsMoving ()
{
return (_campath != null);
}
/**
* Skips immediately to the end of the current camera path.
*/
public void skipPath ()
{
// fake an update far enough into the future to trick the camera path
// into thinking it's done
update(100);
}
/**
* This is called by the {@link JmeApp} on every frame to allow the handler
* to update the camera as necessary.
*/
public void update (float frameTime)
{
if (_campath != null) {
if (_campath.tick(frameTime)) {
CameraPath opath = _campath;
_campath = null;
_campathobs.apply(new CompletedOp(opath));
}
}
}
/**
* Returns the camera being manipulated by this handler.
*/
public Camera getCamera ()
{
return _camera;
}
/**
* Adjusts the camera's location. The specified location will be bounded
* within the current pan and zoom limits.
*/
public void setLocation (Vector3f location)
{
_camera.setLocation(bound(location));
_camera.update();
}
/**
* Pans the camera the specified distance in the x and y directions. These
* distances will be multiplied by the current "view" x and y axes and
* added to the camera's position.
*/
public void panCamera (float x, float y)
{
Vector3f loc = _camera.getLocation();
loc.addLocal(_rxdir.mult(x, _temp));
loc.addLocal(_rydir.mult(y, _temp));
setLocation(loc);
}
/**
* Zooms the camera in (distance < 0) and out (distance > 0) by the
* specified amount. The distance is multiplied by the camera's current
* direction and added to its current position, which is then bounded into
* the pan and zoom volume.
*/
public void zoomCamera (float distance)
{
Vector3f loc = _camera.getLocation();
float dist = getGroundPoint().distance(loc),
ndist = Math.min(Math.max(dist + distance, _minZoom), _maxZoom);
if ((distance = ndist - dist) == 0f) {
return;
}
loc.subtractLocal(_camera.getDirection().mult(distance, _temp));
setLocation(loc);
}
/**
* Locates the point on the ground at which the camera is "looking" and
* rotates the camera from that point around the specified vector by the
* specified angle. Additionally zooms the camera in (deltaZoom < 0) or out
* (deltaZoom > 0) along its direction of view by the specified amount.
*/
public void rotateCamera (
Vector3f spot, Vector3f axis, float deltaAngle, float deltaZoom)
{
// get a vector from the camera's current position to the point around
// which we're going to orbit
Vector3f direction = _camera.getLocation().subtract(spot);
// if we're rotating around the left vector, impose tilt limits
if (axis == _camera.getLeft()) {
float angle = FastMath.asin(_ground.normal.dot(direction) /
direction.length());
float nangle = Math.min(Math.max(angle + deltaAngle, _minTilt),
_maxTilt);
if ((deltaAngle = nangle - angle) == 0f) {
return;
}
}
// create a rotation matrix
_rotm.fromAxisAngle(axis, deltaAngle);
// rotate the direction vector and the camera itself
_rotm.mult(direction, direction);
_rotm.mult(_camera.getUp(), _camera.getUp());
_rotm.mult(_camera.getLeft(), _camera.getLeft());
_rotm.mult(_camera.getDirection(), _camera.getDirection());
// if we're rotating around the ground normal, we need to update our
// notion of side-to-side and forward for panning
if (axis == _ground.normal) {
_rotm.mult(_rxdir, _rxdir);
_rotm.mult(_rydir, _rydir);
}
// finally move the camera to its new location, zooming in or out in
// the process
float scale = 1 + (deltaZoom / direction.length());
direction.scaleAdd(scale, spot);
setLocation(direction);
}
/**
* Swings the camera perpendicular to the ground normal, around the point
* on the ground at which it is looking.
*/
public void orbitCamera (float deltaAngle)
{
rotateCamera(getGroundPoint(), _ground.normal, deltaAngle, 0);
}
/**
* Swings the camera perpendicular to its left vector around the point on
* the ground at which it is looking.
*/
public void tiltCamera (float deltaAngle)
{
rotateCamera(getGroundPoint(), _camera.getLeft(), deltaAngle, 0);
}
/**
* Returns the point on the ground (z = 0) at which the camera is looking.
*/
public Vector3f getGroundPoint ()
{
float dist = -1f * _ground.normal.dot(_camera.getLocation()) /
_ground.normal.dot(_camera.getDirection());
return _camera.getLocation().add(_camera.getDirection().mult(dist));
}
/**
* Returns the ground normal. Z is the default ground plane and the normal
* points in the positive z direction. <em>Do not modify this value.</em>
*/
public Vector3f getGroundNormal ()
{
return _ground.normal;
}
protected Vector3f bound (Vector3f loc)
{
if (!_limitsEnabled) {
return loc;
}
if (_boundViaFrustum) {
bound(_camera.getFrustumLeft(), _camera.getFrustumTop(), loc);
bound(_camera.getFrustumLeft(), _camera.getFrustumBottom(), loc);
bound(_camera.getFrustumRight(), _camera.getFrustumTop(), loc);
bound(_camera.getFrustumRight(), _camera.getFrustumBottom(), loc);
} else {
loc.x = Math.max(Math.min(loc.x, _maxX), _minX);
loc.y = Math.max(Math.min(loc.y, _maxY), _minY);
}
loc.z = Math.max(Math.min(loc.z, _maxZ), _minZ);
return loc;
}
protected void bound (float left, float up, Vector3f loc)
{
// start with the location of the camera moved out into the near
// frustum plane
_temp.set(loc);
_temp.scaleAdd(_camera.getFrustumNear(), _camera.getDirection(), loc);
// then slide it over to a corner of the near frustum rectangle
_temp.scaleAdd(left, _camera.getLeft(), _temp);
_temp.scaleAdd(up, _camera.getUp(), _temp);
// turn this into a vector with origin at the camera's location
_temp.subtractLocal(loc);
_temp.normalizeLocal();
// determine the intersection of said vector with the ground plane
float dist = -1f * _ground.normal.dot(loc) / _ground.normal.dot(_temp);
_temp.scaleAdd(dist, _temp, loc);
// we then assume that if the corner of the "viewable ground rectangle"
// is outside our bounds that we can simply adjust the camera location
// by the amount it is out of bounds
if (_temp.x > _maxX) {
loc.x -= (_temp.x - _maxX);
} else if (_temp.x < _minX) {
loc.x += (_minX - _temp.x);
}
if (_temp.y > _maxY) {
loc.y -= (_temp.y - _maxY);
} else if (_temp.y < _minY) {
loc.y += (_minY - _temp.y);
}
}
/** Used to dispatch {@link CameraPath.Observer#pathCompleted}. */
protected static class CompletedOp implements ObserverList.ObserverOp
{
public CompletedOp (CameraPath path) {
_path = path;
}
public boolean apply (Object observer) {
return ((CameraPath.Observer)observer).pathCompleted(_path);
}
protected CameraPath _path;
}
protected Camera _camera;
protected CameraPath _campath;
protected ObserverList _campathobs =
new ObserverList(ObserverList.SAFE_IN_ORDER_NOTIFY);
protected Matrix3f _rotm = new Matrix3f();
protected Vector3f _temp = new Vector3f();
protected boolean _boundViaFrustum, _limitsEnabled = true;
protected float _minX = -Float.MAX_VALUE, _maxX = Float.MAX_VALUE;
protected float _minY = -Float.MAX_VALUE, _maxY = Float.MAX_VALUE;
protected float _minZ = -Float.MAX_VALUE, _maxZ = Float.MAX_VALUE;
protected float _minZoom = 0f, _maxZoom = Float.MAX_VALUE;
protected float _minTilt = -Float.MAX_VALUE, _maxTilt = Float.MAX_VALUE;
protected Vector3f _rxdir = new Vector3f(1, 0, 0);
protected Vector3f _rydir = new Vector3f(0, 1, 0);
protected static final Vector3f _xdir = new Vector3f(1, 0, 0);
protected static final Vector3f _ydir = new Vector3f(0, 1, 0);
protected static final Plane _ground = new Plane(new Vector3f(0, 0, 1), 0);
}
@@ -0,0 +1,69 @@
//
// $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.camera;
import com.jme.renderer.Camera;
/**
* Used to move the camera along a particular path.
*/
public abstract class CameraPath
{
/** Used to inform observers when a camera path is completed or aborted. */
public interface Observer
{
/**
* Called when this path is finished (potentially early because another
* path was set before this path completed).
*
* @param path the path that was completed.
*
* @return true if the observer should remain in the list, false if it
* should be removed following this notification.
*/
public boolean pathCompleted (CameraPath path);
}
/**
* This is called on every frame to allow the path to adjust the position
* of the camera.
*
* @return true if the path is completed and can be disposed, false if it
* is not yet completed.
*/
public abstract boolean tick (float secondsSince);
/**
* Called if this path is aborted prior to completion due to being replaced
* by a new camera path.
*/
public void abort ()
{
}
protected CameraPath (CameraHandler camhand)
{
_camhand = camhand;
}
protected CameraHandler _camhand;
}
@@ -0,0 +1,191 @@
//
// $Id$
package com.threerings.jme.camera;
import com.jme.math.FastMath;
import com.jme.math.Matrix3f;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.RelativeMouse;
import com.jme.input.action.*;
import com.jme.input.action.InputActionEvent;
import com.threerings.jme.JmeApp;
import com.threerings.jme.Log;
/**
* Sets up camera controls for moving around from a top-down perspective,
* suitable for strategy games and their ilk. The "ground" is assumed to be the
* XY plane.
*/
public class GodViewHandler extends InputHandler
{
/**
* Creates the handler.
*
* @param cam The camera to move with this handler.
*/
public GodViewHandler (CameraHandler camhand)
{
_camhand = camhand;
setKeyBindings();
addActions();
}
protected void setKeyBindings ()
{
KeyBindingManager keyboard = KeyBindingManager.getKeyBindingManager();
// the key bindings for the pan actions
keyboard.set("forward", KeyInput.KEY_W);
keyboard.set("arrow_forward", KeyInput.KEY_UP);
keyboard.set("backward", KeyInput.KEY_S);
keyboard.set("arrow_backward", KeyInput.KEY_DOWN);
keyboard.set("left", KeyInput.KEY_A);
keyboard.set("arrow_left", KeyInput.KEY_LEFT);
keyboard.set("right", KeyInput.KEY_D);
keyboard.set("arrow_right", KeyInput.KEY_RIGHT);
// the key bindings for the zoom actions
keyboard.set("zoomIn", KeyInput.KEY_UP);
keyboard.set("zoomOut", KeyInput.KEY_DOWN);
// the key bindings for the orbit actions
keyboard.set("turnRight", KeyInput.KEY_RIGHT);
keyboard.set("turnLeft", KeyInput.KEY_LEFT);
// the key bindings for the tilt actions
keyboard.set("tiltForward", KeyInput.KEY_HOME);
keyboard.set("tiltBack", KeyInput.KEY_END);
keyboard.set("screenshot", KeyInput.KEY_F12);
}
protected void addActions ()
{
addAction(new KeyScreenShotAction(), "screenshot", false);
addPanActions();
addZoomActions();
addOrbitActions();
addTiltActions();
}
/**
* Adds actions for panning the camera around the scene.
*/
protected void addPanActions ()
{
InputAction forward = new InputAction() {
public void performAction (InputActionEvent evt) {
_camhand.panCamera(0, speed * evt.getTime());
}
};
forward.setSpeed(0.5f);
addAction(forward, "forward", true);
addAction(forward, "arrow_forward", true);
InputAction backward = new InputAction() {
public void performAction (InputActionEvent evt) {
_camhand.panCamera(0, -speed * evt.getTime());
}
};
backward.setSpeed(0.5f);
addAction(backward, "backward", true);
addAction(backward, "arrow_backward", true);
InputAction left = new InputAction() {
public void performAction (InputActionEvent evt) {
_camhand.panCamera(-speed * evt.getTime(), 0);
}
};
left.setSpeed(0.5f);
addAction(left, "left", true);
addAction(left, "arrow_left", true);
InputAction right = new InputAction() {
public void performAction (InputActionEvent evt) {
_camhand.panCamera(speed * evt.getTime(), 0);
}
};
right.setSpeed(0.5f);
addAction(right, "right", true);
addAction(right, "arrow_right", true);
}
/**
* Adds actions for zooming the camaera in and out.
*/
protected void addZoomActions ()
{
InputAction zoomIn = new InputAction() {
public void performAction (InputActionEvent evt) {
_camhand.zoomCamera(-speed * evt.getTime());
}
};
zoomIn.setSpeed(0.5f);
addAction(zoomIn, "zoomIn", true);
InputAction zoomOut = new InputAction() {
public void performAction (InputActionEvent evt) {
_camhand.zoomCamera(speed * evt.getTime());
}
};
zoomOut.setSpeed(0.5f);
addAction(zoomOut, "zoomOut", true);
}
/**
* Adds actions for orbiting the camera around the viewpoint.
*/
protected void addOrbitActions ()
{
addAction(new OrbitAction(-FastMath.PI / 2), "turnRight", true);
addAction(new OrbitAction(FastMath.PI / 2), "turnLeft", true);
}
/**
* Adds actions for tilting the camera (rotating around the yaw axis).
*/
protected void addTiltActions ()
{
addAction(new TiltAction(-FastMath.PI / 2), "tiltForward", true);
addAction(new TiltAction(FastMath.PI / 2), "tiltBack", true);
}
protected class OrbitAction extends InputAction
{
public OrbitAction (float radPerSec)
{
_radPerSec = radPerSec;
}
public void performAction (InputActionEvent evt)
{
_camhand.orbitCamera(_radPerSec * evt.getTime());
}
protected float _radPerSec;
}
protected class TiltAction extends InputAction
{
public TiltAction (float radPerSec)
{
_radPerSec = radPerSec;
}
public void performAction (InputActionEvent evt)
{
_camhand.tiltCamera(_radPerSec * evt.getTime());
}
protected float _radPerSec;
}
protected CameraHandler _camhand;
}
@@ -0,0 +1,87 @@
//
// $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.camera;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
/**
* Pans the camera to the specified location in the specified amount of time.
*/
public class PanPath extends CameraPath
{
/**
* Creates a panning path for the specified camera that will retain the
* camera's current orientation.
*
* @param target the target position for the camera.
* @param duration the number of seconds in which to pan the camera.
*/
public PanPath (CameraHandler camhand, Vector3f target, float duration)
{
this(camhand, target, null, duration);
}
/**
* Creates a panning path for the specified camera.
*
* @param target the target position for the camera.
* @param trot the target rotation for the camera (or <code>null</code> to
* keep its current orientation)
* @param duration the number of seconds in which to pan the camera.
*/
public PanPath (CameraHandler camhand, Vector3f target, Quaternion trot,
float duration)
{
super(camhand);
Camera cam = camhand.getCamera();
_start = new Vector3f(cam.getLocation());
_velocity = target.subtract(_start);
_velocity.divideLocal(duration);
if (trot != null) {
_irot = new Quaternion();
_irot.fromAxes(cam.getLeft(), cam.getUp(), cam.getDirection());
_trot = trot;
}
_duration = duration;
}
// documentation inherited
public boolean tick (float secondsSince)
{
_elapsed = Math.min(_elapsed + secondsSince, _duration);
_camloc.scaleAdd(_elapsed, _velocity, _start);
_camhand.setLocation(_camloc);
if (_irot != null) {
_camhand.getCamera().setAxes(_axes.slerp(_irot, _trot,
_elapsed / _duration));
}
return (_elapsed >= _duration);
}
protected Vector3f _start, _velocity, _camloc = new Vector3f();
protected Quaternion _irot, _trot, _axes = new Quaternion();
protected float _elapsed, _duration;
}
@@ -0,0 +1,113 @@
//
// $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.camera;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.threerings.jme.Log;
/**
* Moves the camera along a cubic Hermite spline path defined by the start and
* end locations and directions. Spline formulas obtained from
* <a href="http://en.wikipedia.org/wiki/Cubic_Hermite_spline">Wikipedia</a>.
*/
public class SplinePath extends CameraPath
{
/**
* Creates a cubic spline path for the camera to follow.
*
* @param tloc the target location
* @param tdir the target direction
* @param axis the heading axis (typically {@link Vector3f#UNIT_Z})
* @param duration the duration of the path
* @param tension the tension parameter, which can range from zero to one:
* higher tension values create a more direct path with a sharper turn,
* lower values create a rounder path with a smoother turn
*/
public SplinePath (CameraHandler camhand, Vector3f tloc,
Vector3f tdir, Vector3f axis, float duration, float tension)
{
super(camhand);
// get the spline function coefficients
Camera cam = camhand.getCamera();
_p0 = new Vector3f(cam.getLocation());
_p1 = new Vector3f(tloc);
float tscale = (1f - tension) * _p0.distance(_p1);
_m0 = cam.getDirection().mult(tscale);
_m1 = tdir.mult(tscale);
_axis = axis;
_duration = duration;
}
// documentation inherited
public boolean tick (float secondsSince)
{
_elapsed = Math.min(_elapsed + secondsSince, _duration);
float t = _elapsed / _duration, t2 = t*t, t3 = t2*t,
h00 = 2*t3 - 3*t2 + 1,
h00p = 6*t2 - 6*t,
h10 = t3 - 2*t2 + t,
h10p = 3*t2 - 4*t + 1,
h01 = -2*t3 + 3*t2,
h01p = -6*t2 + 6*t,
h11 = t3 - t2,
h11p = 3*t2 - 2*t;
// take the derivative to find the direction
_p0.mult(h00p, _dir);
_dir.scaleAdd(h10p, _m0, _dir);
_dir.scaleAdd(h01p, _p1, _dir);
_dir.scaleAdd(h11p, _m1, _dir);
_dir.normalizeLocal();
// evaluate the spline function to find the location
_p0.mult(h00, _loc);
_loc.scaleAdd(h10, _m0, _loc);
_loc.scaleAdd(h01, _p1, _loc);
_loc.scaleAdd(h11, _m1, _loc);
// compute the left and up vectors using the direction and
// axis vectors
Camera cam = _camhand.getCamera();
_axis.cross(_dir, _left);
_left.normalizeLocal();
_dir.cross(_left, _up);
// update the camera's location and orientation
cam.setFrame(_loc, _left, _up, _dir);
return _elapsed >= _duration;
}
/** The parameters of the spline. */
Vector3f _p0, _m0, _p1, _m1, _axis;
/** Working vectors. */
Vector3f _loc = new Vector3f(), _left = new Vector3f(),
_up = new Vector3f(), _dir = new Vector3f();
/** The elapsed time and total duration. */
float _elapsed, _duration;
}
@@ -0,0 +1,168 @@
//
// $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.camera;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.threerings.jme.Log;
/**
* Swings the camera around a point of interest (which should be somewhere
* along the camera's view vector). Also optionally pans the camera and/or
* zooms it in or out (moves it along its view vector) in the process.
*
* <p align="center"><img src="rotate_zoom.png">
*/
public class SwingPath extends CameraPath
{
/**
* Creates a rotating, zooming path for the specified camera.
*
* @param spot the point of interest around which to swing the camera.
* @param axis the axis around which to rotate the camera.
* @param angle the angle through which to rotate the camera.
* @param angvel the (absolute value of the) velocity at which to rotate
* the camera (in radians per second).
* @param zoom the distance to zoom along the camera's view axis (negative
* = in, positive = out).
*/
public SwingPath (CameraHandler camhand, Vector3f spot, Vector3f axis,
float angle, float angvel, float zoom)
{
this(camhand, spot, axis, angle, angvel, null, 0f, null, zoom);
}
/**
* Creates a rotating, panning, zooming path for the specified camera.
*
* @param spot the point of interest around which to swing the camera.
* @param paxis the primary axis around which to rotate the camera.
* @param pangle the angle through which to rotate the camera about the
* primary axis.
* @param angvel the (absolute value of the) velocity at which to rotate
* the camera (in radians per second) about the primary angle.
* @param saxis the secondary axis around which to rotate the camera, or
* <code>null</code> for none
* @param sangle the angle through which to rotate the camera about the
* secondary axis
* @param pan the amount to pan the camera, or <code>null</code> for none
* @param zoom the distance to zoom along the camera's view axis (negative
* = in, positive = out).
*/
public SwingPath (CameraHandler camhand, Vector3f spot, Vector3f paxis,
float pangle, float angvel, Vector3f saxis, float sangle,
Vector3f pan, float zoom)
{
super(camhand);
if (pangle == 0) {
Log.warning("Requested to swing camera through zero degrees " +
"[spot=" + spot + ", paxis=" + paxis +
", angvel=" + angvel + ", zoom=" + zoom + "].");
pangle = 0.0001f;
}
if (angvel <= 0) {
Log.warning("Requested to swing camera with invalid velocity " +
"[spot=" + spot + ", paxis=" + paxis + ", pangle=" +
pangle + ", angvel=" + angvel + ", zoom=" + zoom +
"].");
angvel = FastMath.PI;
}
_spot = new Vector3f(spot);
_paxis = paxis;
_pangle = pangle;
_pangvel = (pangle > 0) ? angvel : -1 * angvel;
_saxis = (saxis == null) ? null : new Vector3f(saxis);
_sangle = sangle;
_sangvel = _sangle * _pangvel / _pangle;
_pan = pan;
if (_pan != null) {
_panvel = _pan.mult(_pangvel / _pangle);
_panned = new Vector3f();
}
_zoom = zoom;
_zoomvel = _zoom * _pangvel / _pangle;
// Log.info("Swinging camera [angle=" + _angle + ", angvel=" + _angvel +
// ", zoom=" + _zoom + ", zoomvel=" + _zoomvel + "].");
}
// documentation inherited
public boolean tick (float secondsSince)
{
float deltaPAngle = (secondsSince * _pangvel);
float deltaSAngle = (secondsSince * _sangvel);
float deltaZoom = (secondsSince * _zoomvel);
_protated += deltaPAngle;
_srotated += deltaSAngle;
_zoomed += deltaZoom;
if (_pan != null) {
_panvel.mult(secondsSince, _deltaPan);
_panned.addLocal(_deltaPan);
}
// clamp our rotation at the target angle and determine whether or not
// we're done
boolean done = false;
if (_pangle > 0 && _protated > _pangle ||
_pangle < 0 && _protated < _pangle) {
deltaPAngle -= (_protated - _pangle);
deltaSAngle -= (_srotated - _sangle);
deltaZoom -= (_zoomed - _zoom);
if (_pan != null) {
_deltaPan.subtractLocal(_panned).addLocal(_pan);
}
_protated = _pangle;
_srotated = _sangle;
_panned = _pan;
_zoomed = _zoom;
done = true;
}
// have the camera handler do the necessary rotating, panning, zooming
if (_pan != null) {
_camhand.setLocation(
_camhand.getCamera().getLocation().addLocal(_deltaPan));
_spot.addLocal(_deltaPan);
}
_camhand.rotateCamera(_spot, _paxis, deltaPAngle, deltaZoom);
if (_saxis != null) {
_rot.fromAngleAxis(deltaPAngle, _paxis).multLocal(_saxis);
_camhand.rotateCamera(_spot, _saxis, deltaSAngle, 0f);
}
return done;
}
protected Vector3f _spot, _paxis, _saxis;
protected float _pangle, _pangvel, _protated;
protected float _sangle, _sangvel, _srotated;
protected Vector3f _pan, _panvel, _panned;
protected float _zoom, _zoomvel, _zoomed;
protected Quaternion _rot = new Quaternion();
protected Vector3f _deltaPan = new Vector3f();
}
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB