8dec58c227
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3541 542714f4-19e9-0310-aa3c-eee0fc999fb1
312 lines
9.9 KiB
Java
312 lines
9.9 KiB
Java
//
|
|
// $Id$
|
|
|
|
package com.threerings.jme.input;
|
|
|
|
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.InputSystem;
|
|
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 app The application to be terminated on an "exit" action.
|
|
* @param cam The camera to move with this handler.
|
|
* @param api The API from which to create a KeyBindingManager.
|
|
*/
|
|
public GodViewHandler (JmeApp app, Camera cam, String api)
|
|
{
|
|
_camera = cam;
|
|
setKeyBindings(api);
|
|
setMouse(cam);
|
|
setActions(cam, app);
|
|
}
|
|
|
|
/**
|
|
* Configures the minimum and maximum z-axis elevation allowed for the
|
|
* camera.
|
|
*/
|
|
public void setZoomLimits (float minZ, float maxZ)
|
|
{
|
|
_minZ = minZ;
|
|
_maxZ = maxZ;
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
protected void setKeyBindings (String api)
|
|
{
|
|
KeyBindingManager keyboard = KeyBindingManager.getKeyBindingManager();
|
|
InputSystem.createInputSystem(api);
|
|
|
|
keyboard.setKeyInput(InputSystem.getKeyInput());
|
|
keyboard.set("forward", KeyInput.KEY_W);
|
|
keyboard.set("backward", KeyInput.KEY_S);
|
|
keyboard.set("left", KeyInput.KEY_A);
|
|
keyboard.set("right", KeyInput.KEY_D);
|
|
keyboard.set("zoomIn", KeyInput.KEY_UP);
|
|
keyboard.set("zoomOut", KeyInput.KEY_DOWN);
|
|
keyboard.set("turnRight", KeyInput.KEY_RIGHT);
|
|
keyboard.set("turnLeft", KeyInput.KEY_LEFT);
|
|
keyboard.set("rollForward", KeyInput.KEY_HOME);
|
|
keyboard.set("rollBack", KeyInput.KEY_END);
|
|
keyboard.set("screenshot", KeyInput.KEY_F12);
|
|
keyboard.set("exit", KeyInput.KEY_ESCAPE);
|
|
|
|
setKeyBindingManager(keyboard);
|
|
}
|
|
|
|
protected void setMouse (Camera cam)
|
|
{
|
|
// RelativeMouse mouse = new RelativeMouse("Mouse Input");
|
|
// mouse.setMouseInput(InputSystem.getMouseInput());
|
|
// setMouse(mouse);
|
|
|
|
// MouseLook mouseLook = new MouseLook(mouse, cam, 1.0f);
|
|
// mouseLook.setKey("mouselook");
|
|
// mouseLook.setLockAxis(
|
|
// new Vector3f(cam.getUp().x, cam.getUp().y, cam.getUp().z));
|
|
// addAction(mouseLook);
|
|
}
|
|
|
|
protected void setActions (Camera cam, final JmeApp app)
|
|
{
|
|
KeyInputAction exit = new KeyInputAction() {
|
|
public void performAction (InputActionEvent evt) {
|
|
app.stop();
|
|
}
|
|
};
|
|
exit.setKey("exit");
|
|
addAction(exit);
|
|
|
|
KeyScreenShotAction screen = new KeyScreenShotAction();
|
|
screen.setKey("screenshot");
|
|
addAction(screen);
|
|
|
|
CameraAction forward = new CameraAction(cam, 0.5f) {
|
|
public void performAction (InputActionEvent evt) {
|
|
Vector3f loc = _camera.getLocation();
|
|
loc.addLocal(_rydir.mult(speed * evt.getTime(), _temp));
|
|
_camera.setLocation(loc);
|
|
_camera.update();
|
|
}
|
|
};
|
|
forward.setKey("forward");
|
|
addAction(forward);
|
|
|
|
CameraAction backward = new CameraAction(cam, 0.5f) {
|
|
public void performAction (InputActionEvent evt) {
|
|
Vector3f loc = _camera.getLocation();
|
|
loc.subtractLocal(_rydir.mult(speed * evt.getTime(), _temp));
|
|
_camera.setLocation(loc);
|
|
_camera.update();
|
|
}
|
|
};
|
|
backward.setKey("backward");
|
|
addAction(backward);
|
|
|
|
CameraAction left = new CameraAction(cam, 0.5f) {
|
|
public void performAction (InputActionEvent evt) {
|
|
Vector3f loc = _camera.getLocation();
|
|
loc.subtractLocal(_rxdir.mult(speed * evt.getTime(), _temp));
|
|
_camera.setLocation(loc);
|
|
_camera.update();
|
|
}
|
|
};
|
|
left.setKey("left");
|
|
addAction(left);
|
|
|
|
CameraAction right = new CameraAction(cam, 0.5f) {
|
|
public void performAction (InputActionEvent evt) {
|
|
Vector3f loc = _camera.getLocation();
|
|
loc.addLocal(_rxdir.mult(speed * evt.getTime(), _temp));
|
|
_camera.setLocation(loc);
|
|
_camera.update();
|
|
}
|
|
};
|
|
right.setKey("right");
|
|
addAction(right);
|
|
|
|
CameraAction zoomIn = new CameraAction(cam, 0.5f) {
|
|
public void performAction (InputActionEvent evt) {
|
|
Vector3f loc = _camera.getLocation();
|
|
if (loc.z > _minZ) {
|
|
_camera.getDirection().mult(speed * evt.getTime(), _temp);
|
|
loc.addLocal(_temp);
|
|
_camera.setLocation(loc);
|
|
_camera.update();
|
|
}
|
|
}
|
|
};
|
|
zoomIn.setKey("zoomIn");
|
|
addAction(zoomIn);
|
|
|
|
CameraAction zoomOut = new CameraAction(cam, 0.5f) {
|
|
public void performAction (InputActionEvent evt) {
|
|
Vector3f loc = _camera.getLocation();
|
|
if (loc.z < _maxZ) {
|
|
_camera.getDirection().mult(speed * evt.getTime(), _temp);
|
|
loc.subtractLocal(_temp);
|
|
_camera.setLocation(loc);
|
|
_camera.update();
|
|
}
|
|
}
|
|
};
|
|
zoomOut.setKey("zoomOut");
|
|
addAction(zoomOut);
|
|
|
|
OrbitAction orbitRight = new OrbitAction(-FastMath.PI / 2);
|
|
orbitRight.setKey("turnRight");
|
|
addAction(orbitRight);
|
|
|
|
OrbitAction orbitLeft = new OrbitAction(FastMath.PI / 2);
|
|
orbitLeft.setKey("turnLeft");
|
|
addAction(orbitLeft);
|
|
|
|
RollAction rollForward = new RollAction(-FastMath.PI / 2);
|
|
rollForward.setKey("rollForward");
|
|
addAction(rollForward);
|
|
|
|
RollAction rollBack = new RollAction(FastMath.PI / 2);
|
|
rollBack.setKey("rollBack");
|
|
addAction(rollBack);
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
protected void rotateCamera (Vector3f around, float deltaAngle)
|
|
{
|
|
// locate the point at which the camera is "pointing" on
|
|
// the ground plane
|
|
Vector3f camloc = _camera.getLocation();
|
|
Vector3f center = groundPoint(_camera);
|
|
|
|
// get a vector from the camera's position to the point
|
|
// around which we're going to orbit
|
|
Vector3f direction = camloc.subtract(center);
|
|
|
|
// create a rotation matrix
|
|
_rotm.fromAxisAngle(around, deltaAngle);
|
|
|
|
// rotate the center to camera 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 (around == _groundNormal) {
|
|
_rotm.mult(_rxdir, _rxdir);
|
|
_rotm.mult(_rydir, _rydir);
|
|
}
|
|
|
|
// and move the camera to its new location
|
|
_camera.setLocation(center.add(direction));
|
|
|
|
_camera.update();
|
|
}
|
|
|
|
protected static Vector3f groundPoint (Camera camera)
|
|
{
|
|
float dist = -1f * _groundNormal.dot(camera.getLocation()) /
|
|
_groundNormal.dot(camera.getDirection());
|
|
return camera.getLocation().add(camera.getDirection().mult(dist));
|
|
}
|
|
|
|
protected abstract class CameraAction extends KeyInputAction
|
|
{
|
|
public CameraAction (Camera camera, float speed)
|
|
{
|
|
_camera = camera;
|
|
this.speed = speed;
|
|
}
|
|
|
|
/** The camera to manipulate. */
|
|
protected Camera _camera;
|
|
|
|
/** A temporary vector. */
|
|
protected Vector3f _temp = new Vector3f();
|
|
}
|
|
|
|
protected class OrbitAction extends KeyInputAction
|
|
{
|
|
public OrbitAction (float radPerSec)
|
|
{
|
|
_radPerSec = radPerSec;
|
|
}
|
|
|
|
public void performAction (InputActionEvent evt)
|
|
{
|
|
rotateCamera(_groundNormal, _radPerSec * evt.getTime());
|
|
}
|
|
|
|
protected float _radPerSec;
|
|
}
|
|
|
|
protected class RollAction extends KeyInputAction
|
|
{
|
|
public RollAction (float radPerSec)
|
|
{
|
|
_radPerSec = radPerSec;
|
|
}
|
|
|
|
public void performAction (InputActionEvent evt)
|
|
{
|
|
rotateCamera(_camera.getLeft(), _radPerSec * evt.getTime());
|
|
}
|
|
|
|
protected float _radPerSec;
|
|
}
|
|
|
|
protected Camera _camera;
|
|
protected Matrix3f _rotm = new Matrix3f();
|
|
|
|
protected float _minZ = Float.MIN_VALUE, _maxZ = Float.MAX_VALUE;
|
|
protected static final Vector3f _xdir = new Vector3f(1, 0, 0);
|
|
protected static final Vector3f _ydir = new Vector3f(0, 1, 0);
|
|
|
|
protected static final Vector3f _rxdir = new Vector3f(1, 0, 0);
|
|
protected static final Vector3f _rydir = new Vector3f(0, 1, 0);
|
|
|
|
protected static final Vector3f _groundNormal = new Vector3f(0, 0, 1);
|
|
}
|