394 lines
19 KiB
C#
394 lines
19 KiB
C#
|
using UnityEngine;
|
||
|
|
||
|
namespace UnityEditor.TerrainTools
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Flags passed to NoiseSettingsGUI.OnGUI. Used to specify which portions of the Noise Settings GUI to draw.
|
||
|
/// </summary>
|
||
|
[System.Flags]
|
||
|
internal enum NoiseSettingsGUIFlags
|
||
|
{
|
||
|
Preview = (1 << 0),
|
||
|
Settings = (1 << 1),
|
||
|
All = ( ~0 ),
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Class used to draw the GUI for Noise Settings.
|
||
|
/// </summary>
|
||
|
internal class NoiseSettingsGUI
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// The SerializedObject for the NoiseSettings that this NoiseSettingsGUI instance is currently rendering the GUI for.
|
||
|
/// </summary>
|
||
|
public SerializedObject serializedNoise;
|
||
|
public bool isScrollingPreview { get; private set; }
|
||
|
|
||
|
// noise settings properties
|
||
|
// noise settings properties
|
||
|
// noise settings properties
|
||
|
|
||
|
// coord space settings properties
|
||
|
private SerializedProperty transformSettings;
|
||
|
private SerializedProperty translation;
|
||
|
private SerializedProperty rotation;
|
||
|
private SerializedProperty scale;
|
||
|
private SerializedProperty flipScaleX;
|
||
|
private SerializedProperty flipScaleY;
|
||
|
private SerializedProperty flipScaleZ;
|
||
|
|
||
|
// domain settings properties
|
||
|
private SerializedProperty domainSettings;
|
||
|
private SerializedProperty noiseTypeName;
|
||
|
private SerializedProperty noiseTypeParams;
|
||
|
private SerializedProperty fractalTypeName;
|
||
|
private SerializedProperty fractalTypeParams;
|
||
|
|
||
|
// filter stack settings
|
||
|
// private SerializedProperty filterSettings;
|
||
|
// private FilterStackView m_filterStackView;
|
||
|
// private FilterStack m_filterStack;
|
||
|
// private SerializedObject m_serializedFilterStack;
|
||
|
// private bool m_showFilterStack;
|
||
|
|
||
|
/// <summary>
|
||
|
/// The current NoiseSettings object that is associated with this instance of NoiseSettingsGUI.
|
||
|
/// </summary>
|
||
|
public NoiseSettings target = null;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Sets up this instance of NoiseSettingsGUI with the specified NoiseSettings object.
|
||
|
/// GUI will be drawn for this NoiseSettings instance.
|
||
|
/// </summary>
|
||
|
/// <param name="noiseSettings"> The NoiseSettings instance for which GUI will be drawn </param>
|
||
|
public void Init(NoiseSettings noiseSettings)
|
||
|
{
|
||
|
Init(new SerializedObject(noiseSettings));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Sets up this instance of NoiseSettingsGUI with the specified SerializedObject containing an object reference
|
||
|
/// to a NoiseSettings instance. GUI will be drawn for this serialized NoiseSettings instance.
|
||
|
/// </summary>
|
||
|
/// <param name="serializedNoise"> A SerializedObject instance containing an object reference to a NoiseSettings object </param>
|
||
|
public void Init(SerializedObject serializedNoise)
|
||
|
{
|
||
|
this.serializedNoise = serializedNoise;
|
||
|
|
||
|
target = this.serializedNoise.targetObject as NoiseSettings;
|
||
|
|
||
|
// transform settings
|
||
|
transformSettings = this.serializedNoise.FindProperty("transformSettings");
|
||
|
translation = transformSettings.FindPropertyRelative("translation");
|
||
|
rotation = transformSettings.FindPropertyRelative("rotation");
|
||
|
scale = transformSettings.FindPropertyRelative("scale");
|
||
|
flipScaleX = transformSettings.FindPropertyRelative("flipScaleX");
|
||
|
flipScaleY = transformSettings.FindPropertyRelative("flipScaleY");
|
||
|
flipScaleZ = transformSettings.FindPropertyRelative("flipScaleZ");
|
||
|
|
||
|
// domain settings
|
||
|
domainSettings = this.serializedNoise.FindProperty("domainSettings");
|
||
|
noiseTypeName = domainSettings.FindPropertyRelative("noiseTypeName");
|
||
|
noiseTypeParams = domainSettings.FindPropertyRelative("noiseTypeParams");
|
||
|
fractalTypeName = domainSettings.FindPropertyRelative("fractalTypeName");
|
||
|
fractalTypeParams = domainSettings.FindPropertyRelative("fractalTypeParams");
|
||
|
|
||
|
// filter settings
|
||
|
// filterSettings = serializedNoise.FindProperty( "filterSettings" );
|
||
|
// m_filterStack = filterSettings.FindPropertyRelative( "filterStack" ).objectReferenceValue as FilterStack;
|
||
|
// m_serializedFilterStack = new SerializedObject( m_filterStack );
|
||
|
// m_filterStackView = new FilterStackView( new GUIContent( "Filters" ), m_serializedFilterStack, m_serializedFilterStack.targetObject as FilterStack );
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Renders the GUI for the NoiseSettings instance associated with this NoiseSettingsGUI instance.
|
||
|
/// </summary>
|
||
|
/// <param name="flags"> Flags specifying which portions of the GUI to draw </param>
|
||
|
public void OnGUI(NoiseSettingsGUIFlags flags = NoiseSettingsGUIFlags.All)
|
||
|
{
|
||
|
serializedNoise.Update();
|
||
|
|
||
|
if((flags & NoiseSettingsGUIFlags.Preview) != 0)
|
||
|
{
|
||
|
DrawPreviewTexture(256f, true);
|
||
|
}
|
||
|
|
||
|
if((flags & NoiseSettingsGUIFlags.Settings) != 0)
|
||
|
{
|
||
|
TerrainToolGUIHelper.DrawFoldout(transformSettings, Styles.transformSettings, TransformSettingsGUI);
|
||
|
TerrainToolGUIHelper.DrawFoldout(domainSettings, Styles.domainSettings, DomainSettingsGUI);
|
||
|
// TerrainToolGUIHelper.DrawFoldout(filterSettings, Styles.filterSettings, FilterSettingsGUI);
|
||
|
}
|
||
|
|
||
|
serializedNoise.ApplyModifiedProperties();
|
||
|
}
|
||
|
|
||
|
bool CheckVector3(System.Func<float, bool> validator, Vector3 value)
|
||
|
{
|
||
|
return validator(value.x) || validator(value.y) || validator(value.z);
|
||
|
}
|
||
|
|
||
|
private void TransformSettingsGUI()
|
||
|
{
|
||
|
Vector3 tv3 = translation.vector3Value;
|
||
|
Vector3 rv3 = rotation.vector3Value;
|
||
|
Vector3 sv3 = scale.vector3Value;
|
||
|
|
||
|
tv3 = EditorGUILayout.Vector3Field(translation.displayName, tv3);
|
||
|
rv3 = EditorGUILayout.Vector3Field(rotation.displayName, rv3);
|
||
|
sv3 = EditorGUILayout.Vector3Field(scale.displayName, sv3);
|
||
|
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
{
|
||
|
EditorGUILayout.PrefixLabel(Styles.flipScale);
|
||
|
flipScaleX.boolValue = GUILayout.Toggle(flipScaleX.boolValue, Styles.flipScaleX, GUI.skin.button);
|
||
|
flipScaleY.boolValue = GUILayout.Toggle(flipScaleY.boolValue, Styles.flipScaleY, GUI.skin.button);
|
||
|
flipScaleZ.boolValue = GUILayout.Toggle(flipScaleZ.boolValue, Styles.flipScaleZ, GUI.skin.button);
|
||
|
}
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
|
||
|
// fix up transform values
|
||
|
|
||
|
// translation
|
||
|
|
||
|
if (!CheckVector3(float.IsNaN, tv3) && !CheckVector3(float.IsInfinity, tv3))
|
||
|
{
|
||
|
translation.vector3Value = tv3;
|
||
|
GUI.changed = true;
|
||
|
}
|
||
|
|
||
|
// rotation
|
||
|
|
||
|
if (!CheckVector3(float.IsNaN, rv3) && !CheckVector3(float.IsInfinity, rv3))
|
||
|
{
|
||
|
rotation.vector3Value = rv3;
|
||
|
GUI.changed = true;
|
||
|
}
|
||
|
|
||
|
// wrap rotation values
|
||
|
if (rotation.vector3Value.x < 0 || rotation.vector3Value.x > 360 ||
|
||
|
rotation.vector3Value.y < 0 || rotation.vector3Value.y > 360 ||
|
||
|
rotation.vector3Value.z < 0 || rotation.vector3Value.z > 360)
|
||
|
{
|
||
|
Vector3 value = rotation.vector3Value;
|
||
|
value.x = (360f + (value.x % 360f)) % 360f;
|
||
|
value.y = (360f + (value.y % 360f)) % 360f;
|
||
|
value.z = (360f + (value.z % 360f)) % 360f;
|
||
|
rotation.vector3Value = value;
|
||
|
GUI.changed = true;
|
||
|
}
|
||
|
|
||
|
// scale
|
||
|
|
||
|
if (!CheckVector3(float.IsNaN, sv3) && !CheckVector3(float.IsInfinity, sv3))
|
||
|
{
|
||
|
scale.vector3Value = sv3;
|
||
|
GUI.changed = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void DomainSettingsGUI()
|
||
|
{
|
||
|
noiseTypeName.stringValue = NoiseLib.NoiseTypePopup(Styles.noiseType, noiseTypeName.stringValue);
|
||
|
INoiseType noiseType = NoiseLib.GetNoiseTypeInstance(noiseTypeName.stringValue);
|
||
|
noiseTypeParams.stringValue = noiseType?.DoGUI(noiseTypeParams.stringValue);
|
||
|
|
||
|
fractalTypeName.stringValue = NoiseLib.FractalTypePopup(Styles.fractalType, fractalTypeName.stringValue);
|
||
|
IFractalType fractalType = NoiseLib.GetFractalTypeInstance(fractalTypeName.stringValue);
|
||
|
fractalTypeParams.stringValue = fractalType?.DoGUI(fractalTypeParams.stringValue);
|
||
|
}
|
||
|
|
||
|
private void DoMinMaxSliderInt(GUIContent label, SerializedProperty prop, SerializedProperty minMaxProp)
|
||
|
{
|
||
|
int min = minMaxProp.vector2IntValue.x;
|
||
|
int max = minMaxProp.vector2IntValue.y;
|
||
|
prop.intValue = TerrainToolGUIHelper.MinMaxSliderInt(label, prop.intValue, ref min, ref max);
|
||
|
minMaxProp.vector2IntValue = new Vector2Int(min, max);
|
||
|
}
|
||
|
|
||
|
private void DoMinMaxSlider(GUIContent label, SerializedProperty prop, SerializedProperty minMaxProp)
|
||
|
{
|
||
|
float min = minMaxProp.vector2Value.x;
|
||
|
float max = minMaxProp.vector2Value.y;
|
||
|
prop.floatValue = TerrainToolGUIHelper.MinMaxSlider(label, prop.floatValue, ref min, ref max);
|
||
|
minMaxProp.vector2Value = new Vector2(min, max);
|
||
|
}
|
||
|
|
||
|
// private void FilterSettingsGUI()
|
||
|
// {
|
||
|
// m_filterStackView.OnGUI();
|
||
|
// }
|
||
|
|
||
|
private void HandlePreviewTextureInput(Rect previewRect, bool scrollLocked)
|
||
|
{
|
||
|
if(GUIUtility.hotControl != 0)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Vector3 t = translation.vector3Value;
|
||
|
Vector3 r = rotation.vector3Value;
|
||
|
Vector3 s = scale.vector3Value;
|
||
|
|
||
|
EventType eventType = Event.current.type;
|
||
|
|
||
|
bool draggingPreview = Event.current.button == 0 &&
|
||
|
(eventType == EventType.MouseDown ||
|
||
|
eventType == EventType.MouseDrag);
|
||
|
|
||
|
Vector2 previewDims = new Vector2(previewRect.width, previewRect.height);
|
||
|
Vector2 abs = new Vector2(Mathf.Abs(s.x), Mathf.Abs(s.z));
|
||
|
|
||
|
isScrollingPreview = false;
|
||
|
|
||
|
if (!scrollLocked && Event.current.type == EventType.ScrollWheel)
|
||
|
{
|
||
|
abs += Vector2.one * .001f;
|
||
|
|
||
|
float scroll = Event.current.delta.y;
|
||
|
|
||
|
s.x += abs.x * scroll * .05f;
|
||
|
s.z += abs.y * scroll * .05f;
|
||
|
|
||
|
scale.vector3Value = s;
|
||
|
|
||
|
Event.current.Use();
|
||
|
isScrollingPreview = true;
|
||
|
}
|
||
|
else if (draggingPreview)
|
||
|
{
|
||
|
// change noise offset panning icon
|
||
|
Vector2 sign = new Vector2(-Mathf.Sign(s.x), Mathf.Sign(s.z));
|
||
|
Vector2 delta = Event.current.delta / previewDims * abs * sign;
|
||
|
Vector3 d3 = new Vector3(delta.x, 0, delta.y);
|
||
|
|
||
|
d3 = Quaternion.Euler( r ) * d3;
|
||
|
|
||
|
t += d3;
|
||
|
|
||
|
translation.vector3Value = t;
|
||
|
|
||
|
Event.current.Use();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Renders an interactive Noise Preview along with tooltip icons and an optional Export button that opens a new ExportNoiseWindow.
|
||
|
/// A background image is also rendered behind the preview that takes up the entire width of the EditorWindow currently being drawn.
|
||
|
/// </summary>
|
||
|
/// <param name = "minSize"> Minimum size for the Preview </param>
|
||
|
/// <param name = "showExportButton"> Whether or not to render the Export button </param>
|
||
|
public void DrawPreviewTexture(float minSize, bool showExportButton = true, bool scrollLocked = false)
|
||
|
{
|
||
|
// Draw label with tooltip
|
||
|
GUILayout.Label( Styles.noisePreview );
|
||
|
|
||
|
float padding = 4f;
|
||
|
float iconWidth = 40f;
|
||
|
int size = (int)Mathf.Min(minSize, EditorGUIUtility.currentViewWidth);
|
||
|
Rect totalRect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, size + padding * 2); // extra pixels for highlight border
|
||
|
|
||
|
Color prev = GUI.color;
|
||
|
GUI.color = new Color(.15f, .15f, .15f, 1f);
|
||
|
GUI.DrawTexture(totalRect, Texture2D.whiteTexture, ScaleMode.StretchToFill, false);
|
||
|
GUI.color = Color.white;
|
||
|
|
||
|
// draw info icon
|
||
|
// if(totalRect.Contains(Event.current.mousePosition))
|
||
|
{
|
||
|
Rect infoIconRect = new Rect( totalRect.x + padding, totalRect.y + padding, iconWidth, iconWidth );
|
||
|
GUI.Label( infoIconRect, Styles.infoIcon );
|
||
|
// GUI.Label( infoIconRect, Styles.noiseTooltip );
|
||
|
}
|
||
|
|
||
|
// draw export button
|
||
|
float buttonWidth = GUI.skin.button.CalcSize(Styles.export).x;
|
||
|
float buttonHeight = EditorGUIUtility.singleLineHeight;
|
||
|
Rect exportRect = new Rect( totalRect.xMax - buttonWidth - padding, totalRect.yMax - buttonHeight - padding, buttonWidth, buttonHeight );
|
||
|
if(GUI.Button(exportRect, Styles.export))
|
||
|
{
|
||
|
serializedNoise.ApplyModifiedProperties();
|
||
|
serializedNoise.Update();
|
||
|
|
||
|
ExportNoiseWindow.ShowWindow( serializedNoise.targetObject as NoiseSettings );
|
||
|
}
|
||
|
|
||
|
float safeSpace = Mathf.Max( iconWidth * 2, buttonWidth * 2 ) + padding * 4;
|
||
|
float minWidth = Mathf.Min( size, totalRect.width - safeSpace );
|
||
|
Rect previewRect = new Rect(totalRect.x + totalRect.width / 2 - minWidth / 2, totalRect.y + totalRect.height / 2 - minWidth / 2, minWidth, minWidth);
|
||
|
|
||
|
EditorGUIUtility.AddCursorRect(previewRect, MouseCursor.Pan);
|
||
|
|
||
|
if (previewRect.Contains(Event.current.mousePosition))
|
||
|
{
|
||
|
serializedNoise.Update();
|
||
|
|
||
|
HandlePreviewTextureInput(previewRect, scrollLocked);
|
||
|
|
||
|
serializedNoise.ApplyModifiedProperties();
|
||
|
}
|
||
|
|
||
|
if ( Event.current.type == EventType.Repaint )
|
||
|
{
|
||
|
RenderTexture prevActive = RenderTexture.active;
|
||
|
|
||
|
// create preview RT here and keep until the next Repaint
|
||
|
var previewRT = RenderTexture.GetTemporary(512, 512, 0, NoiseUtils.previewFormat);
|
||
|
|
||
|
NoiseSettings noiseSettings = serializedNoise.targetObject as NoiseSettings;
|
||
|
RenderTexture tempRT = RenderTexture.GetTemporary(512, 512, 0, NoiseUtils.singleChannelFormat);
|
||
|
|
||
|
NoiseUtils.Blit2D(noiseSettings, tempRT);
|
||
|
NoiseUtils.BlitPreview2D(tempRT, previewRT);
|
||
|
RenderTexture.active = prevActive;
|
||
|
GUI.DrawTexture(previewRect, previewRT, ScaleMode.ScaleToFit, false);
|
||
|
|
||
|
RenderTexture.ReleaseTemporary(tempRT);
|
||
|
RenderTexture.ReleaseTemporary(previewRT);
|
||
|
}
|
||
|
|
||
|
GUI.color = prev;
|
||
|
}
|
||
|
|
||
|
public static class Styles
|
||
|
{
|
||
|
public static GUIContent noiseSettings = EditorGUIUtility.TrTextContent("Noise Settings:");
|
||
|
public static GUIContent randomize = EditorGUIUtility.TrTextContent("Randomize");
|
||
|
public static GUIContent reset = EditorGUIUtility.TrTextContent("Reset");
|
||
|
public static GUIContent flipScale = EditorGUIUtility.TrTextContent("Flip Scale", "Flips the scale of the Noise Domain Space");
|
||
|
public static GUIContent flipScaleX = EditorGUIUtility.TrTextContent("X", "Flips the scale of the Noise Domain Space along the X-axis");
|
||
|
public static GUIContent flipScaleY = EditorGUIUtility.TrTextContent("Y", "Flips the scale of the Noise Domain Space along the Y-axis");
|
||
|
public static GUIContent flipScaleZ = EditorGUIUtility.TrTextContent("Z", "Flips the scale of the Noise Domain Space along the Z-axis");
|
||
|
public static GUIContent noiseType = EditorGUIUtility.TrTextContent("Noise Type", "The type of Noise to be used");
|
||
|
public static GUIContent fractalType = EditorGUIUtility.TrTextContent("Fractal Type", "The type of Fractal to be used when generating Noise");
|
||
|
public static GUIContent noisePreview;
|
||
|
public static GUIContent noiseTooltip = EditorGUIUtility.TrTextContent("",
|
||
|
"Scroll Mouse Wheel:\nZooms the preview in and out and changes the noise scale\n\n" +
|
||
|
"Left-mouse Drag:\nPans the noise field and changes the noise translation\n\n" +
|
||
|
"Color Key:\nCyan = negative noise values\nGrayscale = values between 0 and 1\nBlack = values are 0\nRed = Values greater than 1. Used for debugging texture normalization");
|
||
|
public static GUIContent seed = EditorGUIUtility.TrTextContent("Seed");
|
||
|
public static GUIContent domainSettings = EditorGUIUtility.TrTextContent("Domain Settings", "Settings governing the Noise Domain. This is specific to each Noise Type and Fractal Type implementation");
|
||
|
public static GUIContent transformSettings = EditorGUIUtility.TrTextContent("Transform Settings", "Settings governing the transformations applied to positions in the Noise Domain Space");
|
||
|
// public static GUIContent filterSettings = EditorGUIUtility.TrTextContent("Filter Settings");
|
||
|
public static GUIContent ridgePower = EditorGUIUtility.TrTextContent("Ridge Power");
|
||
|
public static GUIContent billowPower = EditorGUIUtility.TrTextContent("Billow Power");
|
||
|
public static GUIContent voronoiPower = EditorGUIUtility.TrTextContent("Voronoi Power");
|
||
|
public static GUIContent power = EditorGUIUtility.TrTextContent("Power");
|
||
|
public static GUIContent export = EditorGUIUtility.TrTextContent("Export", "Open a window providing options for exporting Noise to Textures");
|
||
|
public static GUIContent infoIcon = new GUIContent("", EditorGUIUtility.FindTexture("console.infoicon"),
|
||
|
"Scroll Mouse Wheel:\nZooms the preview in and out and changes the noise scale\n\n" +
|
||
|
"Left-mouse Drag:\nPans the noise field and changes the noise translation\n\n" +
|
||
|
"Color Key:\nCyan = negative noise values\nGrayscale = values between 0 and 1\nBlack = values are 0\nRed = Values greater than 1. Used for debugging texture normalization");
|
||
|
|
||
|
static Styles()
|
||
|
{
|
||
|
noisePreview = EditorGUIUtility.TrTextContent("Noise Field Preview:");
|
||
|
// ,
|
||
|
// "Scroll Mouse Wheel:\nZooms the preview in and out and changes the noise scale\n\n" +
|
||
|
// "Left-mouse Drag:\nPans the noise field and changes the noise translation\n\n" +
|
||
|
// "Color Key:\nCyan = negative noise values\nGrayscale = values between 0 and 1\nBlack = values are 0\nRed = Values greater than 1. Used for debugging texture normalization");
|
||
|
// noisePreview.image = infoIcon.image;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|