617 lines
27 KiB
C#
617 lines
27 KiB
C#
// Magica Cloth 2.
|
||
// Copyright (c) 2023 MagicaSoft.
|
||
// https://magicasoft.jp
|
||
using UnityEditor;
|
||
using UnityEngine;
|
||
|
||
namespace MagicaCloth2
|
||
{
|
||
/// <summary>
|
||
/// MagicaClothコンポーネントのエディタ拡張
|
||
/// </summary>
|
||
[CustomEditor(typeof(MagicaCloth))]
|
||
[CanEditMultipleObjects]
|
||
public class MagicaClothEditor : Editor
|
||
{
|
||
//=========================================================================================
|
||
private void Awake()
|
||
{
|
||
// 選択のたびに呼ばれるのでMonoの動作とは異なる
|
||
//Debug.Log("MagicaClothEditor.Awake");
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
//Debug.Log("MagicaClothEditor.OnEnable");
|
||
ClothEditorManager.OnEditMeshBuildComplete += OnEditMeshBuildComplete;
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
//Debug.Log("MagicaClothEditor.OnDisable");
|
||
ClothEditorManager.OnEditMeshBuildComplete -= OnEditMeshBuildComplete;
|
||
ClothPainter.ExitPaint();
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
// 選択が外れるたびに呼ばれるのでMonoの動作とは異なる
|
||
//Debug.Log("MagicaClothEditor.OnDestroy");
|
||
//Debug.Log(target != null);
|
||
}
|
||
|
||
private void OnValidate()
|
||
{
|
||
// どうもMonoのValidateは違う
|
||
//Debug.Log("MagicaClothEditor.OnValidate");
|
||
}
|
||
|
||
private void Reset()
|
||
{
|
||
//Debug.Log("MagicaClothEditor.Reset");
|
||
}
|
||
|
||
//=========================================================================================
|
||
int oldAcitve = -1;
|
||
|
||
//=========================================================================================
|
||
/// <summary>
|
||
/// 編集用のセレクションデータを取得する
|
||
/// </summary>
|
||
/// <param name="cloth"></param>
|
||
/// <param name="editMesh"></param>
|
||
/// <returns></returns>
|
||
public SelectionData GetSelectionData(MagicaCloth cloth, VirtualMesh editMesh)
|
||
{
|
||
// すでにセレクションデータが存在し、かつユーザー編集データならばコンバートする
|
||
var selectionData = ClothEditorManager.CreateAutoSelectionData(cloth, cloth.SerializeData, editMesh);
|
||
if (cloth.GetSerializeData2().selectionData != null && cloth.GetSerializeData2().selectionData.userEdit)
|
||
{
|
||
//Debug.Log($"セレクションデータコンバート!");
|
||
selectionData.ConvertFrom(cloth.GetSerializeData2().selectionData);
|
||
selectionData.userEdit = true;
|
||
}
|
||
|
||
return selectionData;
|
||
}
|
||
|
||
/// <summary>
|
||
/// エディットメッシュの構築完了通知(成否問わず)
|
||
/// </summary>
|
||
void OnEditMeshBuildComplete()
|
||
{
|
||
//Debug.Log($"MagicaClothInspector. OnEditMeshBuildComplete.");
|
||
Repaint();
|
||
}
|
||
|
||
/// <summary>
|
||
/// インスペクターGUI
|
||
/// </summary>
|
||
public override void OnInspectorGUI()
|
||
{
|
||
var cloth = target as MagicaCloth;
|
||
|
||
// 状態
|
||
DispVersion();
|
||
DispStatus();
|
||
DispProxyMesh();
|
||
|
||
// 設定
|
||
serializedObject.Update();
|
||
Undo.RecordObject(cloth, "MagicaCloth2");
|
||
EditorGUILayout.Space();
|
||
ClothMainInspector();
|
||
EditorGUILayout.Space();
|
||
EditorGUILayout.Space();
|
||
EditorGUILayout.Space();
|
||
ClothParameterInspector();
|
||
EditorGUILayout.Space();
|
||
EditorGUILayout.Space();
|
||
GizmoInspector();
|
||
serializedObject.ApplyModifiedProperties();
|
||
|
||
//DrawDefaultInspector();
|
||
|
||
// アクティブが変更された場合は編集メッシュを再構築する
|
||
int nowActive = cloth.isActiveAndEnabled ? 1 : 0;
|
||
if (nowActive != oldAcitve)
|
||
{
|
||
//Debug.Log($"[{cloth.name}] rebuild. active:{nowActive}");
|
||
oldAcitve = nowActive;
|
||
ClothEditorManager.RegisterComponent(cloth, nowActive > 0 ? GizmoType.Active : 0, true);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// クロスペイントの適用
|
||
/// </summary>
|
||
/// <param name="selectiondata"></param>
|
||
internal void ApplyClothPainter(SelectionData selectionData)
|
||
{
|
||
if (selectionData == null || selectionData.IsValid() == false)
|
||
return;
|
||
|
||
var cloth = target as MagicaCloth;
|
||
|
||
// セレクションデータ格納
|
||
ClothEditorManager.ApplySelectionData(cloth, selectionData);
|
||
}
|
||
|
||
/// <summary>
|
||
/// クロスペイントの変更による編集メッシュの再構築
|
||
/// </summary>
|
||
internal void UpdateEditMesh()
|
||
{
|
||
var cloth = target as MagicaCloth;
|
||
|
||
// 編集用メッシュの再構築
|
||
ClothEditorManager.RegisterComponent(cloth, GizmoType.Active, true); // 強制更新
|
||
}
|
||
|
||
//=========================================================================================
|
||
void DispVersion()
|
||
{
|
||
EditorGUILayout.LabelField($"Version {AboutMenu.MagicaClothVersion}");
|
||
//using (new EditorGUILayout.HorizontalScope())
|
||
//{
|
||
// //GUILayout.FlexibleSpace();
|
||
// EditorGUILayout.Space();
|
||
// EditorGUILayout.LabelField($"Version {AboutMenu.MagicaClothVersion}", GUILayout.Width(100));
|
||
//}
|
||
}
|
||
|
||
void DispStatus()
|
||
{
|
||
var cloth = target as MagicaCloth;
|
||
|
||
ResultCode result;
|
||
if (EditorApplication.isPlaying)
|
||
{
|
||
result = cloth.Process.Result;
|
||
}
|
||
else
|
||
{
|
||
result = ClothEditorManager.GetResultCode(cloth);
|
||
}
|
||
|
||
MessageType mtype = MessageType.Info;
|
||
if (result.IsError())
|
||
mtype = MessageType.Error;
|
||
else if (result.IsWarning())
|
||
mtype = MessageType.Warning;
|
||
|
||
var infoMessage = result.GetResultInformation();
|
||
if (infoMessage != null)
|
||
EditorGUILayout.HelpBox($"{result.GetResultString()}\n{infoMessage}", mtype);
|
||
else
|
||
EditorGUILayout.HelpBox(result.GetResultString(), mtype);
|
||
}
|
||
|
||
void DispProxyMesh()
|
||
{
|
||
var cloth = target as MagicaCloth;
|
||
|
||
VirtualMesh vmesh = null;
|
||
if (EditorApplication.isPlaying)
|
||
{
|
||
vmesh = cloth.Process?.ProxyMesh;
|
||
}
|
||
else
|
||
{
|
||
vmesh = ClothEditorManager.GetEditMesh(cloth);
|
||
}
|
||
if (vmesh == null)
|
||
return;
|
||
|
||
StaticStringBuilder.Clear();
|
||
if (EditorApplication.isPlaying)
|
||
StaticStringBuilder.AppendLine("[Proxy Mesh]");
|
||
else
|
||
StaticStringBuilder.AppendLine("[Edit Mesh]");
|
||
StaticStringBuilder.AppendLine($"Vertex: {vmesh.VertexCount}");
|
||
StaticStringBuilder.AppendLine($"Edge: {vmesh.EdgeCount}");
|
||
StaticStringBuilder.AppendLine($"Triangle: {vmesh.TriangleCount}");
|
||
StaticStringBuilder.AppendLine($"SkinBoneCount: {vmesh.SkinBoneCount}");
|
||
StaticStringBuilder.Append($"TransformCount: {vmesh.TransformCount}");
|
||
|
||
EditorGUILayout.HelpBox(StaticStringBuilder.ToString(), MessageType.Info);
|
||
}
|
||
|
||
|
||
void ClothMainInspector()
|
||
{
|
||
var cloth = target as MagicaCloth;
|
||
|
||
EditorGUILayout.LabelField("Main", EditorStyles.boldLabel);
|
||
|
||
// Cloth
|
||
{
|
||
var clothType = serializedObject.FindProperty("serializeData.clothType");
|
||
|
||
EditorGUILayout.PropertyField(clothType, new GUIContent("Cloth Type"));
|
||
|
||
var paintMode = serializedObject.FindProperty("serializeData.paintMode");
|
||
|
||
using (new EditorGUI.IndentLevelScope())
|
||
{
|
||
if (cloth.SerializeData.clothType == ClothProcess.ClothType.BoneCloth)
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.rootBones"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.connectionMode"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.rootRotation"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.rotationalInterpolation"));
|
||
}
|
||
else if (cloth.SerializeData.clothType == ClothProcess.ClothType.MeshCloth)
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.sourceRenderers"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.reductionSetting"));
|
||
}
|
||
|
||
EditorGUILayout.Space();
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.updateMode"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.animationPoseRatio"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.normalAxis"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.normalAlignmentSetting.alignmentMode"), new GUIContent("Normal Alignment"));
|
||
if (cloth.SerializeData.normalAlignmentSetting.alignmentMode == NormalAlignmentSettings.AlignmentMode.Transform)
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.normalAlignmentSetting.adjustmentTransform"));
|
||
}
|
||
|
||
if (cloth.SerializeData.clothType == ClothProcess.ClothType.MeshCloth)
|
||
{
|
||
EditorGUILayout.Space();
|
||
EditorGUILayout.PropertyField(paintMode);
|
||
if (paintMode.enumValueIndex != 0)
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.paintMaps"));
|
||
}
|
||
}
|
||
}
|
||
|
||
// ペイントボタン
|
||
if (paintMode.enumValueIndex == 0)
|
||
{
|
||
EditorGUILayout.Space();
|
||
PaintButton(ClothPainter.PaintMode.Attribute);
|
||
}
|
||
else
|
||
EditorGUILayout.Space();
|
||
}
|
||
|
||
// Custom Skinning
|
||
Foldout("Custom Skinning", serializedObject.FindProperty("serializeData.customSkinningSetting.enable"), null, () =>
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.customSkinningSetting.skinningBones"));
|
||
});
|
||
}
|
||
|
||
void ClothParameterInspector()
|
||
{
|
||
var cloth = target as MagicaCloth;
|
||
|
||
ClothPresetUtility.DrawPresetButton(cloth, cloth.SerializeData);
|
||
|
||
// Force
|
||
Foldout("Force", null, () =>
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.gravity"), new GUIContent("Gravity"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.gravityDirection"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.gravityFalloff"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.damping"));
|
||
});
|
||
|
||
// Angle Restoration
|
||
Foldout("Angle Restoration", serializedObject.FindProperty("serializeData.angleRestorationConstraint.useAngleRestoration"), null, () =>
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.angleRestorationConstraint.stiffness"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.angleRestorationConstraint.velocityAttenuation"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.angleRestorationConstraint.gravityFalloff"));
|
||
}
|
||
);
|
||
|
||
// Angle Limit
|
||
Foldout("Angle Limit", serializedObject.FindProperty("serializeData.angleLimitConstraint.useAngleLimit"), null, () =>
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.angleLimitConstraint.limitAngle"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.angleLimitConstraint.stiffness"));
|
||
}
|
||
);
|
||
|
||
// Shape
|
||
Foldout("Shape Restoration", null, () =>
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.distanceConstraint.stiffness"), new GUIContent("Distance Stiffness"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.tetherConstraint.distanceCompression"), new GUIContent("Tether Compression"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.triangleBendingConstraint.stiffness"), new GUIContent("Triangle Bending Stiffness"));
|
||
});
|
||
|
||
// Inertia
|
||
Foldout("Inertia", null, () =>
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.movementInertia"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.rotationInertia"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.depthInertia"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.centrifualAcceleration"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.movementSpeedLimit"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.rotationSpeedLimit"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.particleSpeedLimit"));
|
||
});
|
||
|
||
// Motion
|
||
Foldout("Movement Limit", null, () =>
|
||
{
|
||
var useMaxDistance = serializedObject.FindProperty("serializeData.motionConstraint.useMaxDistance");
|
||
var useBackstop = serializedObject.FindProperty("serializeData.motionConstraint.useBackstop");
|
||
EditorGUILayout.PropertyField(useMaxDistance);
|
||
using (new EditorGUI.DisabledScope(!useMaxDistance.boolValue))
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.motionConstraint.maxDistance"));
|
||
}
|
||
EditorGUILayout.PropertyField(useBackstop);
|
||
using (new EditorGUI.DisabledScope(!useBackstop.boolValue))
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.motionConstraint.backstopRadius"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.motionConstraint.backstopDistance"));
|
||
}
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.motionConstraint.stiffness"));
|
||
|
||
var paintMode = serializedObject.FindProperty("serializeData.paintMode");
|
||
if (paintMode.enumValueIndex == 0)
|
||
PaintButton(ClothPainter.PaintMode.Motion);
|
||
}
|
||
);
|
||
|
||
// Collider Collision
|
||
Foldout("Collider Collision", null, () =>
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.colliderCollisionConstraint.mode"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.radius"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.colliderCollisionConstraint.friction"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.colliderCollisionConstraint.colliderList"));
|
||
}
|
||
);
|
||
|
||
// Self Collision
|
||
Foldout("Self Collision", "Self Collision (Beta)", () =>
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.selfCollisionConstraint.selfMode"));
|
||
var syncMode = serializedObject.FindProperty("serializeData.selfCollisionConstraint.syncMode");
|
||
EditorGUILayout.PropertyField(syncMode);
|
||
if (syncMode.enumValueIndex != 0)
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.selfCollisionConstraint.syncPartner"));
|
||
}
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.selfCollisionConstraint.surfaceThickness"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.selfCollisionConstraint.clothMass"));
|
||
}
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 各プロパティの設定範囲.デフォルトは(0.0 ~ 1.0)
|
||
/// </summary>
|
||
/// <param name="propertyName"></param>
|
||
/// <returns></returns>
|
||
public static Vector2 GetPropertyMinMax(string propertyName)
|
||
{
|
||
var minmax = new Vector2(0.0f, 1.0f);
|
||
|
||
switch (propertyName)
|
||
{
|
||
case "radius":
|
||
minmax.Set(0.001f, 0.5f);
|
||
break;
|
||
case "limitAngle":
|
||
minmax.Set(0.0f, 180.0f);
|
||
break;
|
||
case "maxDistance":
|
||
minmax.Set(0.0f, 5.0f);
|
||
break;
|
||
case "surfaceThickness":
|
||
minmax.Set(Define.System.SelfCollisionThicknessMin, Define.System.SelfCollisionThicknessMax);
|
||
break;
|
||
case "movementSpeedLimit":
|
||
minmax.Set(0.0f, Define.System.MaxMovementSpeedLimit);
|
||
break;
|
||
case "rotationSpeedLimit":
|
||
minmax.Set(0.0f, Define.System.MaxRotationSpeedLimit);
|
||
break;
|
||
case "particleSpeedLimit":
|
||
minmax.Set(0.0f, Define.System.MaxParticleSpeedLimit);
|
||
break;
|
||
}
|
||
|
||
return minmax;
|
||
}
|
||
|
||
void GizmoInspector()
|
||
{
|
||
#if MC2_DEBUG
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData"));
|
||
#else
|
||
FoldOut("Gizmos", null, () =>
|
||
{
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.always"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.enable"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.ztest"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.position"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.axis"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.shape"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.baseLine"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.depth"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.collider"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.animatedPosition"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.animatedAxis"));
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.animatedShape"));
|
||
//EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.basicPosition"));
|
||
//EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.basicAxis"));
|
||
//EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.basicShape"));
|
||
});
|
||
#endif
|
||
}
|
||
|
||
//=========================================================================================
|
||
/// <summary>
|
||
/// 折りたたみ制御
|
||
/// </summary>
|
||
/// <param name="foldKey">折りたたみ保存キー</param>
|
||
/// <param name="title"></param>
|
||
/// <param name="drawAct">内容描画アクション</param>
|
||
/// <param name="enableAct">有効フラグアクション(null=無効)</param>
|
||
/// <param name="enable">現在の有効フラグ</param>
|
||
public void Foldout(
|
||
string foldKey,
|
||
string title = null,
|
||
System.Action drawAct = null,
|
||
System.Action<bool> enableAct = null,
|
||
bool enable = true
|
||
)
|
||
{
|
||
var style = new GUIStyle("ShurikenModuleTitle");
|
||
style.font = new GUIStyle(EditorStyles.label).font;
|
||
style.border = new RectOffset(15, 7, 4, 4);
|
||
style.fixedHeight = 22;
|
||
style.contentOffset = new Vector2(20f, -2f);
|
||
|
||
var rect = GUILayoutUtility.GetRect(16f, 22f, style);
|
||
|
||
GUI.backgroundColor = Color.white;
|
||
GUI.Box(rect, title ?? foldKey, style);
|
||
|
||
var e = Event.current;
|
||
bool foldOut = EditorPrefs.GetBool(foldKey);
|
||
|
||
if (enableAct == null)
|
||
{
|
||
if (e.type == EventType.Repaint)
|
||
{
|
||
var arrowRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f);
|
||
EditorStyles.foldout.Draw(arrowRect, false, false, foldOut, false);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 有効チェック
|
||
var toggleRect = new Rect(rect.x + 4f, rect.y + 4f, 13f, 13f);
|
||
bool sw = GUI.Toggle(toggleRect, enable, string.Empty, new GUIStyle("ShurikenCheckMark"));
|
||
if (sw != enable)
|
||
{
|
||
enableAct(sw);
|
||
}
|
||
}
|
||
|
||
if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition))
|
||
{
|
||
foldOut = !foldOut;
|
||
EditorPrefs.SetBool(foldKey, foldOut);
|
||
e.Use();
|
||
}
|
||
|
||
if (foldOut && drawAct != null)
|
||
{
|
||
using (new EditorGUI.IndentLevelScope())
|
||
{
|
||
using (new EditorGUI.DisabledScope(!enable))
|
||
{
|
||
drawAct();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 折りたたみ制御(Boolプロパティによるチェックあり)
|
||
/// </summary>
|
||
/// <param name="foldKey"></param>
|
||
/// <param name="boolProperty"></param>
|
||
/// <param name="title"></param>
|
||
/// <param name="drawAct"></param>
|
||
public void Foldout(
|
||
string foldKey,
|
||
SerializedProperty boolProperty,
|
||
string title = null,
|
||
System.Action drawAct = null
|
||
)
|
||
{
|
||
Foldout(
|
||
foldKey, title, drawAct,
|
||
(sw) => boolProperty.boolValue = sw,
|
||
boolProperty.boolValue
|
||
);
|
||
}
|
||
|
||
void FoldOut(string key, string title = null, System.Action drawAct = null)
|
||
{
|
||
bool foldOut1 = EditorPrefs.GetBool(key);
|
||
bool foldOut2 = EditorGUILayout.Foldout(foldOut1, title ?? key);
|
||
if (foldOut2)
|
||
{
|
||
using (new EditorGUI.IndentLevelScope())
|
||
{
|
||
drawAct?.Invoke();
|
||
}
|
||
}
|
||
if (foldOut1 != foldOut2)
|
||
{
|
||
EditorPrefs.SetBool(key, foldOut2);
|
||
}
|
||
}
|
||
|
||
void PaintButton(ClothPainter.PaintMode paintMode)
|
||
{
|
||
if (EditorApplication.isPlaying)
|
||
return;
|
||
|
||
var cloth = target as MagicaCloth;
|
||
|
||
using (new EditorGUILayout.HorizontalScope())
|
||
{
|
||
switch (paintMode)
|
||
{
|
||
case ClothPainter.PaintMode.Attribute:
|
||
GUI.backgroundColor = new Color(0.5f, 1.0f, 0.5f);
|
||
break;
|
||
case ClothPainter.PaintMode.Motion:
|
||
GUI.backgroundColor = new Color(0.0f, 1.0f, 1.0f);
|
||
break;
|
||
}
|
||
|
||
EditorGUILayout.Space();
|
||
|
||
bool edit = ClothPainter.HasEditCloth(cloth);
|
||
//var icon = edit ? EditorGUIUtility.IconContent("winbtn_win_close") : EditorGUIUtility.IconContent("d_editicon.sml");
|
||
//var icon = EditorGUIUtility.IconContent("d_Grid.PaintTool");// 良い
|
||
var icon = EditorGUIUtility.IconContent("d_editicon.sml");
|
||
if (GUILayout.Button(icon, GUILayout.Width(40)))
|
||
{
|
||
if (edit == false)
|
||
{
|
||
// 最新の編集メッシュからセレクションデータを生成する
|
||
var editMesh = ClothEditorManager.GetEditMesh(cloth);
|
||
if (editMesh != null)
|
||
{
|
||
// すでにセレクションデータが存在し、かつユーザー編集データならばコンバートする
|
||
var selectionData = GetSelectionData(cloth, editMesh);
|
||
|
||
// セレクションデータにメッシュの最大接続距離を記録する
|
||
selectionData.maxConnectionDistance = editMesh.maxVertexDistance.Value;
|
||
|
||
// ペイント開始
|
||
ClothPainter.EnterPaint(paintMode, this, cloth, editMesh, selectionData);
|
||
SceneView.RepaintAll();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ClothPainter.ExitPaint();
|
||
SceneView.RepaintAll();
|
||
}
|
||
}
|
||
EditorGUILayout.Space();
|
||
GUI.backgroundColor = Color.white;
|
||
}
|
||
EditorGUILayout.Space(10);
|
||
}
|
||
}
|
||
}
|