using System; using System.Text; using UnityEditor.TerrainTools.UI; using UnityEngine; using UnityEngine.TerrainTools; namespace UnityEditor.TerrainTools { internal class BrushSpacingVariator : BaseBrushVariator, IBrushSpacingController { private float m_BrushSpacing = 0.0f; private bool m_AllowPaint = true; private bool m_ThresholdReached = false; private float m_DistanceTravelled = 0.0f; private Vector3 m_LastBrushPos; private float m_defaultBrushSpacing; public float brushSpacing { get { return m_BrushSpacing; } set { m_BrushSpacing = Mathf.Clamp(value, 0f, 100f); } } public bool allowPaint { get => m_AllowPaint; set => m_AllowPaint = value; } class Styles { public readonly GUIContent brushSpacing = EditorGUIUtility.TrTextContent("Brush Spacing", "Distance between each brush stamp in a stroke"); } static readonly Styles styles = new Styles(); public BrushSpacingVariator(string toolName, IBrushEventHandler eventHandler, IBrushTerrainCache terrainCache, float defaultValue = 0.0f) : base(toolName, eventHandler, terrainCache) { m_defaultBrushSpacing = defaultValue; } public override void OnEnterToolMode(BrushShortcutHandler shortcutHandler) { base.OnEnterToolMode(shortcutHandler); m_BrushSpacing = GetEditorPrefs("TerrainBrushSpacing", m_defaultBrushSpacing); } public override void OnExitToolMode(BrushShortcutHandler shortcutHandler) { SetEditorPrefs("TerrainBrushSpacing", m_BrushSpacing); base.OnExitToolMode(shortcutHandler); } public override void OnSceneGUI(Event currentEvent, int controlId, Terrain terrain, IOnSceneGUI editContext) { //maybe this should be scaled by brush size? Vector2 a = new Vector2(m_LastBrushPos.x, m_LastBrushPos.z); Vector2 b = new Vector2(editContext.raycastHit.point.x, editContext.raycastHit.point.z); float d = Vector2.Distance(a, b); float threshold = m_BrushSpacing * 200f; //TODO: make this scalar a user preference? base.OnSceneGUI(currentEvent, controlId, terrain, editContext); m_DistanceTravelled += d; if (m_DistanceTravelled > threshold) { m_ThresholdReached = true; m_LastBrushPos = editContext.raycastHit.point; m_DistanceTravelled = 0.0f; } m_LastBrushPos = editContext.raycastHit.point; } // for updating condensed slider overlays public static event Action BrushSpacingChanged; private float prevBrushSpacing; public override void OnInspectorGUI(Terrain terrain, IOnInspectorGUI editContext) { base.OnInspectorGUI(terrain, editContext); m_BrushSpacing = TerrainToolGUIHelper.PercentSlider(styles.brushSpacing, m_BrushSpacing, 0.0f, 1.0f); if (!Mathf.Approximately(m_BrushSpacing, prevBrushSpacing) && BrushSpacingChanged != null) { BrushSpacingChanged(); prevBrushSpacing = m_BrushSpacing; } } public override bool OnPaint(Terrain terrain, IOnPaint editContext) { base.OnPaint(terrain, editContext); m_AllowPaint = m_ThresholdReached; if (m_AllowPaint) { m_ThresholdReached = false; } return true; } public override void AppendBrushInfo(Terrain terrain, IOnSceneGUI editContext, StringBuilder builder) { base.AppendBrushInfo(terrain, editContext, builder); builder.AppendLine($"Spacing = {m_BrushSpacing:F3}"); } } }