org.concord.energy3d.scene.CameraControl.java Source code

Java tutorial

Introduction

Here is the source code for org.concord.energy3d.scene.CameraControl.java

Source

/**
 * Copyright (c) 2008-2010 Ardor Labs, Inc.
 *
 * This file is part of Ardor3D.
 *
 * Ardor3D is free software: you can redistribute it and/or modify it
 * under the terms of its license which may be found in the accompanying
 * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
 */

package org.concord.energy3d.scene;

import com.ardor3d.framework.Canvas;
import com.ardor3d.input.ButtonState;
import com.ardor3d.input.Key;
import com.ardor3d.input.MouseButton;
import com.ardor3d.input.MouseState;
import com.ardor3d.input.logical.InputTrigger;
import com.ardor3d.input.logical.KeyHeldCondition;
import com.ardor3d.input.logical.LogicalLayer;
import com.ardor3d.input.logical.MouseWheelMovedCondition;
import com.ardor3d.input.logical.TriggerAction;
import com.ardor3d.input.logical.TriggerConditions;
import com.ardor3d.input.logical.TwoInputStates;
import com.ardor3d.math.Matrix3;
import com.ardor3d.math.Vector3;
import com.ardor3d.math.type.ReadOnlyVector3;
import com.ardor3d.renderer.Camera;
import com.ardor3d.renderer.Camera.ProjectionMode;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;

public abstract class CameraControl {
    public enum ButtonAction {
        MOVE, ROTATE, ZOOM, NONE
    };

    protected final Vector3 _upAxis = new Vector3();
    protected final Matrix3 _workerMatrix = new Matrix3();
    protected final Vector3 _workerVector = new Vector3();
    protected InputTrigger _mouseTrigger;
    protected InputTrigger _keyTrigger;
    protected ButtonAction leftButtonAction = ButtonAction.ROTATE;
    protected ButtonAction rightButtonAction = ButtonAction.MOVE;
    protected double _mouseRotateSpeed = .005;
    protected double _moveSpeed = 50;
    protected double _keyRotateSpeed = 2.25;
    protected boolean enabled = true;
    private ReadOnlyVector3 orgCameraDirection;
    private ReadOnlyVector3 newCameraDirection;
    private ReadOnlyVector3 orgCameraLocation;
    private ReadOnlyVector3 newCameraLocation;
    private double animationTime = -1;
    private boolean mouseEnabled = true;
    private boolean leftMouseButtonEnabled = true;
    private boolean rightMouseButtonEnabled = true;

    public CameraControl(final ReadOnlyVector3 upAxis) {
        _upAxis.set(upAxis);
    }

    public ReadOnlyVector3 getUpAxis() {
        return _upAxis;
    }

    public void setUpAxis(final ReadOnlyVector3 upAxis) {
        _upAxis.set(upAxis);
    }

    public double getMouseRotateSpeed() {
        return _mouseRotateSpeed;
    }

    public void setMouseRotateSpeed(final double speed) {
        _mouseRotateSpeed = speed;
    }

    public double getMoveSpeed() {
        return _moveSpeed;
    }

    public void setMoveSpeed(final double speed) {
        _moveSpeed = speed;
    }

    public double getKeyRotateSpeed() {
        return _keyRotateSpeed;
    }

    public void setKeyRotateSpeed(final double speed) {
        _keyRotateSpeed = speed;
    }

    protected abstract void move(final Camera camera, final double dx, final double dy);

    protected abstract void rotate(final Camera camera, final double dx, final double dy);

    /**
     * @param layer
     *            the logical layer to register with
     * @param upAxis
     *            the up axis of the camera
     * @param dragOnly
     *            if true, mouse input will only rotate the camera if one of the mouse buttons (left, center or right)
     *            is down.
     * @return a new FirstPersonControl object
     */
    public void setupTriggers(final LogicalLayer layer, final ReadOnlyVector3 upAxis, final boolean dragOnly) {
        setupMouseTriggers(layer, dragOnly);
    }

    public void removeTriggers(final LogicalLayer layer) {
        if (_mouseTrigger != null) {
            layer.deregisterTrigger(_mouseTrigger);
        }
        if (_keyTrigger != null) {
            layer.deregisterTrigger(_keyTrigger);
        }
    }

