重新导入obi
This commit is contained in:
@@ -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]; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca0c1c4cbbd024d49b15bf3439506500
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,127 @@
|
||||
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 (editor.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 || editor.selectionStatus[index]);
|
||||
}
|
||||
|
||||
public override void OnSceneGUI(SceneView view)
|
||||
{
|
||||
if (Camera.current != null)
|
||||
{
|
||||
paintBrush.raycastTarget = meshBasedEditor.sourceMesh;
|
||||
paintBrush.DoBrush(editor.blueprint.positions);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 332bb5fc94a774291b4c4ebe50f61205
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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 (editor.selectedCount > 0)
|
||||
return "" + editor.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 < editor.selectionStatus.Length; p++)
|
||||
editor.selectionStatus[p] = false;
|
||||
}
|
||||
|
||||
foreach (int p in group.particleIndices)
|
||||
editor.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 < editor.selectionStatus.Length; p++)
|
||||
{
|
||||
if (editor.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 < editor.selectionStatus.Length; i++)
|
||||
{
|
||||
if (editor.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 < editor.selectionStatus.Length; i++)
|
||||
{
|
||||
if (editor.blueprint.IsParticleActive(i))
|
||||
editor.selectionStatus[i] = !editor.selectionStatus[i];
|
||||
}
|
||||
UpdateSelection();
|
||||
}
|
||||
|
||||
GUI.enabled = editor.selectedCount > 0;
|
||||
if (GUILayout.Button(new GUIContent(Resources.Load<Texture2D>("ClearButton"), "Clear selection"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
|
||||
{
|
||||
for (int i = 0; i < editor.selectionStatus.Length; i++)
|
||||
editor.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 editor.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 editor.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 < editor.selectionStatus.Length; i++)
|
||||
{
|
||||
if (editor.blueprint.IsParticleActive(i))
|
||||
{
|
||||
var value = property.Get(i);
|
||||
editor.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 < editor.selectionStatus.Length; i++)
|
||||
{
|
||||
if (!editor.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();
|
||||
editor.dotRadiusScale = EditorGUILayout.Slider(new GUIContent("Particle dot size"), editor.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()
|
||||
{
|
||||
editor.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 < editor.selectionStatus.Length; i++)
|
||||
{
|
||||
if (editor.blueprint.IsParticleActive(i) && editor.selectionStatus[i])
|
||||
{
|
||||
editor.selectedCount++;
|
||||
|
||||
if (editor.activeParticle >= 0)
|
||||
{
|
||||
if (!editor.currentProperty.Equals(editor.activeParticle, i))
|
||||
mixedPropertyValue = true;
|
||||
}
|
||||
else
|
||||
editor.activeParticle = i;
|
||||
}
|
||||
else if (editor.activeParticle == i)
|
||||
editor.activeParticle = -1;
|
||||
}
|
||||
|
||||
// Set initial property value:
|
||||
if (!mixedPropertyValue && editor.activeParticle >= 0)
|
||||
editor.currentProperty.GetDefaultFromIndex(editor.activeParticle);
|
||||
|
||||
editor.Repaint();
|
||||
SceneView.RepaintAll();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3940c62f9ffe4808afc4d2d70ae5e28
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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 || editor.selectionStatus[i])
|
||||
{
|
||||
float value = minPropertyValue + color[(int)textureChannel] * (maxPropertyValue - minPropertyValue);
|
||||
floatProperty.Set(i, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void ColorFromTexture(int i, Color color)
|
||||
{
|
||||
if (!selectionMask || editor.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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7727285b07aa44d6e8f65a8bc1f5d972
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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 < editor.selectionStatus.Length; ++i)
|
||||
{
|
||||
editor.selectionStatus[i] = false;
|
||||
for (int j = 0; j < tetheredGroups.Length; ++j)
|
||||
{
|
||||
if (tetheredGroups[j] && editor.blueprint.groups[j].ContainsParticle(i))
|
||||
{
|
||||
editor.selectionStatus[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
editor.blueprint.GenerateTethers(editor.selectionStatus);
|
||||
editor.Refresh();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Clear tethers",GUILayout.MinHeight(32)))
|
||||
{
|
||||
editor.blueprint.ClearTethers();
|
||||
editor.Refresh();
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6aefc9e7e74be461e93ee58f15c5a1dd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user