添加插件

This commit is contained in:
2025-11-10 00:08:26 +08:00
parent 4059c207c0
commit 76f80db694
2814 changed files with 436400 additions and 178 deletions

View File

@@ -0,0 +1,40 @@
using UnityEngine;
using UnityEditor;
namespace Obi
{
public abstract class ObiBlueprintEditorTool
{
protected ObiActorBlueprintEditor editor;
protected string m_Name;
protected Texture m_Icon;
public string name
{
get { return m_Name; }
}
public Texture icon
{
get
{
return m_Icon;
}
}
public ObiBlueprintEditorTool(ObiActorBlueprintEditor editor)
{
this.editor = editor;
}
public virtual void OnEnable(){}
public virtual void OnDisable(){}
public virtual void OnDestroy(){}
public virtual string GetHelpString() { return string.Empty; }
public abstract void OnInspectorGUI();
public virtual void OnSceneGUI(SceneView sceneView){}
public virtual bool Editable(int index) { return editor.visible[index]; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ca0c1c4cbbd024d49b15bf3439506500
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,130 @@
using UnityEngine;
using UnityEditor;
namespace Obi
{
public class ObiPaintBrushEditorTool : ObiBlueprintEditorTool
{
public ObiRaycastBrush paintBrush;
public bool selectionMask = false;
public int sourcePropertyIndex = 0; /**<index of the property to copy from*/
public ObiMeshBasedActorBlueprintEditor meshBasedEditor
{
get { return editor as ObiMeshBasedActorBlueprintEditor; }
}
public ObiPaintBrushEditorTool(ObiMeshBasedActorBlueprintEditor editor) : base(editor)
{
m_Icon = Resources.Load<Texture2D>("BrushIcon");
m_Name = "Property painting";
paintBrush = new ObiRaycastBrush(editor.sourceMesh,
() =>
{
// As RecordObject diffs with the end of the current frame,
// and this is a multi-frame operation, we need to use RegisterCompleteObjectUndo instead.
Undo.RegisterCompleteObjectUndo(editor.blueprint, "Paint particles");
},
() =>
{
editor.Refresh();
},
() =>
{
EditorUtility.SetDirty(editor.blueprint);
});
}
public override string GetHelpString()
{
return "Paint particle properties directly on the mesh. Most brushes have an alternate mode, accesed by holding 'shift' while painting.";
}
public override void OnInspectorGUI()
{
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
EditorGUILayout.Space();
// toolbar with available brush modes for the current property:
editor.currentProperty.BrushModes(paintBrush);
EditorGUILayout.Space();
EditorGUI.BeginChangeCheck();
editor.currentPropertyIndex = editor.PropertySelector(editor.currentPropertyIndex);
if (EditorGUI.EndChangeCheck())
{
editor.Refresh();
editor.currentProperty.OnSelect(paintBrush);
}
if (paintBrush.brushMode is ObiFloatCopyBrushMode)
{
EditorGUI.BeginChangeCheck();
sourcePropertyIndex = editor.PropertySelector(sourcePropertyIndex, "Copy from");
var sourceProperty = editor.GetProperty(sourcePropertyIndex) as ObiBlueprintFloatProperty;
if (EditorGUI.EndChangeCheck())
{
(paintBrush.brushMode as ObiFloatCopyBrushMode).source = sourceProperty;
}
if (sourceProperty == null)
EditorGUILayout.HelpBox("You can't copy value from this property.", MessageType.Error);
}
if (paintBrush.brushMode.needsInputValue)
editor.currentProperty.PropertyField();
paintBrush.radius = EditorGUILayout.Slider("Brush size", paintBrush.radius, 0.0001f, 0.5f);
paintBrush.innerRadius = EditorGUILayout.Slider("Brush inner size", paintBrush.innerRadius, 0, 1);
paintBrush.opacity = EditorGUILayout.Slider("Brush opacity", paintBrush.opacity, 0, 1);
paintBrush.mirror.axis = (ObiBrushMirrorSettings.MirrorAxis)EditorGUILayout.EnumPopup("Brush mirror axis", paintBrush.mirror.axis);
paintBrush.mirror.space = (ObiBrushMirrorSettings.MirrorSpace)EditorGUILayout.EnumPopup("Brush mirror space", paintBrush.mirror.space);
EditorGUI.BeginChangeCheck();
meshBasedEditor.particleCulling = (ObiMeshBasedActorBlueprintEditor.ParticleCulling)EditorGUILayout.EnumPopup("Culling", meshBasedEditor.particleCulling);
if (ObiActorBlueprintEditor.selectedCount == 0)
{
EditorGUILayout.HelpBox("Select at least one particle to use selection mask.", MessageType.Info);
selectionMask = false;
GUI.enabled = false;
}
selectionMask = EditorGUILayout.Toggle("Selection mask", selectionMask);
if (EditorGUI.EndChangeCheck())
SceneView.RepaintAll();
GUI.enabled = true;
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
editor.RenderModeSelector();
editor.currentProperty.VisualizationOptions();
EditorGUILayout.EndVertical();
}
public override bool Editable(int index)
{
return editor.visible[index] && (!selectionMask || ObiActorBlueprintEditor.selectionStatus[index]);
}
public override void OnSceneGUI(SceneView view)
{
if (Camera.current != null)
{
var blueprint = meshBasedEditor.blueprint as ObiMeshBasedActorBlueprint;
paintBrush.raycastTransform = blueprint != null ? Matrix4x4.TRS(Vector3.zero, blueprint.rotation, blueprint.scale) : Matrix4x4.identity;
paintBrush.raycastTarget = meshBasedEditor.sourceMesh;
paintBrush.DoBrush(editor.blueprint.positions);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 332bb5fc94a774291b4c4ebe50f61205
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,336 @@
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
namespace Obi
{
public class ObiParticleSelectionEditorTool : ObiBlueprintEditorTool
{
ObiScreenSpaceBrush selectionBrush;
ObiSelectBrushMode selectMode;
ObiTethersTool tethersTool;
protected ReorderableList particleGroupList;
protected bool mixedPropertyValue = false;
protected float minSelectionValue;
protected float maxSelectionValue;
public ObiParticleSelectionEditorTool(ObiActorBlueprintEditor editor) : base(editor)
{
m_Icon = Resources.Load<Texture2D>("SelectIcon");
m_Name = "Particle selection";
selectionBrush = new ObiScreenSpaceBrush(null, UpdateSelection, null);
selectMode = new ObiSelectBrushMode(new ObiBlueprintSelected(editor));
selectionBrush.brushMode = selectMode;
tethersTool = new ObiTethersTool();
InitializeGroupsList();
}
public override string GetHelpString()
{
if (ObiActorBlueprintEditor.selectedCount > 0)
return "" + ObiActorBlueprintEditor.selectedCount + " selected particles.";
else
return "No particles selected. Click and drag over particles to select them.";
}
private void InitializeGroupsList()
{
particleGroupList = new ReorderableList(editor.serializedObject,
editor.serializedObject.FindProperty("groups"),
false, true, true, true);
particleGroupList.drawHeaderCallback = (Rect rect) =>
{
EditorGUI.LabelField(rect, "Groups");
};
particleGroupList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
{
var element = particleGroupList.serializedProperty.GetArrayElementAtIndex(index);
rect.y += 4;
SerializedObject obj = new SerializedObject(element.objectReferenceValue);
ObiParticleGroup group = obj.targetObject as ObiParticleGroup;
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight),
obj.FindProperty("m_Name"), new GUIContent("Name"));
rect.y += EditorGUIUtility.singleLineHeight + 2;
if (GUI.Button(new Rect(rect.x, rect.y, rect.width * 0.5f, EditorGUIUtility.singleLineHeight), "Select", EditorStyles.miniButtonLeft))
{
if ((Event.current.modifiers & EventModifiers.Shift) == 0)
{
for (int p = 0; p < ObiActorBlueprintEditor.selectionStatus.Length; p++)
ObiActorBlueprintEditor.selectionStatus[p] = false;
}
foreach (int p in group.particleIndices)
ObiActorBlueprintEditor.selectionStatus[p] = true;
UpdateSelection();
}
if (GUI.Button(new Rect(rect.x + rect.width * 0.5f, rect.y, rect.width * 0.5f, EditorGUIUtility.singleLineHeight), "Set", EditorStyles.miniButtonRight))
{
group.particleIndices.Clear();
for (int p = 0; p < ObiActorBlueprintEditor.selectionStatus.Length; p++)
{
if (ObiActorBlueprintEditor.selectionStatus[p])
group.particleIndices.Add(p);
}
}
obj.ApplyModifiedProperties();
};
particleGroupList.elementHeight = (EditorGUIUtility.singleLineHeight + 2) * 2 + 8;
particleGroupList.onAddCallback = (ReorderableList list) =>
{
var group = editor.blueprint.AppendNewParticleGroup("new group");
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
{
if (ObiActorBlueprintEditor.selectionStatus[i])
group.particleIndices.Add(i);
}
AssetDatabase.SaveAssets();
};
particleGroupList.onRemoveCallback = (ReorderableList list) =>
{
editor.blueprint.RemoveParticleGroupAt(list.index);
};
}
private void SelectionTools()
{
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button(new GUIContent(Resources.Load<Texture2D>("InvertButton"), "Invert selection"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
{
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
{
if (editor.blueprint.IsParticleActive(i))
ObiActorBlueprintEditor.selectionStatus[i] = !ObiActorBlueprintEditor.selectionStatus[i];
}
UpdateSelection();
}
GUI.enabled = ObiActorBlueprintEditor.selectedCount > 0;
if (GUILayout.Button(new GUIContent(Resources.Load<Texture2D>("ClearButton"), "Clear selection"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
{
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
ObiActorBlueprintEditor.selectionStatus[i] = false;
UpdateSelection();
}
if (GUILayout.Button(new GUIContent(Resources.Load<Texture2D>("OptimizeButton"), "Optimize selected"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
{
Undo.RecordObject(editor.blueprint, "Optimize particles away");
editor.blueprint.RemoveSelectedParticles(ref ObiActorBlueprintEditor.selectionStatus);
editor.Refresh();
}
if (GUILayout.Button(new GUIContent(Resources.Load<Texture2D>("RemoveButton"), "Remove selected"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
{
Undo.RecordObject(editor.blueprint, "Remove particles");
editor.blueprint.RemoveSelectedParticles(ref ObiActorBlueprintEditor.selectionStatus, false);
editor.Refresh();
}
GUI.enabled = true;
if (GUILayout.Button(new GUIContent(Resources.Load<Texture2D>("RestoreButton"), "Restore removed particles"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
{
Undo.RecordObject(editor.blueprint, "Restore removed particles");
editor.blueprint.RestoreRemovedParticles();
editor.Refresh();
}
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Property-based selection", EditorStyles.boldLabel);
var property = editor.currentProperty as ObiBlueprintFloatProperty;
if (property != null)
{
if (!Mathf.Approximately(property.minVisualizationValue,property.maxVisualizationValue))
{
EditorGUILayout.HelpBox("Drag the slider to select based on " + property.name + ". You can choose a different property in the \"Property\" dropdown below.", MessageType.None);
minSelectionValue = Mathf.Max(minSelectionValue, property.minVisualizationValue);
maxSelectionValue = Mathf.Min(maxSelectionValue, property.maxVisualizationValue);
maxSelectionValue = Mathf.Max(maxSelectionValue, minSelectionValue);
EditorGUI.BeginChangeCheck();
EditorGUILayout.MinMaxSlider("Select by " + property.name, ref minSelectionValue, ref maxSelectionValue, property.minVisualizationValue, property.maxVisualizationValue);
minSelectionValue = EditorGUILayout.FloatField("Minimum " + property.name, minSelectionValue);
maxSelectionValue = EditorGUILayout.FloatField("Maximum " + property.name, maxSelectionValue);
if (EditorGUI.EndChangeCheck())
{
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
{
if (editor.blueprint.IsParticleActive(i))
{
var value = property.Get(i);
ObiActorBlueprintEditor.selectionStatus[i] = value >= minSelectionValue && value <= maxSelectionValue;
}
}
UpdateSelection();
}
}
else
{
EditorGUILayout.HelpBox("All particles have the same " + property.name + " value.", MessageType.Info);
}
}
else
{
EditorGUILayout.HelpBox("Property-based selection only works with scalar properties.",MessageType.Info);
}
}
public override void OnInspectorGUI()
{
// Selection tools:
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
EditorGUILayout.Space();
selectionBrush.radius = EditorGUILayout.Slider("Brush size", selectionBrush.radius, 5, 200);
if (editor is ObiMeshBasedActorBlueprintEditor)
{
EditorGUI.BeginChangeCheck();
(editor as ObiMeshBasedActorBlueprintEditor).particleCulling = (ObiMeshBasedActorBlueprintEditor.ParticleCulling)EditorGUILayout.EnumPopup("Culling", (editor as ObiMeshBasedActorBlueprintEditor).particleCulling);
if (EditorGUI.EndChangeCheck())
SceneView.RepaintAll();
}
EditorGUILayout.Space();
SelectionTools();
EditorGUILayout.EndVertical();
// Properties:
EditorGUILayout.Space();
GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Properties", EditorStyles.boldLabel);
EditorGUILayout.HelpBox("Select a property to view and edit. Currently editing " + editor.currentProperty.name+".", MessageType.None);
EditorGUI.BeginChangeCheck();
editor.currentPropertyIndex = editor.PropertySelector(editor.currentPropertyIndex);
if (EditorGUI.EndChangeCheck())
{
editor.Refresh();
UpdateSelection();
}
// Property value:
EditorGUI.showMixedValue = mixedPropertyValue;
EditorGUI.BeginChangeCheck();
editor.currentProperty.PropertyField();
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(editor.blueprint, "Set particle property");
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
{
if (!ObiActorBlueprintEditor.selectionStatus[i]) continue;
editor.currentProperty.SetDefaultToIndex(i);
}
editor.Refresh();
}
EditorGUI.showMixedValue = false;
EditorGUILayout.EndVertical();
// Particle groups:
EditorGUILayout.Space();
GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Particle groups", EditorStyles.boldLabel);
particleGroupList.DoLayoutList();
EditorGUILayout.EndVertical();
if (editor.blueprint.usesTethers)
{
EditorGUILayout.Space();
GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
EditorGUILayout.Space();
tethersTool.DoTethers(editor);
EditorGUILayout.EndVertical();
}
EditorGUILayout.Space();
GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
editor.RenderModeSelector();
ObiActorBlueprintEditor.dotRadiusScale = EditorGUILayout.Slider(new GUIContent("Particle dot size"), ObiActorBlueprintEditor.dotRadiusScale, 0, 5);
editor.currentProperty.VisualizationOptions();
EditorGUILayout.EndVertical();
}
public override void OnSceneGUI(SceneView sceneView)
{
if (Camera.current != null)
selectionBrush.DoBrush(editor.blueprint.positions);
}
protected void UpdateSelection()
{
ObiActorBlueprintEditor.selectedCount = 0;
mixedPropertyValue = false;
// Find out how many selected particles we have, and whether they all have the same value for the current property:
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
{
if (editor.blueprint.IsParticleActive(i) && ObiActorBlueprintEditor.selectionStatus[i])
{
ObiActorBlueprintEditor.selectedCount++;
if (ObiActorBlueprintEditor.activeParticle >= 0)
{
if (!editor.currentProperty.Equals(ObiActorBlueprintEditor.activeParticle, i))
mixedPropertyValue = true;
}
else
ObiActorBlueprintEditor.activeParticle = i;
}
else if (ObiActorBlueprintEditor.activeParticle == i)
ObiActorBlueprintEditor.activeParticle = -1;
}
// Set initial property value:
if (!mixedPropertyValue && ObiActorBlueprintEditor.activeParticle >= 0)
editor.currentProperty.GetDefaultFromIndex(ObiActorBlueprintEditor.activeParticle);
editor.Repaint();
SceneView.RepaintAll();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b3940c62f9ffe4808afc4d2d70ae5e28
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,166 @@
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Collections;
using System;
namespace Obi
{
public class ObiPropertyTextureEditorTool : ObiBlueprintEditorTool
{
public enum TextureChannel
{
Red = 0,
Green = 1,
Blue = 2,
Alpha = 3,
}
protected bool selectionMask = false;
protected bool import = true;
protected bool export = true;
protected float minPropertyValue = 0;
protected float maxPropertyValue = 10;
protected int exportWidth = 512;
protected int exportHeight = 512;
protected int padding = 64;
protected Texture2D propertyTexture;
protected TextureChannel textureChannel;
protected ObiBlueprintFloatProperty floatProperty;
protected ObiBlueprintColorProperty colorProperty;
protected Action<int, Color> textureReadCallback;
public ObiMeshBasedActorBlueprintEditor meshBasedEditor
{
get { return editor as ObiMeshBasedActorBlueprintEditor; }
}
public ObiPropertyTextureEditorTool(ObiMeshBasedActorBlueprintEditor editor) : base(editor)
{
m_Icon = Resources.Load<Texture2D>("TextureIcon");
m_Name = "Texture import/export";
}
public override string GetHelpString()
{
return "Import/export particle properties to textures. Assumes that your mesh has non-overlapping UVs.";
}
private void FloatFromTexture(int i, Color color)
{
if (!selectionMask || ObiActorBlueprintEditor.selectionStatus[i])
{
float value = minPropertyValue + color[(int)textureChannel] * (maxPropertyValue - minPropertyValue);
floatProperty.Set(i, value);
}
}
private void ColorFromTexture(int i, Color color)
{
if (!selectionMask || ObiActorBlueprintEditor.selectionStatus[i])
colorProperty.Set(i, color);
}
public override void OnInspectorGUI()
{
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
EditorGUILayout.Space();
EditorGUI.BeginChangeCheck();
editor.currentPropertyIndex = editor.PropertySelector(editor.currentPropertyIndex);
if (EditorGUI.EndChangeCheck())
editor.Refresh();
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
import = EditorGUILayout.BeginFoldoutHeaderGroup(import, "Import texture");
if (import)
{
propertyTexture = (Texture2D)EditorGUILayout.ObjectField("Source", propertyTexture, typeof(Texture2D), false);
floatProperty = editor.currentProperty as ObiBlueprintFloatProperty;
colorProperty = editor.currentProperty as ObiBlueprintColorProperty;
if (floatProperty != null)
{
textureReadCallback = FloatFromTexture;
textureChannel = (TextureChannel)EditorGUILayout.EnumPopup("Source channel", textureChannel);
minPropertyValue = EditorGUILayout.FloatField("Min value", minPropertyValue);
maxPropertyValue = EditorGUILayout.FloatField("Max value", maxPropertyValue);
}
else if (colorProperty != null)
{
textureReadCallback = ColorFromTexture;
}
if (GUILayout.Button("Import"))
{
Undo.RecordObject(editor.blueprint, "Import particle property");
if (!meshBasedEditor.ReadParticlePropertyFromTexture(propertyTexture, textureReadCallback))
{
EditorUtility.DisplayDialog("Invalid texture", "The texture is either null or not readable.", "Ok");
}
// force automatic range calculation for floating point properties.
if (floatProperty != null)
floatProperty.autoRange = true;
editor.Refresh();
}
}
EditorGUILayout.EndFoldoutHeaderGroup();
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
export = EditorGUILayout.BeginFoldoutHeaderGroup(export, "Export texture");
if (export)
{
exportWidth = EditorGUILayout.IntField("Texture width", exportWidth);
exportHeight = EditorGUILayout.IntField("Texture height", exportHeight);
padding = EditorGUILayout.IntField("Padding", padding);
if (GUILayout.Button("Export"))
{
var path = EditorUtility.SaveFilePanel("Save texture as PNG",
"",
"property.png",
"png");
if (path.Length > 0)
{
// force automatic range calculation for floating point properties.
if (floatProperty != null)
floatProperty.autoRange = true;
editor.Refresh();
if (!meshBasedEditor.WriteParticlePropertyToTexture(path, exportWidth, exportHeight, padding))
{
EditorUtility.DisplayDialog("Invalid path", "Could not write a texture to that location.", "Ok");
}
}
}
}
EditorGUILayout.EndFoldoutHeaderGroup();
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
editor.RenderModeSelector();
EditorGUILayout.EndVertical();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7727285b07aa44d6e8f65a8bc1f5d972
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,86 @@
using UnityEngine;
using UnityEditor;
using System;
namespace Obi
{
public class ObiTethersTool
{
protected Rect tetherDropdownRect;
protected bool[] tetheredGroups = new bool[0];
// the GenericMenu.MenuFunction2 event handler for when a menu item is selected
void OnTetherGroupSelected(object index)
{
int i = (int)index;
tetheredGroups[i] = !tetheredGroups[i];
}
public void DoTethers(ObiActorBlueprintEditor editor)
{
EditorGUILayout.LabelField("Tethers", EditorStyles.boldLabel);
var tethers = editor.blueprint.GetConstraintsByType(Oni.ConstraintType.Tether);
int tetherCount = 0;
if (tethers != null)
tetherCount = tethers.GetConstraintCount();
if (tetherCount > 0)
EditorGUILayout.LabelField("" + tetherCount + " tether constraints.", EditorStyles.helpBox);
else
EditorGUILayout.LabelField("No tether constraints. Select at least one particle group in the dropdown, then click 'Generate Tethers'.", EditorStyles.helpBox);
Array.Resize(ref tetheredGroups, editor.blueprint.groups.Count);
// display the GenericMenu when pressing a button
if (GUILayout.Button("Tethered groups", EditorStyles.popup))
{
// create the menu and add items to it
GenericMenu menu = new GenericMenu();
// forward slashes nest menu items under submenus
for (int i = 0; i < editor.blueprint.groups.Count; ++i)
{
menu.AddItem(new GUIContent(editor.blueprint.groups[i].name), tetheredGroups[i], OnTetherGroupSelected, i);
}
// display the menu
menu.DropDown(tetherDropdownRect);
}
if (Event.current.type == EventType.Repaint)
tetherDropdownRect = GUILayoutUtility.GetLastRect();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Generate tethers",GUILayout.MinHeight(32)))
{
// Select all particles in the tethered groups:
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; ++i)
{
ObiActorBlueprintEditor.selectionStatus[i] = false;
for (int j = 0; j < tetheredGroups.Length; ++j)
{
if (tetheredGroups[j] && editor.blueprint.groups[j].ContainsParticle(i))
{
ObiActorBlueprintEditor.selectionStatus[i] = true;
break;
}
}
}
editor.blueprint.GenerateTethers(ObiActorBlueprintEditor.selectionStatus);
editor.Refresh();
}
if (GUILayout.Button("Clear tethers",GUILayout.MinHeight(32)))
{
editor.blueprint.ClearTethers();
editor.Refresh();
}
EditorGUILayout.EndHorizontal();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6aefc9e7e74be461e93ee58f15c5a1dd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: