mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-04-19 05:27:21 -05:00
Migrate MuscleInspectorEditor to generic IMGUI TreeView API (Unity 6000) & fix RowGUIArgs usage
- Replace obsolete TreeView/TreeViewItem/TreeViewState with generic counterparts - Correct RowGUI signature to use nested non-generic TreeView<int>.RowGUIArgs - Implement IEnumerable<BoneNode> to avoid NotImplementedException - Use Mathf.Approximately for stable muscle slider updates - Initialize TreeViewState<int> on enable
This commit is contained in:
parent
dbef64d989
commit
1052c42a47
|
|
@ -1,20 +1,16 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
class BoneNode : IEnumerable<BoneNode>
|
||||
{
|
||||
public HumanBodyBones Bone { get; private set; }
|
||||
|
||||
public List<BoneNode> Children = new List<BoneNode>();
|
||||
|
||||
public int[] Muscles;
|
||||
|
||||
public BoneNode(HumanBodyBones bone, params int[] muscles)
|
||||
|
|
@ -25,45 +21,33 @@ namespace UniHumanoid
|
|||
|
||||
public IEnumerator<BoneNode> GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
yield return this;
|
||||
foreach (var c in Children)
|
||||
{
|
||||
foreach (var n in c) yield return n;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public void Add(BoneNode child)
|
||||
{
|
||||
Children.Add(child);
|
||||
}
|
||||
public void Add(BoneNode child) => Children.Add(child);
|
||||
}
|
||||
|
||||
class BoneTreeViewItem : TreeViewItem
|
||||
class BoneTreeViewItem : TreeViewItem<int>
|
||||
{
|
||||
//HumanBodyBones m_bone;
|
||||
|
||||
public BoneTreeViewItem(int id, int depth, HumanBodyBones bone) : base(id, depth, bone.ToString())
|
||||
{
|
||||
//m_bone = bone;
|
||||
}
|
||||
public BoneTreeViewItem(int id, int depth, HumanBodyBones bone) : base(id, depth, bone.ToString()) { }
|
||||
}
|
||||
|
||||
class MuscleTreeViewItem : TreeViewItem
|
||||
class MuscleTreeViewItem : TreeViewItem<int>
|
||||
{
|
||||
public int Muscle
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public int Muscle { get; private set; }
|
||||
public MuscleTreeViewItem(int id, int depth, int muscle) : base(id, depth, HumanTrait.MuscleName[muscle])
|
||||
{
|
||||
Muscle = muscle;
|
||||
}
|
||||
}
|
||||
|
||||
class BoneTreeView : TreeView
|
||||
class BoneTreeView : TreeView<int>
|
||||
{
|
||||
static BoneNode Skeleton = new BoneNode(HumanBodyBones.Hips)
|
||||
{
|
||||
|
|
@ -109,10 +93,8 @@ namespace UniHumanoid
|
|||
}
|
||||
};
|
||||
|
||||
//Animator m_animator;
|
||||
HumanPoseHandler m_handler;
|
||||
HumanPose m_pose;
|
||||
|
||||
bool m_updated;
|
||||
|
||||
public void Begin()
|
||||
|
|
@ -129,24 +111,21 @@ namespace UniHumanoid
|
|||
m_updated = false;
|
||||
}
|
||||
|
||||
public BoneTreeView(TreeViewState treeViewState, MultiColumnHeader header, HumanPoseHandler handler)
|
||||
public BoneTreeView(TreeViewState<int> treeViewState, MultiColumnHeader header, HumanPoseHandler handler)
|
||||
: base(treeViewState, header)
|
||||
{
|
||||
m_handler = handler;
|
||||
Reload();
|
||||
}
|
||||
|
||||
protected override TreeViewItem BuildRoot()
|
||||
protected override TreeViewItem<int> BuildRoot()
|
||||
{
|
||||
return new TreeViewItem { id = 0, depth = -1 };
|
||||
return new TreeViewItem<int> { id = 0, depth = -1 };
|
||||
}
|
||||
|
||||
protected override IList<TreeViewItem> BuildRows(TreeViewItem root)
|
||||
protected override IList<TreeViewItem<int>> BuildRows(TreeViewItem<int> root)
|
||||
{
|
||||
var rows = GetRows() ?? new List<TreeViewItem>(200);
|
||||
|
||||
// We use the GameObject instanceIDs as ids for items as we want to
|
||||
// select the game objects and not the transform components.
|
||||
var rows = GetRows() ?? new List<TreeViewItem<int>>(200);
|
||||
rows.Clear();
|
||||
|
||||
var item = CreateTreeViewItemForBone(HumanBodyBones.Hips);
|
||||
|
|
@ -163,14 +142,14 @@ namespace UniHumanoid
|
|||
}
|
||||
|
||||
SetupDepthsFromParentsAndChildren(root);
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
void AddChildrenRecursive(BoneNode bone, TreeViewItem item, IList<TreeViewItem> rows)
|
||||
void AddChildrenRecursive(BoneNode bone, TreeViewItem<int> item, IList<TreeViewItem<int>> rows)
|
||||
{
|
||||
int childCount = bone.Children.Count;
|
||||
item.children = new List<TreeViewItem>(childCount);
|
||||
item.children = new List<TreeViewItem<int>>(childCount);
|
||||
|
||||
if (bone.Muscles != null)
|
||||
{
|
||||
foreach (var muscle in bone.Muscles)
|
||||
|
|
@ -187,26 +166,24 @@ namespace UniHumanoid
|
|||
item.AddChild(childItem);
|
||||
rows.Add(childItem);
|
||||
|
||||
//if (child.Children.Count > 0)
|
||||
if (IsExpanded(childItem.id))
|
||||
{
|
||||
if (IsExpanded(childItem.id))
|
||||
{
|
||||
AddChildrenRecursive(child, childItem, rows);
|
||||
}
|
||||
else
|
||||
{
|
||||
childItem.children = CreateChildListForCollapsedParent();
|
||||
}
|
||||
AddChildrenRecursive(child, childItem, rows);
|
||||
}
|
||||
else
|
||||
{
|
||||
childItem.children = CreateChildListForCollapsedParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static TreeViewItem CreateTreeViewItemForBone(HumanBodyBones bone)
|
||||
static TreeViewItem<int> CreateTreeViewItemForBone(HumanBodyBones bone)
|
||||
{
|
||||
return new TreeViewItem((int)bone, -1, Enum.GetName(typeof(HumanBodyBones), bone));
|
||||
return new BoneTreeViewItem((int)bone, -1, bone);
|
||||
}
|
||||
|
||||
protected override void RowGUI(RowGUIArgs args)
|
||||
// inside class BoneTreeView : TreeView<int>
|
||||
protected override void RowGUI(UnityEditor.IMGUI.Controls.TreeView<int>.RowGUIArgs args)
|
||||
{
|
||||
for (int i = 0; i < args.GetNumVisibleColumns(); ++i)
|
||||
{
|
||||
|
|
@ -214,41 +191,33 @@ namespace UniHumanoid
|
|||
}
|
||||
}
|
||||
|
||||
void CellGUI(Rect cellRect, int index, ref RowGUIArgs args)
|
||||
void CellGUI(Rect cellRect, int index, ref UnityEditor.IMGUI.Controls.TreeView<int>.RowGUIArgs args)
|
||||
{
|
||||
// Center cell rect vertically (makes it easier to place controls, icons etc in the cells)
|
||||
CenterRectUsingSingleLineHeight(ref cellRect);
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// Default icon and label
|
||||
args.rowRect = cellRect;
|
||||
base.RowGUI(args);
|
||||
}
|
||||
{
|
||||
args.rowRect = cellRect;
|
||||
base.RowGUI(args);
|
||||
break;
|
||||
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
if (args.item is MuscleTreeViewItem muscleItem)
|
||||
{
|
||||
var muscleItem = args.item as MuscleTreeViewItem;
|
||||
if (muscleItem != null)
|
||||
var muscleIndex = muscleItem.Muscle;
|
||||
var muscles = m_pose.muscles;
|
||||
var value = EditorGUI.Slider(cellRect, GUIContent.none, muscles[muscleIndex], -1f, 1f);
|
||||
if (!Mathf.Approximately(value, muscles[muscleIndex]))
|
||||
{
|
||||
var muscleIndex = muscleItem.Muscle;
|
||||
var muscles = m_pose.muscles;
|
||||
var value = EditorGUI.Slider(cellRect, GUIContent.none, muscles[muscleIndex], -1f, 1f);
|
||||
if (value != muscles[muscleIndex])
|
||||
{
|
||||
muscles[muscleIndex] = value;
|
||||
m_updated = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
muscles[muscleIndex] = value;
|
||||
m_updated = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -278,32 +247,24 @@ namespace UniHumanoid
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
[CustomEditor(typeof(MuscleInspector))]
|
||||
public class MuscleInspectorEditor : Editor
|
||||
{
|
||||
[NonSerialized] bool m_Initialized;
|
||||
[SerializeField] TreeViewState m_TreeViewState; // Serialized in the window layout file so it survives assembly reloading
|
||||
//[SerializeField] MultiColumnHeaderState m_MultiColumnHeaderState;
|
||||
|
||||
// Note: Unity 6000 recommends generic state. It's fine if this isn't serialized by Unity's object serializer;
|
||||
// the TreeView manages its own persistence in editor layouts.
|
||||
[SerializeField] TreeViewState<int> m_TreeViewState;
|
||||
|
||||
SearchField m_SearchField;
|
||||
BoneTreeView m_TreeView;
|
||||
|
||||
MuscleInspector m_target;
|
||||
HumanPoseHandler m_handler;
|
||||
|
||||
|
||||
MultiColumnHeader GetHeaderState()
|
||||
{
|
||||
//bool firstInit = m_MultiColumnHeaderState == null;
|
||||
|
||||
var headerState = BoneTreeView.CreateDefaultMultiColumnHeaderState();
|
||||
/*
|
||||
if (MultiColumnHeaderState.CanOverwriteSerializedFields(m_MultiColumnHeaderState, headerState))
|
||||
{
|
||||
MultiColumnHeaderState.OverwriteSerializedFields(m_MultiColumnHeaderState, headerState);
|
||||
}
|
||||
m_MultiColumnHeaderState = headerState;
|
||||
*/
|
||||
var multiColumnHeader = new MultiColumnHeader(headerState);
|
||||
multiColumnHeader.ResizeToFit();
|
||||
return multiColumnHeader;
|
||||
|
|
@ -311,17 +272,19 @@ namespace UniHumanoid
|
|||
|
||||
void OnEnable()
|
||||
{
|
||||
var mi = this.target as MuscleInspector;
|
||||
if (mi.TryGetComponent<Animator>(out var animator)
|
||||
&& animator.avatar != null
|
||||
&& animator.avatar.isValid
|
||||
&& animator.avatar.isHuman
|
||||
)
|
||||
var mi = target as MuscleInspector;
|
||||
if (mi != null &&
|
||||
mi.TryGetComponent<Animator>(out var animator) &&
|
||||
animator.avatar != null &&
|
||||
animator.avatar.isValid &&
|
||||
animator.avatar.isHuman)
|
||||
{
|
||||
UniGLTF.UniGLTFLogger.Log("MuscleInspectorEditor.OnEnable");
|
||||
m_handler = new HumanPoseHandler(animator.avatar, animator.transform);
|
||||
|
||||
m_TreeView = new BoneTreeView(new TreeViewState(), GetHeaderState(), m_handler);
|
||||
// Use existing state if available, else create a new one
|
||||
if (m_TreeViewState == null) m_TreeViewState = new TreeViewState<int>();
|
||||
m_TreeView = new BoneTreeView(m_TreeViewState, GetHeaderState(), m_handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user