    public void setupMouseTriggers(final LogicalLayer layer, final boolean dragOnly) {
        // Mouse look
        final Predicate<TwoInputStates> someMouseDown = Predicates.or(TriggerConditions.leftButtonDown(),
                Predicates.or(TriggerConditions.rightButtonDown(), TriggerConditions.middleButtonDown()));
        final Predicate<TwoInputStates> dragged = Predicates.and(TriggerConditions.mouseMoved(),
                Predicates.and(someMouseDown, Predicates.not(new KeyHeldCondition(Key.LCONTROL))));
        final TriggerAction dragAction = new TriggerAction() {

            // Test boolean to allow us to ignore first mouse event. First event can wildly vary based on platform.
            private boolean firstPing = true;

            @Override
            public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) {
                if (!enabled || !mouseEnabled)
                    return;
                final MouseState mouse = inputStates.getCurrent().getMouseState();
                if (mouse.getDx() != 0 || mouse.getDy() != 0) {
                    if (!firstPing) {
                        final boolean left = leftMouseButtonEnabled
                                && mouse.getButtonState(MouseButton.LEFT) == ButtonState.DOWN;
                        final boolean right = rightMouseButtonEnabled
                                && mouse.getButtonState(MouseButton.RIGHT) == ButtonState.DOWN;
                        final boolean middle = mouse.getButtonState(MouseButton.MIDDLE) == ButtonState.DOWN;
                        if (left && leftButtonAction == ButtonAction.MOVE
                                || right && rightButtonAction == ButtonAction.MOVE) {
                            final double fac = Camera.getCurrentCamera().getLocation().length() * 150;
                            final double dx = -mouse.getDx() * fac / Camera.getCurrentCamera().getWidth();
                            final double dy = -mouse.getDy() * fac / Camera.getCurrentCamera().getHeight() / 4.0;
                            move(source.getCanvasRenderer().getCamera(), dx, dy);
                            SceneManager.getInstance().getCameraNode().updateFromCamera();
                            Scene.getInstance().updateEditShapes();
                        } else if (left && leftButtonAction == ButtonAction.ROTATE
                                || right && rightButtonAction == ButtonAction.ROTATE) {
                            rotate(source.getCanvasRenderer().getCamera(), -mouse.getDx(), -mouse.getDy());
                            SceneManager.getInstance().getCameraNode().updateFromCamera();
                            Scene.getInstance().updateEditShapes();
                        } else if (middle || left && leftButtonAction == ButtonAction.ZOOM
                                || right && rightButtonAction == ButtonAction.ZOOM) {
                            int dy = inputStates.getCurrent().getMouseState().getDy();
                            if (dy < -4)
                                dy = -4;
                            if (dy > 4)
                                dy = 4;
                            zoom(source, tpf, -dy / 1.0);
                        }
                    } else {
                        firstPing = false;
                    }
                }
            }
        };

        _mouseTrigger = new InputTrigger(dragOnly ? dragged : TriggerConditions.mouseMoved(), dragAction);
        layer.registerTrigger(_mouseTrigger);

