package org.jnect.demo.incquery.gef3d.camera;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw3d.IScene;
import org.eclipse.draw3d.camera.CameraPosition;
import org.eclipse.draw3d.camera.ICamera;
import org.eclipse.draw3d.camera.tracking.LinearMove;
import org.eclipse.draw3d.camera.tracking.TrackingShot;
import org.eclipse.draw3d.camera.tracking.TrackingUtil;
import org.eclipse.draw3d.geometry.IVector3f;
import org.eclipse.draw3d.geometry.Math3D;
import org.eclipse.draw3d.geometry.Vector3fImpl;
import org.eclipse.draw3d.picking.Hit;
import org.eclipse.draw3d.picking.Picker;
import org.eclipse.draw3d.ui.camera.CameraInputHandler;
import org.eclipse.jface.bindings.keys.KeySequence;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.SWTKeySupport;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.Event;
import org.jnect.demo.incquery.gef3d.Jnect3dVisualizationConstants;
/**
* Override default GEF3D camera input handler:
* - fix orbit center to center of Jnect scene
* @author istvanrath
*
*/
public class CustomCameraInputHandler {
/**
* Sensitivity factor for pointing the camera with the mouse.
*/
private final static float FACTOR_LOOK = 0.0002f;
/**
* Sensitivity factor for moving the camera with the mouse.
*/
private final static float FACTOR_MOVE = 0.12f;
/**
* Sensitivity factor for orbiting the camera with the mouse.
*/
private final static float FACTOR_ORBIT = 0.0009f;
// @SuppressWarnings("unused")
private static final Logger log = Logger.getLogger(CameraInputHandler.class
.getName());
@SuppressWarnings("unused")
private static final Logger logger = Logger
.getLogger(CameraInputHandler.class.getName());
private static final int MODIFIER_MASK = SWT.ALT | SWT.SHIFT | SWT.CONTROL
| SWT.MOD1 | SWT.MOD2 | SWT.MOD3 | SWT.MOD4;
/**
* The key sequence to center the camera.
*/
private KeySequence m_centerKey;
/**
* The key that is currently pressed.
*/
private int m_currentKey;
private int m_currentModifiers = 0;
/**
* The modifier key for fast camera movement.
*/
private int m_fastKey = SWT.ALT;
/**
* The speed at which to move the camera when it is moved by the keyboard.
*/
private float m_keySpeed = 50;
/**
* The last mouse location.
*/
private Point m_lastMouseLocation = new Point();
/**
* The mouse button that the user clicks to move point the camera.
*/
private int m_lookButton = 1;
/**
* Indicates whether the user is currently using the mouse to point the
* camera.
*/
private boolean m_mouseLook = false;
/**
* Indicates whether the user is currently using the mouse to move the
* camera.
*/
private boolean m_mouseMove = false;
/**
* The key sequence to move the camera backward.
*/
private KeySequence m_moveBackwardKey;
/**
* The mouse button that the user clicks to move around.
*/
private int m_moveButton = 3;
/**
* The key sequence to move the camera down.
*/
private KeySequence m_moveDownKey;
/**
* The key sequence to move the camera forward.
*/
private KeySequence m_moveForwardKey;
/**
* The key sequence to move the camera to the left.
*/
private KeySequence m_moveLeftKey;
/**
* The key sequence to move the camera to the right.
*/
private KeySequence m_moveRightKey;
/**
* The key sequence to move the camera up.
*/
private KeySequence m_moveUpKey;
/**
* The current orbit center.
*/
private IVector3f m_orbitCenter = new Vector3fImpl(
Jnect3dVisualizationConstants.sceneCenterX,
Jnect3dVisualizationConstants.sceneCenterY,
Jnect3dVisualizationConstants.sceneCenterZ);
/**
* The modifier keys that trigger a camera orbit.
*/
private int m_orbitModifiers;
/**
* The key sequence to roll the camera counter clockwise.
*/
private KeySequence m_rollCCWKey;
/**
* The key sequence to roll the camera clockwise.
*/
private KeySequence m_rollCWKey;
private IScene m_scene;
/**
* The mouse sensitivity.
*/
private float m_sensitivity;
/**
* The modifier key for slow camera movement.
*/
private int m_slowKey = SWT.SHIFT;
private float m_wheelSpeed = 20;
/**
* Handles a mouse button down event.
*
* @param i_button the mouse button
* @param i_stateMask the modifiers state mask
* @param i_x the mouse X coordinate
* @param i_y the mouse Y coordinate
*/
public void buttonDown(int i_button, int i_stateMask, int i_x, int i_y) {
stopCameraTracking();
int modifiers = getModifiers(i_stateMask);
doButtonDown(i_button, modifiers, i_x, i_y);
}
/**
*
*/
protected void stopCameraTracking() {
getCamera().cancelTrackingShot();
}
/**
* Handles a mouse button up event.
*
* @param i_button the mouse button
* @param i_stateMask the modifiers state mask
* @param i_x the mouse X coordinate
* @param i_y the mouse Y coordinate
*/
public void buttonUp(int i_button, int i_stateMask, int i_x, int i_y) {
int modifiers = getModifiers(i_stateMask);
doButtonUp(i_button, modifiers, i_x, i_y);
}
private void doButtonDown(int i_button, int i_modifiers, int i_mx, int i_my) {
m_lastMouseLocation.setLocation(i_mx, i_my);
//m_orbitCenter = null;
if (i_modifiers != 0 && i_modifiers == m_orbitModifiers) {
/* Picker picker = getScene().getPicker(); // don't let orbitcenter to be modified
Hit hit = picker.getHit(i_mx, i_my);
if (hit != null)
m_orbitCenter = hit.getWorldLocation(null); */
} else {
m_mouseLook = i_button == m_lookButton;
m_mouseMove = i_button == m_moveButton;
}
}
private void doButtonUp(int i_button, int i_stateMask, int i_x, int i_y) {
m_lastMouseLocation.setLocation(i_x, i_y);
m_mouseLook = false;
m_mouseMove = false;
//m_orbitCenter = null;
}
/**
* Returns the camera for the scene.
*
* @return the camera
*/
protected ICamera getCamera() {
ICamera camera = getScene().getCamera();
if (camera == null)
throw new AssertionError("camera is null");
return camera;
}
/**
* Return the key strokes represented by the given SWT key event.
*
* @param keyEvent the key event
* @return the key strokes
*/
private KeyStroke[] getKeyStrokes(KeyEvent keyEvent) {
Event event = new Event();
event.character = keyEvent.character;
event.data = keyEvent.data;
event.display = keyEvent.display;
event.doit = keyEvent.doit;
event.keyCode = keyEvent.keyCode;
event.stateMask = keyEvent.stateMask;
event.time = keyEvent.time;
event.widget = keyEvent.widget;
final List<KeyStroke> keyStrokes = new ArrayList<KeyStroke>(3);
/*
* If this is not a keyboard event, then there are no key strokes. This
* can happen if we are listening to focus traversal events.
*/
if ((event.stateMask == 0) && (event.keyCode == 0)
&& (event.character == 0)) {
return keyStrokes.toArray(new KeyStroke[keyStrokes.size()]);
}
// Add each unique key stroke to the list for consideration.
final int firstAccelerator =
SWTKeySupport.convertEventToUnmodifiedAccelerator(event);
keyStrokes.add(SWTKeySupport
.convertAcceleratorToKeyStroke(firstAccelerator));
// We shouldn't allow delete to undergo shift resolution.
if (event.character == SWT.DEL) {
return keyStrokes.toArray(new KeyStroke[keyStrokes.size()]);
}
final int secondAccelerator =
SWTKeySupport.convertEventToUnshiftedModifiedAccelerator(event);
if (secondAccelerator != 0 && secondAccelerator != firstAccelerator) {
keyStrokes.add(SWTKeySupport
.convertAcceleratorToKeyStroke(secondAccelerator));
}
final int thirdAccelerator =
SWTKeySupport.convertEventToModifiedAccelerator(event);
if (thirdAccelerator != 0 && thirdAccelerator != secondAccelerator
&& thirdAccelerator != firstAccelerator) {
keyStrokes.add(SWTKeySupport
.convertAcceleratorToKeyStroke(thirdAccelerator));
}
return keyStrokes.toArray(new KeyStroke[keyStrokes.size()]);
}
private int getModifiers(int i_stateMask) {
return i_stateMask & MODIFIER_MASK;
}
/**
* Returns the current scene.
*
* @return the scene
*/
protected IScene getScene() {
if (m_scene == null)
throw new AssertionError("m_scene is null");
return m_scene;
}
private boolean isKeySequence(KeySequence sequence, KeyStroke[] keyStrokes) {
if (sequence == null)
return false;
KeyStroke[] seqStrokes = sequence.getKeyStrokes();
if (seqStrokes.length != keyStrokes.length)
return false;
for (int i = 0; i < seqStrokes.length; i++) {
KeyStroke seqKeyStroke = seqStrokes[i];
KeyStroke keyStroke = keyStrokes[i];
if (!seqKeyStroke.equals(keyStroke))
return false;
}
return true;
}
/**
* Handles a key down event.
*
* @param i_event the key down event
*/
public void keyDown(KeyEvent i_event) {
stopCameraTracking();
m_currentModifiers = getModifiers(i_event.stateMask);
float speed = m_keySpeed;
int modifiers = getModifiers(i_event.stateMask);
if ((modifiers & m_slowKey) != 0) {
speed /= 10;
i_event.stateMask &= ~m_slowKey;
}
if ((modifiers & m_fastKey) != 0) {
speed *= 10;
i_event.stateMask &= ~m_fastKey;
}
KeyStroke[] keyStrokes = getKeyStrokes(i_event);
if (keyStrokes == null)
return;
if (m_currentKey != i_event.keyCode) {
if (isKeySequence(m_moveLeftKey, keyStrokes)) {
getCamera().moveBy(0, -speed, 0);
} else if (isKeySequence(m_moveRightKey, keyStrokes)) {
getCamera().moveBy(0, speed, 0);
} else if (isKeySequence(m_moveUpKey, keyStrokes)) {
getCamera().moveBy(0, 0, speed);
} else if (isKeySequence(m_moveDownKey, keyStrokes)) {
getCamera().moveBy(0, 0, -speed);
} else if (isKeySequence(m_moveForwardKey, keyStrokes)) {
getCamera().moveBy(speed, 0, 0);
} else if (isKeySequence(m_moveBackwardKey, keyStrokes)) {
getCamera().moveBy(-speed, 0, 0);
} else if (isKeySequence(m_centerKey, keyStrokes)) {
getCamera().reset();
} else if (isKeySequence(m_rollCCWKey, keyStrokes)) {
float roll = (float) Math.toRadians(speed);
getCamera().rotate(roll, 0, 0);
} else if (isKeySequence(m_rollCWKey, keyStrokes)) {
float roll = (float) Math.toRadians(speed);
getCamera().rotate(-roll, 0, 0);
}
}
}
/**
* Handles a key up event.
*
* @param i_event the event
*/
public void keyUp(KeyEvent i_event) {
m_currentModifiers = 0;
}
private float lookSpeed(int i_speed) {
return i_speed * m_sensitivity * FACTOR_LOOK;
}
/**
* Handles a mouse move event.
*
* @param i_stateMask the modifiers state mask
* @param i_x the mouse X coordinate
* @param i_y the mouse Y coordinate
*/
public void mouseMove(int i_stateMask, int i_x, int i_y) {
int dx = i_x - m_lastMouseLocation.x;
int dy = i_y - m_lastMouseLocation.y;
m_lastMouseLocation.setLocation(i_x, i_y);
int modifiers = getModifiers(i_stateMask);
if (modifiers != 0 && modifiers == m_orbitModifiers
&& m_orbitCenter != null) {
float hAngle = (float) Math.asin(orbitSpeed(dx));
float vAngle = (float) Math.asin(orbitSpeed(dy));
getCamera().orbit(m_orbitCenter, -hAngle, vAngle);
} else if (m_mouseLook) {
float yaw = (float) Math.asin(lookSpeed(dx));
float pitch = (float) Math.asin(lookSpeed(dy));
getCamera().rotate(0, pitch, yaw);
} else if (m_mouseMove) {
getCamera().moveBy(0, moveSpeed(-dx), moveSpeed(dy));
}
}
/**
* Handles mouse scroll events.
*
* @param i_count the number of scrolling steps
*/
public void mouseWheelScrolled(int i_count) {
float speed = i_count * m_wheelSpeed;
if ((m_currentModifiers & m_slowKey) != 0)
speed /= 10;
if ((m_currentModifiers & m_fastKey) != 0)
speed *= 10;
getCamera().moveBy(speed, 0, 0);
}
private float moveSpeed(int i_speed) {
return i_speed * m_sensitivity * FACTOR_MOVE;
}
/**
* Handles double click, that is activates a camera track to figure under
* cursor.
*
* @param i_button
* @param i_stateMask
* @param i_x
* @param i_y
*/
public void doubleClick(int i_button, int i_stateMask, int i_mx, int i_my) {
stopCameraTracking();
Picker picker = getScene().getPicker();
Hit hit = picker.getHit(i_mx, i_my);
CameraPosition cameraPos = null;
if (hit != null) {
IFigure figure = hit.getSearchResult();
cameraPos = TrackingUtil.figureToScreen(figure, getCamera());
} else {
cameraPos = new CameraPosition();
if ((i_stateMask & m_orbitModifiers) != 0) {
if ((i_stateMask & SWT.SHIFT) == 0) {
cameraPos.setViewDirection(new Vector3fImpl(1, 0, 0));
cameraPos.setPosition(new Vector3fImpl(-1000, 0, 0));
} else {
cameraPos.setViewDirection(new Vector3fImpl(0, 1, 0));
cameraPos.setUpVector(new Vector3fImpl(0,0,1));
cameraPos.setPosition(new Vector3fImpl(0, -1000, 0));
}
}
}
if (cameraPos != null) {
getCamera().cancelTrackingShot();
LinearMove move = new LinearMove();
move.init(getCamera().getCameraPosition(null), cameraPos);
float moveLength =
Math3D.distance(getCamera().getCameraPosition(null)
.getPosition(), cameraPos.getPosition());
long duration = (long) (Math.log(moveLength * moveLength) * 50);
if (log.isLoggable(Level.INFO)) {
log.info("duration=" + duration); //$NON-NLS-1$
}
if (duration > 2000)
duration = 2000;
if (duration < 0)
duration = 100;
TrackingShot shot = new TrackingShot(duration, getCamera(), move);
getCamera().scheduleTrackingShot(shot);
}
}
/**
* Handles a drag finished event. This is neccessary because in the case of
* native drags, the mouse up event gets lost.
*
* @param i_x the mouse X coordinate
* @param i_y the mouse Y coordinate
*/
public void nativeDragFinished(int i_x, int i_y) {
doButtonUp(1, m_currentModifiers, i_x, i_y);
}
/**
* Handles a drag started event. This is neccessary because in the case of
* native drags, the mouse down event gets lost.
*
* @param i_x the mouse X coordinate
* @param i_y the mouse Y coordinate
*/
public void nativeDragStarted(int i_x, int i_y) {
doButtonDown(1, m_currentModifiers, i_x, i_y);
}
private float orbitSpeed(int i_speed) {
return i_speed * m_sensitivity * FACTOR_ORBIT;
}
/**
* Sets the key sequence that causes the camera to be centered.
*
* @param i_centerKey the key sequence
*/
public void setCenterKey(KeySequence i_centerKey) {
m_centerKey = i_centerKey;
}
/**
* Sets the modifier key mask that causes the camera to move fast.
*
* @param i_fastKey the modifier key mask
*/
public void setFastKey(int i_fastKey) {
m_fastKey = i_fastKey;
}
/**
* Sets the speed by which the camera moves when navigated by keyboard.
*
* @param i_keySpeed the keyboard speed
*/
public void setKeySpeed(float i_keySpeed) {
m_keySpeed = i_keySpeed;
}
/**
* Sets the mouse button that the user holds to point the camera.
*
* @param i_lookButton the mouse button
*/
public void setLookButton(int i_lookButton) {
m_lookButton = i_lookButton;
}
/**
* Sets the key sequence that causes the camera to move backward.
*
* @param i_moveBackwardKey the key sequence
*/
public void setMoveBackwardKey(KeySequence i_moveBackwardKey) {
m_moveBackwardKey = i_moveBackwardKey;
}
/**
* Sets the mouse button that the user holds to move the camera.
*
* @param i_moveButton the mouse button
*/
public void setMoveButton(int i_moveButton) {
m_moveButton = i_moveButton;
}
/**
* Sets the key sequence that causes the camera to move down.
*
* @param i_moveDownKey the key sequence
*/
public void setMoveDownKey(KeySequence i_moveDownKey) {
m_moveDownKey = i_moveDownKey;
}
/**
* Sets the key sequence that causes the camera to move forward.
*
* @param i_moveForwardKey the key sequence.
*/
public void setMoveForwardKey(KeySequence i_moveForwardKey) {
m_moveForwardKey = i_moveForwardKey;
}
/**
* Sets the key sequence that causes the camera to move left.
*
* @param i_moveLeftKey the key sequence
*/
public void setMoveLeftKey(KeySequence i_moveLeftKey) {
m_moveLeftKey = i_moveLeftKey;
}
/**
* Sets the key sequence that causes the camera to move right.
*
* @param i_moveRightKey the key sequence
*/
public void setMoveRightKey(KeySequence i_moveRightKey) {
m_moveRightKey = i_moveRightKey;
}
/**
* Sets the key sequence that causes the camera to move up.
*
* @param i_moveUpKey the key sequence
*/
public void setMoveUpKey(KeySequence i_moveUpKey) {
m_moveUpKey = i_moveUpKey;
}
/**
* Sets the modifier key mask that activates orbit mode.
*
* @param i_orbitModifiers the modifier key mask
*/
public void setOrbitModifiers(int i_orbitModifiers) {
m_orbitModifiers = i_orbitModifiers;
}
/**
* Sets the key sequence that causes the camera to roll counter-clockwise.
*
* @param i_rollCCWKey the key sequence
*/
public void setRollCCWKey(KeySequence i_rollCCWKey) {
m_rollCCWKey = i_rollCCWKey;
}
/**
* Sets the key sequence that causes the camera to roll clockwise.
*
* @param i_rollCWKey the key sequence
*/
public void setRollCWKey(KeySequence i_rollCWKey) {
m_rollCWKey = i_rollCWKey;
}
/**
* Sets the scene that contains the camera.
*
* @param i_scene the scene
*/
public void setScene(IScene i_scene) {
m_scene = i_scene;
}
/**
* Sets the mouse sensitivity.
*
* @param i_sensitivity the mouse sensitivity
*/
public void setSensitivity(float i_sensitivity) {
m_sensitivity = i_sensitivity;
}
/**
* Sets the modifier key mask that causes the camera to move slowly.
*
* @param i_slowKey the modifier key mask
*/
public void setSlowKey(int i_slowKey) {
m_slowKey = i_slowKey;
}
/**
* Sets the speed by which the camera moves when the mouse wheel is
* scrolled.
*
* @param i_wheelSpeed the mouse wheel speed
*/
public void setWheelSpeed(float i_wheelSpeed) {
m_wheelSpeed = i_wheelSpeed;
}
}