using System.Text;
using UnityEngine;
using UnityEngine.TerrainTools;
namespace UnityEditor.TerrainTools
{
///
/// Represents an base terrain tools variator class.
///
public abstract class BaseBrushVariator : IBrushController, IBrushTerrainCache
{
private readonly string m_NamePrefix;
private readonly IBrushEventHandler m_EventHandler;
private readonly IBrushTerrainCache m_TerrainCache;
private static GUIStyle _s_SceneLabelStyle;
///
/// Gets the the GUIStyle of the scene's label.
///
protected static GUIStyle s_SceneLabelStyle {
get
{
if (_s_SceneLabelStyle != null)
{
return _s_SceneLabelStyle;
}
_s_SceneLabelStyle = new GUIStyle
{
normal = new GUIStyleState()
{
background = Texture2D.whiteTexture
},
fontSize = 12
};
return _s_SceneLabelStyle;
}
}
///
/// Checks if the brush is in use.
///
public virtual bool isInUse => m_ModifierActive;
///
/// Initializes and returns an instance of BaseBrushVariator.
///
/// The tool's name which the variator is used with.
/// The brush event handler.
/// The cache reference of the terrain.
protected BaseBrushVariator(string toolName, IBrushEventHandler eventHandler, IBrushTerrainCache terrainCache)
{
m_NamePrefix = toolName;
m_EventHandler = eventHandler;
m_TerrainCache = terrainCache;
}
///
/// Sets the repaint request to true.
///
protected void RequestRepaint()
{
m_EventHandler.RequestRepaint();
}
private void OnModifierKeyPressed()
{
m_ModifierActive = true;
HandleBeginModifier();
}
private void OnModifierKeyReleased()
{
HandleEndModifier();
m_ModifierActive = false;
}
///
/// Gets the editor preferences for boolean values.
///
/// The name of the preference.
/// The default value of the preference.
/// Returns the editor preference value corresponding to the name.
///
protected bool GetEditorPrefs(string name, bool defaultValue)
{
return EditorPrefs.GetBool($"{m_NamePrefix}.{name}", defaultValue);
}
///
/// Sets the editor preferences for boolean values.
///
/// The name of the preference.
/// The prefence value to set.
///
protected void SetEditorPrefs(string name, bool currentValue)
{
EditorPrefs.SetBool($"{m_NamePrefix}.{name}", currentValue);
}
///
/// Gets the editor preferences for float values.
///
/// The name of the preference.
/// The default value of the preference.
/// Returns the editor preference value corresponding to the name.
///
protected float GetEditorPrefs(string name, float defaultValue)
{
return EditorPrefs.GetFloat($"{m_NamePrefix}.{name}", defaultValue);
}
///
/// Sets the editor preferences for float values.
///
/// The name of the preference.
/// The prefence value to set.
///
protected void SetEditorPrefs(string name, float currentValue)
{
EditorPrefs.SetFloat($"{m_NamePrefix}.{name}", currentValue);
}
private bool m_ModifierActive;
private Vector2 m_InitialMousePosition;
///
/// Calculates the difference between the mouses initial and current position.
///
/// The current mouse event.
/// The scale to multiply the delta by.
/// Returns the difference between the initial and current position of the mouse.
///
protected Vector2 CalculateMouseDeltaFromInitialPosition(Event mouseEvent, float scale = 1.0f)
{
Vector2 mousePosition = mouseEvent.mousePosition;
Vector2 delta = m_InitialMousePosition - mousePosition;
Vector2 scaledDelta = delta * scale;
return scaledDelta;
}
///
/// Gets the mouses delta from the mouse event.
///
/// The current mouse event.
/// The scale to multiply the delta by.
/// Returns the mouses delta.
///
protected static Vector2 CalculateMouseDelta(Event mouseEvent, float scale = 1.0f)
{
Vector2 delta = mouseEvent.delta;
Vector2 scaledDelta = delta * scale;
return scaledDelta;
}
///
/// Called when the Variator is initially modified.
///
/// This method is to be overriden when creating custom variators.
/// Returns true when the modification is successful. Otherwise, returns false.
protected virtual bool OnBeginModifier()
{
return false;
}
///
/// Called when a mouse drag is used when modifying a Variator.
///
/// The current mouse event.
/// The terrain in focus.
/// The editcontext to reference.
/// This method is to be overriden when creating custom variators.
/// Returns true when the modification is successful. Otherwise, returns false.
protected virtual bool OnModifierUsingMouseMove(Event mouseEvent, Terrain terrain, IOnSceneGUI editContext)
{
if (!m_ModifierActive)
{
m_InitialMousePosition = mouseEvent.mousePosition;
}
return false;
}
///
/// Called when a mouse wheel is used when modifying a Variator.
///
/// The current mouse event.
/// The terrain in focus.
/// The editcontext to reference.
/// This method is to be overriden when creating custom variators.
/// Returns true when the modification is successful. Otherwise, returns false.
protected virtual bool OnModifierUsingMouseWheel(Event mouseEvent, Terrain terrain, IOnSceneGUI editContext)
{
return false;
}
///
/// Called when the Variator's modification has finished.
///
/// This method is to be overriden when creating custom variators.
/// Returns true when the modification is successful. Otherwise, returns false.
protected virtual bool OnEndModifier()
{
return false;
}
private bool HandleBeginModifier()
{
bool consumeEvent = OnBeginModifier();
return consumeEvent;
}
private bool HandleModifierUsingMouseMove(Event mouseEvent, Terrain terrain, IOnSceneGUI editContext)
{
bool consumeEvent = OnModifierUsingMouseMove(mouseEvent, terrain, editContext);
return consumeEvent;
}
private bool HandleModifierUsingMouseWheel(Event mouseEvent, Terrain terrain, IOnSceneGUI editContext)
{
bool consumeEvent = OnModifierUsingMouseWheel(mouseEvent, terrain, editContext);
return consumeEvent;
}
private bool HandleEndModifier()
{
bool consumeEvent = OnEndModifier();
return consumeEvent;
}
private bool ProcessMouseEvent(Event mouseEvent, int controlId, Terrain terrain, IOnSceneGUI editContext)
{
bool consumeEvent = false;
if (m_ModifierActive)
{
EventType eventType = mouseEvent.GetTypeForControl(controlId);
switch (eventType)
{
case EventType.MouseMove:
{
consumeEvent |= HandleModifierUsingMouseMove(mouseEvent, terrain, editContext);
break;
}
case EventType.ScrollWheel:
{
consumeEvent |= HandleModifierUsingMouseWheel(mouseEvent, terrain, editContext);
break;
}
} // End of switch.
}
if (consumeEvent)
{
// We changed something - time to repaint...
RequestRepaint();
return true;
}
else
{
return false;
}
}
///
/// Defines data when the brush is selected.
///
/// The shortcut handler to subscribe brush shortcuts.
///
///
public virtual void OnEnterToolMode(BrushShortcutHandler shortcutHandler)
{
shortcutHandler.AddActions(BrushShortcutType.RotationSizeStrength, OnModifierKeyPressed, OnModifierKeyReleased);
}
///
/// Defines data when the brush is deselected.
///
/// The shortcut handler to unsubscribe brush shortcuts.
///
///
public virtual void OnExitToolMode(BrushShortcutHandler shortcutHandler)
{
shortcutHandler.RemoveActions(BrushShortcutType.RotationSizeStrength);
}
///
/// Triggers events to render objects and displays within Scene view.
///
/// The event to check whether the mouse is in use.
/// The control ID of the GUI.
/// The terrain in focus.
/// The editcontext to reference
public virtual void OnSceneGUI(Event currentEvent, int controlId, Terrain terrain, IOnSceneGUI editContext)
{
if (currentEvent.isMouse || currentEvent.isScrollWheel)
{
if (ProcessMouseEvent(currentEvent, controlId, terrain, editContext))
{
m_EventHandler.RegisterEvent(currentEvent);
}
}
}
///
/// Renders the brush's GUI within the inspector view.
///
/// The terrain in focus.
/// The editcontext used to show the brush GUI.
public virtual void OnInspectorGUI(Terrain terrain, IOnInspectorGUI editContext)
{
}
///
/// Triggers events when painting on a terrain.
///
/// The terrain in focus.
/// The editcontext to reference.
/// Returns true if the paint opertation is succesful. Otherise, returns false.
public virtual bool OnPaint(Terrain terrain, IOnPaint editContext)
{
return true;
}
///
/// Adds basic information to the selected brush.
///
/// The Terrain in focus.
/// The IOnSceneGUI to reference.
/// The StringBuilder containing the brush information.
public virtual void AppendBrushInfo(Terrain terrain, IOnSceneGUI editContext, StringBuilder builder)
{
}
///
/// Gets and sets the terrain in focus.
///
public Terrain terrainUnderCursor => m_TerrainCache.terrainUnderCursor;
///
/// Gets and sets the value associated to whether there is a raycast hit detecting a terrain under the cursor.
///
public bool isRaycastHitUnderCursorValid => m_TerrainCache.isRaycastHitUnderCursorValid;
///
/// Gets and sets the raycast hit that was under the cursor's position.
///
public RaycastHit raycastHitUnderCursor => m_TerrainCache.raycastHitUnderCursor;
///
/// Checks if the cursor is currently locked and can not be updated.
///
public bool canUpdateTerrainUnderCursor => m_TerrainCache.canUpdateTerrainUnderCursor;
///
/// Handles the locking of the terrain cursor in it's current position.
///
/// This method is commonly used when utilizing shortcuts.
/// Whether the cursor is visible within the scene. When the value is true the cursor is visible.
///
public void LockTerrainUnderCursor(bool cursorVisible)
{
m_TerrainCache.LockTerrainUnderCursor(cursorVisible);
}
///
/// Handles unlocking of the terrain cursor.
///
///
public void UnlockTerrainUnderCursor()
{
m_TerrainCache.UnlockTerrainUnderCursor();
}
}
}