//Stylized Water 2 //Staggart Creations (http://staggart.xyz) //Copyright protected under Unity Asset Store EULA using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; #if UNITY_2021_2_OR_NEWER using PrefabStageUtility = UnityEditor.SceneManagement.PrefabStageUtility; #else using PrefabStageUtility = UnityEditor.Experimental.SceneManagement.PrefabStageUtility; #endif namespace StylizedWater2 { [CanEditMultipleObjects] [CustomEditor(typeof(AlignToWaves))] public class AlignToWavesInspector : Editor { AlignToWaves script; SerializedProperty waterObject; SerializedProperty autoFind; SerializedProperty dynamicMaterial; SerializedProperty waterLevelSource; SerializedProperty waterLevel; SerializedProperty childTransform; SerializedProperty heightOffset; SerializedProperty rollAmount; SerializedProperty samples; private bool editSamples; private bool isRiver; private bool wavesEnabled; private string proSkinPrefix => EditorGUIUtility.isProSkin ? "d_" : ""; private void OnEnable() { script = (AlignToWaves)target; waterObject = serializedObject.FindProperty("waterObject"); autoFind = serializedObject.FindProperty("autoFind"); dynamicMaterial = serializedObject.FindProperty("dynamicMaterial"); waterLevelSource = serializedObject.FindProperty("waterLevelSource"); waterLevel = serializedObject.FindProperty("waterLevel"); childTransform = serializedObject.FindProperty("childTransform"); heightOffset = serializedObject.FindProperty("heightOffset"); rollAmount = serializedObject.FindProperty("rollAmount"); samples = serializedObject.FindProperty("samples"); //Auto fetch if there is only one water body in the scene if (waterObject.objectReferenceValue == null && WaterObject.Instances.Count == 1) { serializedObject.Update(); waterObject.objectReferenceValue = WaterObject.Instances[0]; EditorUtility.SetDirty(target); serializedObject.ApplyModifiedPropertiesWithoutUndo(); } ValidateMaterial(); } private void OnDisable() { AlignToWaves.Disable = false; Tools.hidden = false; } public override void OnInspectorGUI() { UI.DrawHeader(); using (new EditorGUILayout.HorizontalScope()) { GUILayout.Space(EditorGUIUtility.labelWidth); AlignToWaves.EnableInEditor = GUILayout.Toggle(AlignToWaves.EnableInEditor, new GUIContent(" Run in edit-mode (global)", EditorGUIUtility.IconContent( (AlignToWaves.EnableInEditor ? "animationvisibilitytoggleon" : "animationvisibilitytoggleoff")).image), "Button"); } EditorGUILayout.Space(); serializedObject.Update(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(waterObject); EditorGUI.indentLevel++; EditorGUILayout.PropertyField(autoFind); EditorGUILayout.PropertyField(dynamicMaterial); EditorGUI.indentLevel--; UI.DrawNotification(isRiver, "Material has river mode enabled, buoyancy only works for flat water bodies", MessageType.Error); UI.DrawNotification(!wavesEnabled && !isRiver, "Material used on the water object does not have waves enabled.", MessageType.Error); if (script.waterObject && script.waterObject.material) { UI.DrawNotification((script.waterObject.material.GetFloat("_WorldSpaceUV") == 0f), "Material must use world-projected UV", "Change", ()=> script.waterObject.material.SetFloat("_WorldSpaceUV", 1f), MessageType.Error); } if(!autoFind.boolValue && waterObject.objectReferenceValue == null) { UI.DrawNotification("A water object must be assigned!", MessageType.Error); } using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.PrefixLabel("Water level source"); waterLevelSource.intValue = GUILayout.Toolbar(waterLevelSource.intValue, new GUIContent[] { new GUIContent("Fixed Value"), new GUIContent("Water Object") }); } if (waterLevelSource.intValue == (int)AlignToWaves.WaterLevelSource.FixedValue) EditorGUILayout.PropertyField(waterLevel); EditorGUILayout.Space(); EditorGUILayout.PropertyField(heightOffset); EditorGUILayout.PropertyField(rollAmount); EditorGUILayout.Space(); EditorGUILayout.LabelField("Sample positions", EditorStyles.boldLabel); if (targets.Length > 1) { EditorGUILayout.HelpBox("Cannot be modified for a multi-selection", MessageType.Info); } else { if (samples.arraySize > 0) { editSamples = GUILayout.Toggle(editSamples, new GUIContent(" Edit samples", EditorGUIUtility.IconContent("sv_icon_dot0_pix16_gizmo").image), "Button", GUILayout.MaxWidth(125f), GUILayout.MaxHeight(30f)); } else { EditorGUILayout.HelpBox("No sample positions added. The transform's pivot position is used", MessageType.None); } for (int i = 0; i < samples.arraySize; i++) { SerializedProperty param = samples.GetArrayElementAtIndex(i); using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.PropertyField(param, true); if (GUILayout.Button(new GUIContent("", EditorGUIUtility.IconContent(proSkinPrefix + "TreeEditor.Trash").image, "Delete item"), GUILayout.MaxWidth(30f))) { samples.DeleteArrayElementAtIndex(i); selectedSampleIndex = -1; EditorUtility.SetDirty(target); } } } using (new EditorGUILayout.HorizontalScope()) { GUILayout.FlexibleSpace(); if (GUILayout.Button(new GUIContent("Add", EditorGUIUtility.IconContent(proSkinPrefix + "Toolbar Plus").image, "Add new sample point"))) { samples.InsertArrayElementAtIndex(samples.arraySize); selectedSampleIndex = samples.arraySize - 1; EditorUtility.SetDirty(target); } } } EditorGUILayout.PropertyField(childTransform); if (childTransform.objectReferenceValue == null && samples.arraySize > 0) UI.DrawNotification("Assign a transform to rotate/scale the sample positions with"); if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); ValidateMaterial(); } UI.DrawFooter(); } private void ValidateMaterial() { if (script.waterObject && script.waterObject.material) { if (script.waterObject.material != script.waterObject.meshRenderer.sharedMaterial) script.waterObject.material = script.waterObject.meshRenderer.sharedMaterial; wavesEnabled = WaveParameters.WavesEnabled(script.waterObject.material); isRiver = script.waterObject.material.IsKeywordEnabled("_RIVER"); } } private int selectedSampleIndex; Vector3 sampleWorldPos; Vector3 prevSampleWorldPos; private void OnSceneGUI() { if (!script) return; AlignToWaves.Disable = PrefabStageUtility.GetCurrentPrefabStage() != null || editSamples; if (editSamples) { //Mute default controls Tools.hidden = true; Handles.color = new Color(0.66f, 0.66f, 0.66f, 1); for (int i = 0; i < script.samples.Count; i++) { sampleWorldPos = script.ConvertToWorldSpace(script.samples[i]); float size = HandleUtility.GetHandleSize(sampleWorldPos) * 0.25f; if (Handles.Button(sampleWorldPos, Quaternion.identity, size, size, Handles.SphereHandleCap)) { selectedSampleIndex = i; } } if (selectedSampleIndex > -1) { sampleWorldPos = script.ConvertToWorldSpace(script.samples[selectedSampleIndex]); prevSampleWorldPos = sampleWorldPos; sampleWorldPos = Handles.PositionHandle(sampleWorldPos, script.childTransform ? script.childTransform.rotation : script.transform.rotation ); script.samples[selectedSampleIndex] = script.ConvertToLocalSpace(sampleWorldPos); //If moved if (sampleWorldPos != prevSampleWorldPos) { prevSampleWorldPos = sampleWorldPos; EditorUtility.SetDirty(target); } } } else { selectedSampleIndex = -1; Tools.hidden = false; if (script.samples == null) return; Handles.color = new Color(1,1,1, 0.25f); for (int i = 0; i < script.samples.Count; i++) { sampleWorldPos = script.ConvertToWorldSpace(script.samples[i]); Handles.SphereHandleCap(0, sampleWorldPos, SceneView.lastActiveSceneView.camera.transform.rotation, HandleUtility.GetHandleSize(sampleWorldPos) * 0.25f, EventType.Repaint); } } } } }