using System.Linq;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace UniVRM10
{
abstract class SelectedGUIBase
{
protected SerializedObject _so { get; private set; }
protected int _index { get; private set; }
protected SelectedGUIBase(SerializedObject so, int i)
{
_so = so;
_index = i;
}
public SerializedProperty Property { get; protected set; }
public abstract void Draw2D(Rect r);
public abstract void Draw3D();
///
/// 領域を1行と残りに分割する
///
///
///
public static (Rect line, Rect remain) LayoutLine(Rect rect)
{
return (
new Rect(
rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight
),
new Rect(
rect.x, rect.y + EditorGUIUtility.singleLineHeight, rect.width, rect.height - EditorGUIUtility.singleLineHeight
)
);
}
///
/// 領域を上下2分割
///
///
///
///
public static (Rect layout, Rect remain) LayoutVerticalHalf(Rect r)
{
var half = r.height / 2;
return (
new Rect(
r.x, r.y, r.width, half
),
new Rect(
r.x, r.y + half, r.width, r.height
)
);
}
}
class SelectedColliderGroupGUI
{
SerializedObject _so;
int _index;
ReorderableList _colliderGroupList;
public SelectedColliderGroupGUI(SerializedObject so, int i)
{
var target_prop = so.FindProperty($"SpringBone.ColliderGroups.Array.data[{i}]");
_index = i;
_so = new SerializedObject(target_prop.objectReferenceValue);
var prop = _so.FindProperty("Colliders");
_colliderGroupList = new ReorderableList(_so, prop);
_colliderGroupList.drawElementCallback = (rect, index, isActive, isFocused) =>
{
SerializedProperty element = prop.GetArrayElementAtIndex(index);
rect.height -= 4;
rect.y += 2;
EditorGUI.PropertyField(rect, element);
if (isFocused)
{
var id = element.objectReferenceValue.GetInstanceID();
if (id != VRM10SpringBoneCollider.SelectedGuid)
{
VRM10SpringBoneCollider.SelectedGuid = id;
SceneView.RepaintAll();
EditorUtility.SetDirty(element.objectReferenceValue);
}
}
};
}
public void Draw2D(Rect r)
{
Rect layout = default;
(layout, r) = SelectedGUIBase.LayoutLine(r);
EditorGUI.PropertyField(layout, _so.FindProperty("Name"));
(layout, r) = SelectedGUIBase.LayoutLine(r);
GUI.Label(layout, "colliders");
_colliderGroupList.DoList(r);
}
public static void DrawWireCapsule(Vector3 headPos, Vector3 tailPos, float radius)
{
var headToTail = tailPos - headPos;
if (headToTail.sqrMagnitude <= float.Epsilon)
{
Handles.DrawWireDisc(headPos, -SceneView.currentDrawingSceneView.camera.transform.forward, radius);
return;
}
var forward = headToTail.normalized * radius;
var xLen = Mathf.Abs(forward.x);
var yLen = Mathf.Abs(forward.y);
var zLen = Mathf.Abs(forward.z);
var rightWorldAxis = (yLen > xLen && yLen > zLen) ? Vector3.right : Vector3.up;
var up = Vector3.Cross(forward, rightWorldAxis).normalized * radius;
var right = Vector3.Cross(up, forward).normalized * radius;
const int division = 24;
DrawWireCircle(headPos, up, right, division, division);
DrawWireCircle(headPos, up, -forward, division, division / 2);
DrawWireCircle(headPos, right, -forward, division, division / 2);
DrawWireCircle(tailPos, up, right, division, division);
DrawWireCircle(tailPos, up, forward, division, division / 2);
DrawWireCircle(tailPos, right, forward, division, division / 2);
Handles.DrawLine(headPos + right, tailPos + right);
Handles.DrawLine(headPos - right, tailPos - right);
Handles.DrawLine(headPos + up, tailPos + up);
Handles.DrawLine(headPos - up, tailPos - up);
}
private static void DrawWireCircle(Vector3 centerPos, Vector3 xAxis, Vector3 yAxis, int division, int count)
{
for (var idx = 0; idx < division && idx < count; ++idx)
{
var s = ((idx + 0) % division) / (float)division * Mathf.PI * 2f;
var t = ((idx + 1) % division) / (float)division * Mathf.PI * 2f;
Gizmos.DrawLine(
centerPos + xAxis * Mathf.Cos(s) + yAxis * Mathf.Sin(s),
centerPos + xAxis * Mathf.Cos(t) + yAxis * Mathf.Sin(t)
);
}
}
public void Draw3D()
{
var target = _so.targetObject as VRM10SpringBoneColliderGroup;
foreach (var c in target.Colliders)
{
Handles.color = c.IsSelected ? Color.red : Color.cyan;
Matrix4x4 mat = c.transform.localToWorldMatrix;
Handles.matrix = mat * Matrix4x4.Scale(new Vector3(
1.0f / c.transform.lossyScale.x,
1.0f / c.transform.lossyScale.y,
1.0f / c.transform.lossyScale.z
));
switch (c.ColliderType)
{
case VRM10SpringBoneColliderTypes.Sphere:
Handles.DrawWireDisc(c.Offset, -SceneView.currentDrawingSceneView.camera.transform.forward, c.Radius);
break;
case VRM10SpringBoneColliderTypes.Capsule:
DrawWireCapsule(c.Offset, c.Tail, c.Radius);
break;
}
if (c.IsSelected)
{
Handles.color = Color.green;
EditorGUI.BeginChangeCheck();
Handles.matrix = c.transform.localToWorldMatrix;
var offset = Handles.PositionHandle(c.Offset, Quaternion.identity);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(c, "VRM10SpringBoneCollider");
c.Offset = offset;
EditorUtility.SetDirty(_so.targetObject);
}
}
}
}
}
class SelectedSpringGUI : SelectedGUIBase
{
ReorderableList _springColliderGroupList;
ReorderableList _springJointList;
public SelectedSpringGUI(Vrm10Instance target, SerializedObject so, int i) : base(so, i)
{
Property = so.FindProperty($"SpringBone.Springs.Array.data[{i}]");
{
var prop = Property.FindPropertyRelative("ColliderGroups");
_springColliderGroupList = new ReorderableList(so, prop);
_springColliderGroupList.drawElementCallback = (rect, index, isActive, isFocused) =>
{
rect.height -= 4;
rect.y += 2;
SerializedProperty element = prop.GetArrayElementAtIndex(index);
var elements = target.SpringBone.ColliderGroups;
var element_index = elements.IndexOf(element.objectReferenceValue as VRM10SpringBoneColliderGroup);
var colliderGroups = target.SpringBone.ColliderGroups.Select((x, y) => x.GUIName(y)).ToArray();
var new_index = EditorGUI.Popup(rect, element_index, colliderGroups);
if (new_index != element_index)
{
element.objectReferenceValue = elements[new_index];
}
};
}
{
var prop = Property.FindPropertyRelative("Joints");
_springJointList = new ReorderableList(so, prop);
_springJointList.drawElementCallback = (rect, index, isActive, isFocused) =>
{
SerializedProperty element = prop.GetArrayElementAtIndex(index);
rect.height -= 4;
rect.y += 2;
EditorGUI.PropertyField(rect, element);
};
}
}
public override void Draw2D(Rect r)
{
Rect layout = default;
(layout, r) = LayoutLine(r);
EditorGUI.PropertyField(layout, Property.FindPropertyRelative("Name"));
var (top, bottom) = LayoutVerticalHalf(r);
(layout, r) = LayoutLine(top);
GUI.Label(layout, "collider groups");
_springColliderGroupList.DoList(r);
(layout, r) = LayoutLine(bottom);
GUI.Label(layout, "joints");
_springJointList.DoList(r);
}
public override void Draw3D()
{
}
}
}