/**
 * 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.math.Matrix3;
import com.ardor3d.math.Vector3;
import com.ardor3d.math.Vector4;
import com.ardor3d.math.type.ReadOnlyVector3;
import com.ardor3d.renderer.Camera;

public class OrbitControl extends CameraControl {
	private static final double FRONT_DISTANCE_DEFAULT = 8;
	private static double frontDistance = FRONT_DISTANCE_DEFAULT;
	private final Matrix3 _workerMatrix_2 = new Matrix3();
	private final Vector4 _workerVector4 = new Vector4();
	private final Vector3 _center = new Vector3(1, 0, 1);

	public OrbitControl(final ReadOnlyVector3 upAxis) {
		super(upAxis);
	}

	@Override
	protected void rotate(final Camera camera, final double dx, final double dy) {
		if (_center.length() == 0)
			_center.set(camera.getDirection()).multiplyLocal(frontDistance).addLocal(camera.getLocation());
		_workerMatrix.fromAngleNormalAxis(_mouseRotateSpeed * dx, _upAxis != null ? _upAxis : camera.getUp());
		_workerMatrix_2.fromAngleNormalAxis(_mouseRotateSpeed * dy, camera.getLeft());
		_workerMatrix.multiplyLocal(_workerMatrix_2);
		camera.getLocation().subtract(_center, _workerVector);
		_workerMatrix.applyPost(_workerVector, _workerVector);
		_workerVector.addLocal(_center);
		final Vector3 d = _workerVector.subtract(_center, null).normalizeLocal();
		final double MIN = 0.1;
		if (Math.abs(d.getX()) > MIN || Math.abs(d.getY()) > MIN) {
			if (_workerVector.length() > SceneManager.SKY_RADIUS) {
				zoom(SceneManager.getInstance().getCanvas(), 1, -0.1);
				return;
			}
			camera.setLocation(_workerVector);
			camera.lookAt(_center, _upAxis);
		}
	}

	@Override
	protected void move(final Camera camera, final double dx, final double dy) {
		_workerVector4.set(dx * _moveSpeed / 500, dy * _moveSpeed / 500, 0, 0);
		camera.getModelViewProjectionMatrix().applyPost(_workerVector4, _workerVector4);
		_workerVector.set(_workerVector4.getX(), _workerVector4.getY(), _workerVector4.getZ());
		_workerVector.addLocal(camera.getLocation());
		if (_workerVector.length() > SceneManager.SKY_RADIUS)
			return;
		camera.setLocation(_workerVector);
		clearOrbitCenter();
	}

	public void clearOrbitCenter() {
		_center.set(0, 0, 0);
	}

	@Override
	public void reset() {
		clearOrbitCenter();
		computeNewFrontDistance();
	}

	public void computeNewFrontDistance() {
		final Camera currentCamera = SceneManager.getInstance().getCamera();
		if (currentCamera != null) {
			frontDistance = _center.subtractLocal(currentCamera.getLocation()).length();
			clearOrbitCenter();
		}
	}

	@Override
	public void zoomAtPoint(final ReadOnlyVector3 clickedPoint) {
		super.zoomAtPoint(clickedPoint);
		_center.set(clickedPoint);
	}

}

@@ -1033,17 +1033,19 @@
 () == 0)
+ %7B
 %0A
-
 %09%09%09_cent
@@ -1131,24 +1131,28 @@
 ocation());%0A
+%09%09%7D%0A
 %09%09_workerMat
@@ -1625,17 +1625,18 @@
 = 0.
-1
+99
 ;%0A%09%09if (
 Math
@@ -1635,61 +1635,73 @@
 if (
-Math.abs(d.getX()) %3E MIN %7C%7C Math.abs(d.getY()
+!(d.dot(Vector3.UNIT_Z) %3E MIN %7C%7C d.dot(Vector3.NEG_UNIT_Z
 ) %3E MIN)
  %7B%0A%09
@@ -1696,16 +1696,17 @@
 ) %3E MIN)
+)
  %7B%0A%09%09%09if
@@ -2356,16 +2356,18 @@
 _RADIUS)
+ %7B
 %0A%09%09%09retu
@@ -2370,16 +2370,20 @@
 return;%0A
+%09%09%7D%0A
 %09%09camera

Fix problem with camera getting stuck sometimes when looking from top