RoboticArms/Library/PackageCache/com.unity.splines@d3e1e500c9a0/Editor/GUI/SplineDataConversionWindow.cs
2025-11-17 15:16:36 +07:00

160 lines
6.6 KiB
C#

using System;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Splines;
namespace UnityEditor.Splines
{
class SplineDataConversionWindow : EditorWindow
{
static readonly string k_SplineDataConversionMessage = L10n.Tr("Select a reference spline to convert your " +
"SplineData with no data loss. Otherwise data " +
"won't be converted.");
static readonly Regex k_EmbeddedSplineDataContainerIndex =
new Regex(@"((?<=m_Splines\.Array\.data\[)([0-9]+))(?=\])", RegexOptions.Compiled);
SerializedProperty m_SplineDataProperty;
SplineContainer m_TargetContainer;
int m_TargetSpline;
PathIndexUnit m_NewIndexUnit;
string[] m_SplineSelectionContent;
int[] m_SplineSelectionValues;
public static void DoConfirmWindow(Rect rect,
SerializedProperty splineDataProperty,
Component targetComponent,
int newValue,
bool forceShowDialog)
{
var window = Resources.FindObjectsOfTypeAll<SplineDataConversionWindow>().FirstOrDefault();
if (window == null)
window = CreateInstance<SplineDataConversionWindow>();
window.titleContent = new GUIContent("Convert Spline Data Index Unit");
window.m_SplineDataProperty = splineDataProperty;
var(container, index) = FindPlausibleSplineContainer(targetComponent, splineDataProperty);
window.SetTargetSpline(container, index);
window.m_NewIndexUnit = (PathIndexUnit) newValue;
window.minSize = new Vector2(400, 124);
window.maxSize = new Vector2(400, 124);
if (forceShowDialog || container == null || index < 0)
{
window.ShowUtility();
}
else
{
window.ApplyConversion();
DestroyImmediate(window);
}
}
void SetTargetSpline(SplineContainer container, int index)
{
m_TargetContainer = container;
var splines = container == null ? Array.Empty<Spline>() : container.Splines;
m_TargetSpline = math.min(math.max(0, index), splines.Count-1);
m_SplineSelectionContent = new string[splines.Count];
m_SplineSelectionValues = new int[splines.Count];
for (int i = 0, c = splines.Count; i < c; ++i)
{
m_SplineSelectionContent[i] = $"Spline {i}";
m_SplineSelectionValues[i] = i;
}
}
void OnGUI()
{
GUILayout.Label(L10n.Tr("Spline Data Conversion"), EditorStyles.boldLabel);
if(m_TargetContainer == null)
EditorGUILayout.HelpBox(k_SplineDataConversionMessage,MessageType.Warning);
else
EditorGUILayout.HelpBox(L10n.Tr($"The spline {m_TargetContainer} will be used for data conversion."), MessageType.Info);
var container = m_TargetContainer;
container = (SplineContainer)EditorGUILayout.ObjectField("Reference Spline",
container,
typeof(SplineContainer),
true);
if(container != m_TargetContainer)
SetTargetSpline(container, m_TargetSpline);
m_TargetSpline = SplineGUILayout.SplineIndexPopup("Spline", m_TargetSpline, m_TargetContainer);
EditorGUILayout.BeginHorizontal();
if(GUILayout.Button(new GUIContent(L10n.Tr("Convert"), L10n.Tr("Convert data indexes to the new Unit."))))
{
if(m_TargetContainer != null)
ApplyConversion();
Close();
}
if(GUILayout.Button(L10n.Tr("Cancel")))
Close();
EditorGUILayout.EndHorizontal();
}
static (SplineContainer, int) FindPlausibleSplineContainer(Component targetComponent, SerializedProperty prop)
{
SplineContainer container = null;
var fieldInfos = targetComponent.GetType().GetFields(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
var providerFieldInfo = fieldInfos.FirstOrDefault(field => field.FieldType == typeof(SplineContainer));
if(providerFieldInfo != null && providerFieldInfo.FieldType == typeof(SplineContainer))
container = (SplineContainer)providerFieldInfo.GetValue(targetComponent);
if(container == null)
container = targetComponent.gameObject.GetComponent<SplineContainer>();
int index = 0;
// if this is embedded SplineData, try to extract the spline index (if more than one spline)
if (container != null && container.Splines.Count > 1)
{
// m_Splines.Array.data[0].m_ObjectData.m_Data.Array.data[0].Value.m_DataPoints
var match = k_EmbeddedSplineDataContainerIndex.Match(prop.propertyPath);
if (match.Success && int.TryParse(match.Value, out var i))
index = i;
}
return (container, index);
}
void ApplyConversion()
{
m_SplineDataProperty.serializedObject.Update();
ConvertPathUnit(m_SplineDataProperty, m_TargetContainer, m_TargetSpline, m_NewIndexUnit);
m_SplineDataProperty.serializedObject.ApplyModifiedProperties();
}
static void ConvertPathUnit(SerializedProperty splineData,
ISplineContainer container,
int splineIndex,
PathIndexUnit newIndexUnit)
{
var spline = container.Splines[splineIndex];
var transform = container is Component component
? component.transform.localToWorldMatrix
: Matrix4x4.identity;
using var native = new NativeSpline(spline, transform);
var array = splineData.FindPropertyRelative("m_DataPoints");
var pathUnit = splineData.FindPropertyRelative("m_IndexUnit");
var from = (PathIndexUnit) Enum.GetValues(typeof(PathIndexUnit)).GetValue(pathUnit.enumValueIndex);
for (int i = 0, c = array.arraySize; i < c; ++i)
{
var point = array.GetArrayElementAtIndex(i);
var index = point.FindPropertyRelative("m_Index");
index.floatValue = native.ConvertIndexUnit(index.floatValue, from, newIndexUnit);
}
pathUnit.enumValueIndex = (int) newIndexUnit;
}
}
}