using System;
using BansheeEngine;
namespace BansheeEditor
{
///
/// Draws axes that display the orientation of the scene camera. Also allows you to change camera orientation along
/// one of the axes, or change projection modes.
///
[CustomHandle(null)]
public class SceneAxesHandle : Handle
{
private const float CONE_HEIGHT = 0.25f;
private const float CONE_RADIUS = 0.175f;
private HandleSliderLine xAxis;
private HandleSliderLine yAxis;
private HandleSliderLine zAxis;
private HandleSliderPlane projTypePlane;
private bool[] clickStates = new bool[4];
private Vector3 position = Vector3.Zero;
private Quaternion rotation = Quaternion.Identity;
///
/// Creates a new scene axes handle.
///
public SceneAxesHandle()
{
xAxis = new HandleSliderLine(this, Vector3.XAxis, 1.0f);
yAxis = new HandleSliderLine(this, Vector3.YAxis, 1.0f);
zAxis = new HandleSliderLine(this, Vector3.ZAxis, 1.0f);
projTypePlane = new HandleSliderPlane(this, Vector3.XAxis, Vector3.YAxis, 0.4f);
}
///
protected internal override void PreInput()
{
Camera cam = EditorApplication.SceneViewCamera;
if (cam == null)
return;
float distFromCamera = 500.0f;
float x = cam.GetFrustumWidth(distFromCamera) * 0.5f;
float y = x / cam.AspectRatio;
Vector3 localPosition = new Vector3(0, 0, -distFromCamera);
float appoxHandleSize = EditorSettings.DefaultHandleSize * distFromCamera;
localPosition.x = x - appoxHandleSize * 1.2f;
localPosition.y = y - appoxHandleSize * 1.2f;
position = cam.SceneObject.WorldTransform.MultiplyAffine(localPosition);
rotation = Quaternion.Identity;
xAxis.Position = position;
yAxis.Position = position;
zAxis.Position = position;
xAxis.Rotation = rotation;
yAxis.Rotation = rotation;
zAxis.Rotation = rotation;
float handleSize = Handles.GetHandleSize(EditorApplication.SceneViewCamera, position);
Vector3 freeAxisOffset = (Vector3.XAxis * -0.2f + Vector3.YAxis * -0.2f) * handleSize;
projTypePlane.Rotation = EditorApplication.SceneViewCamera.SceneObject.Rotation;
projTypePlane.Position = position + projTypePlane.Rotation.Rotate(freeAxisOffset);
}
///
protected internal override void PostInput()
{
var axes = new []
{
new Tuple(xAxis, () => RotateCameraTo(Vector3.XAxis)),
new Tuple(yAxis, () => RotateCameraTo(Vector3.YAxis)),
new Tuple(zAxis, () => RotateCameraTo(Vector3.ZAxis)),
new Tuple(projTypePlane, ToggleProjectionType)
};
for (int i = 0; i < axes.Length; i++)
{
if (axes[i].Item1.State == HandleSlider.StateType.Active)
{
if (!clickStates[i])
{
axes[i].Item2();
clickStates[i] = true;
}
}
else
{
clickStates[i] = false;
}
}
}
///
protected internal override void Draw()
{
HandleDrawing.Transform = Matrix4.TRS(position, rotation, Vector3.One);
Vector3 cameraForward = EditorApplication.SceneViewCamera.SceneObject.Forward;
float handleSize = Handles.GetHandleSize(EditorApplication.SceneViewCamera, position);
// Draw 1D arrows
Color xColor = Color.Red;
if (xAxis.State == HandleSlider.StateType.Active)
xColor = Color.White;
else if (xAxis.State == HandleSlider.StateType.Hover)
xColor = Color.BansheeOrange;
xColor.a = MathEx.Lerp(1.0f, 0.0f, MathEx.Abs(Vector3.Dot(cameraForward, Vector3.XAxis)), 0.8f, 1.0f);
HandleDrawing.Color = xColor;
Vector3 xConeStart = Vector3.XAxis * (1.0f - CONE_HEIGHT);
HandleDrawing.DrawLine(Vector3.Zero, xConeStart, handleSize);
HandleDrawing.DrawCone(xConeStart, Vector3.XAxis, CONE_HEIGHT, CONE_RADIUS, handleSize);
Color yColor = Color.Green;
if (yAxis.State == HandleSlider.StateType.Active)
yColor = Color.White;
else if (yAxis.State == HandleSlider.StateType.Hover)
yColor = Color.BansheeOrange;
yColor.a = MathEx.Lerp(1.0f, 0.0f, MathEx.Abs(Vector3.Dot(cameraForward, Vector3.YAxis)), 0.8f, 1.0f);
HandleDrawing.Color = yColor;
Vector3 yConeStart = Vector3.YAxis * (1.0f - CONE_HEIGHT);
HandleDrawing.DrawLine(Vector3.Zero, yConeStart, handleSize);
HandleDrawing.DrawCone(yConeStart, Vector3.YAxis, CONE_HEIGHT, CONE_RADIUS, handleSize);
Color zColor = Color.Blue;
if (zAxis.State == HandleSlider.StateType.Active)
zColor = Color.White;
else if (zAxis.State == HandleSlider.StateType.Hover)
zColor = Color.BansheeOrange;
zColor.a = MathEx.Lerp(1.0f, 0.0f, MathEx.Abs(Vector3.Dot(cameraForward, Vector3.ZAxis)), 0.8f, 1.0f);
HandleDrawing.Color = zColor;
Vector3 zConeStart = Vector3.ZAxis * (1.0f - CONE_HEIGHT);
HandleDrawing.DrawLine(Vector3.Zero, zConeStart, handleSize);
HandleDrawing.DrawCone(zConeStart, Vector3.ZAxis, CONE_HEIGHT, CONE_RADIUS, handleSize);
// Draw projection type handle
if (projTypePlane.State == HandleSlider.StateType.Active)
HandleDrawing.Color = Color.White;
else if (projTypePlane.State == HandleSlider.StateType.Hover)
HandleDrawing.Color = Color.BansheeOrange;
else
HandleDrawing.Color = Color.White;
HandleDrawing.DrawCube(Vector3.Zero, new Vector3(0.2f, 0.2f, 0.2f), handleSize);
// TODO - Add a text notifying the user whether ortho/proj is active
}
private void RotateCameraTo(Vector3 axis)
{
// TODO - Rotate to the provided axis. If already looking at that axis, rotate in the opposite direction (-axis)
}
private void ToggleProjectionType()
{
// TODO - Switch between ortographic and perspective
}
}
}