1853 lines
76 KiB
C#
1853 lines
76 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
// Engine
|
|
using UnityEngine;
|
|
// Editor
|
|
using UnityEditor;
|
|
using UnityEditorInternal;
|
|
// Procedural Worlds
|
|
using PWCommon5;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace GeNa.Core
|
|
{
|
|
[CustomEditor(typeof(Spline))]
|
|
public class SplineEditor : GeNaEditor
|
|
{
|
|
#region Static
|
|
|
|
// Colors
|
|
private static Color SPLINE_CURVE_COLOR = new Color(0.8f, 0.8f, 0.8f);
|
|
private static Color SPLINE_SELECTED_CURVE_COLOR = Color.green; //new Color(0.8f, 0.8f, 0.8f);
|
|
private static Color NODE_COLOR = new Color(0.6f, 0.6f, 0.6f);
|
|
private static Color SELECTED_NODE_COLOR = new Color(0.55f, 0.77f, 1f);
|
|
private static Color FIRST_NODE_COLOR = new Color(0.0f, 0.8f, 0.0f);
|
|
private static Color LAST_NODE_COLOR = new Color(0.0f, 0.0f, 0.8f);
|
|
private static Color EXTRUSION_CURVE_COLOR = new Color(0.8f, 0.8f, 0.8f);
|
|
private static Color DIRECTION_BUTTON_COLOR = Color.blue; //Color.red;
|
|
private static Color TANGENT_LINE_COLOR = Color.blue;
|
|
|
|
private static Color UP_BUTTON_COLOR = Color.green;
|
|
|
|
// Panels
|
|
private static bool m_showQuickStart = true;
|
|
private static bool m_showOverview = true;
|
|
private static bool m_showPathFinding = false;
|
|
private static bool m_showExtensions = true;
|
|
private static bool m_showMetrics = false;
|
|
private static bool m_showAdvancedSettings = false;
|
|
|
|
#endregion
|
|
|
|
#region Definitions
|
|
|
|
public enum SelectionType
|
|
{
|
|
Node,
|
|
StartTangent,
|
|
EndTangent,
|
|
Up,
|
|
Scale
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Variables
|
|
|
|
#region Static
|
|
|
|
private static int SPLINE_QUAD_SIZE = 25;
|
|
private static int SPLINE_STYLE_QUAD_SIZE = 15;
|
|
private static int EXTRUSION_QUAD_SIZE = 25;
|
|
private static bool showUpVector = false;
|
|
|
|
#endregion
|
|
|
|
#region GUI
|
|
|
|
private ReorderableList m_extensionReorderable;
|
|
private GeNaSplineExtension m_selectedExtension;
|
|
private ExtensionEntry m_selectedExtensionEntry;
|
|
private GeNaSplineExtensionEditor m_selectedExtensionEditor;
|
|
private Tool m_previousTool;
|
|
|
|
// Switch to drop custom ground level for ingestion
|
|
private bool m_dropGround = false;
|
|
private bool m_splineDirty = false;
|
|
|
|
#endregion
|
|
|
|
#region Spline
|
|
|
|
// Core
|
|
private GeNaSpline m_spline;
|
|
private SplineSettings m_settings;
|
|
private List<GeNaNode> m_selectedNodes = new List<GeNaNode>();
|
|
private GeNaCurve _selectedGeNaCurve;
|
|
private int m_selectedVertex = -1;
|
|
private SelectionType m_selectionType;
|
|
private float m_mouseDragThreshold = .1f;
|
|
private bool m_splineModified = false;
|
|
private Vector2 m_mouseClickPoint = Vector2.zero;
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Node Selection Undo/Redo
|
|
|
|
private bool IsDifferent(List<Vector3> right, List<Vector3> left)
|
|
{
|
|
if (right == null && left == null)
|
|
return false;
|
|
if (right == null || left == null)
|
|
return true;
|
|
if (right.Count != left.Count)
|
|
return true;
|
|
int count = right.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
Vector3 a = right[i];
|
|
Vector3 b = left[i];
|
|
if (a != b)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
#region Unity
|
|
|
|
private void CheckHierarchyChanged()
|
|
{
|
|
}
|
|
|
|
private void DrawCurve(GeNaCurve geNaCurve, Color color)
|
|
{
|
|
// Default Bezier
|
|
Handles.DrawBezier(geNaCurve.P0, geNaCurve.P3, geNaCurve.P1, geNaCurve.P2, color, null, 2);
|
|
}
|
|
|
|
private void OnUndoProcessed()
|
|
{
|
|
m_spline = target as GeNaSpline;
|
|
m_selectedNodes.Clear();
|
|
DeselectAllExtensionEntries();
|
|
}
|
|
|
|
protected void OnEnable()
|
|
{
|
|
Undo.undoRedoPerformed -= OnUndoProcessed;
|
|
Undo.undoRedoPerformed += OnUndoProcessed;
|
|
if (m_editorUtils == null)
|
|
// If there isn't any Editor Utils Initialized
|
|
m_editorUtils = PWApp.GetEditorUtils(this, null, null, null);
|
|
|
|
#region Initialization
|
|
|
|
// Get target Spline
|
|
m_spline = target as GeNaSpline;
|
|
m_splineDirty = true;
|
|
// if (m_spline != null)
|
|
// {
|
|
// ReconnectSpline();
|
|
// }
|
|
m_settings = m_spline.Settings;
|
|
CheckHierarchyChanged();
|
|
// Subscribe Refresh Curves to Undo
|
|
//TODO : Manny : Re-register Undo!
|
|
//Undo.undoRedoPerformed -= m_spline.RefreshCurves;
|
|
//Undo.undoRedoPerformed += m_spline.RefreshCurves;
|
|
//Hide its m_transform
|
|
// Create the Extension List
|
|
CreateExtensionList();
|
|
|
|
#endregion
|
|
|
|
m_spline.OnSubscribe();
|
|
Tools.hidden = true;
|
|
}
|
|
|
|
protected void OnDisable()
|
|
{
|
|
m_splineDirty = false;
|
|
m_selectedNodes.Clear();
|
|
m_spline.OnUnSubscribe();
|
|
Tools.hidden = false;
|
|
GeNaEvents.Destroy(GeNaSpawnerInternal.TempGameObject);
|
|
DeselectAllExtensionEntries();
|
|
}
|
|
|
|
public override void OnSceneGUI()
|
|
{
|
|
if (m_splineDirty)
|
|
{
|
|
SelectExtensionEntry(m_spline.SelectedExtensionIndex);
|
|
m_splineDirty = false;
|
|
}
|
|
|
|
m_spline.OnSceneGUI();
|
|
Initialize();
|
|
|
|
#region Events
|
|
|
|
Event e = Event.current;
|
|
int controlID = GUIUtility.GetControlID(FocusType.Passive);
|
|
bool mouseUp = false;
|
|
switch (e.type)
|
|
{
|
|
case EventType.MouseDown:
|
|
{
|
|
// Spline
|
|
//TODO : Manny : Re-register Undo!
|
|
//Undo.RegisterCompleteObjectUndo(m_spline, "change spline or extrusion topography");
|
|
m_mouseClickPoint = e.mousePosition;
|
|
break;
|
|
}
|
|
case EventType.MouseUp:
|
|
{
|
|
mouseUp = true;
|
|
break;
|
|
}
|
|
case EventType.KeyDown:
|
|
// If the Delete Key is Pressed
|
|
if (e.keyCode == KeyCode.Delete)
|
|
{
|
|
//TODO : Manny : Re-register Undo!
|
|
//Undo.RegisterCompleteObjectUndo(m_spline, "delete");
|
|
// Check if a vertex is selected
|
|
if (m_selectedVertex >= 0)
|
|
{
|
|
e.Use();
|
|
break;
|
|
}
|
|
|
|
// Check if a Node is Selected
|
|
if (m_selectedNodes.Count > 0)
|
|
{
|
|
List<GeNaNode> validNodes = new List<GeNaNode>();
|
|
foreach (GeNaNode node in m_selectedNodes)
|
|
{
|
|
if (m_spline.Nodes.Contains(node))
|
|
{
|
|
validNodes.Add(node);
|
|
}
|
|
}
|
|
|
|
if (validNodes.Count > 0)
|
|
{
|
|
List<GeNaNode> selected = m_selectedNodes;
|
|
m_spline.RecordUndoSnapshot("Remove Node", () =>
|
|
{
|
|
m_spline.RemoveNodes(validNodes);
|
|
m_selectedNodes.Clear();
|
|
m_selectedNodes.Add(m_spline.Nodes.Count > 0 ? m_spline.Nodes.Last() : null);
|
|
});
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
e.Use();
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If the F Key is Pressed
|
|
if (e.keyCode == KeyCode.F)
|
|
{
|
|
if (m_selectedNodes.Count > 0)
|
|
{
|
|
Vector3 averagePos = Vector3.zero;
|
|
foreach (GeNaNode node in m_selectedNodes)
|
|
{
|
|
averagePos += node.Position;
|
|
}
|
|
|
|
averagePos /= (float)m_selectedNodes.Count;
|
|
Vector3 nodePosition = averagePos;
|
|
Vector3 size = Vector3.one * 5f;
|
|
FocusPosition(nodePosition, size);
|
|
e.Use();
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Check Raw Events
|
|
switch (e.rawType)
|
|
{
|
|
case EventType.MouseUp:
|
|
{
|
|
// RecordSelectedNodeChanges("Node Change");
|
|
mouseUp = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Tools
|
|
|
|
Tool currentTool = Tools.current;
|
|
if (m_previousTool != currentTool)
|
|
{
|
|
switch (currentTool)
|
|
{
|
|
case Tool.Scale:
|
|
m_selectionType = SelectionType.Scale;
|
|
break;
|
|
case Tool.Move:
|
|
m_selectionType = SelectionType.Node;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
List<GeNaCurve> connectedCurves = new List<GeNaCurve>();
|
|
if (m_selectedNodes.Count > 0)
|
|
{
|
|
connectedCurves = m_spline.GetConnectedCurves(m_selectedNodes);
|
|
}
|
|
|
|
// Draw a bezier curve for each curve in the m_spline
|
|
foreach (GeNaCurve curve in m_spline.Curves)
|
|
{
|
|
Color color = SPLINE_CURVE_COLOR;
|
|
if (connectedCurves.Contains(curve))
|
|
color = SPLINE_SELECTED_CURVE_COLOR;
|
|
DrawCurve(curve, color);
|
|
}
|
|
|
|
// At least one node?
|
|
if (m_spline.Nodes.Count > 0)
|
|
{
|
|
// Node Selected?
|
|
if (m_selectedNodes.Count > 0)
|
|
{
|
|
Quaternion rotation = Quaternion.identity;
|
|
// If Tools are set to Local AND Spline Smoothing is NOT enabled
|
|
// Draw the nodeSelection handles
|
|
switch (m_selectionType)
|
|
{
|
|
case SelectionType.Node:
|
|
{
|
|
Vector3 averagePos = Vector3.zero;
|
|
foreach (GeNaNode node in m_selectedNodes)
|
|
{
|
|
averagePos += node.Position;
|
|
}
|
|
|
|
averagePos /= (float)m_selectedNodes.Count;
|
|
Vector3 point = averagePos;
|
|
Vector3 result = Handles.PositionHandle(point, rotation);
|
|
// place a handle on the node and manage m_position change
|
|
if (result != point)
|
|
{
|
|
Action postAction = () =>
|
|
{
|
|
foreach (GeNaNode node in m_selectedNodes)
|
|
{
|
|
Vector3 offset = node.Position - averagePos;
|
|
node.Position = result + offset;
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
};
|
|
if (m_splineModified == false)
|
|
m_spline.RecordUndoSnapshot("Nodes Moved", postAction);
|
|
else
|
|
postAction?.Invoke();
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SelectionType.StartTangent:
|
|
{
|
|
Vector3 point = _selectedGeNaCurve.P1;
|
|
Vector3 result = Handles.PositionHandle(point, rotation);
|
|
if (result != point)
|
|
{
|
|
if (m_splineModified == false)
|
|
m_spline.RecordUndoSnapshot("Start Tangent Moved",
|
|
() => { _selectedGeNaCurve.P1 = result; });
|
|
else
|
|
_selectedGeNaCurve.P1 = result;
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SelectionType.EndTangent:
|
|
{
|
|
Vector3 point = _selectedGeNaCurve.P2;
|
|
Vector3 result = Handles.PositionHandle(point, rotation);
|
|
if (result != point)
|
|
{
|
|
if (m_splineModified == false)
|
|
m_spline.RecordUndoSnapshot("End Tangent Moved",
|
|
() => { _selectedGeNaCurve.P2 = result; });
|
|
else
|
|
_selectedGeNaCurve.P2 = result;
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SelectionType.Up:
|
|
{
|
|
foreach (GeNaNode node in m_selectedNodes)
|
|
{
|
|
Vector3 point = node.Position + node.Up * 8f;
|
|
Vector3 result = Handles.PositionHandle(point, rotation);
|
|
if (result != point)
|
|
{
|
|
if (m_splineModified == false)
|
|
m_spline.RecordUndoSnapshot("Up Moved",
|
|
() => { node.Up = (result - node.Position).normalized; });
|
|
else
|
|
node.Up = (result - node.Position).normalized;
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SelectionType.Scale:
|
|
{
|
|
foreach (GeNaNode node in m_selectedNodes)
|
|
{
|
|
if (e.isMouse && e.type == EventType.MouseDown)
|
|
node.Scale = Vector3.one;
|
|
Vector3 point = node.Position;
|
|
Vector3 result = Vector3.one;
|
|
float size = HandleUtility.GetHandleSize(point);
|
|
EditorGUI.BeginChangeCheck();
|
|
{
|
|
result = Handles.ScaleHandle(node.Scale, point, rotation, size);
|
|
}
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
if (m_splineModified == false)
|
|
m_spline.RecordUndoSnapshot("Node Scale Changed",
|
|
() => { node.Scale = result; });
|
|
else
|
|
node.Scale = result;
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Handles.BeginGUI();
|
|
if (m_selectedNodes.Count == 1)
|
|
{
|
|
List<GeNaCurve> curves = m_spline.GetConnectedCurves(m_selectedNodes);
|
|
foreach (GeNaCurve curve in curves)
|
|
if (!DrawCurveHandles(curve))
|
|
break;
|
|
}
|
|
|
|
foreach (GeNaNode node in m_spline.Nodes)
|
|
{
|
|
Vector3 pos = node.Position;
|
|
// First we check if at least one thing is in the camera field of view
|
|
if (!GeNaEditorUtility.IsOnScreen(pos))
|
|
// Continue to next Element
|
|
continue;
|
|
if (!DrawNodeHandles(node))
|
|
break;
|
|
}
|
|
|
|
Handles.EndGUI();
|
|
|
|
#region Add Splines
|
|
|
|
bool raycastHit = GetRayCast(out RaycastHit hitInfo);
|
|
bool selectAll = false;
|
|
if (m_spline.Nodes.Count > 1)
|
|
{
|
|
if (e.control)
|
|
{
|
|
switch (e.type)
|
|
{
|
|
case EventType.KeyDown:
|
|
if (e.keyCode == KeyCode.A)
|
|
{
|
|
selectAll = true;
|
|
e.Use();
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (selectAll)
|
|
{
|
|
m_selectedNodes.Clear();
|
|
m_selectedNodes.AddRange(m_spline.Nodes);
|
|
}
|
|
else
|
|
{
|
|
//Check for the ctrl + left mouse button event - spawn (ignore if Shift is pressed)
|
|
if (e.control && e.isMouse && !e.shift)
|
|
{
|
|
// Left button
|
|
if (e.button == 0)
|
|
{
|
|
switch (e.type)
|
|
{
|
|
case EventType.MouseDown:
|
|
GUIUtility.hotControl = 0;
|
|
if (raycastHit)
|
|
{
|
|
// Cache variable for action
|
|
m_spline.RecordUndoSnapshot("Add Node(s)", () =>
|
|
{
|
|
GeNaNode newNode = m_spline.CreateNewNode(hitInfo.point);
|
|
if (m_spline.AddNode(m_selectedNodes, newNode))
|
|
{
|
|
m_selectedNodes.Clear();
|
|
m_selectedNodes.Add(newNode);
|
|
}
|
|
});
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
|
|
e.Use();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_splineModified)
|
|
{
|
|
if (mouseUp)
|
|
{
|
|
float distance = Vector2.SqrMagnitude(e.mousePosition - m_mouseClickPoint);
|
|
if (distance > m_mouseDragThreshold)
|
|
{
|
|
m_spline.OnSplineEndChanged();
|
|
}
|
|
|
|
m_splineModified = false;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
if (m_selectedExtensionEditor != null)
|
|
m_selectedExtensionEditor.OnSceneGUI();
|
|
if (m_settings.Advanced.DebuggingEnabled)
|
|
DrawDebug();
|
|
if (m_settings.Metrics.ShowMetrics)
|
|
DrawMetrics();
|
|
|
|
#region Footer
|
|
|
|
if (m_spline.IsDirty)
|
|
{
|
|
EditorUtility.SetDirty(m_spline);
|
|
m_spline.IsDirty = false;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
private void ReconnectSpline()
|
|
{
|
|
foreach (ExtensionEntry entry in m_spline.Extensions)
|
|
{
|
|
if (entry == null)
|
|
continue;
|
|
GeNaSplineExtension extension = entry.Extension;
|
|
if (extension == null)
|
|
continue;
|
|
if (extension.Spline == null)
|
|
{
|
|
// extension.SetSpline(m_spline);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draws a string at the specified world position.
|
|
/// </summary>
|
|
/// <param name="text">The text to draw.</param>
|
|
/// <param name="worldPosition">The world position at which to draw the text.</param>
|
|
/// <param name="screenOffset">The screen offset from the world position to adjust the text position.</param>
|
|
/// <returns>Returns true if the text was successfully drawn, false otherwise.</returns>
|
|
private static bool DrawStringAtPosition(string text, Vector3 worldPosition, Vector2 screenOffset = default)
|
|
{
|
|
Rect rect = GeNaEditorUtility.GetGUILabelWorldRect(text, worldPosition, screenOffset,
|
|
EditorStyles.numberField);
|
|
if (GeNaEditorUtility.IsMouseOverRect(rect))
|
|
return false;
|
|
GeNaEditorUtility.DrawString(text, worldPosition, screenOffset, EditorStyles.numberField);
|
|
return true;
|
|
}
|
|
|
|
private void DrawDebug()
|
|
{
|
|
List<GeNaNode> nodes = m_spline.Nodes;
|
|
foreach (GeNaNode node in nodes)
|
|
{
|
|
string title = $"Node ID: {node.ID}";
|
|
string text = title;
|
|
Vector3 worldPos = node.Position;
|
|
Vector2 screenOffset = new Vector2(10f, -100f);
|
|
Rect rect = GeNaEditorUtility.GetGUILabelWorldRect(text, worldPos, screenOffset);
|
|
|
|
GeNaEditorUtility.DrawDottedLineToScreenPoint(worldPos, rect, Color.white, 5f);
|
|
|
|
if (!GeNaEditorUtility.IsMouseOverRect(rect))
|
|
{
|
|
GeNaEditorUtility.DrawString(text, worldPos, screenOffset);
|
|
}
|
|
else
|
|
{
|
|
// Mouse is hovering over text
|
|
text = $"{title}\n" +
|
|
$"x: {worldPos.x:F}\n" +
|
|
$"y: {worldPos.y:F}\n" +
|
|
$"z: {worldPos.z:F}";
|
|
GeNaEditorUtility.DrawString(text, worldPos, screenOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawDottedLineToNodes(List<GeNaNode> nodes, Color color)
|
|
{
|
|
Color oldColor = Handles.color;
|
|
Handles.color = color;
|
|
for (int i = 0; i < nodes.Count - 1; i++)
|
|
{
|
|
GeNaNode a = nodes[i];
|
|
GeNaNode b = nodes[i + 1];
|
|
Handles.DrawDottedLine(a.Position, b.Position, 5f);
|
|
}
|
|
|
|
Handles.color = oldColor;
|
|
}
|
|
|
|
private List<GeNaNode> GetAdjacentNodesForMetrics()
|
|
{
|
|
List<GeNaNode> selectedNodes = new List<GeNaNode>(m_selectedNodes);
|
|
if (selectedNodes.Count == 1)
|
|
{
|
|
Dictionary<uint, GeNaNode> uniqueNodes = new Dictionary<uint, GeNaNode>();
|
|
foreach (GeNaNode node in m_selectedNodes)
|
|
{
|
|
List<GeNaCurve> connectedCurves = m_spline.GetConnectedCurves(node);
|
|
foreach (GeNaCurve curve in connectedCurves)
|
|
{
|
|
GeNaNode startNode = curve.StartNode;
|
|
GeNaNode endNode = curve.EndNode;
|
|
uniqueNodes[startNode.ID] = startNode;
|
|
uniqueNodes[endNode.ID] = endNode;
|
|
}
|
|
}
|
|
|
|
if (uniqueNodes.Count > 0)
|
|
selectedNodes = uniqueNodes.Values.ToList();
|
|
}
|
|
|
|
return selectedNodes;
|
|
}
|
|
|
|
private void DrawAverageMetrics(List<GeNaPointMetrics> nodeMetrics)
|
|
{
|
|
foreach (GeNaPointMetrics metric in nodeMetrics)
|
|
{
|
|
Vector3 worldPos = metric.worldPosition;
|
|
Vector2 screenOffset = new Vector2(10f, -100f);
|
|
Rect rect = GeNaEditorUtility.GetGUILabelWorldRect(metric.title, worldPos, screenOffset);
|
|
GeNaEditorUtility.DrawDottedLineToScreenPoint(worldPos, rect, Color.cyan, 5f);
|
|
// if (!GeNaEditorUtility.IsMouseOverRect(rect))
|
|
// {
|
|
// GeNaEditorUtility.DrawString(text, worldPos, screenOffset);
|
|
// }
|
|
// else
|
|
// {
|
|
GeNaEditorUtility.DrawString(metric.ToBrief(), worldPos, screenOffset);
|
|
// }
|
|
}
|
|
}
|
|
|
|
private void DrawNodeMetric(GeNaPointMetrics metric, Vector2? screenOffset = null)
|
|
{
|
|
Vector2 offset = screenOffset ?? new Vector2(10f, -100f);
|
|
Vector3 worldPos = metric.worldPosition;
|
|
Rect rect = GeNaEditorUtility.GetGUILabelWorldRect(metric.title, worldPos, offset);
|
|
GeNaEditorUtility.DrawDottedLineToScreenPoint(worldPos, rect, Color.white, 5f);
|
|
GeNaEditorUtility.DrawString(metric.ToPositionBrief(), worldPos, offset);
|
|
}
|
|
|
|
private void DrawNodeMetrics(List<GeNaPointMetrics> nodeMetrics)
|
|
{
|
|
foreach (GeNaPointMetrics metric in nodeMetrics)
|
|
{
|
|
DrawNodeMetric(metric);
|
|
}
|
|
}
|
|
|
|
private void DrawCurveMetric(GeNaPointMetrics metric, Vector2? screenOffset = null, Color? lineColor = null)
|
|
{
|
|
Vector3 worldPos = metric.worldPosition;
|
|
Vector2 offset = screenOffset ?? new Vector2(15f, 50f);
|
|
Rect rect = GeNaEditorUtility.GetGUILabelWorldRect(metric.title, worldPos, offset);
|
|
GeNaEditorUtility.DrawDottedLineToScreenPoint(worldPos, rect, lineColor ?? Color.white, 5f);
|
|
GeNaEditorUtility.DrawString(metric.ToCurveBrief(), worldPos, offset);
|
|
}
|
|
|
|
private void DrawTotalMetric(GeNaPointMetrics metric, Vector2? screenOffset = null)
|
|
{
|
|
Vector3 worldPos = metric.worldPosition;
|
|
Vector2 offset = screenOffset ?? new Vector2(15f, -100f);
|
|
Rect rect = GeNaEditorUtility.GetGUILabelWorldRect(metric.title, worldPos, offset);
|
|
GeNaEditorUtility.DrawDottedLineToScreenPoint(worldPos, rect, Color.white, 5f);
|
|
GeNaEditorUtility.DrawString(metric.ToBrief(), worldPos, offset);
|
|
}
|
|
|
|
private void DrawMeasureSpline(List<GeNaNode> selectedNodes)
|
|
{
|
|
SplineSettings settings = m_spline.Settings;
|
|
SplineSettings.MetricsSettings metricsSettings = settings.Metrics;
|
|
if (metricsSettings.MeasureSpline)
|
|
{
|
|
for (int nodeIndex = 0; nodeIndex < selectedNodes.Count - 1; nodeIndex++)
|
|
{
|
|
GeNaNode nodeA = selectedNodes[nodeIndex];
|
|
GeNaNode nodeB = selectedNodes[nodeIndex + 1];
|
|
var foundPath = m_spline.FindPath(nodeA, nodeB);
|
|
if (foundPath.Count > 0)
|
|
{
|
|
foreach (GeNaCurve curve in foundPath)
|
|
{
|
|
DrawCurve(curve, Color.red);
|
|
}
|
|
|
|
SplineSettings.MetricsSettings.SplineMetricsSettings splineMetrics =
|
|
metricsSettings.SplineMetrics;
|
|
float totalLength = m_spline.GetLength(foundPath);
|
|
float currentLength = 0f;
|
|
GeNaSample prevSample = null;
|
|
while (currentLength < totalLength)
|
|
{
|
|
GeNaSample sample = m_spline.GetSampleAtDistance(currentLength, foundPath);
|
|
if (sample == null)
|
|
break;
|
|
|
|
float step = metricsSettings.MarkerDistance;
|
|
|
|
GeNaSample nextSample = m_spline.GetSampleAtDistance(currentLength + step, foundPath);
|
|
|
|
Color oldColor = Handles.color;
|
|
Vector3 offsetPos = sample.Location + Vector3.up;
|
|
Handles.color = Color.white;
|
|
|
|
if (splineMetrics.ShowGradient)
|
|
{
|
|
// If there is a valid previous and next sample
|
|
if (prevSample != null && nextSample != null)
|
|
{
|
|
// Calculate Grade and Slope
|
|
float prevHeight = prevSample.Location.y;
|
|
float nextHeight = nextSample.Location.y;
|
|
float deltaHeight = nextHeight - prevHeight;
|
|
float deltaDistance = (prevSample.Location - nextSample.Location).magnitude;
|
|
float slopeGrade = 0f;
|
|
if (deltaDistance > 0f)
|
|
{
|
|
slopeGrade = (deltaHeight / deltaDistance) * 100f; // calculate grade
|
|
}
|
|
|
|
float slopeInDegrees = Mathf.Atan2(deltaHeight, deltaDistance) * Mathf.Rad2Deg;
|
|
|
|
// Draw Grade and Slope
|
|
GeNaEditorUtility.DrawStringShadow($"Grade: {slopeGrade:0.##}%", offsetPos, 1f,
|
|
new Vector2(5f, -25f));
|
|
GeNaEditorUtility.DrawStringShadow($"Slope: {slopeInDegrees:0.##}°", offsetPos,
|
|
1f, new Vector2(5f, -40f));
|
|
}
|
|
}
|
|
|
|
// Draw Marker Distance
|
|
Handles.DrawLine(sample.Location, offsetPos);
|
|
string measurement = $"{currentLength:0.##}m";
|
|
GeNaEditorUtility.DrawStringShadow(measurement, offsetPos, 1f, new Vector2(5f, -10f));
|
|
Handles.color = oldColor;
|
|
|
|
currentLength += step;
|
|
|
|
prevSample = sample;
|
|
}
|
|
|
|
// Get a sample from the middle of the spline
|
|
float totalTime = (float)foundPath.Count;
|
|
GeNaSample middleSample = m_spline.GetSampleAtTime(totalTime * .5f, foundPath);
|
|
if (middleSample != null)
|
|
{
|
|
GeNaPointMetrics metric = new GeNaPointMetrics()
|
|
{
|
|
title = $"Node ID: {nodeA.ID} -> {nodeB.ID}",
|
|
deltaDistance = m_spline.GetAccurateLength(foundPath),
|
|
worldPosition = middleSample.Location
|
|
};
|
|
|
|
// Use that sample to draw the spline details
|
|
DrawCurveMetric(metric, null, Color.red);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawMeasureCollisions(List<GeNaNode> selectedNodes)
|
|
{
|
|
SplineSettings settings = m_spline.Settings;
|
|
SplineSettings.MetricsSettings metricsSettings = settings.Metrics;
|
|
if (metricsSettings.MeasureCollisions)
|
|
{
|
|
for (int nodeIndex = 0; nodeIndex < selectedNodes.Count - 1; nodeIndex++)
|
|
{
|
|
GeNaNode nodeA = selectedNodes[nodeIndex];
|
|
GeNaNode nodeB = selectedNodes[nodeIndex + 1];
|
|
var foundPath = m_spline.FindPath(nodeA, nodeB);
|
|
if (foundPath.Count > 0)
|
|
{
|
|
foreach (GeNaCurve curve in foundPath)
|
|
{
|
|
DrawCurve(curve, Color.white);
|
|
}
|
|
|
|
SplineSettings.MetricsSettings.CollisionMetricsSettings collisionMetrics =
|
|
metricsSettings.CollisionMetrics;
|
|
float totalLength = m_spline.GetLength(foundPath);
|
|
float currentLength = 0f;
|
|
while (currentLength < totalLength)
|
|
{
|
|
GeNaSample sample = m_spline.GetSampleAtDistance(currentLength, foundPath);
|
|
if (sample == null)
|
|
break;
|
|
|
|
float step = metricsSettings.MarkerDistance;
|
|
|
|
Color oldColor = Handles.color;
|
|
Vector3 offsetPos = sample.Location + Vector3.up;
|
|
Handles.color = Color.red;
|
|
|
|
RaycastHit hit = default;
|
|
if (Physics.Raycast(sample.Location, Vector3.down, out hit, 1000f,
|
|
collisionMetrics.MarkerCollisionMask))
|
|
{
|
|
// Draw Marker Distance
|
|
Handles.DrawLine(hit.point, offsetPos);
|
|
string measurement = $"{currentLength:0.##}m";
|
|
GeNaEditorUtility.DrawStringShadow(measurement, offsetPos, 1f, new Vector2(5f, -10f));
|
|
|
|
float halfDistance = hit.distance * 0.5f;
|
|
|
|
measurement = $"{hit.distance:0.##}m";
|
|
Handles.DrawLine(hit.point, offsetPos);
|
|
GeNaEditorUtility.DrawStringShadow(measurement, offsetPos + Vector3.down * halfDistance,
|
|
1f, new Vector2(5f, -10f));
|
|
|
|
Handles.color = oldColor;
|
|
}
|
|
|
|
currentLength += step;
|
|
}
|
|
|
|
// Get a sample from the middle of the spline
|
|
float totalTime = (float)foundPath.Count;
|
|
GeNaSample middleSample = m_spline.GetSampleAtTime(totalTime * .5f, foundPath);
|
|
if (middleSample != null)
|
|
{
|
|
GeNaPointMetrics metric = new GeNaPointMetrics()
|
|
{
|
|
title = $"Node ID: {nodeA.ID} -> {nodeB.ID}",
|
|
deltaDistance = m_spline.GetAccurateLength(foundPath),
|
|
worldPosition = middleSample.Location
|
|
};
|
|
|
|
// Use that sample to draw the spline details
|
|
DrawCurveMetric(metric, null, Color.red);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawMetrics()
|
|
{
|
|
// Get all adjacent selected nodes
|
|
List<GeNaNode> adjacentSelectedNodes = GetAdjacentNodesForMetrics();
|
|
|
|
// Draws a Cyan Dotted Line along the list of selected nodes (in order)
|
|
DrawDottedLineToNodes(m_selectedNodes, Color.cyan);
|
|
|
|
if (m_selectedNodes.Count > 1)
|
|
{
|
|
DrawMeasureCollisions(adjacentSelectedNodes);
|
|
DrawMeasureSpline(adjacentSelectedNodes);
|
|
}
|
|
|
|
// Draws all of the average metrics between selected nodes
|
|
List<GeNaPointMetrics> averageMetrics = m_spline.GetAverageMetrics(m_selectedNodes);
|
|
DrawAverageMetrics(averageMetrics);
|
|
|
|
// Are there any selected nodes at all?
|
|
if (m_selectedNodes.Count > 0)
|
|
{
|
|
// Get the last node
|
|
int lastIndex = m_selectedNodes.Count - 1;
|
|
GeNaNode lastNode = m_selectedNodes[lastIndex];
|
|
|
|
// Get the last node metric
|
|
GeNaPointMetrics lastNodeMetric = m_spline.GetNodeMetrics(lastNode);
|
|
|
|
int nodeToDrawCount = adjacentSelectedNodes.Count;
|
|
|
|
// Is there more than one selected node?
|
|
if (m_selectedNodes.Count > 1)
|
|
{
|
|
// Move Last Node Metric to the left instead of the default right
|
|
string nodeBrief = lastNodeMetric.ToBrief();
|
|
Vector2 textSize = GeNaEditorUtility.CalculateTextSize(nodeBrief);
|
|
DrawNodeMetric(lastNodeMetric, new Vector2(-textSize.x + 10f, -100f));
|
|
// Calculate and draw the total metrics on the last spline position
|
|
GeNaPointMetrics totalMetrics = m_spline.GetTotalMetrics(averageMetrics);
|
|
totalMetrics.worldPosition = lastNode.Position;
|
|
DrawTotalMetric(totalMetrics);
|
|
|
|
// Draw one less node
|
|
nodeToDrawCount--;
|
|
}
|
|
|
|
// Draws a specified amount of the rest of the node data
|
|
for (int nodeIndex = 0; nodeIndex < nodeToDrawCount; nodeIndex++)
|
|
{
|
|
GeNaNode node = adjacentSelectedNodes[nodeIndex];
|
|
GeNaPointMetrics metric = m_spline.GetNodeMetrics(node);
|
|
DrawNodeMetric(metric);
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool DrawCurveHandles(GeNaCurve geNaCurve)
|
|
{
|
|
// First we check if at least one thing is in the camera field of view
|
|
if (GeNaEditorUtility.IsOnScreen(geNaCurve.P1))
|
|
{
|
|
Vector2 guiStartPos = HandleUtility.WorldToGUIPoint(geNaCurve.P0);
|
|
Vector2 guiStartTangent = HandleUtility.WorldToGUIPoint(geNaCurve.P1);
|
|
Color oldColor = Handles.color;
|
|
Color blue = new Color(0.3f, 0.3f, 1.0f, 1f);
|
|
Handles.color = blue;
|
|
Handles.DrawLine(guiStartTangent, guiStartPos);
|
|
Handles.color = oldColor;
|
|
// Draw directional button handles
|
|
if (Button(guiStartTangent, Styles.knobTexture2D, blue))
|
|
{
|
|
_selectedGeNaCurve = geNaCurve;
|
|
m_selectionType = SelectionType.StartTangent;
|
|
return false;
|
|
}
|
|
|
|
Handles.color = oldColor;
|
|
}
|
|
|
|
// First we check if at least one thing is in the camera field of view
|
|
if (GeNaEditorUtility.IsOnScreen(geNaCurve.P2))
|
|
{
|
|
Vector2 guiEndTangent = HandleUtility.WorldToGUIPoint(geNaCurve.P2);
|
|
Vector2 guiEndPos = HandleUtility.WorldToGUIPoint(geNaCurve.P3);
|
|
Color oldColor = Handles.color;
|
|
Handles.color = Color.red;
|
|
Handles.DrawLine(guiEndTangent, guiEndPos);
|
|
Handles.color = oldColor;
|
|
if (Button(guiEndTangent, Styles.knobTexture2D, Color.red))
|
|
{
|
|
_selectedGeNaCurve = geNaCurve;
|
|
m_selectionType = SelectionType.EndTangent;
|
|
return false;
|
|
}
|
|
|
|
Handles.color = oldColor;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void DrawConnectedNodeHandles(GeNaNode node, Texture2D texture, Color color)
|
|
{
|
|
Event e = Event.current;
|
|
Vector3 pos = node.Position;
|
|
Vector2 guiPos = HandleUtility.WorldToGUIPoint(pos);
|
|
Vector3 up = node.Position + node.Up * 8f;
|
|
Vector2 guiUp = HandleUtility.WorldToGUIPoint(up);
|
|
// For the selected node, we also draw a line and place two buttons for directions
|
|
Handles.color = Color.red;
|
|
// Draw quads direction and inverse direction if they are not selected
|
|
if (m_selectionType != SelectionType.Node)
|
|
if (Button(guiPos, texture, color))
|
|
m_selectionType = SelectionType.Node;
|
|
if (m_spline.Nodes.Contains(node))
|
|
{
|
|
if (showUpVector)
|
|
{
|
|
Handles.color = Color.green;
|
|
Handles.DrawLine(guiPos, guiUp);
|
|
if (m_selectionType != SelectionType.Up)
|
|
{
|
|
if (Button(guiUp, texture, color))
|
|
{
|
|
if (!e.shift)
|
|
{
|
|
m_selectedNodes.Clear();
|
|
}
|
|
|
|
m_selectedNodes.Add(node);
|
|
m_selectionType = SelectionType.Up;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawConnectedNodeHandles(GeNaNode node, GUIStyle style, Color color)
|
|
{
|
|
Event e = Event.current;
|
|
Vector3 pos = node.Position;
|
|
Vector2 guiPos = HandleUtility.WorldToGUIPoint(pos);
|
|
Vector3 up = node.Position + node.Up * 8f;
|
|
Vector2 guiUp = HandleUtility.WorldToGUIPoint(up);
|
|
// For the selected node, we also draw a line and place two buttons for directions
|
|
Handles.color = Color.red;
|
|
// Draw quads direction and inverse direction if they are not selected
|
|
if (m_selectionType != SelectionType.Node)
|
|
if (Button(guiPos, style, color))
|
|
m_selectionType = SelectionType.Node;
|
|
if (m_spline.Nodes.Contains(node))
|
|
{
|
|
if (showUpVector)
|
|
{
|
|
Handles.color = Color.green;
|
|
Handles.DrawLine(guiPos, guiUp);
|
|
if (m_selectionType != SelectionType.Up)
|
|
{
|
|
if (Button(guiUp, style, color))
|
|
{
|
|
if (!e.shift)
|
|
m_selectedNodes.Clear();
|
|
m_selectedNodes.Add(node);
|
|
m_selectionType = SelectionType.Up;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool DrawNodeHandles(GeNaNode currentNode)
|
|
{
|
|
Vector3 pos = currentNode.Position;
|
|
Vector3 guiPos = HandleUtility.WorldToGUIPoint(pos);
|
|
List<GeNaNode> nodes = m_spline.Nodes;
|
|
bool isFirstNode = currentNode == nodes.First();
|
|
bool isLastNode = currentNode == nodes.Last();
|
|
if (m_selectedNodes.Contains(currentNode))
|
|
{
|
|
if (isFirstNode || isLastNode)
|
|
DrawConnectedNodeHandles(currentNode, Styles.knobTexture2D,
|
|
isFirstNode ? FIRST_NODE_COLOR : LAST_NODE_COLOR);
|
|
else
|
|
DrawConnectedNodeHandles(currentNode, Styles.nodeBtn, NODE_COLOR);
|
|
if (Button(guiPos, Styles.knobTexture2D, SELECTED_NODE_COLOR))
|
|
{
|
|
m_selectedNodes.Clear();
|
|
m_selectedNodes.Add(currentNode);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool buttonPressed = false;
|
|
if (isFirstNode || isLastNode)
|
|
buttonPressed = Button(guiPos, Styles.knobTexture2D,
|
|
isFirstNode ? FIRST_NODE_COLOR : LAST_NODE_COLOR);
|
|
else
|
|
buttonPressed = Button(guiPos, Styles.knobTexture2D, NODE_COLOR);
|
|
if (buttonPressed)
|
|
{
|
|
Event e = Event.current;
|
|
if (e.control)
|
|
if (m_selectedNodes.Count > 0)
|
|
{
|
|
GeNaNode[] selected = m_selectedNodes.ToArray();
|
|
m_spline.RecordUndoSnapshot("Connect nodes", () =>
|
|
{
|
|
foreach (GeNaNode node in selected)
|
|
{
|
|
m_spline.AddNode(node, currentNode); //, node);
|
|
}
|
|
});
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
|
|
if (!e.shift)
|
|
m_selectedNodes.Clear();
|
|
m_selectedNodes.Add(currentNode);
|
|
m_selectionType = SelectionType.Node;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
base.OnInspectorGUI();
|
|
|
|
#region Header
|
|
|
|
m_editorUtils.Initialize();
|
|
GUILayout.Space(3f);
|
|
m_editorUtils.GUIHeader();
|
|
GeNaEditorUtility.DisplayWarnings();
|
|
m_editorUtils.GUINewsHeader();
|
|
|
|
#endregion
|
|
|
|
#region Panels
|
|
|
|
m_showQuickStart = m_editorUtils.Panel("Quick Start", QuickStartPanel, m_showQuickStart);
|
|
// Overview Panel
|
|
GUIStyle overviewLabelStyle = Styles.panelLabel;
|
|
string overviewText = string.Format("{0} : {1}", m_editorUtils.GetTextValue("Overview Panel Label"),
|
|
m_spline.Name);
|
|
GUIContent overviewPanelLabel =
|
|
new GUIContent(overviewText, m_editorUtils.GetTooltip("Overview Panel Label"));
|
|
m_showOverview = m_editorUtils.Panel(overviewPanelLabel, OverviewPanel, overviewLabelStyle, m_showOverview);
|
|
m_showPathFinding = m_editorUtils.Panel("Path Finding Label", PathFindingPanel, m_showPathFinding);
|
|
m_showMetrics = m_editorUtils.Panel("Metrics Panel Label", MetricsPanel, m_showMetrics);
|
|
m_showExtensions = m_editorUtils.Panel("Extensions Label", ExtensionPanel, m_showExtensions);
|
|
m_showAdvancedSettings = m_editorUtils.Panel("Advanced Panel Label", AdvancedPanel, m_showAdvancedSettings);
|
|
|
|
#endregion
|
|
|
|
if (m_spline.IsDirty)
|
|
{
|
|
GeNaEditorUtility.ForceUpdate();
|
|
EditorUtility.SetDirty(m_spline);
|
|
m_spline.IsDirty = false;
|
|
}
|
|
|
|
m_previousTool = Tools.current;
|
|
m_editorUtils.GUINewsFooter(false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Utilities
|
|
|
|
/// <summary>
|
|
/// Makes the Scene View Focus on a Given Point and Size
|
|
/// </summary>
|
|
/// <param name="pos"></param>
|
|
/// <param name="size"></param>
|
|
public void FocusPosition(Vector3 pos, Vector3 size)
|
|
{
|
|
SceneView.lastActiveSceneView.Frame(new Bounds(pos, size), false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if the mouse is over the SceneView
|
|
/// </summary>
|
|
private bool MouseOverSceneView(out Vector2 mousePos)
|
|
{
|
|
mousePos = Event.current.mousePosition;
|
|
if (mousePos.x < 0f || mousePos.y < 0f)
|
|
return false;
|
|
Rect swPos = SceneView.lastActiveSceneView.position;
|
|
return !(mousePos.x > swPos.width) &&
|
|
!(mousePos.y > swPos.height);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows the outline of the spawn range and does the raycasting.
|
|
/// </summary>
|
|
/// <returns>The Raycast hit info.</returns>
|
|
private bool GetRayCast(out RaycastHit hitInfo)
|
|
{
|
|
//Stop if not over the SceneView
|
|
if (!MouseOverSceneView(out Vector2 mousePos))
|
|
{
|
|
hitInfo = new RaycastHit();
|
|
return false;
|
|
}
|
|
|
|
//Let's do the raycast first
|
|
Ray ray = HandleUtility.GUIPointToWorldRay(mousePos);
|
|
return Physics.Raycast(ray, out hitInfo, 10000f);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Spline Extension Reorderable
|
|
|
|
private void CreateExtensionList()
|
|
{
|
|
m_extensionReorderable =
|
|
new ReorderableList(m_spline.Extensions, typeof(GeNaSplineExtension), true, true, true, true);
|
|
m_extensionReorderable.elementHeightCallback = OnElementHeightExtensionListEntry;
|
|
m_extensionReorderable.drawElementCallback = DrawExtensionListElement;
|
|
m_extensionReorderable.drawHeaderCallback = DrawExtensionListHeader;
|
|
m_extensionReorderable.onAddCallback = OnAddExtensionListEntry;
|
|
m_extensionReorderable.onRemoveCallback = OnRemoveExtensionListEntry;
|
|
m_extensionReorderable.onReorderCallback = OnReorderExtensionList;
|
|
}
|
|
|
|
private void OnReorderExtensionList(ReorderableList reorderableList)
|
|
{
|
|
//Do nothing, changing the order does not immediately affect anything in the stamper
|
|
}
|
|
|
|
private void OnRemoveExtensionListEntry(ReorderableList reorderableList)
|
|
{
|
|
m_spline.RecordUndoSnapshot("Extension Removed", () =>
|
|
{
|
|
m_selectedExtensionEntry = null;
|
|
int indexToRemove = reorderableList.index;
|
|
m_spline.RemoveExtension(indexToRemove);
|
|
reorderableList.list = m_spline.Extensions;
|
|
if (indexToRemove >= reorderableList.list.Count)
|
|
indexToRemove = reorderableList.list.Count - 1;
|
|
reorderableList.index = indexToRemove;
|
|
if (reorderableList.list.Count > 0)
|
|
{
|
|
int lastIndex = reorderableList.list.Count - 1;
|
|
ExtensionEntry nextEntry = m_spline.Extensions[lastIndex];
|
|
SelectExtensionEntry(nextEntry);
|
|
}
|
|
});
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
|
|
private void OnAddExtensionListEntry(ReorderableList reorderableList)
|
|
{
|
|
m_spline.RecordUndoSnapshot("Extension Added", () =>
|
|
{
|
|
ExtensionEntry extension = m_spline.AddExtension(null);
|
|
reorderableList.list = m_spline.Extensions;
|
|
SelectExtensionEntry(extension);
|
|
});
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
|
|
private void DrawExtensionListHeader(Rect rect)
|
|
{
|
|
DrawExtensionListHeader(rect, true, m_spline.Extensions, m_editorUtils);
|
|
}
|
|
|
|
private void DrawExtensionListElement(Rect rect, int index, bool isActive, bool isFocused)
|
|
{
|
|
ExtensionEntry entry = m_spline.Extensions[index];
|
|
DrawExtensionListElement(rect, entry, m_editorUtils, isFocused);
|
|
}
|
|
|
|
private float OnElementHeightExtensionListEntry(int index)
|
|
{
|
|
return OnElementHeight();
|
|
}
|
|
|
|
public float OnElementHeight()
|
|
{
|
|
return EditorGUIUtility.singleLineHeight + 4f;
|
|
}
|
|
|
|
public void DrawExtensionListHeader(Rect rect, bool currentFoldOutState, List<ExtensionEntry> extensionList,
|
|
EditorUtils editorUtils)
|
|
{
|
|
int oldIndent = EditorGUI.indentLevel;
|
|
EditorGUI.indentLevel = 0;
|
|
EditorGUI.LabelField(rect, editorUtils.GetContent("SpawnerEntryHeader"));
|
|
EditorGUI.indentLevel = oldIndent;
|
|
}
|
|
|
|
public void DrawExtensionList(ReorderableList list, EditorUtils editorUtils)
|
|
{
|
|
Rect maskRect = EditorGUILayout.GetControlRect(true, list.GetHeight());
|
|
list.DoList(maskRect);
|
|
}
|
|
|
|
public void SelectAllExtensionEntries()
|
|
{
|
|
foreach (ExtensionEntry entry in m_spline.Extensions)
|
|
entry.IsSelected = true;
|
|
}
|
|
|
|
public void DeselectAllExtensionEntries()
|
|
{
|
|
foreach (ExtensionEntry entry in m_spline.Extensions)
|
|
entry.IsSelected = false;
|
|
m_selectedExtensionEditor = null;
|
|
m_selectedExtensionEntry = null;
|
|
m_selectedExtension = null;
|
|
}
|
|
|
|
public void SelectExtensionEntry(int entryIndex)
|
|
{
|
|
if (entryIndex < 0 || entryIndex >= m_spline.Extensions.Count)
|
|
{
|
|
m_selectedExtension = null;
|
|
return;
|
|
}
|
|
|
|
SelectExtensionEntry(m_spline.Extensions[entryIndex]);
|
|
}
|
|
|
|
public void SelectExtensionEntry(ExtensionEntry entryToSelect)
|
|
{
|
|
foreach (ExtensionEntry entry in m_spline.Extensions)
|
|
{
|
|
if (entry == entryToSelect)
|
|
continue;
|
|
entry.IsSelected = false;
|
|
}
|
|
|
|
entryToSelect.IsSelected = true;
|
|
if (m_selectedExtensionEditor != null)
|
|
m_selectedExtensionEditor.OnDeselected();
|
|
m_selectedExtensionEntry = entryToSelect;
|
|
m_selectedExtensionEditor = CreateEditor(entryToSelect.Extension) as GeNaSplineExtensionEditor;
|
|
m_selectedExtension = entryToSelect.Extension;
|
|
int selectedExtensionIndex = m_extensionReorderable.list.IndexOf(entryToSelect);
|
|
m_extensionReorderable.index = selectedExtensionIndex;
|
|
m_spline.SelectedExtensionIndex = selectedExtensionIndex;
|
|
if (m_selectedExtensionEditor != null)
|
|
m_selectedExtensionEditor.OnSelected();
|
|
}
|
|
|
|
public void DrawExtensionListElement(Rect rect, ExtensionEntry entry, EditorUtils editorUtils, bool isFocused)
|
|
{
|
|
if (isFocused)
|
|
{
|
|
if (m_selectedExtension != entry.Extension)
|
|
{
|
|
DeselectAllExtensionEntries();
|
|
entry.IsSelected = true;
|
|
SelectExtensionEntry(entry);
|
|
}
|
|
}
|
|
|
|
// Spawner Object
|
|
EditorGUI.BeginChangeCheck();
|
|
{
|
|
int oldIndent = EditorGUI.indentLevel;
|
|
EditorGUI.indentLevel = 0;
|
|
EditorGUI.LabelField(
|
|
new Rect(rect.x, rect.y + 1f, rect.width * 0.18f, EditorGUIUtility.singleLineHeight),
|
|
editorUtils.GetContent("SpawnerEntryActive"));
|
|
entry.IsActive =
|
|
EditorGUI.Toggle(
|
|
new Rect(rect.x + rect.width * 0.18f, rect.y, rect.width * 0.1f,
|
|
EditorGUIUtility.singleLineHeight), entry.IsActive);
|
|
GeNaSplineExtension extension = entry.Extension;
|
|
extension = (GeNaSplineExtension)EditorGUI.ObjectField(
|
|
new Rect(rect.x + rect.width * 0.4f, rect.y + 1f, rect.width * 0.6f,
|
|
EditorGUIUtility.singleLineHeight), extension, typeof(GeNaSplineExtension), false);
|
|
if (extension != entry.Extension)
|
|
{
|
|
if (entry.Extension != null)
|
|
{
|
|
m_spline.RecordUndoSnapshot("Extension Removed",
|
|
() => { m_spline.RemoveExtension(entry.Extension); });
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
|
|
if (extension != null)
|
|
{
|
|
m_spline.RecordUndoSnapshot("Extension Added", () =>
|
|
{
|
|
GeNaSplineExtension newExtension = m_spline.CopyExtension(extension);
|
|
ExtensionEntry newEntry = m_spline.AddExtension(newExtension);
|
|
m_spline.RemoveExtensionEntry(entry);
|
|
SelectExtensionEntry(newEntry);
|
|
});
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel = oldIndent;
|
|
}
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
SceneView.RepaintAll();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Panels
|
|
|
|
private void QuickStartPanel(bool helpEnabled)
|
|
{
|
|
if (ActiveEditorTracker.sharedTracker.isLocked)
|
|
EditorGUILayout.HelpBox(m_editorUtils.GetTextValue("Inspector locked warning"), MessageType.Warning);
|
|
if (m_showQuickStart)
|
|
{
|
|
EditorUtils.CommonStyles editorStyles = m_editorUtils.Styles;
|
|
GUIStyle helpStyle = editorStyles.help;
|
|
m_editorUtils.Label("Create Nodes Help", helpStyle);
|
|
m_editorUtils.Label("Remove Nodes Help", helpStyle);
|
|
m_editorUtils.Label("Multi-Select Nodes Help", helpStyle);
|
|
m_editorUtils.Label("Select All Nodes Help", helpStyle);
|
|
if (m_editorUtils.Button("View Tutorials Btn"))
|
|
Application.OpenURL(PWApp.CONF.TutorialsLink);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handle drop area for new objects
|
|
/// </summary>
|
|
public bool DrawExtensionGUI()
|
|
{
|
|
// Ok - set up for drag and drop
|
|
Event evt = Event.current;
|
|
Rect dropArea = GUILayoutUtility.GetRect(0.0f, 50.0f, GUILayout.ExpandWidth(true));
|
|
string dropMsg = m_dropGround
|
|
? m_editorUtils.GetTextValue("Drop ground lvl box msg")
|
|
: m_editorUtils.GetTextValue("Attach Extensions");
|
|
GUI.Box(dropArea, dropMsg, Styles.gpanel);
|
|
bool recordedUndo = false;
|
|
if (evt.type == EventType.DragPerform || evt.type == EventType.DragUpdated)
|
|
{
|
|
if (!dropArea.Contains(evt.mousePosition))
|
|
return false;
|
|
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
|
|
if (evt.type == EventType.DragPerform)
|
|
{
|
|
DragAndDrop.AcceptDrag();
|
|
//Handle game objects / prefabs
|
|
foreach (Object draggedObject in DragAndDrop.objectReferences)
|
|
{
|
|
if (draggedObject is GameObject go)
|
|
{
|
|
GeNaSpawner spawner = go.GetComponent<GeNaSpawner>();
|
|
if (spawner != null)
|
|
{
|
|
spawner.Load();
|
|
GeNaSpawnerExtension geNaSpawnerExtension = CreateInstance<GeNaSpawnerExtension>();
|
|
geNaSpawnerExtension.name = spawner.name;
|
|
geNaSpawnerExtension.Spawner = spawner;
|
|
GeNaSpawnerData spawnerData = spawner.SpawnerData;
|
|
SpawnerEntry spawnerEntry = geNaSpawnerExtension.SpawnerEntry;
|
|
spawnerEntry.SpawnRange = spawnerData.SpawnRange;
|
|
spawnerEntry.ThrowDistance = spawnerData.ThrowDistance;
|
|
if (!recordedUndo)
|
|
{
|
|
m_spline.RecordUndoSnapshot("Extensions Added", () =>
|
|
{
|
|
ExtensionEntry entry = m_spline.AddExtension(geNaSpawnerExtension);
|
|
SelectExtensionEntry(entry);
|
|
});
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
else
|
|
{
|
|
ExtensionEntry entry = m_spline.AddExtension(geNaSpawnerExtension);
|
|
SelectExtensionEntry(entry);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (draggedObject is GeNaSplineExtension extensionReference)
|
|
{
|
|
if (extensionReference != null)
|
|
{
|
|
if (!recordedUndo)
|
|
{
|
|
m_spline.RecordUndoSnapshot("Extensions Added", () =>
|
|
{
|
|
GeNaSplineExtension newExtension = m_spline.CopyExtension(extensionReference);
|
|
ExtensionEntry entry = m_spline.AddExtension(newExtension);
|
|
SelectExtensionEntry(entry);
|
|
});
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
else
|
|
{
|
|
GeNaSplineExtension newExtension = m_spline.CopyExtension(extensionReference);
|
|
ExtensionEntry entry = m_spline.AddExtension(newExtension);
|
|
SelectExtensionEntry(entry);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void OverviewPanel(bool helpEnabled)
|
|
{
|
|
m_editorUtils.InlineHelp("Overview Panel Label", helpEnabled);
|
|
EditorGUI.BeginChangeCheck();
|
|
{
|
|
m_spline.Name = m_editorUtils.TextField("Spline Name", m_spline.Name, helpEnabled);
|
|
|
|
#region Smooth Spline
|
|
|
|
m_spline.SmoothStrength =
|
|
m_editorUtils.Slider("Smooth Strength", m_spline.SmoothStrength, 0f, 1f, helpEnabled);
|
|
m_spline.AutoSmooth = m_editorUtils.Toggle("Auto Smooth", m_spline.AutoSmooth);
|
|
m_spline.SmoothIntersections =
|
|
m_editorUtils.Toggle("Smooth Intersections", m_spline.SmoothIntersections);
|
|
m_spline.AutoSnapOnSubdivide = m_editorUtils.Toggle("Snap to Ground", m_spline.AutoSnapOnSubdivide);
|
|
|
|
#endregion
|
|
|
|
#region Simplify Spline
|
|
|
|
m_spline.SimplifyEpsilon =
|
|
m_editorUtils.Slider("Simplify Strength", m_spline.SimplifyEpsilon, 0.5f, 5.0f);
|
|
m_spline.SimplifyScale = m_editorUtils.Slider("Simplify Y Scale", m_spline.SimplifyScale, 0.5f, 1.5f);
|
|
|
|
#endregion
|
|
|
|
EditorGUILayout.BeginVertical();
|
|
{
|
|
if (m_spline.Nodes.Count == 0)
|
|
GUI.enabled = false;
|
|
|
|
#region Sub Divisions
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
{
|
|
if (m_editorUtils.Button("Subdivide", helpEnabled))
|
|
{
|
|
m_spline.RecordUndoSnapshot("Subdivide", m_spline.Subdivide);
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
|
|
if (m_editorUtils.Button("Simplify", helpEnabled))
|
|
{
|
|
m_spline.RecordUndoSnapshot("Simplify",
|
|
() => m_spline.SimplifyNodesAndCurves(m_spline.SimplifyScale,
|
|
m_spline.SimplifyEpsilon));
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
|
|
if (m_editorUtils.Button("Smooth Spline", helpEnabled))
|
|
{
|
|
m_spline.RecordUndoSnapshot("Smooth", () => m_spline.Smooth(m_spline.SmoothStrength));
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
}
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
#endregion
|
|
|
|
#region Clear All Nodes
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
{
|
|
if (m_editorUtils.Button("Clear All Nodes", helpEnabled))
|
|
{
|
|
m_spline.RecordUndoSnapshot("Clear All Nodes", () => m_spline.RemoveAllNodes());
|
|
m_selectedNodes.Clear();
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
|
|
if (m_editorUtils.Button("Snap Nodes To Ground", helpEnabled))
|
|
{
|
|
m_spline.RecordUndoSnapshot("Snap to Ground", () => m_spline.SnapNodesToGround());
|
|
m_spline.IsDirty = true;
|
|
m_splineModified = true;
|
|
}
|
|
}
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
#endregion
|
|
|
|
GUI.enabled = true;
|
|
}
|
|
EditorGUILayout.EndVertical();
|
|
}
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
m_spline.IsDirty = true;
|
|
}
|
|
}
|
|
|
|
private void PathFindingPanel(bool helpEnabled)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
{
|
|
bool defaultEnabled = GUI.enabled;
|
|
m_spline.PathFindingEnabled =
|
|
m_editorUtils.Toggle("Path Finding Enabled", m_spline.PathFindingEnabled, helpEnabled);
|
|
bool thisEnabled = GUI.enabled = m_spline.PathFindingEnabled;
|
|
m_spline.UseExistingCurves =
|
|
m_editorUtils.Toggle("UseExistingCurves", m_spline.UseExistingCurves, helpEnabled);
|
|
GUI.enabled = thisEnabled && m_spline.UseExistingCurves;
|
|
EditorGUI.indentLevel++;
|
|
m_spline.CurveTravelCost = m_editorUtils.Slider("CurveTravelCost", m_spline.CurveTravelCost, 0.02f,
|
|
1.0f, helpEnabled);
|
|
EditorGUI.indentLevel--;
|
|
GUI.enabled = thisEnabled;
|
|
m_spline.PathFinderIgnoreMask = EditorUtilsExtensions.LayerMaskField(m_editorUtils, "Ignore Mask",
|
|
m_spline.PathFinderIgnoreMask, helpEnabled);
|
|
m_spline.MaxGrade = m_editorUtils.Slider("Max Grade", m_spline.MaxGrade, 1.0f, 30.0f, helpEnabled);
|
|
m_spline.CellSize = m_editorUtils.IntSlider("Cell Size", m_spline.CellSize, 2, 20, helpEnabled);
|
|
if (GeNaUtility.Gaia2Present)
|
|
{
|
|
EditorGUILayout.BeginHorizontal();
|
|
m_spline.MinHeight = m_editorUtils.FloatField("Min Height", m_spline.MinHeight, helpEnabled);
|
|
if (m_editorUtils.Button("GetGaiaSeaLevel", GUILayout.MaxWidth(125f)))
|
|
{
|
|
m_spline.MinHeight = GeNaEvents.GetSeaLevel(m_spline.MinHeight);
|
|
}
|
|
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
else
|
|
{
|
|
m_spline.MinHeight = m_editorUtils.FloatField("Min Height", m_spline.MinHeight, helpEnabled);
|
|
}
|
|
|
|
m_spline.MaxHeight = m_editorUtils.FloatField("Max Height", m_spline.MaxHeight, helpEnabled);
|
|
m_spline.UseHeuristicB = m_editorUtils.Toggle("Use Heuristic B", m_spline.UseHeuristicB, helpEnabled);
|
|
GUI.enabled = GUI.enabled && !m_spline.UseHeuristicB;
|
|
m_spline.SlopeStrengthFactor = m_editorUtils.Slider("Slope Strength Factor",
|
|
m_spline.SlopeStrengthFactor, 0.1f, 2.0f, helpEnabled);
|
|
GUI.enabled = true;
|
|
}
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
m_spline.IsDirty = true;
|
|
}
|
|
}
|
|
|
|
private void ExtensionPanel(bool helpEnabled)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
{
|
|
if (DrawExtensionGUI())
|
|
return;
|
|
Rect listRect = EditorGUILayout.GetControlRect(true, m_extensionReorderable.GetHeight());
|
|
m_extensionReorderable.DoList(listRect);
|
|
if (m_selectedExtensionEntry != null)
|
|
{
|
|
// Spawner Selected?
|
|
if (m_selectedExtension != null)
|
|
{
|
|
GUI.enabled = m_selectedExtensionEntry.IsActive;
|
|
EditorGUILayout.BeginHorizontal(Styles.gpanel);
|
|
EditorGUILayout.LabelField($"{m_selectedExtension.name} Extension Settings", Styles.boldLabel);
|
|
EditorGUILayout.EndHorizontal();
|
|
EditorGUILayout.BeginVertical(Styles.gpanel);
|
|
if (m_selectedExtensionEditor == null)
|
|
{
|
|
SerializedObject so = new SerializedObject(m_selectedExtension);
|
|
so.Update();
|
|
SerializedProperty iter = so.GetIterator();
|
|
iter.NextVisible(true);
|
|
while (iter.NextVisible(false))
|
|
{
|
|
EditorGUILayout.PropertyField(iter);
|
|
}
|
|
|
|
so.ApplyModifiedProperties();
|
|
}
|
|
else
|
|
{
|
|
m_selectedExtensionEditor.HelpEnabled = helpEnabled;
|
|
m_selectedExtensionEditor.OnInspectorGUI();
|
|
}
|
|
|
|
EditorGUILayout.EndVertical();
|
|
GUI.enabled = true;
|
|
}
|
|
}
|
|
// if (m_editorUtils.Button("FinalizeAll"))
|
|
// {
|
|
// if (EditorUtility.DisplayDialog(m_editorUtils.GetTextValue("FinalizeTitle"),
|
|
// m_editorUtils.GetTextValue("FinalizeMessage"), m_editorUtils.GetTextValue("FinalizeYes"),
|
|
// m_editorUtils.GetTextValue("FinalizeNo")))
|
|
// {
|
|
// Terrain terrainParent = Terrain.activeTerrain;
|
|
// if (terrainParent != null)
|
|
// {
|
|
// GeNaEditorUtility.FinalizeAll(m_spline, terrainParent.gameObject);
|
|
// }
|
|
// else
|
|
// {
|
|
// GeNaEditorUtility.FinalizeAll(m_spline, null);
|
|
// }
|
|
// }
|
|
// }
|
|
}
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
m_spline.IsDirty = true;
|
|
}
|
|
}
|
|
|
|
private void MetricsPanel(bool helpEnabled)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
{
|
|
m_editorUtils.InlineHelp("Metrics Panel Label", helpEnabled);
|
|
SplineSettings.MetricsSettings metricsSettings = m_settings.Metrics;
|
|
metricsSettings.ShowMetrics =
|
|
m_editorUtils.Toggle("Show Metrics", metricsSettings.ShowMetrics, helpEnabled);
|
|
bool defaultEnabled = GUI.enabled;
|
|
GUI.enabled = metricsSettings.ShowMetrics;
|
|
{
|
|
metricsSettings.MarkerDistance =
|
|
m_editorUtils.FloatField("Marker Distance", metricsSettings.MarkerDistance, helpEnabled);
|
|
metricsSettings.MeasureSpline =
|
|
m_editorUtils.Toggle("Measure Spline", metricsSettings.MeasureSpline, helpEnabled);
|
|
var oldEnabled = GUI.enabled;
|
|
GUI.enabled = metricsSettings.ShowMetrics && metricsSettings.MeasureSpline;
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
{
|
|
SplineSettings.MetricsSettings.SplineMetricsSettings splineMetrics =
|
|
metricsSettings.SplineMetrics;
|
|
splineMetrics.ShowGradient =
|
|
m_editorUtils.Toggle("Show Gradient", splineMetrics.ShowGradient, helpEnabled);
|
|
}
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
GUI.enabled = oldEnabled;
|
|
|
|
metricsSettings.MeasureCollisions =
|
|
m_editorUtils.Toggle("Measure Collisions", metricsSettings.MeasureCollisions, helpEnabled);
|
|
|
|
oldEnabled = GUI.enabled;
|
|
GUI.enabled = metricsSettings.ShowMetrics && metricsSettings.MeasureCollisions;
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
{
|
|
SplineSettings.MetricsSettings.CollisionMetricsSettings collisionMetrics =
|
|
metricsSettings.CollisionMetrics;
|
|
collisionMetrics.MarkerCollisionMask =
|
|
m_editorUtils.LayerMaskField("Marker Collision Mask",
|
|
collisionMetrics.MarkerCollisionMask,
|
|
helpEnabled);
|
|
}
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
GUI.enabled = oldEnabled;
|
|
}
|
|
GUI.enabled = defaultEnabled;
|
|
}
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
m_spline.IsDirty = true;
|
|
}
|
|
}
|
|
|
|
private void AdvancedPanel(bool helpEnabled)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
{
|
|
m_editorUtils.InlineHelp("Advanced Panel", helpEnabled);
|
|
SplineSettings.AdvancedSettings advancedSettings = m_settings.Advanced;
|
|
advancedSettings.DebuggingEnabled = m_editorUtils.Toggle("Adv Debugging Enabled",
|
|
advancedSettings.DebuggingEnabled, helpEnabled);
|
|
advancedSettings.VisualizationProximity = m_editorUtils.FloatField("Adv Visualization Proximity",
|
|
advancedSettings.VisualizationProximity, helpEnabled);
|
|
}
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
m_spline.IsDirty = true;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GUI
|
|
|
|
public static bool Button(Vector2 position, Texture2D texture2D, Color color)
|
|
{
|
|
Vector2 quadSize = new Vector2(SPLINE_QUAD_SIZE, SPLINE_QUAD_SIZE);
|
|
Vector2 halfQuadSize = quadSize * .5f;
|
|
Rect buttonRect = new Rect(position - halfQuadSize, quadSize);
|
|
Color oldColor = GUI.color;
|
|
GUI.color = color;
|
|
bool result = GUI.Button(buttonRect, texture2D, GUIStyle.none);
|
|
GUI.color = oldColor;
|
|
return result;
|
|
}
|
|
|
|
public static bool Button(Vector2 position, GUIStyle style, Color color)
|
|
{
|
|
Vector2 quadSize = new Vector2(SPLINE_STYLE_QUAD_SIZE, SPLINE_STYLE_QUAD_SIZE);
|
|
Vector2 halfQuadSize = quadSize * .5f;
|
|
Rect buttonRect = new Rect(position - halfQuadSize, quadSize);
|
|
Color oldColor = GUI.color;
|
|
GUI.color = color;
|
|
bool result = GUI.Button(buttonRect, GUIContent.none, style);
|
|
GUI.color = oldColor;
|
|
return result;
|
|
}
|
|
|
|
public static void DrawQuad(Rect rect, Color color)
|
|
{
|
|
Texture2D texture = new Texture2D(1, 1);
|
|
texture.SetPixel(0, 0, color);
|
|
texture.Apply();
|
|
GUI.skin.box.normal.background = texture;
|
|
GUI.Box(rect, GUIContent.none);
|
|
}
|
|
|
|
public static void DrawQuad(Vector2 position, Color color)
|
|
{
|
|
Vector2 quadSize = new Vector2(EXTRUSION_QUAD_SIZE, EXTRUSION_QUAD_SIZE);
|
|
Vector2 halfQuadSize = quadSize * .5f;
|
|
Rect quad = new Rect(position - halfQuadSize, quadSize);
|
|
DrawQuad(quad, color);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
} |