        layer.registerTrigger(new InputTrigger(new MouseWheelMovedCondition(), new TriggerAction() {
            @Override
            public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) {
                zoom(source, tpf, inputStates.getCurrent().getMouseState().getDwheel());
            }
        }));
    }

    public InputTrigger getKeyTrigger() {
        return _keyTrigger;
    }

    public InputTrigger getMouseTrigger() {
        return _mouseTrigger;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(final boolean enabled) {
        this.enabled = enabled;
    }

    public void setMouseButtonActions(final ButtonAction leftButtonAction, final ButtonAction rightButtonAction) {
        this.leftButtonAction = leftButtonAction;
        this.rightButtonAction = rightButtonAction;
    }

    public void setMouseEnabled(final boolean enabled) {
        mouseEnabled = enabled;
    }

    public boolean isMouseEnabled() {
        return mouseEnabled;
    }

    public void reset() {

    }

    protected void zoom(final Canvas canvas, final double tpf, final double val) {
        if (Camera.getCurrentCamera().getProjectionMode() == ProjectionMode.Parallel) {
            final double fac = val > 0 ? 1.1 : 0.9;
            final Camera camera = canvas.getCanvasRenderer().getCamera();
            camera.setFrustumTop(camera.getFrustumTop() * fac);
            camera.setFrustumBottom(camera.getFrustumBottom() * fac);
            camera.setFrustumLeft(camera.getFrustumLeft() * fac);
            camera.setFrustumRight(camera.getFrustumRight() * fac);
            camera.update();
            setMoveSpeed(2 * camera.getFrustumTop());
        } else {
            final Camera camera = canvas.getCanvasRenderer().getCamera();
            final Vector3 loc = new Vector3(camera.getDirection()).multiplyLocal(-val * (_moveSpeed * 10) * 2 * tpf)
                    .addLocal(camera.getLocation());
            if (loc.length() > SceneManager.SKY_RADIUS)
                return;
            camera.setLocation(loc);

            if (this instanceof OrbitControl)
                ((OrbitControl) this).computeNewFrontDistance();
        }
        SceneManager.getInstance().getCameraNode().updateFromCamera();
        Scene.getInstance().updateEditShapes();
        SceneManager.getInstance().refresh();
    }

    public void zoomAtPoint(final ReadOnlyVector3 clickedPoint) {
        final boolean isPrintPreview = PrintController.getInstance().isPrintPreview();
        final double zoomInDistance = isPrintPreview ? 50 : 20;
        final double zoomDistance;
        final boolean zoomOut = Camera.getCurrentCamera().getLocation().distance(clickedPoint) < zoomInDistance + 1;
        if (zoomOut)
            zoomDistance = 100.0;
        else
            zoomDistance = zoomInDistance;

        orgCameraDirection = new Vector3(Camera.getCurrentCamera().getDirection());
        orgCameraLocation = new Vector3(Camera.getCurrentCamera().getLocation());
        if (isPrintPreview) {
            newCameraDirection = Vector3.UNIT_Y;
        } else {
            newCameraDirection = clickedPoint.subtract(Camera.getCurrentCamera().getLocation(), null)
                    .normalizeLocal();
        }
        if (isPrintPreview && zoomOut)
            newCameraLocation = PrintController.getInstance().getZoomAllCameraLocation();
        else
            newCameraLocation = clickedPoint.subtract(newCameraDirection.multiply(zoomDistance, null), null);
        animationTime = SceneManager.getInstance().getTimer().getTimeInSeconds();
    }

    public boolean isAnimating() {
        return animationTime != -1;
    }

    public void animate() {
        final double currentTime = SceneManager.getInstance().getTimer().getTimeInSeconds();
        final double t = currentTime - animationTime;
        final double animationDuration = 1.0;
        final ReadOnlyVector3 currentDirection = orgCameraDirection.multiply(animationDuration - t, null)
                .addLocal(newCameraDirection.multiply(t, null)).normalizeLocal();
        final ReadOnlyVector3 currentLocation = orgCameraLocation.multiply(animationDuration - t, null)
                .addLocal(newCameraLocation.multiply(t, null));
        Camera.getCurrentCamera().setLocation(currentLocation);
        Camera.getCurrentCamera().lookAt(currentLocation.add(currentDirection, null), Vector3.UNIT_Z);
        SceneManager.getInstance().getCameraNode().updateFromCamera();
        Scene.getInstance().updateEditShapes();
        if (t > animationDuration)
            animationTime = -1;
    }

    public ButtonAction getRightButtonAction() {
        return rightButtonAction;
    }

    public void setRightButtonAction(final ButtonAction rightButtonAction) {
        this.rightButtonAction = rightButtonAction;
    }

    public boolean isLeftMouseButtonEnabled() {
        return leftMouseButtonEnabled;
    }

    public void setLeftMouseButtonEnabled(final boolean leftMouseButtonEnabled) {
        this.leftMouseButtonEnabled = leftMouseButtonEnabled;
    }

    public boolean isRightMouseButtonEnabled() {
        return rightMouseButtonEnabled;
    }

    public void setRightMouseButtonEnabled(final boolean rightMouseButtonEnabled) {
        this.rightMouseButtonEnabled = rightMouseButtonEnabled;
    }

    public ButtonAction getLeftButtonAction() {
        return leftButtonAction;
    }

    public void setLeftButtonAction(final ButtonAction leftButtonAction) {
        this.leftButtonAction = leftButtonAction;
    }

}