namespace Dreamteck.Splines.Editor { using UnityEngine; using System.Collections; using UnityEditor; [CustomEditor(typeof(SplineMesh), true)] [CanEditMultipleObjects] public class SplineMeshEditor : MeshGenEditor { private int selectedChannel = -1; SplineMesh.Channel renameChannel = null; MeshDefinitionWindow definitionWindow = null; MeshScaleModifierEditor scaleModifierEditor; private Mesh GetMeshFromObject(Object obj) { SplineMesh user = (SplineMesh)target; if (!(obj is GameObject)) return null; GameObject gameObj = (GameObject)obj; MeshFilter filter = gameObj.GetComponent(); Mesh returnMesh = null; if (filter != null && filter.sharedMesh != null) returnMesh = filter.sharedMesh; MeshRenderer rend = user.GetComponent(); if (rend == null) return returnMesh; MeshRenderer meshRend = gameObj.GetComponent(); if (meshRend == null) return returnMesh; bool found = false; for (int i = 0; i < meshRend.sharedMaterials.Length; i++) { for (int j = 0; j < rend.sharedMaterials.Length; j++) { if(meshRend.sharedMaterials[i] == rend.sharedMaterials[j]) { found = true; break; } } } if (!found) { if(EditorUtility.DisplayDialog("New Materials", "The added object has one or more materials which are not refrenced by the renderer. Would you like to add them?", "Yes", "No")) { if(rend.sharedMaterial == AssetDatabase.GetBuiltinExtraResource("Default-Diffuse.mat")) { if (EditorUtility.DisplayDialog("Replace Material", "The renderer is using the default material. Replace it?", "Yes", "No")) rend.sharedMaterials = new Material[0]; } for (int i = 0; i < meshRend.sharedMaterials.Length; i++) AddMaterial(rend, meshRend.sharedMaterials[i]); } } return returnMesh; } void AddMaterial(MeshRenderer target, Material material) { for (int i = 0; i < target.sharedMaterials.Length; i++) { if (target.sharedMaterials[i] == material) return; } Material[] newMaterials = new Material[target.sharedMaterials.Length + 1]; target.sharedMaterials.CopyTo(newMaterials, 0); newMaterials[newMaterials.Length - 1] = material; target.sharedMaterials = newMaterials; } void OnDuplicateChannel(object index) { SplineMesh extruder = (SplineMesh)target; SplineMesh.Channel source = extruder.GetChannel((int)index); SplineMesh.Channel newChannel = extruder.AddChannel(source.name); source.CopyTo(newChannel); } void OnRenameChannel(object index) { SplineMesh extruder = (SplineMesh)target; renameChannel = extruder.GetChannel((int)index); Repaint(); } void OnDeleteChannel(object index) { SplineMesh extruder = (SplineMesh)target; extruder.RemoveChannel((int)index); Repaint(); } void OnMoveChannelUp(object index) { SplineMesh extruder = (SplineMesh)target; extruder.SwapChannels((int)index, ((int)index)-1); Repaint(); } void OnMoveChannelDown(object index) { SplineMesh extruder = (SplineMesh)target; extruder.SwapChannels((int)index, ((int)index) + 1); Repaint(); } protected override void DuringSceneGUI(SceneView currentSceneView) { base.DuringSceneGUI(currentSceneView); if (scaleModifierEditor != null) scaleModifierEditor.DrawScene(); } protected override void BodyGUI() { showSize = false; showDoubleSided = false; showFlipFaces = false; base.BodyGUI(); SplineMesh user = (SplineMesh)target; EditorGUI.BeginChangeCheck(); EditorGUILayout.Space(); EditorGUILayout.LabelField("Uv Coordinates", EditorStyles.boldLabel); user.uvOffset = EditorGUILayout.Vector2Field("UV Offset", user.uvOffset); user.uvScale = EditorGUILayout.Vector2Field("UV Scale", user.uvScale); if (targets.Length > 1) { EditorGUILayout.HelpBox("Cannot edit channels when multiple objects are selected", MessageType.Info); return; } EditorGUILayout.Space(); EditorGUILayout.LabelField("Channels", EditorStyles.boldLabel); for (int i = 0; i < user.GetChannelCount(); i++) { if (ChannelPanel(i)) { if (Event.current.type == EventType.MouseDown) { Repaint(); if (Event.current.button == 0) { if (selectedChannel == i) { selectedChannel = -1; } else { selectedChannel = i; scaleModifierEditor = new MeshScaleModifierEditor(user, this, i); scaleModifierEditor.alwaysOpen = true; } } else if (Event.current.button == 1) { GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("Rename"), false, OnRenameChannel, i); menu.AddItem(new GUIContent("Duplicate"), false, OnDuplicateChannel, i); if (i == 0) menu.AddDisabledItem(new GUIContent("Move Up")); else menu.AddItem(new GUIContent("Move Up"), false, OnMoveChannelUp, i); if (i == user.GetChannelCount() - 1) menu.AddDisabledItem(new GUIContent("Move Down")); else menu.AddItem(new GUIContent("Move Down"), false, OnMoveChannelDown, i); menu.AddSeparator(""); menu.AddItem(new GUIContent("Delete"), false, OnDeleteChannel, i); menu.ShowAsContext(); } } } } if (GUILayout.Button("New Channel")) user.AddChannel("Channel " + (user.GetChannelCount() + 1)); if (EditorGUI.EndChangeCheck()) EditorUtility.SetDirty(user); } bool ChannelPanel(int channelIndex) { SplineMesh.Channel channel = ((SplineMesh)target).GetChannel(channelIndex); bool open = selectedChannel == channelIndex; GUILayout.BeginVertical(EditorStyles.helpBox); if (renameChannel == channel && Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter)) { renameChannel = null; Repaint(); } if (renameChannel == channel) channel.name = EditorGUILayout.TextField(channel.name); else EditorGUILayout.LabelField(channel.name, EditorStyles.boldLabel); if (!open) { GUILayout.EndVertical(); return GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition); } Rect labelRect = GUILayoutUtility.GetLastRect(); EditorGUI.indentLevel++; EditorGUILayout.Space(); EditorGUILayout.LabelField("Mesh Objects", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); EditorGUIUtility.labelWidth = 100f; EditorGUILayout.BeginVertical(); for (int i = 0; i < channel.GetMeshCount(); i++) MeshRow(channel, i); Object obj = null; obj = EditorGUILayout.ObjectField("Add Mesh", obj, typeof(Object), true); if (obj != null) { if (obj is Mesh) channel.AddMesh((Mesh)obj); else { Mesh m = GetMeshFromObject(obj); if (m != null) channel.AddMesh(m); } } EditorGUILayout.EndVertical(); EditorGUILayout.BeginVertical(); channel.type = (SplineMesh.Channel.Type)EditorGUILayout.EnumPopup("Type", channel.type); if (channel.autoCount) EditorGUILayout.TextField("Auto Count: " + channel.count); else channel.count = EditorGUILayout.IntField("Count", channel.count); channel.autoCount = EditorGUILayout.Toggle("Auto Count", channel.autoCount); channel.randomOrder = EditorGUILayout.Toggle("Random Order", channel.randomOrder); if (channel.randomOrder) channel.randomSeed = EditorGUILayout.IntField("Seed", channel.randomSeed); EditorGUILayout.EndVertical(); EditorGUIUtility.labelWidth = 0f; EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); float clipFrom = (float)channel.clipFrom; float clipTo = (float)channel.clipTo; EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.MinMaxSlider(new GUIContent("Clip Range:"), ref clipFrom, ref clipTo, 0f, 1f); EditorGUIUtility.labelWidth = 0f; EditorGUILayout.EndHorizontal(); channel.clipFrom = clipFrom; channel.clipTo = clipTo; EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(30)); channel.clipFrom = EditorGUILayout.FloatField((float)channel.clipFrom); channel.clipTo = EditorGUILayout.FloatField((float)channel.clipTo); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.LabelField("Geometry", EditorStyles.boldLabel); if(channel.type != SplineMesh.Channel.Type.Place) channel.spacing = EditorGUILayout.Slider("Spacing", (float)channel.spacing, 0f, 1f); //Offset channel.minOffset = EditorGUILayout.Vector2Field(channel.randomOffset ? "Offset Min" : "Offset", channel.minOffset); if(channel.randomOffset) channel.maxOffset = EditorGUILayout.Vector2Field("Offset Max", channel.maxOffset); EditorGUILayout.BeginHorizontal(); EditorGUIUtility.labelWidth = 130f; channel.randomOffset = EditorGUILayout.Toggle("Randomize Offset", channel.randomOffset); if (channel.randomOffset) channel.offsetSeed = EditorGUILayout.IntField("Seed", channel.offsetSeed); EditorGUIUtility.labelWidth = 0f; EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); //Rotation if (channel.type == SplineMesh.Channel.Type.Extrude) { Vector3 rot = channel.minRotation; rot.z = EditorGUILayout.FloatField(channel.randomRotation ? "Rotation Min" : "Rotation", rot.z); channel.minRotation = rot; if (channel.randomRotation) { rot = channel.maxRotation; rot.z = EditorGUILayout.FloatField("Rotation Max", rot.z); channel.maxRotation = rot; } } else { channel.minRotation = EditorGUILayout.Vector3Field(channel.randomRotation ? "Rotation Min" : "Rotation", channel.minRotation); if (channel.randomRotation) channel.maxRotation = EditorGUILayout.Vector3Field("Rotation Max", channel.maxRotation); } EditorGUILayout.BeginHorizontal(); EditorGUIUtility.labelWidth = 130f; channel.randomRotation = EditorGUILayout.Toggle("Randomize Rotation", channel.randomRotation); if (channel.randomRotation) channel.rotationSeed = EditorGUILayout.IntField("Seed", channel.rotationSeed); EditorGUIUtility.labelWidth = 0f; EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); //Scale if (channel.type == SplineMesh.Channel.Type.Extrude) { float lastZ = channel.minScale.z; Vector3 scale = channel.minScale; scale = EditorGUILayout.Vector2Field(channel.randomScale ? "Scale Min" : "Scale", scale); scale += Vector3.forward * lastZ; channel.minScale = scale; if (channel.randomScale) { lastZ = channel.maxScale.z; scale = channel.maxScale; scale = EditorGUILayout.Vector2Field("Scale Max", scale); scale += Vector3.forward * lastZ; channel.maxScale = scale; } } else { channel.minScale = EditorGUILayout.Vector3Field(channel.randomScale ? "Scale Min" : "Scale", channel.minScale); if (channel.randomScale) channel.maxScale = EditorGUILayout.Vector3Field("Scale Max", channel.maxScale); } EditorGUILayout.BeginHorizontal(); EditorGUIUtility.labelWidth = 130f; channel.randomScale = EditorGUILayout.Toggle("Randomize Scale", channel.randomScale); if (channel.randomScale) channel.scaleSeed = EditorGUILayout.IntField("Seed", channel.scaleSeed); EditorGUIUtility.labelWidth = 0f; EditorGUILayout.EndHorizontal(); if (channel.randomScale) { EditorGUI.indentLevel++; EditorGUIUtility.labelWidth = 120f; channel.uniformRandomScale = EditorGUILayout.Toggle("Uniform", channel.uniformRandomScale); EditorGUIUtility.labelWidth = 0f; EditorGUI.indentLevel--; } EditorGUILayout.Space(); EditorGUILayout.LabelField("UV Coordinates", EditorStyles.boldLabel); channel.uvOffset = EditorGUILayout.Vector2Field("UV Offset", channel.uvOffset); channel.uvScale = EditorGUILayout.Vector2Field("UV Scale", channel.uvScale); //Override EditorGUILayout.Space(); EditorGUILayout.LabelField("Override", EditorStyles.boldLabel); channel.overrideNormal = EditorGUILayout.Toggle("Normal", channel.overrideNormal); if(channel.overrideNormal) channel.customNormal = EditorGUILayout.Vector3Field("Normal", channel.customNormal); if (channel.type == SplineMesh.Channel.Type.Extrude) { channel.overrideUVs = (SplineMesh.Channel.UVOverride)EditorGUILayout.EnumPopup("UVs", channel.overrideUVs); if(channel.overrideUVs != SplineMesh.Channel.UVOverride.None) { } } channel.overrideMaterialID = EditorGUILayout.Toggle("Material IDs", channel.overrideMaterialID); if (channel.overrideMaterialID) channel.targetMaterialID = EditorGUILayout.IntField("Target ID", channel.targetMaterialID); if (scaleModifierEditor != null) { EditorGUILayout.LabelField("Scale Regions", EditorStyles.boldLabel); scaleModifierEditor.DrawInspector(); } EditorGUI.indentLevel--; GUILayout.EndVertical(); return labelRect.Contains(Event.current.mousePosition); } void OnDuplicateMesh(object mesh) { MeshLink link = (MeshLink)mesh; link.channel.DuplicateMesh(link.index); } void OnDeleteMesh(object mesh) { MeshLink link = (MeshLink)mesh; link.channel.RemoveMesh(link.index); Repaint(); } void OnMoveMeshUp(object mesh) { MeshLink link = (MeshLink)mesh; link.channel.SwapMeshes(link.index, link.index - 1); Repaint(); } void OnMoveMeshDown(object mesh) { MeshLink link = (MeshLink)mesh; link.channel.SwapMeshes(link.index, link.index + 1); Repaint(); } void MeshRow(SplineMesh.Channel channel, int index) { SplineMesh.Channel.MeshDefinition definition = channel.GetMesh(index); EditorGUILayout.BeginHorizontal(); GUILayout.Space(15); if(definition.mesh == null) GUILayout.Box("NULL", EditorStyles.helpBox, GUILayout.MinWidth(200)); else GUILayout.Box(definition.mesh.name, EditorStyles.helpBox, GUILayout.MinWidth(200)); EditorGUILayout.EndHorizontal(); Rect rect = GUILayoutUtility.GetLastRect(); if (Event.current.type == EventType.MouseDown && rect.Contains(Event.current.mousePosition)){ if(Event.current.button == 0) { definitionWindow = EditorWindow.GetWindow(true); definitionWindow.Init((SplineMesh)target, definition); } if(Event.current.button == 1) { GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("Duplicate"), false, OnDuplicateMesh, new MeshLink(index, channel)); if (index == 0) menu.AddDisabledItem(new GUIContent("Move Up")); else menu.AddItem(new GUIContent("Move Up"), false, OnMoveMeshUp, new MeshLink(index, channel)); if (index == channel.GetMeshCount() - 1) menu.AddDisabledItem(new GUIContent("Move Down")); else menu.AddItem(new GUIContent("Move Down"), false, OnMoveMeshDown, new MeshLink(index, channel)); menu.AddSeparator(""); menu.AddItem(new GUIContent("Delete"), false, OnDeleteMesh, new MeshLink(index, channel)); menu.ShowAsContext(); } } } protected override void OnDestroy() { base.OnDestroy(); if (definitionWindow != null) definitionWindow.Close(); } internal class MeshLink { internal int index = 0; internal SplineMesh.Channel channel; internal MeshLink(int i, SplineMesh.Channel l) { index = i; channel = l; } } public class MeshDefinitionWindow : EditorWindow { internal SplineMesh.Channel.MeshDefinition definition = null; internal SplineMesh extrude = null; internal void Init(SplineMesh e, SplineMesh.Channel.MeshDefinition d) { minSize = new Vector2(482, 180); extrude = e; definition = d; if(definition.mesh != null) titleContent = new GUIContent("Configure " + definition.mesh.name); else titleContent = new GUIContent("Configure Mesh"); } private void OnGUI() { EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginVertical(); EditorGUILayout.LabelField("Geometry", EditorStyles.boldLabel); definition.mesh = (Mesh)EditorGUILayout.ObjectField(definition.mesh, typeof(Mesh), true); definition.mirror = (SplineMesh.Channel.MeshDefinition.MirrorMethod)EditorGUILayout.EnumPopup("Mirror", definition.mirror); definition.offset = EditorGUILayout.Vector3Field("Offset", definition.offset); definition.rotation = EditorGUILayout.Vector3Field("Rotation", definition.rotation); definition.scale = EditorGUILayout.Vector3Field("Scale", definition.scale); var spacing = definition.spacing; EditorGUILayout.BeginHorizontal(); EditorGUIUtility.labelWidth = 40; EditorGUILayout.LabelField("Spacing"); spacing.front = EditorGUILayout.FloatField("Front", spacing.front); spacing.back = EditorGUILayout.FloatField("Back", spacing.back); definition.spacing = spacing; EditorGUILayout.EndHorizontal(); EditorGUIUtility.labelWidth = 0; EditorGUILayout.EndVertical(); EditorGUILayout.BeginVertical(); EditorGUILayout.LabelField("Faces", EditorStyles.boldLabel); definition.doubleSided = EditorGUILayout.Toggle("Double sided", definition.doubleSided); if (definition.doubleSided) definition.flipFaces = false; else definition.flipFaces = EditorGUILayout.Toggle("Flip Faces", definition.flipFaces); definition.removeInnerFaces = EditorGUILayout.Toggle("Remove Inner Faces", definition.removeInnerFaces); EditorGUILayout.LabelField("UVs", EditorStyles.boldLabel); definition.uvOffset = EditorGUILayout.Vector2Field("UV Offset", definition.uvOffset); definition.uvScale = EditorGUILayout.Vector2Field("UV Scale", definition.uvScale); definition.uvRotation = EditorGUILayout.Slider("UV Rotation", definition.uvRotation, -180f, 180f); definition.vertexGroupingMargin = EditorGUILayout.FloatField("Vertex Grouping Margin", definition.vertexGroupingMargin); EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); if (GUI.changed) extrude.Rebuild(); } } } }