318 lines
10 KiB
C#
318 lines
10 KiB
C#
using UnityEngine;
|
|
using UnityEditor;
|
|
using System.Collections.Generic;
|
|
using RayFire;
|
|
|
|
namespace RayFireEditor
|
|
{
|
|
[CanEditMultipleObjects]
|
|
[CustomEditor (typeof(RayfireCluster))]
|
|
public class RayfireClusterEditor : Editor
|
|
{
|
|
// Draw gizmo
|
|
[DrawGizmo (GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)]
|
|
static void DrawGizmosSelected (RayfireCluster cluster, GizmoType gizmoType)
|
|
{
|
|
// Color preview
|
|
if (cluster.colorPreview == true)
|
|
ColorPreview (cluster);
|
|
|
|
// Show bounds
|
|
if (cluster.showGizmo == true)
|
|
{
|
|
if (cluster.transform.childCount > 0)
|
|
{
|
|
Bounds bound = RFCluster.GetChildrenBound (cluster.transform);
|
|
Gizmos.color = cluster.wireColor;
|
|
Gizmos.DrawWireCube (bound.center, bound.size);
|
|
|
|
float size = bound.size.magnitude * 0.02f;
|
|
Gizmos.color = new Color (1.0f, 0.60f, 0f);
|
|
Gizmos.DrawSphere (bound.min, size);
|
|
Gizmos.DrawSphere (bound.max, size);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Preview variables
|
|
float lowestScale = 0.85f;
|
|
bool resetState = false;
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
// Get cluster
|
|
RayfireCluster cluster = target as RayfireCluster;
|
|
|
|
// Space
|
|
GUILayout.Space (8);
|
|
|
|
// Fragment
|
|
if (GUILayout.Button ("Clusterize", GUILayout.Height (25)))
|
|
{
|
|
float temp = cluster.previewScale;
|
|
cluster.previewScale = 0f;
|
|
resetState = true;
|
|
ResetScale (cluster, cluster.previewScale);
|
|
cluster.Clusterize();
|
|
cluster.previewScale = temp;
|
|
if (cluster.scalePreview == true)
|
|
ScalePreview (cluster);
|
|
}
|
|
|
|
// Space
|
|
GUILayout.Space (1);
|
|
|
|
// Fragmentation section Begin
|
|
GUILayout.BeginHorizontal();
|
|
|
|
// Delete all fragments
|
|
if (GUILayout.Button ("Extract Shards", GUILayout.Height (22)))
|
|
{
|
|
cluster.previewScale = 0f;
|
|
resetState = true;
|
|
ResetScale (cluster, cluster.previewScale);
|
|
cluster.Extract();
|
|
}
|
|
|
|
// Delete last
|
|
if (GUILayout.Button ("Select Shards", GUILayout.Height (22)))
|
|
SelectShards (cluster);
|
|
|
|
// Fragmentation section End
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
// Space
|
|
GUILayout.Space (1);
|
|
|
|
// Preview toggles begin
|
|
GUILayout.BeginHorizontal();
|
|
|
|
// Color preview toggle
|
|
EditorGUI.BeginChangeCheck();
|
|
cluster.colorPreview = GUILayout.Toggle (cluster.colorPreview, " Color Preview ", "Button");
|
|
if (EditorGUI.EndChangeCheck() == true)
|
|
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
|
|
|
|
// Start check for scale toggle change
|
|
EditorGUI.BeginChangeCheck();
|
|
cluster.scalePreview = GUILayout.Toggle (cluster.scalePreview, "Scale Preview", "Button");
|
|
if (EditorGUI.EndChangeCheck() == true)
|
|
{
|
|
if (cluster.scalePreview == true)
|
|
ScalePreview (cluster);
|
|
else
|
|
{
|
|
resetState = true;
|
|
ResetScale (cluster, 0f);
|
|
}
|
|
}
|
|
|
|
// Show bounds toggle
|
|
cluster.showGizmo = GUILayout.Toggle (cluster.showGizmo, "Show Gizmo ", "Button");
|
|
|
|
// Preview toggles end
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
// Space
|
|
GUILayout.Space (3);
|
|
|
|
// Preview section Begin
|
|
GUILayout.BeginHorizontal();
|
|
|
|
// Label
|
|
GUILayout.Label ("Preview", GUILayout.Width (50));
|
|
|
|
// Start check for slider change
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
// Slider
|
|
cluster.previewScale = GUILayout.HorizontalSlider (cluster.previewScale, 0f, 0.99f);
|
|
if (cluster.previewScale > 0f)
|
|
if (EditorGUI.EndChangeCheck() == true)
|
|
{
|
|
if (cluster.scalePreview == true)
|
|
ScalePreview (cluster);
|
|
if (cluster.colorPreview == true)
|
|
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
|
|
}
|
|
|
|
// Reset scale if fragments were deleted
|
|
ResetScale (cluster, cluster.previewScale);
|
|
|
|
// Preview section End
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
// Space
|
|
GUILayout.Space (3);
|
|
|
|
// Info section Begin
|
|
GUILayout.BeginHorizontal();
|
|
|
|
// Label
|
|
GUILayout.Label ("Clusters: " + cluster.allClusters.Count);
|
|
|
|
// Label
|
|
GUILayout.Label (" Layers: " + MaxLayer (cluster));
|
|
|
|
// Label
|
|
GUILayout.Label (" Shards: " + cluster.allShards.Count);
|
|
|
|
// Info section End
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
// Space
|
|
GUILayout.Space (3);
|
|
|
|
// Draw script UI
|
|
DrawDefaultInspector();
|
|
}
|
|
|
|
// Color preview
|
|
static void ColorPreview (RayfireCluster cluster)
|
|
{
|
|
Random.InitState (1);
|
|
|
|
// Scale cluster roots
|
|
if (cluster.allClusters.Count > 0)
|
|
{
|
|
// Get max depth
|
|
int maxDepth = 1;
|
|
foreach (RFCluster cls in cluster.allClusters)
|
|
if (cls.depth > maxDepth)
|
|
maxDepth = cls.depth;
|
|
|
|
// Depth step
|
|
float step = 1f / maxDepth;
|
|
int colorDepth = (int)(cluster.previewScale / step) + 1;
|
|
|
|
// Get clusters to colorize
|
|
List<RFCluster> colorClusters = new List<RFCluster>();
|
|
foreach (RFCluster cls in cluster.allClusters)
|
|
{
|
|
if (cls.childClusters.Count == 0 || cls.shards.Count > 0)
|
|
{
|
|
if (cls.depth <= colorDepth)
|
|
colorClusters.Add (cls);
|
|
}
|
|
else
|
|
{
|
|
if (cls.depth == colorDepth)
|
|
colorClusters.Add (cls);
|
|
}
|
|
}
|
|
|
|
//Random.InitState(1);
|
|
foreach (var cls in colorClusters)
|
|
{
|
|
Random.InitState (cls.id);
|
|
Gizmos.color = new Color (Random.Range (0.2f, 0.8f), Random.Range (0.2f, 0.8f), Random.Range (0.2f, 0.8f));
|
|
|
|
//List<RFShard> nestedShards = cls.GetNestedShards(true);
|
|
if (cls.tm != null)
|
|
{
|
|
MeshFilter[] meshFilters = cls.tm.GetComponentsInChildren<MeshFilter>();
|
|
foreach (var mf in meshFilters)
|
|
Gizmos.DrawMesh (mf.sharedMesh, mf.transform.position, mf.transform.rotation, mf.transform.lossyScale * 1.01f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set all clusters scale by preview
|
|
void ScalePreview (RayfireCluster cluster)
|
|
{
|
|
// Scale cluster roots
|
|
if (cluster.allClusters.Count > 0)
|
|
{
|
|
// Get max depth
|
|
int maxDepth = 1;
|
|
foreach (RFCluster cls in cluster.allClusters)
|
|
if (cls.depth > maxDepth)
|
|
maxDepth = cls.depth;
|
|
|
|
// Depth step
|
|
float step = 1f / maxDepth;
|
|
|
|
foreach (RFCluster cls in cluster.allClusters)
|
|
{
|
|
if (cls.depth > 0)
|
|
{
|
|
// Get multiplier
|
|
float scaleMult = lowestScale;
|
|
|
|
// Get local range
|
|
float max = step * cls.depth;
|
|
float min = max - step;
|
|
|
|
// Scale should be lowest possible
|
|
if (cluster.previewScale < min)
|
|
scaleMult = 1f;
|
|
|
|
// Scale should be highest possible
|
|
else if (cluster.previewScale > max)
|
|
scaleMult = lowestScale;
|
|
|
|
// Scale should interpolated
|
|
else
|
|
{
|
|
float k = Mathf.InverseLerp (min, max, cluster.previewScale);
|
|
scaleMult = Mathf.Lerp (1.0f, lowestScale, k);
|
|
}
|
|
|
|
// Set scale
|
|
cls.tm.localScale = Vector3.one * scaleMult;
|
|
}
|
|
}
|
|
|
|
resetState = true;
|
|
}
|
|
}
|
|
|
|
// Reset original object and fragments scale
|
|
void ResetScale (RayfireCluster cluster, float scaleValue)
|
|
{
|
|
// Rest scale
|
|
if (resetState == true && scaleValue == 0f)
|
|
{
|
|
if (cluster.allClusters.Count > 0)
|
|
{
|
|
foreach (var cls in cluster.allClusters)
|
|
{
|
|
if (cls.tm != null)
|
|
{
|
|
if (cls.depth > 0)
|
|
{
|
|
cls.tm.localScale = Vector3.one;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
resetState = false;
|
|
}
|
|
}
|
|
|
|
// Select shards
|
|
static void SelectShards (RayfireCluster cluster)
|
|
{
|
|
List<RFShard> shards = new List<RFShard>();
|
|
foreach (var cls in cluster.allClusters)
|
|
shards.AddRange (cls.shards);
|
|
GameObject[] objects = new GameObject[shards.Count];
|
|
for (int i = 0; i < shards.Count; i++)
|
|
objects[i] = shards[i].tm.gameObject;
|
|
if (objects.Length > 1)
|
|
Selection.objects = objects;
|
|
}
|
|
|
|
// Get max depth
|
|
static int MaxLayer (RayfireCluster cluster)
|
|
{
|
|
int depth = 0;
|
|
foreach (var cls in cluster.allClusters)
|
|
if (cls.depth > depth)
|
|
depth = cls.depth;
|
|
return depth;
|
|
}
|
|
}
|
|
} |