470 lines
20 KiB
C#
470 lines
20 KiB
C#
using UnityEditor;
|
|
using UnityEngine;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace Module.Inspector.Editor.Utilities
|
|
{
|
|
public static class EditorHandleUtility
|
|
{
|
|
private static readonly Color DEFAULT_AXIS_COLOR = new Color(0.7f, 0.7f, 0.7f, 0.93f);
|
|
private static readonly Color X_AXIS_COLOR = new Color(0.85882354f, 0.24313726f, 0.11372549f, 0.93f);
|
|
private static readonly Color Y_AXIS_COLOR = new Color(0.6039216f, 0.9529412f, 0.28235295f, 0.93f);
|
|
private static readonly Color Z_AXIS_COLOR = new Color(0.22745098f, 0.47843137f, 0.972549f, 0.93f);
|
|
|
|
private static readonly Color EDGE_COLOR = new Color(0.6039216f, 0.9529412f, 0.28235295f, 0.93f);
|
|
private static readonly Color EDGE_COLOR2 = new Color(0.6039216f, 0.9529412f, 0.28235295f, 0.4f);
|
|
|
|
private static readonly Quaternion CIRCLE_CAP_ROTATION = Quaternion.Euler(90f, 0f, 0f);
|
|
private static readonly Quaternion CIRCLE_CAP_ROTATION2 = Quaternion.Euler(0f, 90f, 0f);
|
|
private static readonly Quaternion RECTANGLE_CAP_ROTATION = Quaternion.Euler(90f, 0f, 0f);
|
|
|
|
public static Vector2 RectHandle(Vector3 worldPosition, Quaternion worldRotation, Vector2 rectSize, EAxis axii)
|
|
{
|
|
float size = HandleUtility.GetHandleSize(worldPosition);
|
|
float dotSize = size * 0.125f;
|
|
|
|
Handles.matrix = Matrix4x4.TRS(worldPosition, worldRotation * RECTANGLE_CAP_ROTATION, Vector3.one);
|
|
Color color = Handles.color;
|
|
|
|
Handles.color = EDGE_COLOR;
|
|
Handles.DrawWireCube(Vector3.zero, rectSize);
|
|
|
|
if ((axii & EAxis.X) != 0)
|
|
{
|
|
var point = new Vector3(rectSize.x * 0.5f, 0f, 0f);
|
|
Handles.color = DEFAULT_AXIS_COLOR;
|
|
point = Handles.Slider(point, Vector3.right, dotSize, Handles.CubeHandleCap, 0.01f);
|
|
rectSize.x = Mathf.Max(point.x, 0f) * 2f;
|
|
}
|
|
|
|
if ((axii & EAxis.Y) != 0)
|
|
{
|
|
var point = new Vector3(0f, rectSize.y * 0.5f, 0f);
|
|
Handles.color = DEFAULT_AXIS_COLOR;
|
|
point = Handles.Slider(point, Vector3.up, dotSize, Handles.CubeHandleCap, 0.01f);
|
|
rectSize.y = Mathf.Max(point.y, 0f) * 2f;
|
|
}
|
|
|
|
Handles.color = color;
|
|
Handles.matrix = Matrix4x4.identity;
|
|
return rectSize;
|
|
}
|
|
|
|
public static float CircleHandle(Vector3 worldPosition, Quaternion worldRotation, float circleSize)
|
|
{
|
|
float size = HandleUtility.GetHandleSize(worldPosition);
|
|
float dotSize = size * 0.125f;
|
|
|
|
Handles.matrix = Matrix4x4.TRS(worldPosition, worldRotation, Vector3.one);
|
|
Color color = Handles.color;
|
|
|
|
Handles.color = EDGE_COLOR;
|
|
Handles.CircleHandleCap(-1, Vector3.zero, CIRCLE_CAP_ROTATION, circleSize, EventType.Repaint);
|
|
|
|
var point = new Vector3(circleSize, 0f, 0f);
|
|
Handles.color = DEFAULT_AXIS_COLOR;
|
|
point = Handles.Slider(point, Vector3.right, dotSize, Handles.CubeHandleCap, 0.01f);
|
|
circleSize = Mathf.Max(point.x, 0f);
|
|
|
|
Handles.color = color;
|
|
Handles.matrix = Matrix4x4.identity;
|
|
return circleSize;
|
|
}
|
|
|
|
public static float SphereHandle(Vector3 worldPosition, Quaternion worldRotation, float sphereSize)
|
|
{
|
|
float size = HandleUtility.GetHandleSize(worldPosition);
|
|
float dotSize = size * 0.125f;
|
|
|
|
Handles.matrix = Matrix4x4.TRS(worldPosition, worldRotation, Vector3.one);
|
|
Color color = Handles.color;
|
|
|
|
Handles.color = EDGE_COLOR;
|
|
Handles.CircleHandleCap(-1, Vector3.zero, CIRCLE_CAP_ROTATION, sphereSize, EventType.Repaint);
|
|
|
|
Handles.color = EDGE_COLOR2;
|
|
Handles.CircleHandleCap(-1, Vector3.zero, Quaternion.identity, sphereSize, EventType.Repaint);
|
|
Handles.CircleHandleCap(-1, Vector3.zero, CIRCLE_CAP_ROTATION2, sphereSize, EventType.Repaint);
|
|
|
|
var point = new Vector3(sphereSize, 0f, 0f);
|
|
Handles.color = DEFAULT_AXIS_COLOR;
|
|
point = Handles.Slider(point, Vector3.right, dotSize, Handles.CubeHandleCap, 0.01f);
|
|
sphereSize = Mathf.Max(point.x, 0f);
|
|
|
|
Handles.color = color;
|
|
Handles.matrix = Matrix4x4.identity;
|
|
return sphereSize;
|
|
}
|
|
|
|
public static Vector3 BoxHandle(Vector3 worldPosition, Quaternion worldRotation, Vector3 boxSize, EAxis axii = EAxis.All)
|
|
{
|
|
float size = HandleUtility.GetHandleSize(worldPosition);
|
|
float dotSize = size * 0.125f;
|
|
|
|
Handles.matrix = Matrix4x4.TRS(worldPosition, worldRotation, Vector3.one);
|
|
Color color = Handles.color;
|
|
|
|
Handles.color = EDGE_COLOR;
|
|
Handles.DrawWireCube(Vector3.zero, boxSize);
|
|
|
|
if ((axii & EAxis.X) != 0)
|
|
{
|
|
var point = new Vector3(boxSize.x * 0.5f, 0f, 0f);
|
|
Handles.color = DEFAULT_AXIS_COLOR;
|
|
point = Handles.Slider(point, Vector3.right, dotSize, Handles.CubeHandleCap, 0.01f);
|
|
boxSize.x = Mathf.Max(point.x, 0f) * 2f;
|
|
}
|
|
|
|
if ((axii & EAxis.Y) != 0)
|
|
{
|
|
var point = new Vector3(0f, boxSize.y * 0.5f, 0f);
|
|
Handles.color = DEFAULT_AXIS_COLOR;
|
|
point = Handles.Slider(point, Vector3.up, dotSize, Handles.CubeHandleCap, 0.01f);
|
|
boxSize.y = Mathf.Max(point.y, 0f) * 2f;
|
|
}
|
|
|
|
if ((axii & EAxis.Z) != 0)
|
|
{
|
|
var point = new Vector3(0f, 0f, boxSize.z * 0.5f);
|
|
Handles.color = DEFAULT_AXIS_COLOR;
|
|
point = Handles.Slider(point, Vector3.forward, dotSize, Handles.CubeHandleCap, 0.01f);
|
|
boxSize.z = Mathf.Max(point.z, 0f) * 2f;
|
|
}
|
|
|
|
Handles.color = color;
|
|
Handles.matrix = Matrix4x4.identity;
|
|
return boxSize;
|
|
}
|
|
|
|
public static Vector3 PositionHandle(Vector3 worldPosition, Quaternion worldRotation, EAxis axii = EAxis.All)
|
|
{
|
|
float size = HandleUtility.GetHandleSize(worldPosition);
|
|
float twoAxisSize = size * 0.1f;
|
|
Color color = Handles.color;
|
|
|
|
if ((axii & (EAxis.X | EAxis.Y)) == (EAxis.X | EAxis.Y))
|
|
{
|
|
Handles.color = Z_AXIS_COLOR;
|
|
Vector3 offset = worldRotation * new Vector3(twoAxisSize, twoAxisSize, 0f);
|
|
|
|
worldPosition = Handles.Slider2D(worldPosition + offset,
|
|
worldRotation * Vector3.forward,
|
|
worldRotation * Vector3.right,
|
|
worldRotation * Vector3.up, twoAxisSize,
|
|
Handles.RectangleHandleCap, 0.01f) - offset;
|
|
}
|
|
|
|
if ((axii & (EAxis.X | EAxis.Z)) == (EAxis.X | EAxis.Z))
|
|
{
|
|
Handles.color = Y_AXIS_COLOR;
|
|
Vector3 offset = worldRotation * new Vector3(twoAxisSize, 0f, twoAxisSize);
|
|
|
|
worldPosition = Handles.Slider2D(worldPosition + offset,
|
|
worldRotation * Vector3.up,
|
|
worldRotation * Vector3.right,
|
|
worldRotation * Vector3.forward, twoAxisSize,
|
|
Handles.RectangleHandleCap, 0.01f) - offset;
|
|
}
|
|
|
|
if ((axii & (EAxis.Y | EAxis.Z)) == (EAxis.Y | EAxis.Z))
|
|
{
|
|
Handles.color = X_AXIS_COLOR;
|
|
Vector3 offset = worldRotation * new Vector3(0f, twoAxisSize, twoAxisSize);
|
|
|
|
worldPosition = Handles.Slider2D(worldPosition + offset,
|
|
worldRotation * Vector3.right,
|
|
worldRotation * Vector3.up,
|
|
worldRotation * Vector3.forward, twoAxisSize,
|
|
Handles.RectangleHandleCap, 0.01f) - offset;
|
|
}
|
|
|
|
if ((axii & EAxis.X) != 0)
|
|
{
|
|
Handles.color = X_AXIS_COLOR;
|
|
worldPosition = Handles.Slider(worldPosition, worldRotation * Vector3.right, size, Handles.ArrowHandleCap, 0.01f);
|
|
}
|
|
|
|
if ((axii & EAxis.Y) != 0)
|
|
{
|
|
Handles.color = Y_AXIS_COLOR;
|
|
worldPosition = Handles.Slider(worldPosition, worldRotation * Vector3.up, size, Handles.ArrowHandleCap, 0.01f);
|
|
}
|
|
|
|
if ((axii & EAxis.Z) != 0)
|
|
{
|
|
Handles.color = Z_AXIS_COLOR;
|
|
worldPosition = Handles.Slider(worldPosition, worldRotation * Vector3.forward, size, Handles.ArrowHandleCap, 0.01f);
|
|
}
|
|
|
|
Handles.color = color;
|
|
return worldPosition;
|
|
}
|
|
|
|
public static Quaternion RotationHandle(Vector3 worldPosition, Quaternion worldRotation)
|
|
{
|
|
Color color = Handles.color;
|
|
worldRotation = Handles.RotationHandle(worldRotation, worldPosition);
|
|
Handles.color = color;
|
|
return worldRotation;
|
|
}
|
|
public static bool TryGetWorldPosition(SerializedProperty serializedProperty, string fieldPosition, Space space, out Vector3 worldPosition)
|
|
{
|
|
SerializedProperty spPosition = serializedProperty.GetSibling(fieldPosition);
|
|
|
|
if (spPosition != null)
|
|
{
|
|
worldPosition = GetWorldPosition(spPosition, space);
|
|
}
|
|
else
|
|
{
|
|
Transform transform = GetTransform(serializedProperty);
|
|
worldPosition = transform != null ? transform.position : Vector3.zero;
|
|
}
|
|
|
|
return spPosition != null;
|
|
}
|
|
|
|
public static Vector3 GetWorldPosition(SerializedProperty serializedProperty, string fieldPosition, Space space)
|
|
{
|
|
Vector3 worldPosition = Vector3.zero;
|
|
SerializedProperty spPosition = serializedProperty.GetSibling(fieldPosition);
|
|
|
|
if (spPosition != null)
|
|
{
|
|
worldPosition = GetWorldPosition(spPosition, space);
|
|
}
|
|
else
|
|
{
|
|
Transform transform = GetTransform(serializedProperty);
|
|
|
|
if (transform != null)
|
|
worldPosition = transform.position;
|
|
}
|
|
|
|
return worldPosition;
|
|
}
|
|
|
|
private static Transform GetTransform(SerializedProperty serializedProperty)
|
|
{
|
|
Object target = serializedProperty.serializedObject.targetObject;
|
|
|
|
if (target is Component component)
|
|
return component.transform;
|
|
|
|
return null;
|
|
}
|
|
|
|
public static Vector3 GetWorldPosition(SerializedProperty serializedProperty, Space space)
|
|
{
|
|
Vector3 worldPosition = Vector3.zero;
|
|
var requireObjectTransform = true;
|
|
|
|
switch (serializedProperty.propertyType)
|
|
{
|
|
case SerializedPropertyType.Integer:
|
|
worldPosition = new Vector3(serializedProperty.intValue, serializedProperty.intValue, serializedProperty.intValue);
|
|
break;
|
|
case SerializedPropertyType.Float:
|
|
worldPosition = new Vector3(serializedProperty.floatValue, serializedProperty.floatValue, serializedProperty.floatValue);
|
|
break;
|
|
case SerializedPropertyType.ObjectReference:
|
|
if (serializedProperty.objectReferenceValue != null && serializedProperty.objectReferenceValue is Transform transform)
|
|
{
|
|
worldPosition = transform.position;
|
|
requireObjectTransform = false;
|
|
}
|
|
break;
|
|
case SerializedPropertyType.Vector2:
|
|
worldPosition = serializedProperty.vector2Value;
|
|
break;
|
|
case SerializedPropertyType.Vector3:
|
|
worldPosition = serializedProperty.vector3Value;
|
|
break;
|
|
case SerializedPropertyType.Vector2Int:
|
|
worldPosition = new Vector3(serializedProperty.vector2IntValue.x, serializedProperty.vector2IntValue.y, 0.0f);
|
|
break;
|
|
case SerializedPropertyType.Vector3Int:
|
|
worldPosition = new Vector3(serializedProperty.vector3IntValue.x, serializedProperty.vector3IntValue.y, serializedProperty.vector3IntValue.z);
|
|
break;
|
|
}
|
|
|
|
if (requireObjectTransform && space == Space.Self)
|
|
{
|
|
Transform objectTransform = GetTransform(serializedProperty);
|
|
|
|
if (objectTransform != null)
|
|
worldPosition = objectTransform.TransformPoint(worldPosition);
|
|
}
|
|
|
|
return worldPosition;
|
|
}
|
|
|
|
public static void SetWorldPosition(SerializedProperty serializedProperty, string fieldPosition, Vector3 worldPosition, Space space)
|
|
{
|
|
SerializedProperty spPosition = serializedProperty.GetSibling(fieldPosition);
|
|
|
|
if (spPosition != null)
|
|
{
|
|
SetWorldPosition(spPosition, worldPosition, space);
|
|
}
|
|
else
|
|
{
|
|
Transform transform = GetTransform(serializedProperty);
|
|
|
|
if (transform != null)
|
|
transform.position = worldPosition;
|
|
}
|
|
}
|
|
|
|
public static void SetWorldPosition(SerializedProperty serializedProperty, Vector3 worldPosition, Space space)
|
|
{
|
|
bool requireObjectTransform = !(serializedProperty.propertyType == SerializedPropertyType.ObjectReference && serializedProperty.objectReferenceValue != null && serializedProperty.objectReferenceValue is Transform);
|
|
|
|
if (requireObjectTransform && space == Space.Self)
|
|
{
|
|
Transform objectTransform = GetTransform(serializedProperty);
|
|
|
|
if (objectTransform != null)
|
|
worldPosition = objectTransform.InverseTransformPoint(worldPosition);
|
|
}
|
|
|
|
switch (serializedProperty.propertyType)
|
|
{
|
|
case SerializedPropertyType.Integer:
|
|
serializedProperty.intValue = Mathf.RoundToInt(worldPosition.x);
|
|
break;
|
|
case SerializedPropertyType.Float:
|
|
serializedProperty.floatValue = worldPosition.x;
|
|
break;
|
|
case SerializedPropertyType.ObjectReference:
|
|
if (serializedProperty.objectReferenceValue != null && serializedProperty.objectReferenceValue is Transform transform)
|
|
transform.position = worldPosition;
|
|
break;
|
|
case SerializedPropertyType.Vector2:
|
|
serializedProperty.vector2Value = worldPosition;
|
|
break;
|
|
case SerializedPropertyType.Vector3:
|
|
serializedProperty.vector3Value = worldPosition;
|
|
break;
|
|
case SerializedPropertyType.Vector2Int:
|
|
serializedProperty.vector2IntValue = new Vector2Int(Mathf.RoundToInt(worldPosition.x), Mathf.RoundToInt(worldPosition.y));
|
|
break;
|
|
case SerializedPropertyType.Vector3Int:
|
|
serializedProperty.vector3IntValue = new Vector3Int(Mathf.RoundToInt(worldPosition.x), Mathf.RoundToInt(worldPosition.y), Mathf.RoundToInt(worldPosition.z));
|
|
break;
|
|
}
|
|
}
|
|
|
|
public static bool TryGetWorldRotation(SerializedProperty serializedProperty, string fieldRotation, Space space, out Quaternion worldRotation)
|
|
{
|
|
SerializedProperty spRotation = serializedProperty.GetSibling(fieldRotation);
|
|
|
|
if (spRotation != null)
|
|
{
|
|
worldRotation = GetWorldRotation(spRotation, space);
|
|
}
|
|
else
|
|
{
|
|
Transform transform = GetTransform(serializedProperty);
|
|
worldRotation = transform != null ? transform.rotation : Quaternion.identity;
|
|
}
|
|
|
|
return spRotation != null;
|
|
}
|
|
|
|
public static Quaternion GetWorldRotation(SerializedProperty serializedProperty, string fieldRotation, Space space)
|
|
{
|
|
Quaternion worldRotation = Quaternion.identity;
|
|
SerializedProperty spRotation = serializedProperty.GetSibling(fieldRotation);
|
|
|
|
if (spRotation != null)
|
|
{
|
|
worldRotation = GetWorldRotation(spRotation, space);
|
|
}
|
|
else
|
|
{
|
|
Transform transform = GetTransform(serializedProperty);
|
|
|
|
if (transform != null)
|
|
worldRotation = transform.rotation;
|
|
}
|
|
|
|
return worldRotation;
|
|
}
|
|
|
|
public static Quaternion GetWorldRotation(SerializedProperty serializedProperty, Space space)
|
|
{
|
|
Quaternion worldRotation = Quaternion.identity;
|
|
var requireObjectTransform = true;
|
|
|
|
switch (serializedProperty.propertyType)
|
|
{
|
|
case SerializedPropertyType.ObjectReference:
|
|
if (serializedProperty.objectReferenceValue is Transform transform)
|
|
{
|
|
worldRotation = transform.rotation;
|
|
requireObjectTransform = false;
|
|
}
|
|
|
|
break;
|
|
case SerializedPropertyType.Quaternion:
|
|
worldRotation = serializedProperty.quaternionValue;
|
|
|
|
if (Mathf.Approximately(worldRotation.x, 0.0f) && Mathf.Approximately(worldRotation.y, 0.0f) && Mathf.Approximately(worldRotation.z, 0.0f) && Mathf.Approximately(worldRotation.w, 0.0f))
|
|
worldRotation = Quaternion.identity;
|
|
break;
|
|
}
|
|
|
|
if (requireObjectTransform && space == Space.Self)
|
|
{
|
|
Transform objectTransform = GetTransform(serializedProperty);
|
|
|
|
if (objectTransform != null)
|
|
worldRotation = objectTransform.rotation * worldRotation;
|
|
}
|
|
|
|
return worldRotation;
|
|
}
|
|
|
|
public static void SetWorldRotation(SerializedProperty serializedProperty, string fieldRotation, Quaternion worldRotation, Space space)
|
|
{
|
|
SerializedProperty spRotation = serializedProperty.GetSibling(fieldRotation);
|
|
|
|
if (spRotation != null)
|
|
{
|
|
SetWorldRotation(spRotation, worldRotation, space);
|
|
}
|
|
else
|
|
{
|
|
Transform transform = GetTransform(serializedProperty);
|
|
|
|
if (transform != null)
|
|
transform.rotation = worldRotation;
|
|
}
|
|
}
|
|
|
|
public static void SetWorldRotation(SerializedProperty serializedProperty, Quaternion worldRotation, Space space)
|
|
{
|
|
bool requireObjectTransform = !(serializedProperty.propertyType == SerializedPropertyType.ObjectReference && serializedProperty.objectReferenceValue != null && serializedProperty.objectReferenceValue is Transform);
|
|
|
|
if (requireObjectTransform && space == Space.Self)
|
|
{
|
|
Transform objectTransform = GetTransform(serializedProperty);
|
|
|
|
if (objectTransform != null)
|
|
worldRotation = Quaternion.Inverse(objectTransform.rotation) * worldRotation;
|
|
}
|
|
|
|
switch (serializedProperty.propertyType)
|
|
{
|
|
case SerializedPropertyType.ObjectReference:
|
|
if (serializedProperty.objectReferenceValue is Transform transform)
|
|
transform.rotation = worldRotation;
|
|
break;
|
|
case SerializedPropertyType.Quaternion:
|
|
serializedProperty.quaternionValue = worldRotation;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} |