将Spline移出Plugin,以调整SplineRenderer的OnWillCameraRender

This commit is contained in:
SoulliesOfficial
2025-03-01 22:58:20 -05:00
parent 860d7393fb
commit 5d775ae687
529 changed files with 237 additions and 119 deletions

View File

@@ -0,0 +1,291 @@
namespace Dreamteck.Splines.Editor
{
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
public class BakeTool : SplineTool
{
public enum BakeGroup { All, Selected, AllExcluding }
BakeGroup bakeGroup = BakeGroup.All;
MeshGenerator[] found = new MeshGenerator[0];
List<MeshGenerator> selected = new List<MeshGenerator>();
List<MeshGenerator> excluded = new List<MeshGenerator>();
bool isStatic = true;
bool removeComputer = false;
bool permanent = false;
bool copy = false;
BakeMeshWindow.SaveFormat format = BakeMeshWindow.SaveFormat.MeshAsset;
string savePath = "";
DirectoryInfo dirInfo;
Vector2 scroll1, scroll2;
public override string GetName()
{
return "Bake Meshes";
}
public override void Draw(Rect windowRect)
{
bakeGroup = (BakeGroup)EditorGUILayout.EnumPopup("Bake Mode", bakeGroup);
if (bakeGroup == BakeGroup.Selected)
{
MeshGenSelector(ref selected, "Selected");
} else if(bakeGroup == BakeGroup.AllExcluding)
{
MeshGenSelector(ref excluded, "Excluded");
}
format = (BakeMeshWindow.SaveFormat)EditorGUILayout.EnumPopup("Save Format", format);
bool saveMesh = format != BakeMeshWindow.SaveFormat.Scene;
if (format != BakeMeshWindow.SaveFormat.Scene)
{
copy = EditorGUILayout.Toggle("Save without baking", copy);
}
bool isCopy = format != BakeMeshWindow.SaveFormat.Scene && copy;
switch (format)
{
case BakeMeshWindow.SaveFormat.Scene: EditorGUILayout.HelpBox("Saves the mesh inside the scene", MessageType.Info); break;
case BakeMeshWindow.SaveFormat.MeshAsset: EditorGUILayout.HelpBox("Saves the mesh as an .asset file inside the project. This makes using the mesh in prefabs and across scenes possible.", MessageType.Info); break;
case BakeMeshWindow.SaveFormat.OBJ: EditorGUILayout.HelpBox("Exports the mesh as an OBJ file which can be imported in a third-party modeling application.", MessageType.Info); break;
}
EditorGUILayout.Space();
if (!isCopy)
{
isStatic = EditorGUILayout.Toggle("Make Static", isStatic);
permanent = EditorGUILayout.Toggle("Permanent", permanent);
if (permanent)
{
removeComputer = EditorGUILayout.Toggle("Remove SplineComputer", removeComputer);
if (removeComputer) EditorGUILayout.HelpBox("WARNING: Removing Spline Computers may cause other SplineUsers to stop working. Select this if you are sure that no other SplineUser uses the selected Spline Computers.", MessageType.Warning);
}
}
if (GUILayout.Button("Bake"))
{
if (saveMesh)
{
savePath = EditorUtility.OpenFolderPanel("Save Directory", Application.dataPath, "folder");
if (!Directory.Exists(savePath) || savePath == "")
{
EditorUtility.DisplayDialog("Save error", "Invalid save directory. Please select a valid save directory and try again", "OK");
return;
}
if (format == BakeMeshWindow.SaveFormat.OBJ && !savePath.StartsWith(Application.dataPath) && !copy)
{
EditorUtility.DisplayDialog("Save error", "OBJ files can be saved outside of the project folder only when \"Save without baking\" is selected. Please select a directory inside the project in order to save.", "OK");
return;
}
if (format == BakeMeshWindow.SaveFormat.MeshAsset && !savePath.StartsWith(Application.dataPath))
{
EditorUtility.DisplayDialog("Save error", "Asset files cannot be saved outside of the project directory. Please select a path inside the project directory.", "OK");
return;
}
}
string suff = "all";
if (bakeGroup == BakeGroup.Selected) suff = "selected";
if (bakeGroup == BakeGroup.AllExcluding) suff = "all excluding";
if(EditorUtility.DisplayDialog("Bake " + suff, "This operation cannot be undone. Are you sure you want to bake the meshes?", "Yes", "No"))
{
switch (bakeGroup)
{
case BakeGroup.All: BakeAll(); break;
case BakeGroup.Selected: BakeSelected(); break;
case BakeGroup.AllExcluding: BakeExcluding(); break;
}
}
}
}
private void BakeAll()
{
EditorUtility.ClearProgressBar();
for (int i = 0; i < found.Length; i++)
{
float percent = (float)i / (found.Length - 1);
EditorUtility.DisplayProgressBar("Baking progress", "Baking generator " + i, percent);
Bake(found[i]);
}
EditorUtility.ClearProgressBar();
}
private void BakeSelected()
{
EditorUtility.ClearProgressBar();
for (int i = 0; i < selected.Count; i++)
{
float percent = (float)i / (selected.Count - 1);
EditorUtility.DisplayProgressBar("Baking progress", "Baking generator " + i, percent);
Bake(selected[i]);
}
EditorUtility.ClearProgressBar();
}
private void BakeExcluding()
{
EditorUtility.ClearProgressBar();
for (int i = 0; i < found.Length; i++)
{
float percent = (float)i / (found.Length - 1);
EditorUtility.DisplayProgressBar("Baking progress", "Baking generator " + i, percent);
Bake(found[i]);
}
EditorUtility.ClearProgressBar();
}
private void Bake(MeshGenerator gen)
{
MeshFilter filter = gen.GetComponent<MeshFilter>();
if(filter == null)
{
EditorUtility.DisplayDialog("Save error", "No mesh present in " + gen.name, "OK");
return;
}
if (copy)
{
UnityEditor.MeshUtility.Optimize(filter.sharedMesh);
Unwrapping.GenerateSecondaryUVSet(filter.sharedMesh);
}
else gen.Bake(isStatic, true);
if(format == BakeMeshWindow.SaveFormat.OBJ)
{
MeshRenderer renderer = gen.GetComponent<MeshRenderer>();
dirInfo = new DirectoryInfo(savePath);
FileInfo[] files = dirInfo.GetFiles(filter.sharedMesh.name + "*.obj");
string meshName = filter.sharedMesh.name;
if (files.Length > 0) meshName += "_" + files.Length;
string path = savePath + "/" + meshName + ".obj";
string objString = Dreamteck.MeshUtility.ToOBJString(filter.sharedMesh, renderer.sharedMaterials);
File.WriteAllText(path, objString);
if (copy)
{
string relativepath = "Assets" + path.Substring(Application.dataPath.Length);
AssetDatabase.ImportAsset(relativepath, ImportAssetOptions.ForceSynchronousImport);
filter.sharedMesh = AssetDatabase.LoadAssetAtPath<Mesh>(relativepath);
}
}
if(format == BakeMeshWindow.SaveFormat.MeshAsset)
{
dirInfo = new DirectoryInfo(savePath);
FileInfo[] files = dirInfo.GetFiles(filter.sharedMesh.name + "*.asset");
string meshName = filter.sharedMesh.name;
if (files.Length > 0) meshName += "_" + files.Length;
string path = savePath + "/" + meshName + ".asset";
string relativepath = "Assets" + path.Substring(Application.dataPath.Length);
if (copy)
{
Mesh assetMesh = Dreamteck.MeshUtility.Copy(filter.sharedMesh);
AssetDatabase.CreateAsset(assetMesh, relativepath);
} else AssetDatabase.CreateAsset(filter.sharedMesh, relativepath);
}
if (permanent && !copy)
{
SplineComputer meshGenComputer = gen.spline;
if (permanent)
{
meshGenComputer.Unsubscribe(gen);
Object.DestroyImmediate(gen);
}
if (removeComputer)
{
if (meshGenComputer.GetComponents<Component>().Length == 2) Object.DestroyImmediate(meshGenComputer.gameObject);
else Object.DestroyImmediate(meshGenComputer);
}
}
}
private void Refresh()
{
found = Object.FindObjectsOfType<MeshGenerator>();
}
void OnFocus()
{
Refresh();
}
public override void Open(EditorWindow window)
{
base.Open(window);
isStatic = LoadBool("isStatic", true);
format = (BakeMeshWindow.SaveFormat)LoadInt("format", 0);
removeComputer = LoadBool("removeComputer", false);
copy = LoadBool("copy", false);
Refresh();
}
public override void Close()
{
base.Close();
SaveBool("isStatic", isStatic);
SaveInt("format", (int)format);
SaveBool("copy", copy);
SaveBool("removeComputer", removeComputer);
}
protected override string GetPrefix()
{
return "BakeTool";
}
private void MeshGenSelector(ref List<MeshGenerator> list, string title)
{
List<MeshGenerator> availalbe = new List<MeshGenerator>(found);
for (int i = availalbe.Count-1; i >= 0; i--)
{
for (int n = 0; n < list.Count; n++)
{
if (list[n] == availalbe[i])
{
availalbe.RemoveAt(i);
break;
}
}
}
GUILayout.Box("Available", GUILayout.Width(Screen.width - 15 - Screen.width/3f), GUILayout.Height(100));
Rect rect = GUILayoutUtility.GetLastRect();
rect.y += 15;
rect.height -= 15;
scroll1 = GUI.BeginScrollView(rect, scroll1, new Rect(0, 0, rect.width, 22 * availalbe.Count));
for (int i = 0; i < availalbe.Count; i++)
{
GUI.Label(new Rect(5, 22 * i, rect.width - 30, 22), availalbe[i].name);
if (GUI.Button(new Rect(rect.width - 29, 22 * i, 22, 22), "+"))
{
list.Add(availalbe[i]);
availalbe.RemoveAt(i);
break;
}
}
GUI.EndScrollView();
EditorGUILayout.Space();
GUILayout.Box(title, GUILayout.Width(Screen.width - 15 - Screen.width / 3f), GUILayout.Height(100));
rect = GUILayoutUtility.GetLastRect();
rect.y += 15;
rect.height -= 15;
scroll2 = GUI.BeginScrollView(rect, scroll2, new Rect(0, 0, rect.width, 22 * list.Count));
for (int i = list.Count-1; i >= 0; i--)
{
GUI.Label(new Rect(5, 22 * i, rect.width - 30, 22), list[i].name);
if (GUI.Button(new Rect(rect.width - 29, 22 * i, 22, 22), "x"))
{
list.RemoveAt(i);
}
}
GUI.EndScrollView();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 659dbb6c3db842b4bbe63915d9097d5a
timeCreated: 1466788468
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,121 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using System.IO;
namespace Dreamteck.Splines
{
public class CatenaryTool : SplineTool
{
protected GameObject obj;
protected ObjectController spawner;
private float _sag = 0f;
private float _minSagDistance = 0f;
private float _maxSagDistance = 10f;
private Dictionary<SplineComputer, SplinePoint[]> _editSplines = new Dictionary<SplineComputer, SplinePoint[]>();
public override string GetName()
{
return "Catenary Tool";
}
protected override string GetPrefix()
{
return "CatenaryTool";
}
public override void Open(EditorWindow window)
{
base.Open(window);
_sag = EditorPrefs.GetFloat("DreamteckSplines.CatenaryTool._sag", 0f);
_minSagDistance = EditorPrefs.GetFloat("DreamteckSplines.CatenaryTool._minSagDistance", 0f);
_maxSagDistance = EditorPrefs.GetFloat("DreamteckSplines.CatenaryTool._maxSagDistance", 10f);
}
public override void Close()
{
base.Close();
EditorPrefs.SetFloat("DreamteckSplines.CatenaryTool._sag", _sag);
EditorPrefs.SetFloat("DreamteckSplines.CatenaryTool._minSagDistance", _minSagDistance);
EditorPrefs.SetFloat("DreamteckSplines.CatenaryTool._maxSagDistance", _minSagDistance);
}
public override void Draw(Rect windowRect)
{
base.Draw(windowRect);
if(_editSplines.Keys.Count == 0 && splines.Count > 0)
{
if(GUILayout.Button("Convert Selected"))
{
ConvertSelected();
}
} else
{
EditorGUI.BeginChangeCheck();
_sag = EditorGUILayout.FloatField("Sag", _sag);
_minSagDistance = EditorGUILayout.FloatField("Min Distance", _minSagDistance);
_maxSagDistance = EditorGUILayout.FloatField("Max Distance", _maxSagDistance);
var keys = _editSplines.Keys;
if (EditorGUI.EndChangeCheck())
{
SceneView.RepaintAll();
foreach (var key in keys)
{
for (int i = 0; i < key.pointCount; i++)
{
ModifyPoint(key, i);
}
key.SetPoints(_editSplines[key]);
}
}
if (GUILayout.Button("Apply"))
{
foreach (var key in keys)
{
EditorUtility.SetDirty(key);
}
_editSplines.Clear();
}
}
}
private void ModifyPoint(SplineComputer spline, int index)
{
var current = _editSplines[spline][index];
if(index > 0)
{
var previous = _editSplines[spline][index - 1];
Vector3 prevDirection = (previous.position - current.position)/3f;
float sagAmount = Mathf.InverseLerp(_minSagDistance, _maxSagDistance, prevDirection.magnitude) * _sag;
current.SetTangentPosition(current.position + prevDirection + Vector3.down * sagAmount);
}
if(index < _editSplines[spline].Length - 1)
{
var next = _editSplines[spline][index + 1];
Vector3 nextDirection = (next.position - current.position) / 3f;
float sagAmount = Mathf.InverseLerp(_minSagDistance, _maxSagDistance, nextDirection.magnitude) * _sag;
current.SetTangent2Position(current.position + nextDirection + Vector3.down * sagAmount);
}
_editSplines[spline][index] = current;
}
private void ConvertSelected()
{
_editSplines.Clear();
foreach(var spline in splines)
{
var points = spline.GetPoints();
for (int i = 0; i < points.Length; i++)
{
points[i].type = SplinePoint.Type.Broken;
}
spline.type = Spline.Type.Bezier;
_editSplines.Add(spline, points);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 62aeb649c30348f4ea6cec4a6481b8fd
timeCreated: 1456934986
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,200 @@
namespace Dreamteck.Splines.Editor
{
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class Explorer : SplineTool
{
GUIStyle normalRow;
GUIStyle selectedRow;
List<SplineComputer> sceneSplines = new List<SplineComputer>();
List<int> selected = new List<int>();
Vector2 scroll = Vector2.zero;
bool mouseLeft = false;
public override string GetName()
{
return "Spline Explorer";
}
protected override string GetPrefix()
{
return "SplineExplorer";
}
public override void Open(EditorWindow window)
{
base.Open(window);
normalRow = new GUIStyle(GUI.skin.box);
normalRow.normal.background = null;
normalRow.alignment = TextAnchor.MiddleLeft;
selectedRow = new GUIStyle(normalRow);
selectedRow.normal.background = SplineEditorGUI.white;
selectedRow.normal.textColor = SplinePrefs.highlightContentColor;
GetSceneSplines();
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui += OnScene;
#else
SceneView.onSceneGUIDelegate += OnScene;
#endif
}
public override void Close()
{
base.Close();
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui -= OnScene;
#else
SceneView.onSceneGUIDelegate -= OnScene;
#endif
}
void OnScene(SceneView current)
{
if(selected.Count > 1)
{
for (int i = 0; i < selected.Count; i++)
{
if (!sceneSplines[selected[i]].editorAlwaysDraw)
{
DSSplineDrawer.DrawSplineComputer(sceneSplines[selected[i]]);
}
}
}
}
void GetSceneSplines()
{
sceneSplines = new List<SplineComputer>(Resources.FindObjectsOfTypeAll<SplineComputer>());
}
public override void Draw(Rect rect)
{
switch (Event.current.type)
{
case EventType.MouseDown:
if (Event.current.button == 0) mouseLeft = true;
break;
case EventType.MouseUp: if (Event.current.button == 0) mouseLeft = false; break;
}
Rect lastRect;
scroll = EditorGUILayout.BeginScrollView(scroll, GUILayout.Width(rect.width), GUILayout.Height(rect.height));
EditorGUILayout.BeginHorizontal(normalRow);
EditorGUILayout.LabelField("Name", EditorStyles.boldLabel, GUILayout.Width(rect.width - 200));
EditorGUILayout.LabelField("Color", EditorStyles.boldLabel, GUILayout.Width(65));
EditorGUILayout.LabelField("Draw", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.LabelField("Thickness", EditorStyles.boldLabel, GUILayout.Width(60));
EditorGUILayout.EndHorizontal();
EditorGUI.BeginChangeCheck();
for (int i = 0; i < sceneSplines.Count; i++)
{
bool isSelected = selected.Contains(i);
if (isSelected) GUI.backgroundColor = SplinePrefs.highlightColor;
EditorGUILayout.BeginHorizontal(isSelected ? selectedRow : normalRow);
EditorGUILayout.LabelField(sceneSplines[i].name, isSelected ? selectedRow : normalRow, GUILayout.Width(rect.width-200));
GUI.backgroundColor = Color.white;
Color pathColor = sceneSplines[i].editorPathColor;
pathColor = EditorGUILayout.ColorField(pathColor, GUILayout.Width(65));
if(pathColor != sceneSplines[i].editorPathColor)
{
foreach (int index in selected) sceneSplines[index].editorPathColor = pathColor;
}
bool alwaysDraw = sceneSplines[i].editorAlwaysDraw;
alwaysDraw = EditorGUILayout.Toggle(alwaysDraw, GUILayout.Width(40));
if(alwaysDraw != sceneSplines[i].editorAlwaysDraw)
{
foreach (int index in selected)
{
if (alwaysDraw)
{
DSSplineDrawer.RegisterComputer(sceneSplines[index]);
}
else
{
DSSplineDrawer.UnregisterComputer(sceneSplines[index]);
}
}
}
bool thickness = sceneSplines[i].editorDrawThickness;
thickness = EditorGUILayout.Toggle(thickness, GUILayout.Width(40));
if(thickness != sceneSplines[i].editorDrawThickness)
{
foreach (int index in selected) sceneSplines[index].editorDrawThickness = thickness;
}
EditorGUILayout.EndHorizontal();
lastRect = GUILayoutUtility.GetLastRect();
if (mouseLeft)
{
if (lastRect.Contains(Event.current.mousePosition))
{
if (Event.current.control)
{
if (!selected.Contains(i)) selected.Add(i);
}
else if (selected.Count > 0 && Event.current.shift)
{
int closest = selected[0];
int delta = sceneSplines.Count;
for (int j = 0; j < selected.Count; j++)
{
int d = Mathf.Abs(i - selected[j]);
if (d < delta)
{
delta = d;
closest = selected[j];
}
}
if (closest < i)
{
for (int j = closest + 1; j <= i; j++)
{
if (selected.Contains(j)) continue;
selected.Add(j);
}
}
else
{
for (int j = closest - 1; j >= i; j--)
{
if (selected.Contains(j)) continue;
selected.Add(j);
}
}
}
else selected = new List<int>(new int[] { i });
List<GameObject> selectGo = new List<GameObject>();
foreach(int index in selected) selectGo.Add(sceneSplines[index].gameObject);
Selection.objects = selectGo.ToArray();
Repaint();
}
}
}
if (EditorGUI.EndChangeCheck()) SceneView.RepaintAll();
EditorGUILayout.EndScrollView();
if(Event.current.type == EventType.KeyDown)
{
if (Event.current.keyCode == KeyCode.DownArrow)
{
if (selected.Count > 0) selected = new List<int>(new int[] { selected[0] });
else selected[0]++;
}
else if (Event.current.keyCode == KeyCode.UpArrow)
{
if (selected.Count > 0) selected = new List<int>(new int[] { selected[selected.Count - 1] });
else selected[0]++;
}
if (selected.Count == 0) return;
if (selected[0] < 0) selected[0] = sceneSplines.Count - 1;
if (selected[0] >= sceneSplines.Count) selected[0] = 0;
if (sceneSplines.Count > 0) Selection.activeGameObject = sceneSplines[selected[0]].gameObject;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: aa5e1620a9cb5114c9f0581fbafceb67
timeCreated: 1496308185
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,391 @@
namespace Dreamteck.Splines.Editor
{
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using System.IO;
using Dreamteck.Splines.IO;
public class ImportExportTool : SplineTool
{
private float scaleFactor = 1f;
private bool alwaysDraw = true;
private string importPath = "";
private string exportPath = "";
List<SplinePoint[]> originalPoints = new List<SplinePoint[]>();
List<SplineComputer> imported = new List<SplineComputer>();
List<SplineComputer> exported = new List<SplineComputer>();
GameObject importedParent = null;
enum Mode { None, Import, Export }
enum ExportFormat { SVG, CSV }
enum Axis { X, Y, Z }
Mode mode = Mode.None;
ExportFormat format = ExportFormat.SVG;
Axis importAxis = Axis.Z;
Axis exportAxis = Axis.Z;
bool importOptions = false;
List<CSV.ColumnType> exportColumns = new List<CSV.ColumnType>();
List<CSV.ColumnType> importColumns = new List<CSV.ColumnType>();
bool flatCSV = false;
public override string GetName()
{
return "Import/Export";
}
protected override string GetPrefix()
{
return "ImportExport";
}
public override void Open(EditorWindow window)
{
base.Open(window);
importPath = LoadString("importPath", "");
exportPath = LoadString("exportPath", "");
alwaysDraw = LoadBool("alwaysDraw", true);
flatCSV = LoadBool("flatCSV", false);
importAxis = (Axis)LoadInt("importAxis", 2);
exportAxis = (Axis)LoadInt("exportAxis", 2);
LoadColumns("importColumns", ref importColumns);
LoadColumns("exportColumns", ref exportColumns);
}
void LoadColumns(string name, ref List<CSV.ColumnType> destination)
{
string text = LoadString(name, "");
destination = new List<CSV.ColumnType>();
if (text == "")
{
destination.Add(CSV.ColumnType.Position);
destination.Add(CSV.ColumnType.Tangent);
destination.Add(CSV.ColumnType.Tangent2);
destination.Add(CSV.ColumnType.Normal);
destination.Add(CSV.ColumnType.Size);
destination.Add(CSV.ColumnType.Color);
return;
}
string[] elements = text.Split(',');
foreach (string element in elements)
{
int i = 0;
if (int.TryParse(element, out i)) destination.Add((CSV.ColumnType)i);
}
}
public override void Close()
{
base.Close();
if(importPath != "") SaveString("importPath", Path.GetDirectoryName(importPath));
if (exportPath != "") SaveString("exportPath", Path.GetDirectoryName(exportPath));
string columnString = "";
foreach(CSV.ColumnType col in importColumns)
{
if (columnString != "") columnString += ",";
columnString += ((int)col).ToString();
}
SaveString("importColumns", columnString);
columnString = "";
foreach (CSV.ColumnType col in exportColumns)
{
if (columnString != "") columnString += ",";
columnString += ((int)col).ToString();
}
SaveString("exportColumns", columnString);
SaveBool("alwaysDraw", alwaysDraw);
SaveBool("flatCSV", flatCSV);
SaveInt("importAxis", (int)importAxis);
SaveInt("exportAxis", (int)exportAxis);
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui -= OnScene;
#else
SceneView.onSceneGUIDelegate -= OnScene;
#endif
}
protected override void Save()
{
base.Save();
if (importedParent != null)
{
Selection.activeGameObject = importedParent;
importedParent = null;
} else
{
foreach(SplineComputer comp in imported)
{
if(comp != null)
{
Selection.activeGameObject = comp.gameObject;
break;
}
}
}
imported.Clear();
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui -= OnScene;
#else
SceneView.onSceneGUIDelegate -= OnScene;
#endif
mode = Mode.None;
}
protected override void Cancel()
{
base.Cancel();
foreach (SplineComputer spline in imported) GameObject.DestroyImmediate(spline.gameObject);
GameObject.DestroyImmediate(importedParent);
imported.Clear();
SceneView.RepaintAll();
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui -= OnScene;
#else
SceneView.onSceneGUIDelegate -= OnScene;
#endif
mode = Mode.None;
}
void CSVColumnUI(List<CSV.ColumnType> columns)
{
EditorGUILayout.LabelField("Dataset Columns");
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("-", GUILayout.MaxWidth(30)) && columns.Count > 0) columns.RemoveAt(columns.Count - 1);
for (int i = 0; i < columns.Count; i++)
{
columns[i] = (CSV.ColumnType)EditorGUILayout.EnumPopup(columns[i]);
}
if (GUILayout.Button("+", GUILayout.MaxWidth(30)) && columns.Count > 0) columns.Add(CSV.ColumnType.Position);
EditorGUILayout.EndHorizontal();
}
void OnScene(SceneView current)
{
for (int i = 0; i < imported.Count; i++)
{
DSSplineDrawer.DrawSplineComputer(imported[i]);
}
}
void ImportUI()
{
EditorGUI.BeginChangeCheck();
scaleFactor = EditorGUILayout.FloatField("Scale Factor", scaleFactor);
importAxis = (Axis)EditorGUILayout.EnumPopup("Facing Axis", importAxis);
alwaysDraw = EditorGUILayout.Toggle("Always Draw", alwaysDraw);
if (EditorGUI.EndChangeCheck()) ApplyPoints();
SaveCancelUI();
}
void ExportUI()
{
if(exported.Count == 0)
{
mode = Mode.None;
return;
}
EditorGUILayout.Space();
format = (ExportFormat)EditorGUILayout.EnumPopup("Format", format);
if (format == ExportFormat.SVG)
{
exportAxis = (Axis)EditorGUILayout.EnumPopup("Projection Axis", exportAxis);
EditorGUILayout.HelpBox("The SVG is a 2D vector format so the exported spline will be flattened along the selected axis", MessageType.Info);
}
else
{
CSVColumnUI(exportColumns);
flatCSV = EditorGUILayout.Toggle("Flat", flatCSV);
if(flatCSV) exportAxis = (Axis)EditorGUILayout.EnumPopup("Projection Axis", exportAxis);
EditorGUILayout.HelpBox("The exported splined will be flattened along the selected axis.", MessageType.Info);
}
if (GUILayout.Button("Save File"))
{
string extension = "*";
switch (format)
{
case ExportFormat.SVG: extension = "svg"; break;
case ExportFormat.CSV: extension = "csv"; break;
}
exportPath = EditorUtility.SaveFilePanel("Export splines", exportPath, "spline", extension);
if (exportPath != "")
{
if (Directory.Exists(Path.GetDirectoryName(exportPath)))
{
switch (format)
{
case ExportFormat.SVG: ExportSVG(exportPath); break;
case ExportFormat.CSV: ExportCSV(exportPath); break;
}
}
}
}
}
public override void Draw(Rect windowRect)
{
if (mode == Mode.Import)
{
ImportUI();
}
else
{
importOptions = EditorGUILayout.Foldout(importOptions, "Import Options");
if (importOptions) CSVColumnUI(importColumns);
if (GUILayout.Button("Import"))
{
importPath = EditorUtility.OpenFilePanel("Browse File", importPath, "svg,csv");
if (File.Exists(importPath))
{
splines.Clear();
string ext = Path.GetExtension(importPath).ToLower();
switch (ext)
{
case ".svg": ImportSVG(importPath); break;
case ".csv": ImportCSV(importPath); break;
case ".xml": ImportSVG(importPath); break;
}
}
}
exported = GetSelectedSplines();
if (exported.Count == 0) GUI.color = new Color(1f, 1f, 1f, 0.5f);
if (mode == Mode.Export) ExportUI();
if (mode != Mode.Export)
{
if (GUILayout.Button("Export") && exported.Count > 0) mode = Mode.Export;
}
}
}
List<SplineComputer> GetSelectedSplines()
{
List<SplineComputer> selected = new List<SplineComputer>();
foreach(GameObject obj in Selection.gameObjects)
{
SplineComputer comp = obj.GetComponent<SplineComputer>();
if (comp != null) selected.Add(comp);
}
return selected;
}
void ApplyPoints()
{
if (originalPoints.Count != imported.Count) return;
if (imported.Count == 0) return;
Quaternion lookRot = Quaternion.identity;
switch (importAxis)
{
case Axis.X: lookRot = Quaternion.LookRotation(Vector3.right); break;
case Axis.Y: lookRot = Quaternion.LookRotation(Vector3.down); break;
case Axis.Z: lookRot = Quaternion.LookRotation(Vector3.forward); break;
}
for (int i = 0; i < imported.Count; i++)
{
SplinePoint[] transformed = new SplinePoint[originalPoints[i].Length];
originalPoints[i].CopyTo(transformed, 0);
for (int j = 0; j < transformed.Length; j++)
{
transformed[j].position *= scaleFactor;
transformed[j].tangent *= scaleFactor;
transformed[j].tangent2 *= scaleFactor;
transformed[j].position = lookRot * transformed[j].position;
transformed[j].tangent = lookRot * transformed[j].tangent;
transformed[j].tangent2 = lookRot * transformed[j].tangent2;
transformed[j].normal = lookRot * transformed[j].normal;
}
imported[i].SetPoints(transformed);
if (alwaysDraw)
{
DSSplineDrawer.RegisterComputer(imported[i]);
}
else
{
DSSplineDrawer.UnregisterComputer(imported[i]);
}
}
SceneView.RepaintAll();
}
void GetImportedPoints()
{
foreach (SplineComputer comp in imported)
{
if (comp != null)
{
originalPoints.Add(comp.GetPoints(SplineComputer.Space.Local));
mode = Mode.Import;
} else imported.Remove(comp);
}
}
void ImportSVG(string file)
{
SVG svg = new SVG(file);
originalPoints.Clear();
imported = svg.CreateSplineComputers(Vector3.zero, Quaternion.identity);
if (imported.Count == 0) return;
importedParent = new GameObject(svg.name);
foreach (SplineComputer comp in imported) comp.transform.parent = importedParent.transform;
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui += OnScene;
#else
SceneView.onSceneGUIDelegate += OnScene;
#endif
GetImportedPoints();
ApplyPoints();
promptSave = true;
}
void ExportSVG(string file)
{
SVG svg = new SVG(exported);
svg.Write(file, (SVG.Axis)((int)exportAxis));
}
void ExportCSV(string file)
{
CSV csv = new CSV(exported[0]);
csv.columns = exportColumns;
if (flatCSV)
{
switch (exportAxis)
{
case Axis.X: csv.FlatX(); break;
case Axis.Y: csv.FlatY(); break;
case Axis.Z: csv.FlatZ(); break;
}
}
csv.Write(file);
}
void ImportCSV(string file)
{
CSV csv = new CSV(file, importColumns);
originalPoints.Clear();
imported.Clear();
imported.Add(csv.CreateSplineComputer(Vector3.zero, Quaternion.identity));
if (imported.Count == 0) return;
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui += OnScene;
#else
SceneView.onSceneGUIDelegate += OnScene;
#endif
GetImportedPoints();
ApplyPoints();
promptSave = true;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 9fac175ae39d238478fae9bbe2683559
timeCreated: 1456934986
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,656 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
namespace Dreamteck.Splines
{
public class LevelTerrainTool : SplineTool
{
public override string GetName()
{
return "Level Terrain";
}
protected override string GetPrefix()
{
return "LevelTerrainTool";
}
public struct Point
{
public int x;
public int y;
public Vector2 vector
{
get { return new Vector2(x, y); }
set {
x = (int)value.x;
y = (int)value.y;
}
}
public Point(int newX, int newY)
{
x = newX;
y = newY;
}
public Point(Vector2 input)
{
x = Mathf.RoundToInt(input.x);
y = Mathf.RoundToInt(input.y);
}
}
public class TerrainPaintPoint
{
public Point leftPoint;
public Point rightPoint;
public float leftHeight = 0f;
public float rightHeight = 0f;
public Point center;
public float floatDiameter = 0f;
public float GetHeight(float percent)
{
return Mathf.Lerp(leftHeight, rightHeight, percent);
}
}
public float size = 1f;
public int feather = 1;
public float offset = 0f;
public float clipFrom = 0f;
public float clipTo = 1f;
private float[,] heights = null;
private Texture2D brushPreview = null;
private Texture2D basePreview = null;
private Texture2D drawPreview = null;
private float maxDrawHeight = 0f;
private bool init = false;
Terrain terrain = null;
void GetSplinesAndTerrain()
{
if(splines.Count == 0) GetSplines();
for (int i = 0; i < Selection.gameObjects.Length; i++)
{
if (terrain == null) terrain = Selection.gameObjects[i].GetComponent<Terrain>();
}
Terrain[] terrains = GameObject.FindObjectsOfType<Terrain>();
if(terrains.Length == 1)
{
//if there is only one terrain in the scene, automatically select it
terrain = terrains[0];
}
}
void OnGUI()
{
// Draw();
}
public override void Open(EditorWindow window)
{
base.Open(window);
GetSplinesAndTerrain();
}
public override void Close()
{
base.Close();
if (promptSave)
{
if (EditorUtility.DisplayDialog("Apply changes?", "Changes to the terrain have been made. Do you want to keep them?", "Yes", "No"))
{
SaveChanges();
}
else RevertToBase();
}
}
public override void Draw(Rect windowRect)
{
base.Draw(windowRect);
EditorGUILayout.Space();
EditorGUI.BeginChangeCheck();
terrain = (Terrain)EditorGUILayout.ObjectField("Terrain", terrain, typeof(Terrain), true);
if (EditorGUI.EndChangeCheck())
{
heights = null;
}
if (splines.Count == 0) EditorGUILayout.HelpBox("No spline selected! Select an object with a SplineComputer component.", MessageType.Warning);
if (terrain == null) EditorGUILayout.HelpBox("No terrain selected! You need to select a terrain.", MessageType.Warning);
if (splines.Count == 0 || terrain == null) return;
if (!init)
{
init = true;
brushPreview = GenerateBrushThumbnail();
}
if (heights == null)
{
GetBase();
}
GUILayout.BeginHorizontal();
GUILayout.BeginVertical();
float lastSize = size;
size = EditorGUILayout.FloatField("Brush radius", size);
if (size < 0f) size = 0f;
if(lastSize != size) brushPreview = GenerateBrushThumbnail();
int lastBlur = feather;
int maxFeatherCount = Mathf.Max(heights.GetLength(0)/64, 2);
feather = EditorGUILayout.IntSlider("Feather", feather, 0, maxFeatherCount);
if (lastBlur != feather) brushPreview = GenerateBrushThumbnail();
GUILayout.EndVertical();
GUILayout.Box("", GUILayout.Width(64), GUILayout.Height(64));
Rect rect = GUILayoutUtility.GetLastRect();
GUI.DrawTexture(rect, brushPreview);
GUILayout.EndHorizontal();
offset = EditorGUILayout.FloatField("Height offset", offset);
EditorGUILayout.MinMaxSlider(new GUIContent("Spline range"), ref clipFrom, ref clipTo, 0f, 1f);
if (GUILayout.Button("Level")) CarveTerrain();
GUILayout.BeginHorizontal();
GUILayout.Label("Terrain heightmap:");
GUILayout.Label("Path heightmap:");
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Box("", GUILayout.Width((windowRect.width-10)/2), GUILayout.Height((windowRect.width - 10) / 2));
rect = GUILayoutUtility.GetLastRect();
GUI.DrawTexture(rect, basePreview);
GUILayout.Box("", GUILayout.Width((windowRect.width - 10) / 2), GUILayout.Height((windowRect.width - 10) / 2));
rect = GUILayoutUtility.GetLastRect();
GUI.DrawTexture(rect, drawPreview);
GUILayout.EndHorizontal();
if (promptSave)
{
GUILayout.BeginHorizontal();
if (GUILayout.Button("Revert")) RevertToBase();
if (GUILayout.Button("Apply")) SaveChanges();
GUILayout.EndHorizontal();
}
}
void OnFocus()
{
GetSplinesAndTerrain();
if (promptSave)
{
bool isChanged = false;
float[,] newHeights = terrain.terrainData.GetHeights(0, 0, terrain.terrainData.heightmapResolution, terrain.terrainData.heightmapResolution);
if (newHeights.GetLength(0) != heights.GetLength(0) || newHeights.GetLength(1) != heights.GetLength(1))
{
isChanged = true;
} else {
for (int x = 0; x < heights.GetLength(0); x++)
{
for (int y = 0; y < heights.GetLength(1); y++)
{
if (heights[x,y] != newHeights[x, y])
{
isChanged = true;
break;
}
}
}
}
if (isChanged)
{
if (EditorUtility.DisplayDialog("Preserve terrain ?", "The terrain has been edited from outside. Do you want to load the new height data? \r\n WARNING: Doing so will apply your leveled data to the terrain.", "Yes", "No"))
{
GetBase();
}
}
}
}
void OnLostFocus()
{
// RevertToBase();
}
void CarveTerrain()
{
float[,] drawLayer = new float[terrain.terrainData.heightmapResolution, terrain.terrainData.heightmapResolution];
float[,] alphaLayer = new float[terrain.terrainData.heightmapResolution, terrain.terrainData.heightmapResolution];
Undo.RecordObject(terrain, "Carve");
for (int i = 0; i < splines.Count; i++)
{
PaintHeightMap(terrain, splines[i], ref drawLayer, ref alphaLayer);
}
float[,] blurLayer = new float[drawLayer.GetLength(0), drawLayer.GetLength(1)];
GaussBlur(ref drawLayer, ref blurLayer, feather);
float[,] blurAlphaLayer = new float[drawLayer.GetLength(0), drawLayer.GetLength(1)];
GaussBlur(ref alphaLayer, ref blurAlphaLayer, feather);
float[,] finalLayer = new float[drawLayer.GetLength(0), drawLayer.GetLength(1)];
Color[] pixels = drawPreview.GetPixels();
drawPreview = new Texture2D(drawLayer.GetLength(0), drawLayer.GetLength(1));
for (int x = 0; x < drawLayer.GetLength(0); x++)
{
for (int y = 0; y < drawLayer.GetLength(1); y++)
{
finalLayer[x, y] = Mathf.Lerp(heights[x, y], blurLayer[x, y], blurAlphaLayer[x,y]);
pixels[x * drawPreview.width + y] = Color.Lerp(Color.black, Color.white, blurLayer[x, y]/maxDrawHeight*blurAlphaLayer[x,y]);
}
}
terrain.terrainData.SetHeights(0, 0, finalLayer);
drawPreview.SetPixels(pixels);
drawPreview.Apply();
}
Texture2D GenerateBrushThumbnail()
{
Texture2D tex = new Texture2D(65, 65, TextureFormat.RGB24, false);
Color[] colors = tex.GetPixels();
for (int i = 0; i < colors.Length; i++)
{
colors[i] = Color.white;
}
//Get the brush size, compared to the blur amount
int hmSize = ToHeightmapSize(size);
float percent = 1f;
if(hmSize > 0) percent = Mathf.Clamp01((float)(feather* feather) / hmSize);
int r = Mathf.RoundToInt(30 * (1f - percent));
int center = 32;
for (int x = center - 30; x <= center; x++)
{
for (int y = center - 30; y <= center; y++)
{
float value = (x - center) * (x - center) + (y - center) * (y - center);
int xSym = center - (x - center);
int ySym = center - (y - center);
if (value <= r * r)
{
colors[x * tex.width + y] = Color.black;
colors[xSym * tex.width + y] = Color.black;
colors[x * tex.width + ySym] = Color.black;
colors[xSym * tex.width + ySym] = Color.black;
} else
if (value <= 30 * 30 && value > r*r)
{
float rr = r * r;
float val = value - rr;
float div = 30 * 30 - rr;
float alpha = Mathf.Clamp01(val / div);
//Debug.Log(val + "/" + div + " = " + alpha);
Color col = Color.Lerp(Color.black, Color.white, alpha);
colors[x * tex.width + y] = col;
colors[xSym * tex.width + y] = col;
colors[x * tex.width + ySym] = col;
colors[xSym * tex.width + ySym] = col;
}
if (value <= 30 * 30 && value >= 29 * 29)
{
Color col = Color.Lerp(Color.gray, Color.white, 1f-percent);
colors[x * tex.width + y] = col;
colors[xSym * tex.width + y] = col;
colors[x * tex.width + ySym] = col;
colors[xSym * tex.width + ySym] = col;
}
}
}
tex.SetPixels(colors);
tex.Apply();
return tex;
}
void GetBase()
{
GetSplinesAndTerrain();
if (terrain == null) return;
heights = terrain.terrainData.GetHeights(0, 0, terrain.terrainData.heightmapResolution, terrain.terrainData.heightmapResolution);
basePreview = new Texture2D(heights.GetLength(0), heights.GetLength(1));
drawPreview = new Texture2D(heights.GetLength(0), heights.GetLength(1));
Color[] pixels = new Color[basePreview.width * basePreview.height];
Color[] blackPixels = new Color[basePreview.width * basePreview.height];
float maxHeight = 0f;
for (int x = 0; x < basePreview.width; x++)
{
for(int y = 0; y < basePreview.height; y++)
{
if (heights[x, y] > maxHeight) maxHeight = heights[x, y];
pixels[x * basePreview.width + y] = Color.Lerp(Color.black, Color.white, heights[x, y]);
blackPixels[x * basePreview.width + y] = Color.black;
}
}
if(maxHeight > 0f)
{
for (int x = 0; x < basePreview.width; x++)
{
for (int y = 0; y < basePreview.height; y++)
{
pixels[x * basePreview.width + y] /= maxHeight;
}
}
}
basePreview.SetPixels(pixels);
basePreview.Apply();
drawPreview.SetPixels(blackPixels);
drawPreview.Apply();
promptSave = false;
}
void SaveChanges()
{
GetBase();
}
void RevertToBase()
{
if (terrain == null) return;
terrain.terrainData.SetHeights(0, 0, heights);
heights = null;
}
void PaintHeightMap(Terrain terrain, SplineComputer computer, ref float[,] drawLayer, ref float[,] alphaLayer)
{
if (heights == null) GetBase();
SplineSample[] results = new SplineSample[computer.iterations];
computer.Evaluate(ref results, clipFrom, clipTo);
Draw(results, ref drawLayer, ref alphaLayer);
}
int ToHeightmapSize(float value)
{
float avgSize = (terrain.terrainData.size.x + terrain.terrainData.size.z) / 2f;
int result = Mathf.RoundToInt(value / avgSize * terrain.terrainData.heightmapResolution);
return result;
}
Point ToHeightmapCoords(Vector3 pos)
{
Vector3 terrainPos = pos - terrain.transform.position;
terrainPos.x /= terrain.terrainData.size.x;
terrainPos.z /= terrain.terrainData.size.z;
terrainPos.x = Mathf.Clamp01(terrainPos.x);
terrainPos.z = Mathf.Clamp01(terrainPos.z);
int x = Mathf.RoundToInt(terrainPos.z * terrain.terrainData.heightmapResolution);
int y = Mathf.RoundToInt(terrainPos.x * terrain.terrainData.heightmapResolution);
return new Point(x, y);
}
float ToHeightmapValue(float y)
{
float terrainHeight = y - terrain.transform.position.y;
terrainHeight /= terrain.terrainData.size.y;
return terrainHeight;
}
void PaintSegment(TerrainPaintPoint fromPoint, TerrainPaintPoint toPoint, ref float[,] layer, ref float[,] alphaLayer, bool writeAlpha = true, bool overWriteHeight = true)
{
//Flip the points if the forward one has a bigger radius so the lerp can work well
if (Vector2.Distance(fromPoint.leftPoint.vector, fromPoint.rightPoint.vector) < Vector2.Distance(toPoint.leftPoint.vector, toPoint.rightPoint.vector))
{
TerrainPaintPoint temp = fromPoint;
fromPoint = toPoint;
toPoint = temp;
}
List<Point> drawn = new List<Point>();
Vector2 currentPosition = fromPoint.leftPoint.vector;
Vector2 fromRight = fromPoint.rightPoint.vector;
float alphaStartPercent = 0f;
float alphaEndPercent = 1f;
if(feather > 0)
{
currentPosition += (fromPoint.leftPoint.vector - fromPoint.center.vector).normalized * feather * 4f;
fromRight += (fromPoint.rightPoint.vector - fromPoint.center.vector).normalized * feather * 4f;
float span = (fromPoint.leftPoint.vector - fromPoint.rightPoint.vector).magnitude / (fromRight - currentPosition).magnitude;
float rest = (1f - span) / 2f;
alphaStartPercent = rest;
alphaEndPercent = 1f - rest;
}
float armLength = Vector2.Distance(currentPosition, fromRight);
if (armLength < 1f) return;
while (true)
{
float armDistance = Vector2.Distance(currentPosition, fromRight);
float armPercent = 1f-armDistance / armLength;
//This can be optimized, take it outside of the cycle
Point fromPos = new Point(currentPosition);
Vector2 leftvector = toPoint.leftPoint.vector;
Vector2 rightVector = toPoint.rightPoint.vector;
if (feather > 0)
{
leftvector += (toPoint.leftPoint.vector - toPoint.center.vector).normalized * feather * 4f;
rightVector += (toPoint.rightPoint.vector - toPoint.center.vector).normalized * feather * 4f;
}
Vector2 toArm = Vector2.Lerp(leftvector, rightVector, armPercent);
Point toPos = new Point(toArm);
int dx = Mathf.Abs(toPos.x - fromPos.x), sx = fromPos.x < toPos.x ? 1 : -1;
int dy = -Mathf.Abs(toPos.y - fromPos.y), sy = fromPos.y < toPos.y ? 1 : -1;
int err = dx + dy, e2;
Point current = fromPos;
Vector2 target = new Vector2(toPos.x - fromPos.x, toPos.y - fromPos.y);
float fromHeight = fromPoint.GetHeight(armPercent);
float toHeight = toPoint.GetHeight(armPercent);
while (true)
{
if (current.x >= 0 && current.x < layer.GetLength(0) && current.y >= 0 && current.y < layer.GetLength(1))
{
if (overWriteHeight || layer[current.x, current.y] == 0f)
{
if (!ContainsPoint(ref drawn, current))
{
Vector2 currentDist = new Vector2(current.x - fromPos.x, current.y - fromPos.y);
float positionPercent = Mathf.Clamp01(currentDist.magnitude / target.magnitude);
float height = Mathf.Lerp(fromHeight, toHeight, positionPercent);
float alphaValue = 0f;
if (armPercent >= alphaStartPercent && armPercent <= alphaEndPercent) alphaValue = 1f;
if (writeAlpha) Plot(current.x, current.y, height, alphaValue, ref alphaLayer, ref layer);
else Plot(current.x, current.y, height, alphaLayer[current.x, current.y], ref alphaLayer, ref layer);
drawn.Add(current);
}
}
}
if (current.x == toPos.x && current.y == toPos.y) break;
e2 = 2 * err;
if (e2 > dy)
{
err += dy;
current.x += sx;
} else if (e2 < dx)
{
err += dx;
current.y += sy;
}
}
if (currentPosition == fromRight) break;
currentPosition = Vector2.MoveTowards(currentPosition, fromRight, 1f);
}
}
private bool ContainsPoint(ref List<Point> list, Point point)
{
for(int i = 0; i < list.Count; i++)
{
if (list[i].x == point.x && list[i].y == point.y) return true;
}
return false;
}
void Draw(SplineSample[] points, ref float[,] drawLayer, ref float[,] alphaLayer)
{
List<SplineSample> selectedPoints = new List<SplineSample>();
Point last = new Point();
//Filter out points that are too close to each other
for (int i = 0; i < points.Length; i++)
{
Point current = ToHeightmapCoords(points[i].position + points[i].up * offset);
if (i == 0 || i == points.Length-1)
{
last = new Point(current.x, current.y);
selectedPoints.Add(points[i]);
} else if (Vector2.Distance(new Vector2(current.x, current.y), new Vector2(last.x, last.y)) >= 1.5f)
{
selectedPoints.Add(points[i]);
last = new Point(current.x, current.y);
}
}
if (selectedPoints.Count <= 1) return;
TerrainPaintPoint[] paintPoints = new TerrainPaintPoint[selectedPoints.Count];
for (int i = 0; i < selectedPoints.Count; i++)
{
ConvertToPaintPoint(selectedPoints[i], ref paintPoints[i]);
}
//Paint the points
for (int i = 0; i < paintPoints.Length - 1; i++)
{
promptSave = true;
PaintSegment(paintPoints[i], paintPoints[i + 1], ref drawLayer, ref alphaLayer);
}
SplineSample exResult = selectedPoints[0];
exResult.position += exResult.position - selectedPoints[1].position;
TerrainPaintPoint exPoint = null;
ConvertToPaintPoint(exResult, ref exPoint);
PaintSegment(paintPoints[0], exPoint, ref drawLayer, ref alphaLayer, false, false);
exResult = selectedPoints[selectedPoints.Count-1];
exResult.position += exResult.position - selectedPoints[selectedPoints.Count - 2].position;
ConvertToPaintPoint(exResult, ref exPoint);
PaintSegment(paintPoints[paintPoints.Length-1], exPoint, ref drawLayer, ref alphaLayer, false, false);
//Extrapolate the ending and the begining
}
TerrainPaintPoint ConvertToPaintPoint(SplineSample result, ref TerrainPaintPoint paintPoint)
{
paintPoint = new TerrainPaintPoint();
Vector3 right = -Vector3.Cross(result.forward, result.up).normalized * size * 0.5f * result.size;
Vector3 leftPoint = result.position - right + result.up * offset;
Vector3 rightPoint = result.position + right + result.up * offset;
paintPoint.center = ToHeightmapCoords(result.position + result.up * offset);
paintPoint.leftPoint = ToHeightmapCoords(leftPoint);
paintPoint.rightPoint = ToHeightmapCoords(rightPoint);
paintPoint.leftHeight = ToHeightmapValue(leftPoint.y);
paintPoint.rightHeight = ToHeightmapValue(rightPoint.y);
paintPoint.floatDiameter = Vector2.Distance(new Vector2(leftPoint.x, leftPoint.z), new Vector2(rightPoint.x, rightPoint.z));
if (paintPoint.leftHeight > maxDrawHeight) maxDrawHeight = paintPoint.leftHeight;
if (paintPoint.rightHeight > maxDrawHeight) maxDrawHeight = paintPoint.rightHeight;
return paintPoint;
}
Point Project(Point fromPoint, Point toPoint, int x, int y)
{
Vector2 dir = toPoint.vector - fromPoint.vector;
Vector2 point = new Vector2(x, y);
dir.Normalize();
Vector2 v = point - fromPoint.vector;
float d = Vector2.Dot(v, dir);
return new Point(fromPoint.vector + dir * d);
}
void GaussBlur(ref float[,] source, ref float[,] target, int r)
{
int w = source.GetLength(0);
int h = source.GetLength(1);
int[] bxs = GBGetBoxes(r, 3);
float[] flatSource = new float[source.GetLength(0) * source.GetLength(1)];
float[] flatTarget = new float[source.GetLength(0) * source.GetLength(1)];
for (int x = 0; x < source.GetLength(0); x++)
{
for (int y = 0; y < source.GetLength(1); y++)
{
if (r == 0) target[x, y] = source[x, y];
else flatSource[x * source.GetLength(0) + y] = source[x, y];
}
}
if (r == 0) return;
BoxBlur(ref flatSource, ref flatTarget, w, h, (bxs[0] - 1) / 2);
BoxBlur(ref flatTarget, ref flatSource, w, h, (bxs[1] - 1) / 2);
BoxBlur(ref flatSource, ref flatTarget, w, h, (bxs[2] - 1) / 2);
for (int i = 0; i < flatSource.Length; i++)
{
int x = Mathf.FloorToInt(i / source.GetLength(0));
int y = i - x * source.GetLength(0);
target[x, y] = flatTarget[i];
}
}
int[] GBGetBoxes(int sigma, int n)
{
float wIdeal = Mathf.Sqrt((12 * sigma * sigma / n) + 1);
int wl = Mathf.FloorToInt(wIdeal); if (wl % 2 == 0) wl--;
int wu = wl + 2;
float mIdeal = (12 * sigma * sigma - n * wl * wl - 4 * n * wl - 3 * n) / (-4 * wl - 4);
float m = Mathf.Round(mIdeal);
int[] sizes = new int[n];
for (int i = 0; i < n; i++) sizes[i] = i < m ? wl : wu;
return sizes;
}
void BoxBlur(ref float[] source, ref float[] target, int w, int h, int r)
{
for (int i = 0; i < source.Length; i++) target[i] = source[i];
HorizontalBlur(ref target, ref source, w, h, r);
VerticalBlur(ref source, ref target, w, h, r);
}
void HorizontalBlur(ref float[] source, ref float[] target, int w, int h, int r)
{
float iarr = 1f / (r*2f + 1f);
for (int i = 0; i < h; i++)
{
int ti = i * w, li = ti, ri = ti + r;
float fv = source[ti], lv = source[ti + w - 1], val = (r + 1) * fv;
for (int j = 0; j < r; j++) val += source[ti + j];
for (int j = 0; j <= r; j++) { val += source[ri++] - fv; target[ti++] = val * iarr; }
for (int j = r + 1; j < w - r; j++) { val += source[ri++] - source[li++]; target[ti++] = val * iarr; }
for (int j = w - r; j < w; j++) { val += lv - source[li++]; target[ti++] = val * iarr; }
}
}
void VerticalBlur(ref float[] source, ref float[] target, int w, int h, int r)
{
float iarr = 1f / (r * 2f + 1f);
for (int i = 0; i < w; i++)
{
int ti = i, li = ti, ri = ti + r * w;
float fv = source[ti], lv = source[ti + w * (h - 1)], val = (r + 1) * fv;
for (var j = 0; j < r; j++) val += source[ti + j * w];
for (var j = 0; j <= r; j++) { val += source[ri] - fv; target[ti] = val * iarr; ri += w; ti += w; }
for (var j = r + 1; j < h - r; j++) { val += source[ri] - source[li]; target[ti] = val * iarr; li += w; ri += w; ti += w; }
for (var j = h - r; j < h; j++) { val += lv - source[li]; target[ti] = val * iarr; li += w; ti += w; }
}
}
private void Plot(int x, int y, float value, float alpha, ref float[,] alphaTarget, ref float[,] target)
{
if (x < 0 || x >= target.GetLength(0)) return;
if (y < 0 || y >= target.GetLength(1)) return;
if (value > target[x, y])
{
target[x, y] = value;
alphaTarget[x, y] = alpha;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 055df9d61bd3d9e4382c517846ff1502
timeCreated: 1457202793
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,415 @@
namespace Dreamteck.Splines.Editor
{
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using System.IO;
public class ObjectSpawnTool : SplineTool
{
internal class SpawnCollection
{
public class SpawnObject
{
public GameObject instance;
public GameObject source;
public SpawnObject(GameObject instance, GameObject source)
{
this.instance = instance;
this.source = source;
}
}
internal SplineComputer spline;
internal List<SpawnObject> objects = new List<SpawnObject>();
internal void Clear()
{
for (int i = 0; i < objects.Count; i++) Object.DestroyImmediate(objects[i].instance);
objects.Clear();
}
internal void Spawn(GameObject obj, Vector3 position, Quaternion rotation)
{
GameObject go = null;
bool isPrefab = PrefabUtility.GetPrefabAssetType(obj) != PrefabAssetType.NotAPrefab;
if (isPrefab) go = (GameObject)PrefabUtility.InstantiatePrefab(obj);
else go = Object.Instantiate(obj, position, rotation);
go.transform.parent = spline.transform;
objects.Add(new SpawnObject(go, obj));
}
internal void Destroy(int index)
{
Object.DestroyImmediate(objects[index].instance);
objects.RemoveAt(index);
}
internal SpawnCollection(SplineComputer spline)
{
this.spline = spline;
}
}
internal List<SpawnCollection> collections = new List<SpawnCollection>();
double clipFrom = 0.0, clipTo = 1.0;
List<GameObject> objects = new List<GameObject>();
int spawnCount = 1;
enum Iteration { Ordered, Random }
Iteration iteration = Iteration.Ordered;
private int offsetSeed = 0;
private int rotationSeed = 0;
private int scaleSeed = 0;
private int orderSeed = 0;
private float positionOffset = 0f;
private Vector2 randomSize = Vector2.one;
private Vector2 offset = Vector2.zero;
private Vector3 minRotationOffset = Vector3.zero;
private Vector3 maxRotationOffset = Vector3.zero;
private Vector3 minScaleMultiplier = Vector3.one;
private Vector3 maxScaleMultiplier = Vector3.one;
private bool randomizeOffset = false;
private bool useRandomOffsetRotation = false;
private bool shellOffset = true;
private bool applyRotation = true;
private bool applyScale = false;
bool uniform = false;
SplineSample result = new SplineSample();
System.Random orderRandom, offsetRandom, rotationRandom, scaleRandom;
public override string GetName()
{
return "Spawn Objects";
}
protected override string GetPrefix()
{
return "ObjectSpawnTool";
}
public override void Close()
{
base.Close();
for (int i = 0; i < splines.Count; i++) splines[i].onRebuild -= Rebuild;
if (promptSave)
{
if (EditorUtility.DisplayDialog("Save changes?", "You are about to close the Object Spawn Tool, do you want to save the generated objects?", "Yes", "No")) Save();
else Cancel();
}
else Cancel();
promptSave = false;
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui -= OnScene;
#else
SceneView.onSceneGUIDelegate -= OnScene;
#endif
}
public override void Open(EditorWindow window)
{
base.Open(window);
GetSplines();
collections.Clear();
for (int i = 0; i < splines.Count; i++)
{
collections.Add(new SpawnCollection(splines[i]));
splines[i].onRebuild += Rebuild;
}
Rebuild();
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui += OnScene;
#else
SceneView.onSceneGUIDelegate += OnScene;
#endif
}
void OnScene(SceneView current)
{
for (int i = 0; i < collections.Count; i++)
{
if (collections[i].spline != null) DSSplineDrawer.DrawSplineComputer(collections[i].spline);
}
}
protected override void OnSplineAdded(SplineComputer spline)
{
base.OnSplineAdded(spline);
collections.Add(new SpawnCollection(spline));
spline.onRebuild += Rebuild;
Rebuild();
}
protected override void OnSplineRemoved(SplineComputer spline)
{
base.OnSplineRemoved(spline);
for (int i = 0; i < collections.Count; i++)
{
if (collections[i].spline == spline)
{
collections[i].Clear();
collections.RemoveAt(i);
spline.onRebuild -= Rebuild;
Rebuild();
return;
}
}
}
public override void Draw(Rect windowRect)
{
base.Draw(windowRect);
if (splines.Count == 0)
{
EditorGUILayout.HelpBox("No spline selected! Select an object with a SplineComputer component.", MessageType.Warning);
return;
}
EditorGUI.BeginChangeCheck();
ClipUI(ref clipFrom, ref clipTo);
uniform = EditorGUILayout.Toggle("Uniform Samples", uniform);
EditorGUILayout.Space();
float labelWidth = EditorGUIUtility.labelWidth;
float fieldWidth = EditorGUIUtility.fieldWidth;
EditorGUIUtility.labelWidth = 0;
EditorGUIUtility.fieldWidth = 0;
EditorGUILayout.BeginVertical();
for (int i = 0; i < objects.Count; i++)
{
EditorGUILayout.BeginHorizontal();
objects[i] = (GameObject)EditorGUILayout.ObjectField(objects[i], typeof(GameObject), true);
if (GUILayout.Button("x", GUILayout.Width(20)))
{
objects.RemoveAt(i);
i--;
Rebuild();
Repaint();
continue;
}
if (i > 0)
{
if (GUILayout.Button("▲", GUILayout.Width(20)))
{
GameObject temp = objects[i - 1];
objects[i - 1] = objects[i];
objects[i] = temp;
Rebuild();
}
}
if (i < objects.Count - 1)
{
if (GUILayout.Button("▼", GUILayout.Width(20)))
{
GameObject temp = objects[i + 1];
objects[i + 1] = objects[i];
objects[i] = temp;
Rebuild();
}
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndVertical();
GameObject newObj = null;
newObj = (GameObject)EditorGUILayout.ObjectField("Add Object", newObj, typeof(GameObject), true);
if (newObj != null)
{
objects.Add(newObj);
Rebuild();
}
EditorGUILayout.Space();
EditorGUIUtility.labelWidth = labelWidth;
EditorGUIUtility.fieldWidth = fieldWidth;
bool hasObj = false;
for (int i = 0; i < objects.Count; i++)
{
if (objects[i] != null)
{
hasObj = true;
break;
}
}
if (hasObj) spawnCount = EditorGUILayout.IntField("Spawn count", spawnCount);
else spawnCount = 0;
iteration = (Iteration)EditorGUILayout.EnumPopup("Iteration", iteration);
if (iteration == Iteration.Random) orderSeed = EditorGUILayout.IntField("Order Seed", orderSeed);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Transform", EditorStyles.boldLabel);
applyRotation = EditorGUILayout.Toggle("Apply Rotation", applyRotation);
if (applyRotation)
{
EditorGUI.indentLevel++;
minRotationOffset = EditorGUILayout.Vector3Field("Min. Rotation Offset", minRotationOffset);
maxRotationOffset = EditorGUILayout.Vector3Field("Max. Rotation Offset", maxRotationOffset);
rotationSeed = EditorGUILayout.IntField("Rotation Seed", rotationSeed);
EditorGUI.indentLevel--;
}
applyScale = EditorGUILayout.Toggle("Apply Scale", applyScale);
if (applyScale)
{
EditorGUI.indentLevel++;
minScaleMultiplier = EditorGUILayout.Vector3Field("Min. Scale Multiplier", minScaleMultiplier);
maxScaleMultiplier = EditorGUILayout.Vector3Field("Max. Scale Multiplier", maxScaleMultiplier);
scaleSeed = EditorGUILayout.IntField("Scale Seed", scaleSeed);
EditorGUI.indentLevel--;
}
positionOffset = EditorGUILayout.Slider("Evaluate Offset", positionOffset, -1f, 1f);
offset = EditorGUILayout.Vector2Field("Offset", offset);
randomizeOffset = EditorGUILayout.Toggle("Randomize Offset", randomizeOffset);
if (randomizeOffset)
{
randomSize = EditorGUILayout.Vector2Field("Size", randomSize);
offsetSeed = EditorGUILayout.IntField("Offset Seed", offsetSeed);
shellOffset = EditorGUILayout.Toggle("Shell", shellOffset);
useRandomOffsetRotation = EditorGUILayout.Toggle("Apply offset rotation", useRandomOffsetRotation);
}
if (EditorGUI.EndChangeCheck())
{
promptSave = true;
Rebuild();
}
EditorGUILayout.BeginHorizontal();
if(collections.Count > 0)
{
if (GUILayout.Button("Save"))
{
Save();
}
if (GUILayout.Button("Cancel"))
{
Cancel();
}
} else
{
if (GUILayout.Button("New")) Open(windowInstance);
}
EditorGUILayout.EndHorizontal();
}
protected override void Save()
{
base.Save();
//register created object undo for each object in collections
collections.Clear();
//Set scene dirty
}
protected override void Cancel()
{
base.Cancel();
foreach (SpawnCollection collection in collections) collection.Clear();
collections.Clear();
}
void InitializeRandomization()
{
orderRandom = new System.Random(orderSeed);
if (randomizeOffset) offsetRandom = new System.Random(offsetSeed);
if(applyRotation) rotationRandom = new System.Random(rotationSeed);
if(applyScale) scaleRandom = new System.Random(scaleSeed);
}
protected override void Rebuild()
{
base.Rebuild();
if (objects.Count == 0) return;
InitializeRandomization();
foreach (SpawnCollection c in collections)
{
if(c == null) continue;
if (c.spline == null || spawnCount <= 0)
{
c.Clear();
continue;
}
HandleCollection(c);
}
}
void HandleCollection(SpawnCollection collection)
{
collection.Clear();
if (collection.spline == null) return;
while(collection.objects.Count > spawnCount && collection.objects.Count >= 0) collection.Destroy(collection.objects.Count - 1);
int orderIndex = 0;
while (collection.objects.Count < spawnCount)
{
switch (iteration)
{
case Iteration.Ordered:
collection.Spawn(objects[orderIndex], Vector3.zero, Quaternion.identity);
orderIndex++;
if (orderIndex >= objects.Count) orderIndex = 0;
break;
case Iteration.Random:
collection.Spawn(objects[orderRandom.Next(objects.Count)], Vector3.zero, Quaternion.identity);
break;
}
}
float splineLength = 0f;
if (uniform) splineLength = collection.spline.CalculateLength() * (float)(clipTo - clipFrom);
for (int i = 0; i < spawnCount; i++)
{
double percent = 0.0;
if(spawnCount > 1) percent = (double)i / (spawnCount - 1);
double evaluate = 0.0;
if (uniform) evaluate = collection.spline.Travel(clipFrom, splineLength * (float)percent, Spline.Direction.Forward);
else evaluate = DMath.Lerp(clipFrom, clipTo, percent);
//Handle uniform splines
evaluate += positionOffset;
if (evaluate > 1f) evaluate -= 1f;
else if (evaluate < 0f) evaluate += 1f;
collection.spline.Evaluate(evaluate, ref result);
HandleObject(collection.objects[i]);
}
}
void HandleObject(SpawnCollection.SpawnObject obj)
{
Transform instanceTransform = obj.instance.transform;
Transform sourceTransform = obj.source.transform;
Vector3 right = result.right;
instanceTransform.position = result.position;
instanceTransform.position += -right * offset.x + result.up * offset.y;
Quaternion offsetRot = Quaternion.Euler(minRotationOffset);
if (applyRotation)
{
offsetRot = Quaternion.Euler(Mathf.Lerp(minRotationOffset.x, maxRotationOffset.x, (float)rotationRandom.NextDouble()), Mathf.Lerp(minRotationOffset.y, maxRotationOffset.y, (float)rotationRandom.NextDouble()), Mathf.Lerp(minRotationOffset.z, maxRotationOffset.z, (float)rotationRandom.NextDouble()));
instanceTransform.rotation = result.rotation * offsetRot;
}
if (randomizeOffset)
{
float distance = (float)offsetRandom.NextDouble();
float angleInRadians = (float)offsetRandom.NextDouble() * 360f * Mathf.Deg2Rad;
Vector2 randomCircle = new Vector2(distance * Mathf.Cos(angleInRadians), distance * Mathf.Sin(angleInRadians));
if (shellOffset) randomCircle.Normalize();
else randomCircle = Vector2.ClampMagnitude(randomCircle, 1f);
instanceTransform.position += randomCircle.x * right * randomSize.x * result.size * 0.5f + randomCircle.y * result.up * randomSize.y * result.size * 0.5f;
if (useRandomOffsetRotation) instanceTransform.rotation = Quaternion.LookRotation(result.forward, instanceTransform.position - result.position) * offsetRot;
}
if (applyScale)
{
Vector3 scale = sourceTransform.localScale * result.size;
scale.x *= Mathf.Lerp(minScaleMultiplier.x, maxScaleMultiplier.x, (float)scaleRandom.NextDouble());
scale.y *= Mathf.Lerp(minScaleMultiplier.y, maxScaleMultiplier.y, (float)scaleRandom.NextDouble());
scale.z *= Mathf.Lerp(minScaleMultiplier.z, maxScaleMultiplier.z, (float)scaleRandom.NextDouble());
instanceTransform.localScale = scale;
} else instanceTransform.localScale = sourceTransform.localScale;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3e6dd39825fd0634e9f633f90371a585
timeCreated: 1456934986
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,208 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
namespace Dreamteck.Splines
{
public class SplineTool
{
protected List<SplineComputer> splines = new List<SplineComputer>();
protected bool promptSave = false;
protected EditorWindow windowInstance = null;
public virtual string GetName()
{
return "Tool";
}
public virtual void Open(EditorWindow window)
{
windowInstance = window;
GetSplines();
}
public virtual void Close()
{
if(promptSave) ClosingDialog();
}
private void ClosingDialog()
{
if (EditorUtility.DisplayDialog("Unsaved Changes", ClosingDialogText(), "Yes", "No")) Save();
else Cancel();
}
protected virtual string ClosingDialogText()
{
return "There are unsaved changes. Do you wish to save them?";
}
protected virtual void Save()
{
promptSave = false;
}
protected virtual void Cancel()
{
promptSave = false;
}
protected virtual string GetPrefix()
{
return "SplineTool";
}
public virtual void Draw(Rect rect)
{
//EditorGUILayout.LabelField("Spline User", EditorStyles.boldLabel);
EditorGUILayout.LabelField("Selected Splines", EditorStyles.boldLabel);
for (int i = 0; i < splines.Count; i++)
{
SplineComputer lastComputer = splines[i];
splines[i] = (SplineComputer)EditorGUILayout.ObjectField(splines[i], typeof(SplineComputer), true);
if (splines[i] == null)
{
splines.RemoveAt(i);
i--;
OnSplineRemoved(lastComputer);
continue;
}
if (lastComputer != splines[i])
{
for (int j = 0; j < splines.Count; j++)
{
if (j == i) continue;
if (splines[j] == splines[i])
{
splines[i] = lastComputer;
break;
}
}
}
}
SplineComputer newComp = null;
newComp = (SplineComputer)EditorGUILayout.ObjectField(newComp, typeof(SplineComputer), true);
if(newComp != null)
{
for (int i = 0; i < splines.Count; i++)
{
if (splines[i] == newComp)
{
newComp = null;
break;
}
}
if (newComp != null)
{
splines.Add(newComp);
OnSplineAdded(newComp);
}
}
EditorGUILayout.Space();
}
protected virtual void OnSplineAdded(SplineComputer spline)
{
}
protected virtual void OnSplineRemoved(SplineComputer spline)
{
}
protected void ClipUI(SplineUser user)
{
float fclipFrom = (float)user.clipFrom, fclipTo = (float)user.clipTo;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.MinMaxSlider(new GUIContent("Clip range:"), ref fclipFrom, ref fclipTo, 0f, 1f);
EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(30));
user.clipFrom = EditorGUILayout.FloatField(fclipFrom);
user.clipTo = EditorGUILayout.FloatField(fclipTo);
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndHorizontal();
}
protected void ClipUI(ref double from, ref double to)
{
float fclipFrom = (float)from, fclipTo = (float)to;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.MinMaxSlider(new GUIContent("Clip range:"), ref fclipFrom, ref fclipTo, 0f, 1f);
EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(30));
from = EditorGUILayout.FloatField(fclipFrom);
to = EditorGUILayout.FloatField(fclipTo);
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndHorizontal();
}
protected void SaveCancelUI()
{
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Save")) Save();
if (GUILayout.Button("Cancel")) Cancel();
EditorGUILayout.EndHorizontal();
}
protected virtual void Rebuild()
{
}
protected void Repaint()
{
windowInstance.Repaint();
}
protected void GetSplines()
{
splines.Clear();
for (int i = 0; i < Selection.gameObjects.Length; i++)
{
splines.Add(Selection.gameObjects[i].GetComponent<SplineComputer>());
}
}
protected float LoadFloat(string name, float d)
{
return EditorPrefs.GetFloat(GetPrefix() + "_" + name, d);
}
protected string LoadString(string name, string d)
{
return EditorPrefs.GetString(GetPrefix() + "_" + name, d);
}
protected bool LoadBool(string name, bool d)
{
return EditorPrefs.GetBool(GetPrefix() + "_" + name, d);
}
protected int LoadInt(string name, int d)
{
return EditorPrefs.GetInt(GetPrefix() + "_" + name, d);
}
protected void SaveFloat(string name, float value)
{
EditorPrefs.SetFloat(GetPrefix() + "_" + name, value);
}
protected void SaveString(string name, string value)
{
EditorPrefs.SetString(GetPrefix() + "_" + name, value);
}
protected void SaveBool(string name, bool value)
{
EditorPrefs.SetBool(GetPrefix() + "_" + name, value);
}
protected void SaveInt(string name, int value)
{
EditorPrefs.SetInt(GetPrefix() + "_" + name, value);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d43ab6043eb5d1a429ba1bfac215730e
timeCreated: 1450642283
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,75 @@
namespace Dreamteck.Splines.Editor
{
using UnityEngine;
using System;
using System.Collections.Generic;
using UnityEditor;
public class SplineToolsWindow : EditorWindow
{
private static SplineTool[] tools;
private int toolIndex = -1;
private Vector2 scroll = Vector2.zero;
private const float menuWidth = 150f;
[MenuItem("Window/Dreamteck/Splines/Tools")]
static void Init()
{
SplineToolsWindow window = (SplineToolsWindow)EditorWindow.GetWindow(typeof(SplineToolsWindow));
window.Show();
}
private void Awake()
{
titleContent = new GUIContent("Spline Tools");
name = "Spline tools";
autoRepaintOnSceneChange = true;
List<Type> types = FindDerivedClasses.GetAllDerivedClasses(typeof(SplineTool));
tools = new SplineTool[types.Count];
int count = 0;
foreach (Type t in types)
{
tools[count] = (SplineTool)Activator.CreateInstance(t);
count++;
}
if (toolIndex >= 0 && toolIndex < tools.Length) tools[toolIndex].Open(this);
}
void OnDestroy()
{
if (toolIndex >= 0 && toolIndex < tools.Length) tools[toolIndex].Close();
}
void OnGUI()
{
if (tools == null) Awake();
GUI.color = new Color(0f, 0f, 0f, 0.15f);
GUI.DrawTexture(new Rect(0, 0, menuWidth, position.height), SplineEditorGUI.white, ScaleMode.StretchToFill);
GUI.color = Color.white;
GUILayout.BeginHorizontal();
GUILayout.BeginScrollView(scroll, GUILayout.Width(menuWidth), GUILayout.Height(position.height-10));
if (tools == null) Init();
SplineEditorGUI.SetHighlightColors(SplinePrefs.highlightColor, SplinePrefs.highlightContentColor);
for (int i = 0; i < tools.Length; i ++)
{
if (SplineEditorGUI.EditorLayoutSelectableButton(new GUIContent(tools[i].GetName()), true, toolIndex == i))
{
if (toolIndex >= 0 && toolIndex < tools.Length) tools[toolIndex].Close();
toolIndex = i;
if (toolIndex < tools.Length) tools[toolIndex].Open(this);
}
}
GUILayout.EndScrollView();
if(toolIndex >= 0 && toolIndex < tools.Length)
{
GUILayout.BeginVertical();
tools[toolIndex].Draw(new Rect(menuWidth, 0, position.width - menuWidth - 5f, position.height - 10));
GUILayout.EndVertical();
}
GUILayout.EndHorizontal();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e87a0b749a684c34c84ee3aab5993592
timeCreated: 1450551681
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,118 @@
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
namespace Dreamteck.Splines
{
public class UpdateTool : SplineTool
{
protected GameObject obj;
protected ObjectController spawner;
private string updated = "";
public override string GetName()
{
return "Update Components";
}
protected override string GetPrefix()
{
return "UpdateTool";
}
public override void Draw(Rect windowRect)
{
if (GUILayout.Button("Update All Spline Components"))
{
updated = "";
UpdateComputers();
UpdateNodes();
UpdateUsers();
}
if (GUILayout.Button("Update SplineUsers"))
{
updated = "";
UpdateUsers();
}
if (GUILayout.Button("Update MeshGenerators"))
{
updated = "";
UpdateMeshGenerators();
}
if (GUILayout.Button("Update SplineComputers"))
{
updated = "";
UpdateComputers();
}
if (GUILayout.Button("Update Nodes In Scene"))
{
updated = "";
UpdateNodes();
}
EditorGUILayout.Space();
GUILayout.Label(updated);
}
private void UpdateNodes()
{
Node[] nodes = GameObject.FindObjectsOfType<Node>();
EditorUtility.ClearProgressBar();
for (int i = 0; i < nodes.Length; i++)
{
EditorUtility.DisplayProgressBar("Updating nodes", "Updating node " + nodes[i].name, (float)i / (nodes.Length - 1));
nodes[i].UpdateConnectedComputers();
EditorUtility.SetDirty(nodes[i]);
updated += i + " - " + nodes[i].name + System.Environment.NewLine;
}
EditorUtility.ClearProgressBar();
if (nodes.Length == 0) updated += System.Environment.NewLine+"No active Nodes found in the scene.";
}
private void UpdateUsers()
{
SplineUser[] users = GameObject.FindObjectsOfType<SplineUser>();
EditorUtility.ClearProgressBar();
for (int i = 0; i < users.Length; i++)
{
EditorUtility.DisplayProgressBar("Updating users", "Updating user " + users[i].name, (float)i/(users.Length-1));
users[i].Rebuild();
EditorUtility.SetDirty(users[i]);
updated += i + " - " + users[i].name + System.Environment.NewLine;
}
EditorUtility.ClearProgressBar();
if (users.Length == 0) updated += System.Environment.NewLine+"No active SplineUsers found in the scene.";
}
private void UpdateMeshGenerators()
{
MeshGenerator[] users = GameObject.FindObjectsOfType<MeshGenerator>();
EditorUtility.ClearProgressBar();
for (int i = 0; i < users.Length; i++)
{
EditorUtility.DisplayProgressBar("Updating mesh generators", "Updating generator " + users[i].name, (float)i / (users.Length - 1));
users[i].Rebuild();
EditorUtility.SetDirty(users[i]);
updated += i + " - " + users[i].name + System.Environment.NewLine;
}
EditorUtility.ClearProgressBar();
if (users.Length == 0) updated += System.Environment.NewLine + "No active MeshGenerators found in the scene.";
}
private void UpdateComputers()
{
SplineComputer[] computers = GameObject.FindObjectsOfType<SplineComputer>();
EditorUtility.ClearProgressBar();
for (int i = 0; i < computers.Length; i++)
{
EditorUtility.DisplayProgressBar("Updating spline computers", "Updating computer " + computers[i].name, (float)i / (computers.Length - 1));
computers[i].RebuildImmediate();
EditorUtility.SetDirty(computers[i]);
updated += i + " - " + computers[i].name + System.Environment.NewLine;
}
EditorUtility.ClearProgressBar();
if (computers.Length == 0) updated += System.Environment.NewLine+"No active SplineComputers found in the scene.";
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1b86089eb8b849648b253ed7b5be27a7
timeCreated: 1456934986
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: