More JME wirey uppy bits.
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3513 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -28,18 +28,27 @@ import com.samskivert.util.RunQueue;
|
|||||||
import com.samskivert.util.StringUtil;
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
import com.jme.app.AbstractGame;
|
import com.jme.app.AbstractGame;
|
||||||
|
import com.jme.input.InputHandler;
|
||||||
|
import com.jme.math.Vector3f;
|
||||||
|
import com.jme.renderer.Camera;
|
||||||
|
import com.jme.renderer.ColorRGBA;
|
||||||
|
import com.jme.scene.Node;
|
||||||
|
import com.jme.system.DisplaySystem;
|
||||||
|
import com.jme.system.JmeException;
|
||||||
import com.jme.system.PropertiesIO;
|
import com.jme.system.PropertiesIO;
|
||||||
import com.jme.system.lwjgl.LWJGLPropertiesDialog;
|
import com.jme.system.lwjgl.LWJGLPropertiesDialog;
|
||||||
import com.jme.util.Timer;
|
import com.jme.util.Timer;
|
||||||
|
|
||||||
import com.threerings.presents.client.Client;
|
import com.threerings.presents.client.Client;
|
||||||
|
|
||||||
|
import com.threerings.jme.input.GodViewHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extends the {@link AbstractGame} providing integration with the
|
* Defines a basic application framework providing integration with the
|
||||||
* <a href="../presents/package.html">Presents</a> networking system and
|
* <a href="../presents/package.html">Presents</a> networking system and
|
||||||
* targeting a fixed framerate.
|
* targeting a fixed framerate.
|
||||||
*/
|
*/
|
||||||
public abstract class JmeApp extends AbstractGame
|
public class JmeApp
|
||||||
implements RunQueue
|
implements RunQueue
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -63,10 +72,14 @@ public abstract class JmeApp extends AbstractGame
|
|||||||
if (framesPerSecond <= 0) {
|
if (framesPerSecond <= 0) {
|
||||||
throw new IllegalArgumentException("FPS must be > 0.");
|
throw new IllegalArgumentException("FPS must be > 0.");
|
||||||
}
|
}
|
||||||
_targetTicksPerFrame = _timer.getResolution() / framesPerSecond;
|
_targetFrameTime = (float)_timer.getResolution() / framesPerSecond;
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited
|
/**
|
||||||
|
* Initializes this application and starts up the main rendering and
|
||||||
|
* event processing loop. This method will not return until the
|
||||||
|
* application is terminated with a call to {@link #stop}.
|
||||||
|
*/
|
||||||
public void start ()
|
public void start ()
|
||||||
{
|
{
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@@ -75,10 +88,10 @@ public abstract class JmeApp extends AbstractGame
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// load up our renderer configuration
|
// load up our renderer configuration
|
||||||
properties = new PropertiesIO(getConfigPath("jme.cfg"));
|
_properties = new PropertiesIO(getConfigPath("jme.cfg"));
|
||||||
if (!properties.load()) {
|
if (!_properties.load()) {
|
||||||
LWJGLPropertiesDialog dialog =
|
LWJGLPropertiesDialog dialog =
|
||||||
new LWJGLPropertiesDialog(properties, (String)null);
|
new LWJGLPropertiesDialog(_properties, (String)null);
|
||||||
while (dialog.isVisible()) {
|
while (dialog.isVisible()) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(5);
|
Thread.sleep(5);
|
||||||
@@ -90,26 +103,28 @@ public abstract class JmeApp extends AbstractGame
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create an appropriate timer
|
// create an appropriate timer
|
||||||
_timer = Timer.getTimer(properties.getRenderer());
|
_timer = Timer.getTimer(_properties.getRenderer());
|
||||||
|
|
||||||
// default to 60 fps
|
// default to 60 fps
|
||||||
setTargetFrameRate(60);
|
setTargetFrameRate(60);
|
||||||
|
|
||||||
// initialize the AbstractGame
|
// initialize the rendering system
|
||||||
initSystem();
|
initDisplay();
|
||||||
assertDisplayCreated();
|
if (!_display.isCreated()) {
|
||||||
|
throw new IllegalStateException("Failed to initialize display?");
|
||||||
|
}
|
||||||
|
|
||||||
// initialize our derived class
|
// initialize our main camera controls and user input handling
|
||||||
initGame();
|
initInput();
|
||||||
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
Log.logStackTrace(t);
|
Log.logStackTrace(t);
|
||||||
quit();
|
exit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// enter the main rendering and event processing loop
|
// enter the main rendering and event processing loop
|
||||||
while (!finished && !display.isClosing()) {
|
while (!_finished && !_display.isClosing()) {
|
||||||
try {
|
try {
|
||||||
processFrame();
|
processFrame();
|
||||||
_failures = 0;
|
_failures = 0;
|
||||||
@@ -118,21 +133,28 @@ public abstract class JmeApp extends AbstractGame
|
|||||||
Log.logStackTrace(t);
|
Log.logStackTrace(t);
|
||||||
// stick a fork in things if we fail too many times in a row
|
// stick a fork in things if we fail too many times in a row
|
||||||
if (++_failures > MAX_SUCCESSIVE_FAILURES) {
|
if (++_failures > MAX_SUCCESSIVE_FAILURES) {
|
||||||
finish();
|
stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cleanup();
|
cleanup();
|
||||||
display.reset();
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
Log.logStackTrace(t);
|
Log.logStackTrace(t);
|
||||||
} finally {
|
} finally {
|
||||||
quit();
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructs the application to stop the main loop, cleanup and exit.
|
||||||
|
*/
|
||||||
|
public void stop ()
|
||||||
|
{
|
||||||
|
_finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
// documentation inherited from interface RunQueue
|
// documentation inherited from interface RunQueue
|
||||||
public void postRunnable (Runnable r)
|
public void postRunnable (Runnable r)
|
||||||
{
|
{
|
||||||
@@ -145,18 +167,70 @@ public abstract class JmeApp extends AbstractGame
|
|||||||
return Thread.currentThread() == _dispatchThread;
|
return Thread.currentThread() == _dispatchThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the underlying rendering system, creating a display of
|
||||||
|
* the proper resolution and depth.
|
||||||
|
*/
|
||||||
|
protected void initDisplay ()
|
||||||
|
throws JmeException
|
||||||
|
{
|
||||||
|
// create the main display system
|
||||||
|
_display = DisplaySystem.getDisplaySystem(_properties.getRenderer());
|
||||||
|
_display.createWindow(
|
||||||
|
_properties.getWidth(), _properties.getHeight(),
|
||||||
|
_properties.getDepth(), _properties.getFreq(),
|
||||||
|
_properties.getFullscreen());
|
||||||
|
|
||||||
|
// create a camera
|
||||||
|
float width = _display.getWidth(), height = _display.getHeight();
|
||||||
|
_camera = _display.getRenderer().createCamera((int)width, (int)height);
|
||||||
|
|
||||||
|
// start with a black background
|
||||||
|
_display.getRenderer().setBackgroundColor(ColorRGBA.black);
|
||||||
|
|
||||||
|
// set up the camera
|
||||||
|
_camera.setFrustumPerspective(45.0f, width / height, 1, 1000);
|
||||||
|
Vector3f loc = new Vector3f(0.0f, 0.0f, 25.0f);
|
||||||
|
Vector3f left = new Vector3f( -1.0f, 0.0f, 0.0f);
|
||||||
|
Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);
|
||||||
|
Vector3f dir = new Vector3f(0.0f, 0f, -1.0f);
|
||||||
|
_camera.setFrame(loc, left, up, dir);
|
||||||
|
_camera.update();
|
||||||
|
_display.getRenderer().setCamera(_camera);
|
||||||
|
|
||||||
|
// tell the renderer to keep track of rendering information (total
|
||||||
|
// triangles drawn, etc.)
|
||||||
|
_display.getRenderer().enableStatistics(true);
|
||||||
|
|
||||||
|
// // set our display title
|
||||||
|
// _display.setTitle("TBD");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up a main input controller to handle the camera and deal with
|
||||||
|
* global user input.
|
||||||
|
*/
|
||||||
|
protected void initInput ()
|
||||||
|
{
|
||||||
|
_input = new GodViewHandler(this, _camera, _properties.getRenderer());
|
||||||
|
|
||||||
|
// /** Signal to all key inputs they should work Nx faster. */
|
||||||
|
// input.setKeySpeed(150f);
|
||||||
|
// input.setMouseSpeed(1f);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a single frame.
|
* Processes a single frame.
|
||||||
*/
|
*/
|
||||||
protected final void processFrame ()
|
protected final void processFrame ()
|
||||||
{
|
{
|
||||||
_frameStart = _timer.getTime();
|
float frameStart = _timer.getTime();
|
||||||
|
|
||||||
// update our simulation and render a frame
|
// update our simulation and render a frame
|
||||||
update(-1f);
|
update(frameStart);
|
||||||
render(-1f);
|
render(frameStart);
|
||||||
|
|
||||||
display.getRenderer().displayBackBuffer();
|
_display.getRenderer().displayBackBuffer();
|
||||||
_frames++;
|
_frames++;
|
||||||
|
|
||||||
// now process events or sleep until the next frame
|
// now process events or sleep until the next frame
|
||||||
@@ -171,14 +245,58 @@ public abstract class JmeApp extends AbstractGame
|
|||||||
} else {
|
} else {
|
||||||
r.run();
|
r.run();
|
||||||
}
|
}
|
||||||
} while (_timer.getTime() - _frameStart < _targetTicksPerFrame);
|
} while (_timer.getTime() - frameStart < _targetFrameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited
|
/**
|
||||||
protected void quit ()
|
* Called every frame to update whatever sort of real time business we
|
||||||
|
* have that needs updating.
|
||||||
|
*/
|
||||||
|
protected void update (float frameTime)
|
||||||
{
|
{
|
||||||
if (display != null) {
|
// recalculate the frame rate
|
||||||
display.close();
|
_timer.update();
|
||||||
|
|
||||||
|
// update the input system
|
||||||
|
float timePerFrame = _timer.getTimePerFrame();
|
||||||
|
_input.update(timePerFrame);
|
||||||
|
|
||||||
|
// run all of the controllers attached to nodes
|
||||||
|
_root.updateGeometricState(timePerFrame, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called every frame to issue the rendering instructions for this frame.
|
||||||
|
*/
|
||||||
|
protected void render (float frameTime)
|
||||||
|
{
|
||||||
|
// clear out our previous information
|
||||||
|
_display.getRenderer().clearStatistics();
|
||||||
|
_display.getRenderer().clearBuffers();
|
||||||
|
|
||||||
|
// draw the root node and all of its children
|
||||||
|
_display.getRenderer().draw(_root);
|
||||||
|
|
||||||
|
// this would render bounding boxes
|
||||||
|
// _display.getRenderer().drawBounds(_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the application is terminating cleanly after having
|
||||||
|
* successfully completed initialization and begun the main loop.
|
||||||
|
*/
|
||||||
|
protected void cleanup ()
|
||||||
|
{
|
||||||
|
_display.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the display and exits the JVM process.
|
||||||
|
*/
|
||||||
|
protected void exit ()
|
||||||
|
{
|
||||||
|
if (_display != null) {
|
||||||
|
_display.close();
|
||||||
}
|
}
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
@@ -205,14 +323,19 @@ public abstract class JmeApp extends AbstractGame
|
|||||||
protected Timer _timer;
|
protected Timer _timer;
|
||||||
protected Thread _dispatchThread;
|
protected Thread _dispatchThread;
|
||||||
protected Queue _evqueue = new Queue();
|
protected Queue _evqueue = new Queue();
|
||||||
|
protected boolean _finished;
|
||||||
|
|
||||||
|
protected PropertiesIO _properties;
|
||||||
|
protected DisplaySystem _display;
|
||||||
|
protected Camera _camera;
|
||||||
|
protected InputHandler _input;
|
||||||
|
protected Node _root;
|
||||||
|
|
||||||
protected int _failures;
|
protected int _failures;
|
||||||
|
|
||||||
protected int _frames;
|
protected int _frames;
|
||||||
protected float _lastFPSStamp;
|
protected float _lastFPSStamp;
|
||||||
|
protected float _targetFrameTime;
|
||||||
protected long _targetTicksPerFrame;
|
|
||||||
protected long _frameStart;
|
|
||||||
|
|
||||||
/** If we fail 100 frames in a row, stick a fork in ourselves. */
|
/** If we fail 100 frames in a row, stick a fork in ourselves. */
|
||||||
protected static final int MAX_SUCCESSIVE_FAILURES = 100;
|
protected static final int MAX_SUCCESSIVE_FAILURES = 100;
|
||||||
|
|||||||
@@ -0,0 +1,248 @@
|
|||||||
|
//
|
||||||
|
// $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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
setKeyBindings(api);
|
||||||
|
setMouse(cam);
|
||||||
|
setActions(cam, app);
|
||||||
|
}
|
||||||
|
|
||||||
|
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("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.addLocal(_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.subtractLocal(_rxdir.mult(speed * evt.getTime(), _temp));
|
||||||
|
_camera.setLocation(loc);
|
||||||
|
_camera.update();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
right.setKey("right");
|
||||||
|
addAction(right);
|
||||||
|
|
||||||
|
KeyForwardAction zoomIn = new KeyForwardAction(cam, 0.5f);
|
||||||
|
zoomIn.setKey("zoomIn");
|
||||||
|
addAction(zoomIn);
|
||||||
|
KeyBackwardAction zoomOut = new KeyBackwardAction(cam, 0.5f);
|
||||||
|
zoomOut.setKey("zoomOut");
|
||||||
|
addAction(zoomOut);
|
||||||
|
|
||||||
|
// CameraAction lookUp = new CameraAction(cam, 0.5f) {
|
||||||
|
// public void performAction (InputActionEvent evt) {
|
||||||
|
// _incr.fromAxisAngle(_camera.getLeft(),
|
||||||
|
// -FastMath.PI * evt.getTime() / 2);
|
||||||
|
// _incr.mult(_camera.getLeft(), _camera.getLeft());
|
||||||
|
// _incr.mult(_camera.getDirection(), _camera.getDirection());
|
||||||
|
// _incr.mult(_camera.getUp(), _camera.getUp());
|
||||||
|
// _camera.update();
|
||||||
|
// }
|
||||||
|
// private Matrix3f _incr = new Matrix3f();
|
||||||
|
// };
|
||||||
|
// lookUp.setKey("lookUp");
|
||||||
|
// addAction(lookUp);
|
||||||
|
|
||||||
|
// CameraAction lookDown = new CameraAction(cam, 0.5f) {
|
||||||
|
// public void performAction (InputActionEvent evt) {
|
||||||
|
// _incr.fromAxisAngle(_camera.getLeft(),
|
||||||
|
// FastMath.PI * evt.getTime() / 2);
|
||||||
|
// _incr.mult(_camera.getLeft(), _camera.getLeft());
|
||||||
|
// _incr.mult(_camera.getDirection(), _camera.getDirection());
|
||||||
|
// _incr.mult(_camera.getUp(), _camera.getUp());
|
||||||
|
// _camera.update();
|
||||||
|
// }
|
||||||
|
// private Matrix3f _incr = new Matrix3f();
|
||||||
|
// };
|
||||||
|
// lookDown.setKey("lookDown");
|
||||||
|
// addAction(lookDown);
|
||||||
|
|
||||||
|
CameraAction orbitRight = new OrbitAction(cam, -FastMath.PI / 2);
|
||||||
|
orbitRight.setKey("turnRight");
|
||||||
|
addAction(orbitRight);
|
||||||
|
|
||||||
|
CameraAction orbitLeft = new OrbitAction(cam, FastMath.PI / 2);
|
||||||
|
orbitLeft.setKey("turnLeft");
|
||||||
|
addAction(orbitLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 CameraAction
|
||||||
|
{
|
||||||
|
public OrbitAction (Camera camera, float radPerSec)
|
||||||
|
{
|
||||||
|
super(camera, 0f);
|
||||||
|
_radPerSec = radPerSec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void performAction (InputActionEvent evt)
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// compute the amount we wish to orbit
|
||||||
|
float deltaA = _radPerSec * evt.getTime();
|
||||||
|
// create a rotation matrix
|
||||||
|
_rotm.fromAxisAngle(_groundNormal, deltaA);
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
_rotm.mult(_rxdir, _rxdir);
|
||||||
|
_rotm.mult(_rydir, _rydir);
|
||||||
|
|
||||||
|
// and move the camera to its new location
|
||||||
|
_camera.setLocation(center.add(direction));
|
||||||
|
|
||||||
|
_camera.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float _radPerSec;
|
||||||
|
protected Matrix3f _rotm = new Matrix3f();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user