305 lines
11 KiB
C#
305 lines
11 KiB
C#
using System.Collections.Generic;
|
|
using UnityEditor;
|
|
using UnityEditor.IMGUI.Controls;
|
|
using UnityEngine;
|
|
|
|
namespace UniVRM10
|
|
{
|
|
public class SpringBoneTreeView : TreeView
|
|
{
|
|
public Vrm10Instance Target { get; private set; }
|
|
SerializedObject _so;
|
|
|
|
TreeViewItem _root;
|
|
TreeViewItem _colliderGroups;
|
|
TreeViewItem _springs;
|
|
|
|
int _nextNodeID = 0;
|
|
|
|
Dictionary<int, object> _map = new Dictionary<int, object>();
|
|
|
|
public SpringBoneTreeView(TreeViewState state, Vrm10Instance target, SerializedObject so) : base(state)
|
|
{
|
|
Target = target;
|
|
_so = so;
|
|
|
|
_root = new TreeViewItem(_nextNodeID++, -1, "Root");
|
|
var springBone = new TreeViewItem(_nextNodeID++, 0, "SpringBone");
|
|
_root.AddChild(springBone);
|
|
|
|
_colliderGroups = new TreeViewItem(_nextNodeID++, 1, "ColliderGroups");
|
|
springBone.AddChild(_colliderGroups);
|
|
|
|
_springs = new TreeViewItem(_nextNodeID++, 1, "Springs");
|
|
springBone.AddChild(_springs);
|
|
|
|
// load
|
|
_map = new Dictionary<int, object>();
|
|
if (target != null)
|
|
{
|
|
if (target.SpringBone?.ColliderGroups != null)
|
|
{
|
|
for (var i = 0; i < target.SpringBone.ColliderGroups.Count; ++i)
|
|
{
|
|
var colliderGroup = target.SpringBone.ColliderGroups[i];
|
|
var name = colliderGroup.GUIName(i);
|
|
var id = _nextNodeID++;
|
|
var item = new TreeViewItem(id, 2, name);
|
|
_map.Add(id, colliderGroup);
|
|
_colliderGroups.AddChild(item);
|
|
}
|
|
}
|
|
|
|
if (target.SpringBone?.Springs != null)
|
|
{
|
|
for (var i = 0; i < target.SpringBone.Springs.Count; ++i)
|
|
{
|
|
var spring = target.SpringBone.Springs[i];
|
|
var name = spring.GUIName(i);
|
|
var id = _nextNodeID++;
|
|
var item = new TreeViewItem(id, 2, name);
|
|
_map.Add(id, spring);
|
|
_springs.AddChild(item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override TreeViewItem BuildRoot()
|
|
{
|
|
return _root;
|
|
}
|
|
|
|
object _selected;
|
|
|
|
protected override void SelectionChanged(IList<int> selectedIds)
|
|
{
|
|
_selected = null;
|
|
if (selectedIds.Count > 0 && _map.TryGetValue(selectedIds[0], out object value))
|
|
{
|
|
if (value is VRM10SpringBoneColliderGroup colliderGroup)
|
|
{
|
|
var i = Target.SpringBone.ColliderGroups.IndexOf(colliderGroup);
|
|
_selected = new SelectedColliderGroupGUI(_so, i);
|
|
}
|
|
else if (value is Vrm10InstanceSpringBone.Spring spring)
|
|
{
|
|
var i = Target.SpringBone.Springs.IndexOf(spring);
|
|
_selected = new SelectedSpringGUI(Target, _so, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
const int WINDOW_HEIGHT = 500;
|
|
const int TREE_WIDTH = 160;
|
|
|
|
// |
|
|
// left | right
|
|
// |
|
|
public void Draw2D()
|
|
{
|
|
var r = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, GUILayout.Height(WINDOW_HEIGHT));
|
|
|
|
// left
|
|
OnGUI(new Rect(r.x, r.y, TREE_WIDTH, r.height));
|
|
|
|
// right
|
|
if (_selected is SelectedColliderGroupGUI colliderGroup)
|
|
{
|
|
colliderGroup.Draw2D(new Rect(r.x + TREE_WIDTH, r.y, r.width - TREE_WIDTH, r.height));
|
|
}
|
|
else if (_selected is SelectedSpringGUI spring)
|
|
{
|
|
spring.Draw2D(new Rect(r.x + TREE_WIDTH, r.y, r.width - TREE_WIDTH, r.height));
|
|
}
|
|
}
|
|
|
|
Color s_selectedColor = new Color(0.5f, 0, 0, 0.5f);
|
|
Color s_hoverColor = new Color(0.5f, 0.5f, 0, 0.5f);
|
|
Color s_Color = new Color(0.6f, 0.6f, 0.6f, 0.5f);
|
|
|
|
Color GetColor(MonoBehaviour target)
|
|
{
|
|
if (target == Active)
|
|
{
|
|
return s_selectedColor;
|
|
}
|
|
if (target == Hover)
|
|
{
|
|
return s_hoverColor;
|
|
}
|
|
return s_Color;
|
|
}
|
|
|
|
Vrm10InstanceSpringBone last = null;
|
|
MonoBehaviour Hover = null;
|
|
public MonoBehaviour Active = null;
|
|
|
|
public bool Draw3D(Vrm10InstanceSpringBone springBone)
|
|
{
|
|
var lastActive = Active;
|
|
var lastHover = Hover;
|
|
|
|
if (springBone != last)
|
|
{
|
|
Active = null;
|
|
Hover = null;
|
|
last = springBone;
|
|
}
|
|
|
|
if (_selected is SelectedColliderGroupGUI colliderGroup)
|
|
{
|
|
// colliderGroup.Draw3D();
|
|
}
|
|
else if (_selected is SelectedSpringGUI spring)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
MonoBehaviour newActive = null;
|
|
|
|
//
|
|
// collider
|
|
//
|
|
foreach (var group in springBone.ColliderGroups)
|
|
{
|
|
foreach (var collider in group.Colliders)
|
|
{
|
|
var color = GetColor(collider);
|
|
var (isActive, isHover) = DrawCollider(collider, color);
|
|
if (isActive)
|
|
{
|
|
newActive = collider;
|
|
}
|
|
if (isHover)
|
|
{
|
|
Hover = collider;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// joint
|
|
//
|
|
foreach (var spring in springBone.Springs)
|
|
{
|
|
VRM10SpringBoneJoint head = null;
|
|
for (int i = 0; i < spring.Joints.Count; ++i)
|
|
{
|
|
var joint = spring.Joints[i];
|
|
var color = GetColor(joint);
|
|
var (isActive, isHover) = DrawJoint(joint, color, head);
|
|
if (isActive)
|
|
{
|
|
newActive = joint;
|
|
}
|
|
if (isHover)
|
|
{
|
|
Hover = joint;
|
|
}
|
|
head = joint;
|
|
}
|
|
}
|
|
|
|
if (Active is VRM10SpringBoneCollider activeCollider)
|
|
{
|
|
// Active な collider の移動ハンドル(Offset, Tail)
|
|
EditorGUI.BeginChangeCheck();
|
|
Handles.matrix = activeCollider.transform.localToWorldMatrix;
|
|
var offset = Handles.PositionHandle(activeCollider.Offset, Quaternion.identity);
|
|
var tail = Vector3.zero;
|
|
if (activeCollider.ColliderType == VRM10SpringBoneColliderTypes.Capsule)
|
|
{
|
|
tail = Handles.PositionHandle(activeCollider.Tail, Quaternion.identity);
|
|
}
|
|
var offsetChanged = EditorGUI.EndChangeCheck();
|
|
if (offsetChanged)
|
|
{
|
|
// apply
|
|
Undo.RecordObject(activeCollider, "activeCollider");
|
|
activeCollider.Offset = offset;
|
|
if (activeCollider.ColliderType == VRM10SpringBoneColliderTypes.Capsule)
|
|
{
|
|
activeCollider.Tail = tail;
|
|
}
|
|
}
|
|
Handles.matrix = Matrix4x4.identity;
|
|
}
|
|
|
|
if (newActive != null)
|
|
{
|
|
Selection.activeObject = newActive.gameObject;
|
|
Active = newActive;
|
|
}
|
|
if (Hover != null)
|
|
{
|
|
Handles.Label(Hover.transform.position, Hover.name);
|
|
}
|
|
|
|
return lastActive != Active || lastHover != Hover;
|
|
}
|
|
|
|
static bool IsLeftDown()
|
|
{
|
|
return Event.current.type == EventType.MouseDown && Event.current.button == 0;
|
|
}
|
|
|
|
(bool IsActive, bool IsHover) DrawCollider(VRM10SpringBoneCollider collider, Color color)
|
|
{
|
|
if (Event.current.type == EventType.Repaint || Event.current.type == EventType.Layout)
|
|
{
|
|
Handles.matrix = collider.transform.localToWorldMatrix;
|
|
Handles.color = color;
|
|
switch (collider.ColliderType)
|
|
{
|
|
case VRM10SpringBoneColliderTypes.Sphere:
|
|
// Handles.color = Color.magenta;
|
|
Handles.SphereHandleCap(collider.GetInstanceID(), collider.Offset, Quaternion.identity, collider.Radius * 2, Event.current.type);
|
|
break;
|
|
|
|
case VRM10SpringBoneColliderTypes.Capsule:
|
|
// Handles.color = Color.cyan;
|
|
Handles.SphereHandleCap(collider.GetInstanceID(), collider.Offset, Quaternion.identity, collider.Radius * 2, Event.current.type);
|
|
Handles.SphereHandleCap(collider.GetInstanceID(), collider.Tail, Quaternion.identity, collider.Radius * 2, Event.current.type);
|
|
Handles.DrawLine(collider.Offset, collider.Tail);
|
|
break;
|
|
}
|
|
Handles.matrix = Matrix4x4.identity;
|
|
}
|
|
|
|
var isHover = HandleUtility.nearestControl == collider.GetInstanceID();
|
|
return (IsLeftDown() && isHover, isHover);
|
|
}
|
|
|
|
(bool IsActive, bool IsHover) DrawJoint(VRM10SpringBoneJoint joint, Color color, VRM10SpringBoneJoint head)
|
|
{
|
|
if (Event.current.type == EventType.Repaint || Event.current.type == EventType.Layout)
|
|
{
|
|
|
|
if (head == null)
|
|
{
|
|
// 先頭
|
|
Handles.color = color;
|
|
Handles.CubeHandleCap(joint.GetInstanceID(), joint.transform.position, joint.transform.rotation,
|
|
// head の radius
|
|
joint.m_jointRadius, Event.current.type);
|
|
}
|
|
else
|
|
{
|
|
// line
|
|
Handles.color = Color.green;
|
|
Handles.DrawLine(joint.transform.position, head.transform.position);
|
|
// joint
|
|
Handles.color = color;
|
|
Handles.SphereHandleCap(joint.GetInstanceID(), joint.transform.position, joint.transform.rotation,
|
|
// head の radius
|
|
head.m_jointRadius * 2, Event.current.type);
|
|
}
|
|
}
|
|
|
|
var isHover = HandleUtility.nearestControl == joint.GetInstanceID();
|
|
return (IsLeftDown() && isHover, isHover);
|
|
}
|
|
}
|
|
}
|