Add Unity3D projects

This commit is contained in:
2024-03-09 19:25:59 +00:00
parent 1c71f24fab
commit 829289c881
4626 changed files with 441247 additions and 0 deletions

View File

@ -0,0 +1,196 @@
#if UNITY_EDITOR
#region "Imports"
using UnityEngine;
using UnityEditor;
using RoadArchitect;
#endregion
namespace RoadArchitect
{
/// <summary> Provides the menu items inside the editor </summary>
public class EditorMenu
{
/// <summary> Creates the road system. </summary>
[MenuItem("Window/Road Architect/Create road system")]
public static void CreateRoadSystem()
{
Object[] allRoadSystemObjects = GameObject.FindObjectsOfType<RoadSystem>();
int nextCount = (allRoadSystemObjects.Length + 1);
allRoadSystemObjects = null;
GameObject newRoadSystemObject = new GameObject("RoadArchitectSystem" + nextCount.ToString());
RoadSystem newRoadSystem = newRoadSystemObject.AddComponent<RoadSystem>();
//Add road for new road system.
newRoadSystem.AddRoad(true);
GameObject masterIntersectionsObject = new GameObject("Intersections");
masterIntersectionsObject.transform.parent = newRoadSystemObject.transform;
}
/// <summary> Add road to gameobject. Not sure if this is necessary. </summary>
[MenuItem("Window/Road Architect/Add road")]
public static void AddRoad()
{
Object[] allRoadSystemObjects = GameObject.FindObjectsOfType<RoadSystem>();
if (allRoadSystemObjects != null && allRoadSystemObjects.Length == 0)
{
CreateRoadSystem();
return;
}
else
{
RoadSystem firstRoadSystem = (RoadSystem)allRoadSystemObjects[0];
Selection.activeGameObject = firstRoadSystem.AddRoad();
}
}
/// <summary> Updates all roads. Used when things get out of sync. </summary>
[MenuItem("Window/Road Architect/Update All Roads")]
public static void UpdateAllRoads()
{
Road[] allRoadObjects = GameObject.FindObjectsOfType<Road>();
int roadCount = allRoadObjects.Length;
Road singleRoad = null;
SplineC[] tPiggys = null;
if (roadCount > 1)
{
tPiggys = new SplineC[roadCount - 1];
}
for (int count = 0; count < roadCount; count++)
{
singleRoad = allRoadObjects[count];
if (count > 0)
{
tPiggys[count - 1] = singleRoad.spline;
}
}
singleRoad = allRoadObjects[0];
if (tPiggys != null && tPiggys.Length > 0)
{
singleRoad.PiggyBacks = tPiggys;
}
singleRoad.UpdateRoad();
}
/// <summary> Show the help screen. </summary>
[MenuItem("Window/Road Architect/Help")]
public static void ShowHelpWindow()
{
HelpWindow helpWindow = EditorWindow.GetWindow<HelpWindow>();
helpWindow.Initialize();
}
/// <summary> WARNING: Only call this on an empty scene that has some terrains on it. We are not responsbile for data loss if this function is called by the user. </summary>
[MenuItem("Window/Road Architect/Testing/Run all unit tests (caution)")]
public static void TestProgram()
{
if (EditorUtility.DisplayDialog("Warning !", "This will delete your RoadSystem 1, 6, 7, 8 and 9 and will create a lot of test roads.", "OK", "Cancel"))
{
RoadArchitect.Tests.UnitTests.RoadArchitectUnitTests();
}
}
[MenuItem("Window/Road Architect/Testing/Run unit test 1-5 (caution)")]
public static void Test1To5()
{
if (EditorUtility.DisplayDialog("Warning !", "This will delete your first RoadSystem and will create a lot of test roads.", "OK", "Cancel"))
{
RoadArchitect.Tests.UnitTests.RoadArchitectUnitTest1To5();
}
}
[MenuItem("Window/Road Architect/Testing/Run unit test 6 (caution)")]
public static void Test6()
{
if (EditorUtility.DisplayDialog("Warning !", "This will delete your sixth RoadSystem and will create a lot of test roads.", "OK", "Cancel"))
{
RoadArchitect.Tests.UnitTests.RoadArchitectUnitTest6();
}
}
[MenuItem("Window/Road Architect/Testing/Run unit test 7 (caution)")]
public static void Test7()
{
if (EditorUtility.DisplayDialog("Warning !", "This will delete your seventh RoadSystem and will create a lot of test roads.", "OK", "Cancel"))
{
RoadArchitect.Tests.UnitTests.RoadArchitectUnitTest7();
}
}
[MenuItem("Window/Road Architect/Testing/Run unit test 8 (caution)")]
public static void Test8()
{
if (EditorUtility.DisplayDialog("Warning !", "This will delete your eigth RoadSystem and will create a test roads.", "OK", "Cancel"))
{
RoadArchitect.Tests.UnitTests.RoadArchitectUnitTest8();
}
}
[MenuItem("Window/Road Architect/Testing/Run unit test 9 (caution)")]
public static void Test9()
{
if (EditorUtility.DisplayDialog("Warning !", "This will delete your RoadArchitectSystem9 and will create test roads.", "OK", "Cancel"))
{
RoadArchitect.Tests.UnitTests.RoadArchitectUnitTest9();
}
}
[MenuItem("Window/Road Architect/Testing/Run unit test 10 (caution)")]
public static void Test10()
{
if (EditorUtility.DisplayDialog("Warning !", "This will delete your RoadArchitectSystem10 and will create test roads.", "OK", "Cancel"))
{
RoadArchitect.Tests.UnitTests.RoadArchitectUnitTest10();
}
}
/// <summary> WARNING: Only call this on an empty scene that has some terrains on it. We are not responsbile for data loss if this function is called by the user. </summary>
[MenuItem("Window/Road Architect/Testing/Clean up tests (caution)")]
public static void TestCleanup()
{
if (EditorUtility.DisplayDialog("Warning !", "This will delete your RoadSystem 1, 6, 7, 8 and 9", "OK", "Cancel"))
{
RoadArchitect.Tests.UnitTests.CleanupAllTests();
}
}
/// <summary> Get code line count for RA project </summary>
[MenuItem("Window/Road Architect/Testing/Get line count of RA")]
public static void TestCodeCount()
{
string mainDir = System.IO.Path.Combine(System.Environment.CurrentDirectory, RoadEditorUtility.GetBasePathForIO());
string[] files = System.IO.Directory.GetFiles(mainDir, "*.cs", System.IO.SearchOption.AllDirectories);
int lineCount = 0;
foreach (string file in files)
{
lineCount += System.IO.File.ReadAllLines(file).Length;
}
Debug.Log(string.Format("{0:n0}", lineCount) + " lines of code in Road Architect.");
}
[MenuItem("Window/Road Architect/Report a Bug")]
public static void ReportBug()
{
Application.OpenURL("https://github.com/FritzsHero/RoadArchitect/issues");
}
}
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 09c94f91ab2d0d34c9c464536e8633e9
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,60 @@
#if UNITY_EDITOR
#region "Imports"
using UnityEditor;
using UnityEngine;
#endregion
namespace RoadArchitect
{
/// <summary> Used for progress information for other areas of RA. </summary>
public class EditorProgressWindow : EditorWindow
{
private float seconds = 10.0f;
private float startValue = 0f;
private float progress = 0f;
private static void Init()
{
EditorProgressWindow window = (EditorProgressWindow)EditorWindow.GetWindow(typeof(EditorProgressWindow));
window.Show();
}
private void OnGUI()
{
seconds = EditorGUILayout.FloatField("Time to wait:", seconds);
if (GUILayout.Button("Display bar"))
{
if (seconds < 1)
{
Debug.LogError("Seconds should be bigger than 1");
return;
}
startValue = (float)EditorApplication.timeSinceStartup;
}
if (progress < seconds)
{
EditorUtility.DisplayProgressBar(
"Simple Progress Bar",
"Shows a progress bar for the given seconds",
progress / seconds);
}
else
{
EngineIntegration.ClearProgressBar();
}
progress = (float)(EditorApplication.timeSinceStartup - startValue);
}
private void OnInspectorUpdate()
{
Repaint();
}
}
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 36611904ee7524a45afea00db85e5039
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,32 @@
#if UNITY_EDITOR
using UnityEngine;
namespace RoadArchitect
{
public class EditorUtilities
{
/// <summary> Opens the loacally stored manual </summary>
public static void OpenOfflineManual()
{
Application.OpenURL(System.Environment.CurrentDirectory.Replace(@"\", "/") + "/" + RoadEditorUtility.GetBasePath() + "/RoadArchitectManual.htm");
}
/// <summary> Loads the _texture from _path if necessary </summary>
public static void LoadTexture<T>(ref T _texture, string _path) where T : Texture
{
_texture = EngineIntegration.LoadAssetFromPath<T>(_path);
}
public static void DrawLine(float _spacing = 4f, float _size = 1f)
{
//Horizontal bar
GUILayout.Space(_spacing);
GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(_size));
GUILayout.Space(_spacing);
}
}
}
#endif

View File

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

View File

@ -0,0 +1,70 @@
#if UNITY_EDITOR
#region "Imports"
using UnityEngine;
using UnityEditor;
#endregion
namespace RoadArchitect
{
public class HelpWindow : EditorWindow
{
private void OnGUI()
{
EditorStyles.label.wordWrap = true;
EditorStyles.miniLabel.wordWrap = true;
EditorGUILayout.LabelField("Road Architect Help", EditorStyles.boldLabel);
GUILayout.Space(12f);
EditorGUILayout.LabelField("Please visit the online manual for help.");
GUILayout.Space(4f);
if (GUILayout.Button("Click here to open online manual", EditorStyles.toolbarButton, GUILayout.Width(310f)))
{
Application.OpenURL("https://github.com/FritzsHero/RoadArchitect/wiki");
}
EditorGUILayout.LabelField("https://github.com/FritzsHero/RoadArchitect/wiki");
if (GUILayout.Button("Click here to open offline manual", EditorStyles.toolbarButton, GUILayout.Width(310f)))
{
EditorUtilities.OpenOfflineManual();
}
GUILayout.Space(12f);
EditorGUILayout.LabelField("Please visit us or reach out to us on Github (links below) with any questions or comments.");
EditorGUILayout.LabelField("If you encounter Bugs or have a Feature Suggestion, you can submit them on the following sites:");
GUILayout.Space(12f);
if (GUILayout.Button("RoadArchitect Repository", EditorStyles.toolbarButton, GUILayout.Width(310f)))
{
Application.OpenURL("https://github.com/FritzsHero/RoadArchitect");
}
EditorGUILayout.LabelField("https://github.com/FritzsHero/RoadArchitect");
GUILayout.Space(4f);
if (GUILayout.Button("RoadArchitect Issues", EditorStyles.toolbarButton, GUILayout.Width(310f)))
{
Application.OpenURL("https://github.com/FritzsHero/RoadArchitect/issues");
}
EditorGUILayout.LabelField("https://github.com/FritzsHero/RoadArchitect/issues");
GUILayout.Space(12f);
}
public void Initialize()
{
Rect rect = new Rect(340, 170, 400, 400);
position = rect;
Show();
titleContent.text = "Help Info";
}
}
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 83a696e187e0572418fa95bc2a0cecd0
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,395 @@
/*
Based on ObjExporter.cs, this "wrapper" lets you export to .OBJ directly from the editor menu.
Use by selecting the objects you want to export, and select the appropriate menu item from "Custom->Export".
Exported models are put in a folder called "ExportedObj" in the root of your project.
Textures should also be copied and placed in the same folder.
*/
#if UNITY_EDITOR
#region "Imports"
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;
#endregion
namespace RoadArchitect
{
public class ObjExporter : ScriptableObject
{
private static int vertexOffset = 0;
private static int normalOffset = 0;
private static int uvOffset = 0;
//User should probably be able to change this. It is currently left as an excercise for
//the reader.
private static string targetFolder = "ExportedObj";
private struct ObjMaterial
{
public string name;
public string textureName;
}
private static string MeshToString(MeshFilter _meshFilter, Dictionary<string, ObjMaterial> _materialList)
{
Mesh mesh = _meshFilter.sharedMesh;
Renderer renderer = _meshFilter.GetComponent<Renderer>();
//Material[] mats = mf.renderer.sharedMaterials;
Material[] materials = renderer.sharedMaterials;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("g ").Append(_meshFilter.name).Append("\n");
foreach (Vector3 lv in mesh.vertices)
{
Vector3 wv = _meshFilter.transform.TransformPoint(lv);
//This is sort of ugly - inverting x-component since we're in
//a different coordinate system than "everyone" is "used to".
stringBuilder.Append(string.Format("v {0} {1} {2}\n", -wv.x, wv.y, wv.z));
}
stringBuilder.Append("\n");
foreach (Vector3 lv in mesh.normals)
{
Vector3 wv = _meshFilter.transform.TransformDirection(lv);
stringBuilder.Append(string.Format("vn {0} {1} {2}\n", -wv.x, wv.y, wv.z));
}
stringBuilder.Append("\n");
foreach (Vector3 v in mesh.uv)
{
stringBuilder.Append(string.Format("vt {0} {1}\n", v.x, v.y));
}
for (int material = 0; material < mesh.subMeshCount; material++)
{
stringBuilder.Append("\n");
stringBuilder.Append("usemtl ").Append(materials[material].name).Append("\n");
stringBuilder.Append("usemap ").Append(materials[material].name).Append("\n");
//See if this material is already in the materiallist.
try
{
ObjMaterial objMaterial = new ObjMaterial();
objMaterial.name = materials[material].name;
if (materials[material].mainTexture)
{
objMaterial.textureName = EngineIntegration.GetAssetPath(materials[material].mainTexture);
}
else
{
objMaterial.textureName = null;
}
_materialList.Add(objMaterial.name, objMaterial);
}
catch (ArgumentException)
{
//Already in the dictionary
}
int[] triangles = mesh.GetTriangles(material);
for (int index = 0; index < triangles.Length; index += 3)
{
//Because we inverted the x-component, we also needed to alter the triangle winding.
stringBuilder.Append(string.Format("f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}\n",
triangles[index] + 1 + vertexOffset, triangles[index + 1] + 1 + normalOffset, triangles[index + 2] + 1 + uvOffset));
}
}
vertexOffset += mesh.vertices.Length;
normalOffset += mesh.normals.Length;
uvOffset += mesh.uv.Length;
return stringBuilder.ToString();
}
private static void Clear()
{
vertexOffset = 0;
normalOffset = 0;
uvOffset = 0;
}
private static Dictionary<string, ObjMaterial> PrepareFileWrite()
{
Clear();
return new Dictionary<string, ObjMaterial>();
}
private static void MaterialsToFile(Dictionary<string, ObjMaterial> _materialList, string _folder, string _fileName)
{
using (StreamWriter streamWriter = new StreamWriter(Path.Combine(_folder, _fileName) + ".mtl"))
{
foreach (KeyValuePair<string, ObjMaterial> kvp in _materialList)
{
streamWriter.Write("\n");
streamWriter.Write("newmtl {0}\n", kvp.Key);
streamWriter.Write("Ka 0.6 0.6 0.6\n");
streamWriter.Write("Kd 0.6 0.6 0.6\n");
streamWriter.Write("Ks 0.9 0.9 0.9\n");
streamWriter.Write("d 1.0\n");
streamWriter.Write("Ns 0.0\n");
streamWriter.Write("illum 2\n");
if (kvp.Value.textureName != null)
{
string destinationFile = kvp.Value.textureName;
int stripIndex = destinationFile.LastIndexOf(Path.PathSeparator);
if (stripIndex >= 0)
{
destinationFile = destinationFile.Substring(stripIndex + 1).Trim();
}
string relativeFile = destinationFile;
destinationFile = Path.Combine(_folder, destinationFile);
//Debug.Log("Copying texture from " + kvp.Value.textureName + " to " + destinationFile);
try
{
//Copy the source file
File.Copy(kvp.Value.textureName, destinationFile);
}
catch
{
}
streamWriter.Write("map_Kd {0}", relativeFile);
}
streamWriter.Write("\n\n\n");
}
}
}
private static void MeshToFile(MeshFilter _meshFilter, string _folder, string _fileName)
{
Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();
using (StreamWriter streamWriter = new StreamWriter(Path.Combine(_folder, _fileName) + ".obj"))
{
streamWriter.Write("mtllib ./" + _fileName + ".mtl\n");
streamWriter.Write(MeshToString(_meshFilter, materialList));
}
MaterialsToFile(materialList, _folder, _fileName);
}
private static void MeshesToFile(MeshFilter[] _meshFilter, string _folder, string _fileName)
{
Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();
using (StreamWriter streamWriter = new StreamWriter(Path.Combine(_folder, _fileName) + ".obj"))
{
streamWriter.Write("mtllib ./" + _fileName + ".mtl\n");
for (int index = 0; index < _meshFilter.Length; index++)
{
streamWriter.Write(MeshToString(_meshFilter[index], materialList));
}
}
MaterialsToFile(materialList, _folder, _fileName);
}
private static bool CreateTargetFolder()
{
try
{
System.IO.Directory.CreateDirectory(targetFolder);
}
catch
{
EditorUtility.DisplayDialog("Error!", "Failed to create target folder!", "");
return false;
}
return true;
}
[MenuItem("Window/Road Architect/Export/Export all MeshFilters in selection to separate OBJs")]
private static void ExportSelectionToSeparate()
{
if (!CreateTargetFolder())
{
return;
}
Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);
if (selection.Length == 0)
{
EditorUtility.DisplayDialog("No source object selected!", "Please select one or more target objects", "");
return;
}
int exportedObjects = 0;
for (int index = 0; index < selection.Length; index++)
{
Component[] meshfilter = selection[index].GetComponentsInChildren<MeshFilter>();
for (int m = 0; m < meshfilter.Length; m++)
{
exportedObjects++;
MeshToFile((MeshFilter)meshfilter[m], targetFolder, selection[index].name + "_" + index + "_" + m);
}
}
if (exportedObjects > 0)
{
EditorUtility.DisplayDialog("Objects exported", "Exported " + exportedObjects + " objects", "");
}
else
{
EditorUtility.DisplayDialog("Objects not exported", "Make sure at least some of your selected objects have mesh filters!", "");
}
}
[MenuItem("Window/Road Architect/Export/Export whole selection to single OBJ")]
private static void ExportWholeSelectionToSingle()
{
if (!CreateTargetFolder())
{
return;
}
Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);
if (selection.Length == 0)
{
EditorUtility.DisplayDialog("No source object selected!", "Please select one or more target objects", "");
return;
}
int exportedObjects = 0;
ArrayList mfList = new ArrayList();
for (int index = 0; index < selection.Length; index++)
{
Component[] meshfilter = selection[index].GetComponentsInChildren<MeshFilter>();
for (int m = 0; m < meshfilter.Length; m++)
{
exportedObjects++;
mfList.Add(meshfilter[m]);
}
}
if (exportedObjects > 0)
{
MeshFilter[] meshFilters = new MeshFilter[mfList.Count];
for (int index = 0; index < mfList.Count; index++)
{
meshFilters[index] = (MeshFilter)mfList[index];
}
string sceneName = UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().name;
//string filename = EditorApplication.currentScene + "_" + exportedObjects;
string filename = sceneName + "_" + exportedObjects;
int stripIndex = filename.LastIndexOf(Path.PathSeparator);
if (stripIndex >= 0)
{
filename = filename.Substring(stripIndex + 1).Trim();
}
MeshesToFile(meshFilters, targetFolder, filename);
EditorUtility.DisplayDialog("Objects exported", "Exported " + exportedObjects + " objects to " + filename, "");
}
else
EditorUtility.DisplayDialog("Objects not exported", "Make sure at least some of your selected objects have mesh filters!", "");
}
[MenuItem("Window/Road Architect/Export/Export each selected to single OBJ")]
private static void ExportEachSelectionToSingle()
{
if (!CreateTargetFolder())
{
return;
}
Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);
if (selection.Length == 0)
{
EditorUtility.DisplayDialog("No source object selected!", "Please select one or more target objects", "");
return;
}
int exportedObjects = 0;
for (int index = 0; index < selection.Length; index++)
{
Component[] meshfilter = selection[index].GetComponentsInChildren<MeshFilter>();
MeshFilter[] mf = new MeshFilter[meshfilter.Length];
for (int m = 0; m < meshfilter.Length; m++)
{
exportedObjects++;
mf[m] = (MeshFilter)meshfilter[m];
}
MeshesToFile(mf, targetFolder, selection[index].name + "_" + index);
}
if (exportedObjects > 0)
{
EditorUtility.DisplayDialog("Objects exported", "Exported " + exportedObjects + " objects", "");
}
else
{
EditorUtility.DisplayDialog("Objects not exported", "Make sure at least some of your selected objects have mesh filters!", "");
}
}
[MenuItem("Window/Road Architect/Export/Exporters by Hrafnkell Freyr Hlooversson from Unity3D wiki")]
private static void OpenLink()
{
Application.OpenURL("http://wiki.unity3d.com/index.php?title=ObjExporter");
}
}
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cd895ddcc671fce4897906afe978103f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f2d67b50d8bfdea40b03587f29096fa8
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: db6a849a9f10a2b4c947989f1bbf77a5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,378 @@
#if UNITY_EDITOR
#region "Imports"
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
#endregion
namespace RoadArchitect
{
[CustomEditor(typeof(RoadSystem))]
public class RoadSystemEditor : Editor
{
#region "Vars"
//Main target for this editor file:
private RoadSystem roadSystem;
//Serialized properties:
private SerializedProperty isAllowingUpdates;
private SerializedProperty isTempMultithreading;
private SerializedProperty isTempSaveMeshAssets;
//Editor only variables:
private bool isInitialized;
// //Editor only camera variables:
private RoadIntersection[] intersections = null;
private int intersectionIndex = 0;
private SplineN[] bridges = null;
private int bridgesIndex = 0;
private bool isBridgeInitialized = false;
private bool isIntersectionInitialized = false;
private bool isEditorCameraFlipped = false;
private float cameraZoomFactor = 1f;
private float cameraHeightOffset = 1f;
private bool isCameraCustomRotated = false;
private Vector3 customCameraRotation = new Vector3(0.5f, 0f, -0.5f);
//Editor only graphic variables:
private Texture2D loadButtonBG = null;
private Texture2D loadButtonBGGlow = null;
private Texture2D warningLabelBG;
private GUIStyle warningLabelStyle;
private GUIStyle loadButton = null;
#endregion
private void OnEnable()
{
roadSystem = (RoadSystem)target;
isAllowingUpdates = serializedObject.FindProperty("isAllowingRoadUpdates");
isTempMultithreading = serializedObject.FindProperty("isMultithreaded");
isTempSaveMeshAssets = serializedObject.FindProperty("isSavingMeshes");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorStyles.label.wordWrap = true;
if(!isInitialized)
{
isInitialized = true;
InitChecks();
}
//Add road button:
RoadArchitect.EditorUtilities.DrawLine();
if (GUILayout.Button("Add road", loadButton, GUILayout.Width(128f)))
{
Selection.activeObject = roadSystem.AddRoad();
}
RoadArchitect.EditorUtilities.DrawLine();
//Update all roads button:
if (GUILayout.Button("Update all roads", EditorStyles.miniButton, GUILayout.Width(120f)))
{
roadSystem.UpdateAllRoads();
}
isAllowingUpdates.boolValue = EditorGUILayout.Toggle("Allow Roads to Update", roadSystem.isAllowingRoadUpdates);
//Multi-threading input:
isTempMultithreading.boolValue = EditorGUILayout.Toggle("Multi-threading enabled", roadSystem.isMultithreaded);
if (isTempMultithreading.boolValue != roadSystem.isMultithreaded)
{
roadSystem.UpdateAllRoadsMultiThreadedOption(isTempMultithreading.boolValue);
}
//Save mesh assets input:
isTempSaveMeshAssets.boolValue = EditorGUILayout.Toggle("Save mesh assets: ", roadSystem.isSavingMeshes);
if (isTempSaveMeshAssets.boolValue != roadSystem.isSavingMeshes)
{
roadSystem.UpdateAllRoadsSavingMeshesOption(isTempSaveMeshAssets.boolValue);
}
if (roadSystem.isSavingMeshes)
{
GUILayout.Label("WARNING: Saving meshes as assets is very slow and can increase road generation time by several minutes.", warningLabelStyle);
}
//Online manual button:
GUILayout.Space(4f);
if (GUILayout.Button("Online manual", EditorStyles.miniButton, GUILayout.Width(120f)))
{
Application.OpenURL("https://github.com/MicroGSD/RoadArchitect/wiki");
}
//Offline manual button:
GUILayout.Space(4f);
if (GUILayout.Button("Offline manual", EditorStyles.miniButton, GUILayout.Width(120f)))
{
RoadArchitect.EditorUtilities.OpenOfflineManual();
}
if (roadSystem.editorPlayCamera == null)
{
roadSystem.EditorCameraSetSingle();
}
RoadArchitect.EditorUtilities.DrawLine();
//View intersection
IntersectionView();
//View bridges
BridgeView();
if(bridges.Length > 0 || intersections.Length > 0)
{
EditorGUILayout.LabelField("* Hotkeys only work when this RoadArchitectSystem object is selected and the scene view has focus", EditorStyles.miniLabel);
}
//Hotkey check:
DoHotKeyCheck();
if (GUI.changed)
{
serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(roadSystem);
}
}
private void InitChecks()
{
string basePath = RoadEditorUtility.GetBasePath();
RoadArchitect.EditorUtilities.LoadTexture(ref warningLabelBG, basePath + "/Editor/Icons/WarningLabelBG.png");
RoadArchitect.EditorUtilities.LoadTexture(ref loadButtonBG, basePath + "/Editor/Icons/otherbg.png");
RoadArchitect.EditorUtilities.LoadTexture(ref loadButtonBGGlow, basePath + "/Editor/Icons/otherbg2.png");
if (loadButton == null)
{
loadButton = new GUIStyle(GUI.skin.button);
loadButton.contentOffset = new Vector2(0f, 1f);
loadButton.normal.textColor = new Color(1f, 1f, 1f, 1f);
loadButton.normal.background = loadButtonBG;
loadButton.active.background = loadButtonBGGlow;
loadButton.focused.background = loadButtonBGGlow;
loadButton.hover.background = loadButtonBGGlow;
loadButton.fixedHeight = 16f;
loadButton.fixedWidth = 128f;
loadButton.padding = new RectOffset(0, 0, 0, 0);
}
if (warningLabelStyle == null)
{
warningLabelStyle = new GUIStyle(GUI.skin.textArea);
warningLabelStyle.normal.textColor = Color.red;
warningLabelStyle.active.textColor = Color.red;
warningLabelStyle.hover.textColor = Color.red;
warningLabelStyle.normal.background = warningLabelBG;
warningLabelStyle.active.background = warningLabelBG;
warningLabelStyle.hover.background = warningLabelBG;
warningLabelStyle.padding = new RectOffset(8, 8, 8, 8);
}
}
private void IntersectionView()
{
//View intersection
if (!isIntersectionInitialized)
{
isIntersectionInitialized = true;
intersections = roadSystem.GetComponentsInChildren<RoadIntersection>();
}
if (intersections.Length > 0)
{
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("View next intersection", GUILayout.Width(150f)))
{
IncrementIntersection();
}
EditorGUILayout.LabelField("Hotkey K");
EditorGUILayout.EndHorizontal();
}
}
private void IncrementIntersection()
{
if (intersections.Length > 0)
{
intersectionIndex += 1;
if (intersectionIndex >= intersections.Length)
{
intersectionIndex = 0;
}
ShowIntersection();
}
}
private void BridgeView()
{
//View bridges
if (!isBridgeInitialized)
{
isBridgeInitialized = true;
SplineN[] nodes = roadSystem.transform.GetComponentsInChildren<SplineN>();
List<SplineN> nodeList = new List<SplineN>();
foreach (SplineN node in nodes)
{
if (node.isBridgeStart && node.isBridgeMatched)
{
nodeList.Add(node);
}
}
bridges = nodeList.ToArray();
bridgesIndex = 0;
}
if (bridges.Length > 0)
{
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("View next bridge", GUILayout.Width(150f)))
{
IncrementBridge();
}
EditorGUILayout.LabelField("Hotkey L");
EditorGUILayout.EndHorizontal();
if (EditorApplication.isPlaying)
{
bool isCameraFlipped = EditorGUILayout.Toggle("Flip camera Y:", isEditorCameraFlipped);
if (isCameraFlipped != isEditorCameraFlipped)
{
isEditorCameraFlipped = isCameraFlipped;
ShowBridge();
}
float changeChecker = EditorGUILayout.Slider("Zoom factor:", cameraZoomFactor, 0.02f, 10f);
if (!RootUtils.IsApproximately(changeChecker, cameraZoomFactor, 0.001f))
{
cameraZoomFactor = changeChecker;
ShowBridge();
}
changeChecker = EditorGUILayout.Slider("Height offset:", cameraHeightOffset, 0f, 8f);
if (!RootUtils.IsApproximately(changeChecker, cameraHeightOffset, 0.001f))
{
cameraHeightOffset = changeChecker;
ShowBridge();
}
bool isCustomRotated = EditorGUILayout.Toggle("Custom camera rot:", isCameraCustomRotated);
if (isCustomRotated != isCameraCustomRotated)
{
isCameraCustomRotated = isCustomRotated;
ShowBridge();
}
if (isCameraCustomRotated)
{
Vector3 changedRotation = default(Vector3);
changedRotation.x = EditorGUILayout.Slider("Rotation X:", customCameraRotation.x, -1f, 1f);
changedRotation.z = EditorGUILayout.Slider("Rotation Z:", customCameraRotation.z, -1f, 1f);
if (changedRotation != customCameraRotation)
{
customCameraRotation = changedRotation;
ShowBridge();
}
}
}
}
}
private void IncrementBridge()
{
if (bridges.Length > 0)
{
bridgesIndex += 1;
if (bridgesIndex >= bridges.Length)
{
bridgesIndex = 0;
}
ShowBridge();
}
}
private void ShowIntersection()
{
if (EditorApplication.isPlaying && roadSystem.editorPlayCamera != null)
{
roadSystem.editorPlayCamera.transform.position = intersections[intersectionIndex].transform.position + new Vector3(-40f, 20f, -40f);
roadSystem.editorPlayCamera.transform.rotation = Quaternion.LookRotation(intersections[intersectionIndex].transform.position - (intersections[intersectionIndex].transform.position + new Vector3(-40f, 20f, -40f)));
}
else
{
SceneView.lastActiveSceneView.pivot = intersections[intersectionIndex].transform.position;
SceneView.lastActiveSceneView.Repaint();
}
}
private void ShowBridge()
{
if (EditorApplication.isPlaying && roadSystem.editorPlayCamera != null)
{
Vector3 bridgePosition = ((bridges[bridgesIndex].pos - bridges[bridgesIndex].bridgeCounterpartNode.pos) * 0.5f) + bridges[bridgesIndex].bridgeCounterpartNode.pos;
float bridgeLength = Vector3.Distance(bridges[bridgesIndex].pos, bridges[bridgesIndex].bridgeCounterpartNode.pos);
//Rotation:
Vector3 cameraRotation = Vector3.Cross((bridges[bridgesIndex].pos - bridges[bridgesIndex].bridgeCounterpartNode.pos), Vector3.up);
if (isCameraCustomRotated)
{
cameraRotation = customCameraRotation;
}
else
{
cameraRotation = cameraRotation.normalized;
}
//Calc offset:
Vector3 bridgeOffset = cameraRotation * (bridgeLength * 0.5f * cameraZoomFactor);
//Height offset:
bridgeOffset.y = Mathf.Lerp(20f, 120f, (bridgeLength * 0.001f)) * cameraZoomFactor * cameraHeightOffset;
roadSystem.editorPlayCamera.transform.position = bridgePosition + bridgeOffset;
roadSystem.editorPlayCamera.transform.rotation = Quaternion.LookRotation(bridgePosition - (bridgePosition + bridgeOffset));
}
else
{
SceneView.lastActiveSceneView.pivot = bridges[bridgesIndex].transform.position;
SceneView.lastActiveSceneView.Repaint();
}
}
public void OnSceneGUI()
{
DoHotKeyCheck();
}
private void DoHotKeyCheck()
{
Event current = Event.current;
if (current.type == EventType.KeyDown)
{
if (current.keyCode == KeyCode.K)
{
IncrementIntersection();
}
else if (current.keyCode == KeyCode.L)
{
IncrementBridge();
}
}
}
}
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d698b63effc4b914e93d9826206bee51
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,297 @@
#if UNITY_EDITOR
#region "Imports"
using UnityEngine;
using UnityEditor;
using System.Text.RegularExpressions;
using System.IO;
#endregion
namespace RoadArchitect
{
public class SaveWindow : EditorWindow
{
public enum WindowTypeEnum
{
Extrusion,
Edge,
BridgeWizard
};
#region "Vars"
private WindowTypeEnum windowType = WindowTypeEnum.Extrusion;
private Texture2D temp2D = null;
private Texture2D temp2D2 = null;
private string thumbString = "";
private string desc = "";
private string fileName = "DefaultName";
private string displayName = "DefaultName";
private string displayName2 = "";
private string titleText = "";
// private string tPath = "";
private bool isFileExisting = false;
private bool isBridge = false;
private Splination.SplinatedMeshMaker[] tSMMs = null;
private EdgeObjects.EdgeObjectMaker[] tEOMs = null;
private string path = "";
private const int titleLabelHeight = 20;
#endregion
private void OnGUI()
{
GUILayout.Space(4f);
EditorGUILayout.LabelField(titleText, EditorStyles.boldLabel);
temp2D2 = (Texture2D)EditorGUILayout.ObjectField("Square thumb (optional):", temp2D, typeof(Texture2D), false);
if (temp2D2 != temp2D)
{
temp2D = temp2D2;
thumbString = EngineIntegration.GetAssetPath(temp2D);
}
if (path.Length < 5)
{
path = RootUtils.GetDirLibrary();
}
EditorGUILayout.LabelField("Short description (optional):");
desc = EditorGUILayout.TextArea(desc, GUILayout.Height(40f));
displayName2 = EditorGUILayout.TextField("Display name:", displayName);
if (string.Compare(displayName2, displayName) != 0)
{
displayName = displayName2;
SanitizeFilename();
CheckFileExistence();
}
if (isFileExisting)
{
EditorGUILayout.LabelField("File exists already!", EditorStyles.miniLabel);
}
if (windowType == WindowTypeEnum.Edge)
{
EditorGUILayout.LabelField(Path.Combine(path, "EOM" + fileName + ".rao"), EditorStyles.miniLabel);
}
else if (windowType == WindowTypeEnum.Extrusion)
{
EditorGUILayout.LabelField(Path.Combine(path, "ESO" + fileName + ".rao"), EditorStyles.miniLabel);
}
else
{
EditorGUILayout.LabelField(Path.Combine(Path.Combine(path, "Groups"), fileName + ".rao"), EditorStyles.miniLabel);
}
GUILayout.Space(4f);
isBridge = EditorGUILayout.Toggle("Is bridge related:", isBridge);
GUILayout.Space(8f);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Cancel"))
{
Close();
}
if (windowType == WindowTypeEnum.Extrusion)
{
DoExtrusion();
}
else if (windowType == WindowTypeEnum.Edge)
{
DoEdgeObject();
}
else if (windowType == WindowTypeEnum.BridgeWizard)
{
DoBridge();
}
EditorGUILayout.EndHorizontal();
}
private void DoExtrusion()
{
if (GUILayout.Button("Save extrusion"))
{
SanitizeFilename();
tSMMs[0].isBridge = isBridge;
tSMMs[0].thumbString = thumbString;
tSMMs[0].desc = desc;
tSMMs[0].displayName = displayName;
tSMMs[0].SaveToLibrary(fileName, false);
Close();
}
}
private void DoEdgeObject()
{
if (GUILayout.Button("Save edge object"))
{
SanitizeFilename();
tEOMs[0].isBridge = isBridge;
tEOMs[0].thumbString = thumbString;
tEOMs[0].desc = desc;
tEOMs[0].displayName = displayName;
tEOMs[0].SaveToLibrary(fileName, false);
Close();
}
}
private void DoBridge()
{
if (GUILayout.Button("Save group"))
{
SanitizeFilename();
WizardObject WO = new WizardObject();
WO.thumbString = thumbString;
WO.desc = desc;
WO.displayName = displayName;
WO.fileName = fileName;
WO.isBridge = isBridge;
WO.isDefault = false;
RoadUtility.SaveNodeObjects(ref tSMMs, ref tEOMs, ref WO);
Close();
}
}
private void SanitizeFilename()
{
Regex regex = new Regex("[^a-zA-Z0-9 -]");
fileName = regex.Replace(displayName, "");
fileName = fileName.Replace(" ", "-");
fileName = fileName.Replace("_", "-");
}
private void CheckFileExistence()
{
if (windowType == WindowTypeEnum.Edge)
{
if (File.Exists(Path.Combine(path, "EOM" + fileName + ".rao")))
{
isFileExisting = true;
}
else
{
isFileExisting = false;
}
}
else if (windowType == WindowTypeEnum.Extrusion)
{
if (File.Exists(Path.Combine(path, "ESO" + fileName + ".rao")))
{
isFileExisting = true;
}
else
{
isFileExisting = false;
}
}
else
{
if (File.Exists(Path.Combine(Path.Combine(path, "B"), fileName + ".rao")))
{
isFileExisting = true;
}
else
{
isFileExisting = false;
}
}
}
#region "Init"
public void Initialize(ref Rect _rect, WindowTypeEnum _windowType, SplineN _node, Splination.SplinatedMeshMaker _SMM = null, EdgeObjects.EdgeObjectMaker _EOM = null)
{
int rectHeight = 300;
int rectWidth = 360;
float Rx = ((float)_rect.width / 2f) - ((float)rectWidth / 2f) + _rect.x;
float Ry = ((float)_rect.height / 2f) - ((float)rectHeight / 2f) + _rect.y;
if (Rx < 0)
{
Rx = _rect.x;
}
if (Ry < 0)
{
Ry = _rect.y;
}
if (Rx > (_rect.width + _rect.x))
{
Rx = _rect.x;
}
if (Ry > (_rect.height + _rect.y))
{
Ry = _rect.y;
}
Rect rect = new Rect(Rx, Ry, rectWidth, rectHeight);
if (rect.width < 300)
{
rect.width = 300;
rect.x = _rect.x;
}
if (rect.height < 300)
{
rect.height = 300;
rect.y = _rect.y;
}
position = rect;
windowType = _windowType;
Show();
titleContent.text = "Save";
if (windowType == WindowTypeEnum.Extrusion)
{
titleText = "Save extrusion";
tSMMs = new Splination.SplinatedMeshMaker[1];
tSMMs[0] = _SMM;
if (_SMM != null)
{
fileName = _SMM.objectName;
displayName = fileName;
}
}
else if (windowType == WindowTypeEnum.Edge)
{
titleText = "Save edge object";
tEOMs = new EdgeObjects.EdgeObjectMaker[1];
tEOMs[0] = _EOM;
if (_EOM != null)
{
fileName = _EOM.objectName;
displayName = fileName;
}
}
else if (windowType == WindowTypeEnum.BridgeWizard)
{
isBridge = true;
tSMMs = _node.SplinatedObjects.ToArray();
tEOMs = _node.EdgeObjects.ToArray();
titleText = "Save group";
fileName = "Group" + Random.Range(0, 10000).ToString();
displayName = fileName;
}
if (path.Length < 5)
{
path = RootUtils.GetDirLibrary();
}
CheckFileExistence();
}
#endregion
}
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3d228ad4f1407c8439cc06fbea6105f3
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,41 @@
#if UNITY_EDITOR
#region "Imports"
using UnityEngine;
using UnityEditor;
#endregion
namespace RoadArchitect
{
[CustomEditor(typeof(SplineC))]
public class SplineCEditor : Editor
{
private SplineC spline;
private int browseNode = 0;
private void OnEnable()
{
spline = (SplineC)target;
}
public override void OnInspectorGUI()
{
#region NodeBrowser
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Browse to node:", EditorStyles.boldLabel);
browseNode = EditorGUILayout.IntField(browseNode);
if (GUILayout.Button("Browse"))
{
if (browseNode < spline.nodes.Count)
{
Selection.objects = new Object[1] { spline.nodes[browseNode] };
}
}
EditorGUILayout.EndHorizontal();
#endregion
}
}
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3d58d1757d440da4d888627fc1b0d993
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,27 @@
#if UNITY_EDITOR
#region "Imports"
using UnityEditor;
#endregion
namespace RoadArchitect
{
[CustomEditor(typeof(SplineF))]
public class SplineFEditor : Editor
{
private SplineF splineF;
private void OnEnable()
{
splineF = (SplineF)target;
}
public override void OnInspectorGUI()
{
//Intentionally left empty.
}
}
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1dd0c2cac8820d84ea773a41ba7cde2f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,27 @@
#if UNITY_EDITOR
#region "Imports"
using UnityEditor;
#endregion
namespace RoadArchitect
{
[CustomEditor(typeof(SplineI))]
public class SplineIEditor : Editor
{
private SplineI splineI;
private void OnEnable()
{
splineI = (SplineI)target;
}
public override void OnInspectorGUI()
{
//Intentionally left empty.
}
}
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6ca689edb7ae35b43b50bd73fc934e96
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0b18264adf12b2e4fad840ded7592b28
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,304 @@
#if UNITY_EDITOR
#region "Imports"
using UnityEngine;
using UnityEditor;
#endregion
namespace RoadArchitect
{
[CustomEditor(typeof(RoadTerrain))]
public class TerrainEditor : Editor
{
#region "Vars"
private RoadTerrain terrain;
//Serialized properties:
SerializedProperty splatImageWidth;
SerializedProperty splatImageHeight;
SerializedProperty splatBackgroundColor;
SerializedProperty splatForegroundColor;
SerializedProperty splatWidth;
SerializedProperty isSkippingBridges;
SerializedProperty isSkippingTunnels;
SerializedProperty isSplatSingleRoad;
SerializedProperty splatSingleChoiceIndex;
SerializedProperty roadSingleChoiceUID;
//Editor only variables:
private bool isInitialized;
private string[] roads = null;
private string[] roadsString = null;
private Texture refreshButtonText = null;
private GUIStyle imageButton = null;
private Texture2D loadButtonBG = null;
private Texture2D loadButtonBGGlow = null;
private GUIStyle loadButton = null;
SplatImageResoMatchingEnum splatReso = SplatImageResoMatchingEnum.None;
#endregion
public enum SplatImageResoMatchingEnum
{
None,
Match512x512,
Match1024x1024,
Match2048x2048,
Match4096x4096,
MatchHeightmapResolution,
MatchDetailResolution,
MatchTerrainSize
};
private static string[] TheSplatResoOptions = new string[]{
"Select option to match resolution",
"512 x 512",
"1024 x 1024",
"2048 x 2048",
"4096 x 4096",
"Match heightmap resolution",
"Match detail resolution",
"Match terrain size"
};
private void OnEnable()
{
terrain = (RoadTerrain)target;
splatImageWidth = serializedObject.FindProperty("splatResoWidth");
splatImageHeight = serializedObject.FindProperty("splatResoHeight");
splatBackgroundColor = serializedObject.FindProperty("splatBackground");
splatForegroundColor = serializedObject.FindProperty("splatForeground");
splatWidth = serializedObject.FindProperty("splatWidth");
isSkippingBridges = serializedObject.FindProperty("isSplatSkipBridges");
isSkippingTunnels = serializedObject.FindProperty("isSplatSkipTunnels");
isSplatSingleRoad = serializedObject.FindProperty("isSplatSingleRoad");
splatSingleChoiceIndex = serializedObject.FindProperty("splatSingleChoiceIndex");
roadSingleChoiceUID = serializedObject.FindProperty("roadSingleChoiceUID");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
if(!isInitialized)
{
isInitialized = true;
InitNullChecks();
}
RoadArchitect.EditorUtilities.DrawLine();
EditorGUILayout.BeginHorizontal();
//Main label:
EditorGUILayout.LabelField("Splat map generation:", EditorStyles.boldLabel);
//Online manual button:
if (GUILayout.Button("Online manual", EditorStyles.miniButton, GUILayout.Width(120f)))
{
Application.OpenURL("https://github.com/MicroGSD/RoadArchitect/wiki");
}
EditorGUILayout.EndHorizontal();
GUILayout.Space(6f);
//Splat Resolution input:
splatImageWidth.intValue = terrain.splatResoWidth;
splatImageHeight.intValue = terrain.splatResoHeight;
EditorGUILayout.BeginHorizontal();
splatReso = (SplatImageResoMatchingEnum)EditorGUILayout.Popup("Match resolutions:", (int)splatReso, TheSplatResoOptions);
if (GUILayout.Button(refreshButtonText, imageButton, GUILayout.Width(16f)))
{
splatImageWidth.intValue = 1024;
splatImageHeight.intValue = 1024;
}
EditorGUILayout.EndHorizontal();
if (splatReso != SplatImageResoMatchingEnum.None)
{
if (splatReso == SplatImageResoMatchingEnum.MatchHeightmapResolution)
{
splatImageWidth.intValue = terrain.terrain.terrainData.heightmapResolution;
splatImageHeight.intValue = terrain.terrain.terrainData.heightmapResolution;
}
else if (splatReso == SplatImageResoMatchingEnum.MatchDetailResolution)
{
splatImageWidth.intValue = terrain.terrain.terrainData.detailResolution;
splatImageHeight.intValue = terrain.terrain.terrainData.detailResolution;
}
else if (splatReso == SplatImageResoMatchingEnum.MatchTerrainSize)
{
splatImageWidth.intValue = (int)terrain.terrain.terrainData.size.x;
splatImageHeight.intValue = (int)terrain.terrain.terrainData.size.z;
}
else if (splatReso == SplatImageResoMatchingEnum.Match512x512)
{
splatImageWidth.intValue = 512;
splatImageHeight.intValue = 512;
}
else if (splatReso == SplatImageResoMatchingEnum.Match1024x1024)
{
splatImageWidth.intValue = 1024;
splatImageHeight.intValue = 1024;
}
else if (splatReso == SplatImageResoMatchingEnum.Match2048x2048)
{
splatImageWidth.intValue = 2048;
splatImageHeight.intValue = 2048;
}
else if (splatReso == SplatImageResoMatchingEnum.Match4096x4096)
{
splatImageWidth.intValue = 4096;
splatImageHeight.intValue = 4096;
}
splatReso = SplatImageResoMatchingEnum.None;
}
//Splat image width input:
splatImageWidth.intValue = EditorGUILayout.IntField("Splat image width:", splatImageWidth.intValue);
//Splat image height input:
splatImageHeight.intValue = EditorGUILayout.IntField("Splat image height:", splatImageHeight.intValue);
//Splat background color input:
EditorGUILayout.BeginHorizontal();
splatBackgroundColor.colorValue = EditorGUILayout.ColorField("Splat background:", terrain.splatBackground);
//Default button:
if (GUILayout.Button(refreshButtonText, imageButton, GUILayout.Width(16f)))
{
splatBackgroundColor.colorValue = new Color(0f, 0f, 0f, 1f);
}
EditorGUILayout.EndHorizontal();
//Splat foreground color input:
EditorGUILayout.BeginHorizontal();
splatForegroundColor.colorValue = EditorGUILayout.ColorField("Splat foreground:", terrain.splatForeground);
//Default button:
if (GUILayout.Button(refreshButtonText, imageButton, GUILayout.Width(16f)))
{
splatForegroundColor.colorValue = new Color(1f, 1f, 1f, 1f);
}
EditorGUILayout.EndHorizontal();
//Splat width (meters) input:
EditorGUILayout.BeginHorizontal();
splatWidth.floatValue = EditorGUILayout.Slider("Splat width (meters):", terrain.splatWidth, 0.02f, 256f);
//Default button:
if (GUILayout.Button(refreshButtonText, imageButton, GUILayout.Width(16f)))
{
splatWidth.floatValue = 30f;
}
EditorGUILayout.EndHorizontal();
//Skip bridges:
isSkippingBridges.boolValue = EditorGUILayout.Toggle("Skip bridges: ", terrain.isSplatSkipBridges);
//Skip tunnels:
isSkippingTunnels.boolValue = EditorGUILayout.Toggle("Skip tunnels: ", terrain.isSplatSkipTunnels);
//Splat single road bool input:
EditorGUILayout.BeginHorizontal();
isSplatSingleRoad.boolValue = EditorGUILayout.Toggle("Splat a single road: ", terrain.isSplatSingleRoad);
//Splat single road , road input:
if (terrain.isSplatSingleRoad)
{
LoadSplatSingleChoice();
splatSingleChoiceIndex.intValue = EditorGUILayout.Popup(terrain.splatSingleChoiceIndex, roadsString, GUILayout.Width(150f));
roadSingleChoiceUID.stringValue = roads[splatSingleChoiceIndex.intValue];
}
EditorGUILayout.EndHorizontal();
//Generate splatmap button:
GUILayout.Space(8f);
if (GUILayout.Button("Generate splatmap for this terrain"))
{
GenerateSplatMap();
}
GUILayout.Space(10f);
if (GUI.changed)
{
serializedObject.ApplyModifiedProperties();
//Necessary?
//EditorUtility.SetDirty(target);
}
}
private void InitNullChecks()
{
string basePath = RoadEditorUtility.GetBasePath();
RoadArchitect.EditorUtilities.LoadTexture(ref refreshButtonText, basePath + "/Editor/Icons/refresh2.png");
RoadArchitect.EditorUtilities.LoadTexture(ref loadButtonBG, basePath + "/Editor/Icons/FlexBG.png");
RoadArchitect.EditorUtilities.LoadTexture(ref loadButtonBGGlow, basePath + "/Editor/Icons/FlexBG.png");
if (imageButton == null)
{
imageButton = new GUIStyle(GUI.skin.button);
imageButton.contentOffset = new Vector2(0f, 0f);
imageButton.border = new RectOffset(0, 0, 0, 0);
imageButton.fixedHeight = 16f;
imageButton.padding = new RectOffset(0, 0, 0, 0);
imageButton.normal.background = null;
}
if (loadButton == null)
{
loadButton = new GUIStyle(GUI.skin.button);
loadButton.contentOffset = new Vector2(0f, 1f);
loadButton.normal.textColor = new Color(1f, 1f, 1f, 1f);
loadButton.normal.background = loadButtonBG;
loadButton.active.background = loadButtonBGGlow;
loadButton.focused.background = loadButtonBGGlow;
loadButton.hover.background = loadButtonBGGlow;
loadButton.fixedHeight = 16f;
loadButton.padding = new RectOffset(0, 0, 0, 0);
}
}
private void LoadSplatSingleChoice()
{
roads = null;
roadsString = null;
Object[] allRoads = GameObject.FindObjectsOfType<Road>();
int roadsCount = allRoads.Length;
roads = new string[roadsCount];
roadsString = new string[roadsCount];
int counter = 0;
foreach (Road road in allRoads)
{
roads[counter] = road.UID;
roadsString[counter] = road.transform.name;
counter += 1;
}
}
private void GenerateSplatMap()
{
byte[] bytes = null;
if (terrain.isSplatSingleRoad && terrain.roadSingleChoiceUID != "")
{
bytes = RoadUtility.MakeSplatMap(terrain.terrain, terrain.splatBackground, terrain.splatForeground, terrain.splatResoWidth, terrain.splatResoHeight, terrain.splatWidth, terrain.isSplatSkipBridges, terrain.isSplatSkipTunnels, terrain.roadSingleChoiceUID);
}
else
{
bytes = RoadUtility.MakeSplatMap(terrain.terrain, terrain.splatBackground, terrain.splatForeground, terrain.splatResoWidth, terrain.splatResoHeight, terrain.splatWidth, terrain.isSplatSkipBridges, terrain.isSplatSkipTunnels);
}
if (bytes != null && bytes.Length > 3)
{
string path = UnityEditor.EditorUtility.SaveFilePanel("Save splat map", Application.dataPath, "Splat", "png");
if (path != null && path.Length > 3)
{
System.IO.File.WriteAllBytes(path, bytes);
}
bytes = null;
}
}
}
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0a8e0720738e16f42b9c3590ab753d23
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,559 @@
#if UNITY_EDITOR
#region "Imports"
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
#endregion
namespace RoadArchitect
{
public class Wizard : EditorWindow
{
public enum WindowTypeEnum
{
Extrusion,
Edge,
Groups,
BridgeComplete,
};
private readonly string[] WindowTypeDescBridge = new string[]{
"Extrusion items",
"Edge objects",
"Other groups",
"Complete bridges",
};
private readonly string[] WindowTypeDesc = new string[]{
"Extrusion items",
"Edge objects",
"Other groups"
};
#region "Vars"
private WindowTypeEnum windowType = WindowTypeEnum.Extrusion;
private WindowTypeEnum windowTypePrevious = WindowTypeEnum.Extrusion;
private static string path = "";
private GUIStyle thumbStyle;
private Vector2 scrollPos = new Vector2(0f, 25f);
private SplineN thisNode = null;
private List<WizardObject> objectList = null;
private bool isUsingNoGUI = false;
public Rect rect;
#endregion
private void OnGUI()
{
DoGUI();
}
private void DoGUI()
{
if (isUsingNoGUI)
{
return;
}
if (objectList == null)
{
Close();
return;
}
GUILayout.Space(4f);
EditorGUILayout.BeginHorizontal();
string[] options = thisNode.isBridgeStart ? WindowTypeDescBridge : WindowTypeDesc;
if (!thisNode.isBridgeStart && windowType == WindowTypeEnum.BridgeComplete)
{
// Prevent category error when changing from bridge to normal node
windowType = WindowTypeEnum.Extrusion;
}
windowType = (WindowTypeEnum)EditorGUILayout.Popup("Category: ", (int)windowType, options, GUILayout.Width(312f));
if (windowType != windowTypePrevious)
{
windowTypePrevious = windowType;
InitWindow();
}
EditorGUILayout.LabelField("");
EditorGUILayout.LabelField("Single-click items to load", EditorStyles.boldLabel, GUILayout.Width(200f));
EditorGUILayout.EndHorizontal();
if (objectList.Count == 0)
{
return;
}
int objectCount = objectList.Count;
int spacingWidth = 160;
int spacingHeight = 200;
int heightOffset = 30;
int scrollHeightOffset = 25;
int xCount = 0;
int yCount = 0;
int yMod = Mathf.FloorToInt((float)position.width / 142f) - 1;
int yMax = 0;
if (yMod == 0)
{
yMax = 1;
}
else
{
yMax = Mathf.CeilToInt((float)objectCount / (float)yMod);
}
bool isScrolling = false;
if ((((yMax) * spacingHeight) + 25) > position.height)
{
scrollPos = GUI.BeginScrollView(new Rect(0, 25, position.width - 10, position.height - 30), scrollPos, new Rect(0, 0, (yMod * spacingWidth) + 25, (((yMax) * spacingHeight) + 50)));
isScrolling = true;
heightOffset = scrollHeightOffset;
}
EditorGUILayout.BeginHorizontal();
bool isClicked = false;
for (int i = 0; i < objectCount; i++)
{
if (i > 0)
{
if (yMod == 0)
{
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
yCount += 1;
xCount = 0;
}
else
{
if (i % yMod == 0)
{
EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); yCount += 1; xCount = 0;
}
}
}
if (xCount == 0)
{
isClicked = DoItem((xCount * spacingWidth) + 5, (yCount * spacingHeight) + heightOffset, i);
}
else
{
isClicked = DoItem(xCount * spacingWidth, (yCount * spacingHeight) + heightOffset, i);
}
if (isClicked)
{
if (windowType == WindowTypeEnum.Extrusion)
{
Splination.SplinatedMeshMaker SMM = thisNode.AddSplinatedObject();
SMM.SetDefaultTimes(thisNode.isEndPoint, thisNode.time, thisNode.nextTime, thisNode.idOnSpline, thisNode.spline.distance);
SMM.LoadFromLibrary(objectList[i].fileName, objectList[i].isDefault);
thisNode.CheckRenameSplinatedObject(SMM);
SMM.isDefault = objectList[i].isDefault;
SMM.Setup(true);
}
else if (windowType == WindowTypeEnum.Edge)
{
EdgeObjects.EdgeObjectMaker EOM = thisNode.AddEdgeObject();
EOM.SetDefaultTimes(thisNode.isEndPoint, thisNode.time, thisNode.nextTime, thisNode.idOnSpline, thisNode.spline.distance);
EOM.LoadFromLibrary(objectList[i].fileName, objectList[i].isDefault);
thisNode.CheckRenameEdgeObject(EOM);
EOM.isDefault = objectList[i].isDefault;
EOM.Setup();
}
else if (windowType == WindowTypeEnum.Groups)
{
thisNode.LoadWizardObjectsFromLibrary(objectList[i].fileName, objectList[i].isDefault, objectList[i].isBridge);
}
else if (windowType == WindowTypeEnum.BridgeComplete)
{
thisNode.LoadWizardObjectsFromLibrary(objectList[i].fileName, objectList[i].isDefault, objectList[i].isBridge);
}
objectList.Clear();
objectList = null;
EditorGUILayout.EndHorizontal();
if (isScrolling)
{
GUI.EndScrollView();
}
isUsingNoGUI = true;
Close();
return;
}
xCount += 1;
}
EditorGUILayout.EndHorizontal();
if (isScrolling)
{
GUI.EndScrollView();
}
}
private bool DoItem(int _x1, int _y1, int _i)
{
if (objectList[_i].thumb != null)
{
if (GUI.Button(new Rect(_x1, _y1, 132f, 132f), objectList[_i].thumb))
{
return true;
}
}
else
{
if (GUI.Button(new Rect(_x1, _y1, 132f, 132f), "No image"))
{
return true;
}
}
GUI.Label(new Rect(_x1, _y1 + 132f, 148f, 20f), objectList[_i].displayName, EditorStyles.boldLabel);
GUI.Label(new Rect(_x1, _y1 + 148f, 148f, 52f), objectList[_i].desc, EditorStyles.miniLabel);
return false;
}
#region "Init"
/// <summary> Initializes the wizard </summary>
public void Initialize(WindowTypeEnum _windowType, SplineN _node)
{
if (rect.width < 1f && rect.height < 1f)
{
rect.x = 275f;
rect.y = 200f;
rect.width = 860f;
rect.height = 500f;
}
position = rect;
windowType = _windowType;
windowTypePrevious = _windowType;
thisNode = _node;
InitWindow();
Show();
}
private void InitWindow()
{
if (objectList != null)
{
objectList.Clear();
objectList = null;
}
objectList = new List<WizardObject>();
if (windowType == WindowTypeEnum.Extrusion)
{
titleContent.text = "Extrusion";
InitObjs();
}
else if (windowType == WindowTypeEnum.Edge)
{
titleContent.text = "Edge objects";
InitObjs();
}
else if (windowType == WindowTypeEnum.BridgeComplete)
{
titleContent.text = "Bridges";
InitGroups(true);
}
else if (windowType == WindowTypeEnum.Groups)
{
titleContent.text = "Groups";
InitGroups(false);
}
thumbStyle = new GUIStyle(GUI.skin.button);
thumbStyle.contentOffset = new Vector2(0f, 0f);
thumbStyle.border = new RectOffset(0, 0, 0, 0);
thumbStyle.fixedHeight = 128f;
thumbStyle.fixedWidth = 128f;
thumbStyle.padding = new RectOffset(0, 0, 0, 0);
thumbStyle.normal.background = null;
thumbStyle.hover.background = null;
thumbStyle.active.background = null;
EditorStyles.label.wordWrap = true;
EditorStyles.miniLabel.wordWrap = true;
GUI.skin.label.wordWrap = true;
}
#region "Init complete bridges"
private void InitGroups(bool _isBridge)
{
string[] names = null;
string[] paths = null;
//Load user custom ones first:
GetGroupListing(out names, out paths, thisNode.spline.road.laneAmount, false);
LoadGroupObjs(ref names, ref paths, _isBridge);
//Load RoadArchitect ones last:
GetGroupListing(out names, out paths, thisNode.spline.road.laneAmount, true);
LoadGroupObjs(ref names, ref paths, _isBridge);
}
private void LoadGroupObjs(ref string[] _names, ref string[] _paths, bool _isBridge)
{
int nameCount = _names.Length;
string path = "";
//string thumbString = "";
for (int index = 0; index < nameCount; index++)
{
WizardObject tO = WizardObject.LoadFromLibrary(_paths[index]);
if (tO == null)
{
continue;
}
if (tO.isBridge != _isBridge)
{
continue;
}
try
{
tO.thumb = EngineIntegration.LoadAssetFromPath<Texture2D>(tO.thumbString);
}
catch
{
tO.thumb = null;
}
tO.fileName = _names[index];
tO.FullPath = path;
objectList.Add(tO);
}
oListSort();
}
public static void GetGroupListing(out string[] _names, out string[] _paths, int _lanes, bool _isDefault = false)
{
path = RootUtils.GetDirLibrary();
Debug.Log(path);
string laneText = "-2L";
if (_lanes == 4)
{
laneText = "-4L";
}
else if (_lanes == 6)
{
laneText = "-6L";
}
_names = null;
_paths = null;
DirectoryInfo info;
if (_isDefault)
{
// W folder is now the Default folder
info = new DirectoryInfo(Path.Combine(Path.Combine(path, "Groups"), "Default"));
}
else
{
info = new DirectoryInfo(Path.Combine(path, "Groups"));
}
FileInfo[] fileInfo = info.GetFiles();
int count = 0;
foreach (FileInfo tInfo in fileInfo)
{
if (tInfo.Extension.ToLower().Contains("rao"))
{
if (!_isDefault)
{
count += 1;
}
else
{
if (tInfo.Name.Contains(laneText))
{
count += 1;
}
}
}
}
_names = new string[count];
_paths = new string[count];
count = 0;
foreach (FileInfo tInfo in fileInfo)
{
if (tInfo.Extension.ToLower().Contains("rao"))
{
if (!_isDefault)
{
_names[count] = tInfo.Name.Replace(".rao", "");
_paths[count] = tInfo.FullName;
count += 1;
}
else
{
if (tInfo.Name.Contains(laneText))
{
_names[count] = tInfo.Name.Replace(".rao", "");
_paths[count] = tInfo.FullName;
count += 1;
}
}
}
}
}
#endregion
#region "Init objs"
private void InitObjs()
{
string[] names = null;
string[] paths = null;
//Load user custom ones first:
if (windowType == WindowTypeEnum.Extrusion)
{
Splination.SplinatedMeshMaker.GetLibraryFiles(out names, out paths, false);
}
else
{
EdgeObjects.EdgeObjectMaker.GetLibraryFiles(out names, out paths, false);
}
LoadObjs(ref names, ref paths, false);
//Load RoadArchitect ones last:
if (windowType == WindowTypeEnum.Extrusion)
{
Splination.SplinatedMeshMaker.GetLibraryFiles(out names, out paths, true);
}
else
{
EdgeObjects.EdgeObjectMaker.GetLibraryFiles(out names, out paths, true);
}
LoadObjs(ref names, ref paths, true);
}
private void LoadObjs(ref string[] _names, ref string[] _paths, bool _isDefault = false)
{
int namesCount = _names.Length;
string path = "";
string stringPath = "";
string desc = "";
string displayName = "";
string thumbString = "";
bool isBridge;
for (int i = 0; i < namesCount; i++)
{
isBridge = false;
path = _paths[i];
if (windowType == WindowTypeEnum.Extrusion)
{
Splination.SplinatedMeshMaker.SplinatedMeshLibraryMaker SLM = RootUtils.LoadXML<Splination.SplinatedMeshMaker.SplinatedMeshLibraryMaker>(ref path);
if (SLM == null)
{
continue;
}
stringPath = SLM.CurrentSplinationString;
desc = SLM.desc;
displayName = SLM.displayName;
thumbString = SLM.thumbString;
isBridge = SLM.isBridge;
}
else if (windowType == WindowTypeEnum.Edge)
{
EdgeObjects.EdgeObjectMaker.EdgeObjectLibraryMaker ELM = RootUtils.LoadXML<EdgeObjects.EdgeObjectMaker.EdgeObjectLibraryMaker>(ref path);
if (ELM == null)
{
continue;
}
stringPath = ELM.edgeObjectString;
desc = ELM.desc;
displayName = ELM.displayName;
thumbString = ELM.thumbString;
isBridge = ELM.isBridge;
}
//Don't continue if bridge pieces and this is not a bridge piece:
if (windowType == WindowTypeEnum.Extrusion && isBridge)
{
continue;
}
WizardObject tO = new WizardObject();
#region "Image"
try
{
tO.thumb = EngineIntegration.LoadAssetFromPath<Texture2D>(thumbString);
}
catch
{
tO.thumb = null;
}
if (tO.thumb == null)
{
try
{
GameObject xObj = EngineIntegration.LoadAssetFromPath<GameObject>(stringPath);
tO.thumb = AssetPreview.GetAssetPreview(xObj);
}
catch
{
tO.thumb = null;
}
}
#endregion
tO.displayName = displayName;
tO.fileName = _names[i];
tO.FullPath = path;
tO.desc = desc;
tO.isDefault = _isDefault;
objectList.Add(tO);
}
oListSort();
}
private void oListSort()
{
objectList.Sort((WizardObject object1, WizardObject object2) =>
{
if (object1.isDefault != object2.isDefault)
{
return object1.isDefault.CompareTo(object2.isDefault);
}
else if (object1.sortID != object2.sortID)
{
return object1.sortID.CompareTo(object2.sortID);
}
else
{
return object1.displayName.CompareTo(object2.displayName);
}
});
}
#endregion
#endregion
}
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4ed90bd0a0e8eca4788cb2fc0a693239
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: