2024-03-05 17:34:41 +08:00
#if GRIFFIN
2023-12-30 17:37:48 +08:00
using Pinwheel.Griffin.BackupTool ;
using System.Collections.Generic ;
using UnityEditor ;
using UnityEngine ;
namespace Pinwheel.Griffin.StampTool
{
[CustomEditor(typeof(GGeometryStamper))]
public class GGeometryStamperInspector : Editor
{
private GGeometryStamper instance ;
private Dictionary < GStylizedTerrain , RenderTexture > previewTextures ;
private static readonly string HISTORY_PREFIX = "Stamp Geometry" ;
private readonly Vector3 [ ] worldPoints = new Vector3 [ 4 ] ;
private readonly Vector3 [ ] worldBox = new Vector3 [ 8 ] ;
private void OnEnable ( )
{
Undo . undoRedoPerformed + = OnUndoRedo ;
SceneView . duringSceneGui + = DuringSceneGUI ;
instance = target as GGeometryStamper ;
Tools . hidden = true ;
instance . Internal_UpdateFalloffTexture ( ) ;
GCommon . RegisterBeginRender ( OnCameraRender ) ;
GCommon . RegisterBeginRenderSRP ( OnCameraRenderSRP ) ;
UpdatePreview ( ) ;
}
private void OnDisable ( )
{
Tools . hidden = false ;
Undo . undoRedoPerformed - = OnUndoRedo ;
SceneView . duringSceneGui - = DuringSceneGUI ;
GCommon . UnregisterBeginRender ( OnCameraRender ) ;
GCommon . UnregisterBeginRenderSRP ( OnCameraRenderSRP ) ;
if ( previewTextures ! = null )
{
foreach ( GStylizedTerrain t in previewTextures . Keys )
{
RenderTexture rt = previewTextures [ t ] ;
if ( rt = = null )
continue ;
rt . Release ( ) ;
Object . DestroyImmediate ( rt ) ;
}
}
}
private void OnUndoRedo ( )
{
if ( Selection . activeGameObject ! = instance . gameObject )
return ;
if ( string . IsNullOrEmpty ( GUndoCompatibleBuffer . Instance . CurrentBackupName ) )
return ;
GBackup . Restore ( GUndoCompatibleBuffer . Instance . CurrentBackupName ) ;
UpdatePreview ( ) ;
}
2024-03-05 17:34:41 +08:00
private class GBaseGUI
{
public static readonly GUIContent GROUP_ID = new GUIContent ( "Group Id" , "Id of the terrain group which is edited by this tool" ) ;
public static readonly GUIContent ENABLE_TERRAIN_MASK = new GUIContent ( "Enable Terrain Mask" , "Use terrain mask (R) to lock a particular region from editing" ) ;
public static readonly GUIContent SHOW_TERRAIN_MASK = new GUIContent ( "Show Terrain Mask" , "Draw an overlay of the terrain mask in the scene view" ) ;
public static readonly GUIContent ENABLE_TOPOGRAPHIC = new GUIContent ( "Enable Topographic" , "Draw topographic view over the terrain for better sense of altitude" ) ;
}
2023-12-30 17:37:48 +08:00
public override void OnInspectorGUI ( )
{
EditorGUI . BeginChangeCheck ( ) ;
2024-03-05 17:34:41 +08:00
instance . GroupId = GEditorCommon . ActiveTerrainGroupPopupWithAllOption ( GBaseGUI . GROUP_ID , instance . GroupId ) ;
instance . EnableTerrainMask = EditorGUILayout . Toggle ( GBaseGUI . ENABLE_TERRAIN_MASK , instance . EnableTerrainMask ) ;
if ( instance . EnableTerrainMask )
{
GEditorSettings . Instance . stampTools . showTerrainMask = EditorGUILayout . Toggle ( GBaseGUI . SHOW_TERRAIN_MASK , GEditorSettings . Instance . stampTools . showTerrainMask ) ;
}
GEditorSettings . Instance . topographic . enable = EditorGUILayout . Toggle ( GBaseGUI . ENABLE_TOPOGRAPHIC , GEditorSettings . Instance . topographic . enable ) ;
2023-12-30 17:37:48 +08:00
DrawInstructionGUI ( ) ;
DrawTransformGUI ( ) ;
DrawStampGUI ( ) ;
DrawGizmosGUI ( ) ;
DrawActionGUI ( ) ;
#if GRIFFIN_VEGETATION_STUDIO_PRO
GEditorCommon . DrawVspIntegrationGUI ( ) ;
#endif
GEditorCommon . DrawBackupHelpBox ( ) ;
if ( EditorGUI . EndChangeCheck ( ) )
{
UpdatePreview ( ) ;
}
}
public override bool RequiresConstantRepaint ( )
{
return false ;
}
2024-03-05 17:34:41 +08:00
private class GInstructionGUI
{
public static readonly string LABEL = "Instruction" ;
public static readonly string ID = "geo-stamper-instruction" ;
public static readonly string INSTRUCTION = "Stamp features onto the terrain surface." ;
}
2023-12-30 17:37:48 +08:00
private void DrawInstructionGUI ( )
{
2024-03-05 17:34:41 +08:00
GEditorCommon . Foldout ( GInstructionGUI . LABEL , true , GInstructionGUI . ID , ( ) = >
2023-12-30 17:37:48 +08:00
{
2024-03-05 17:34:41 +08:00
EditorGUILayout . LabelField ( GInstructionGUI . INSTRUCTION , GEditorCommon . WordWrapItalicLabel ) ;
2023-12-30 17:37:48 +08:00
} ) ;
}
2024-03-05 17:34:41 +08:00
private class GTransformGUI
{
public static readonly string LABEL = "Transform" ;
public static readonly string ID = "geo-stamper-transform" ;
public static readonly GUIContent POSITION = new GUIContent ( "Position" , "Position of the stamper" ) ;
public static readonly GUIContent ROTATION = new GUIContent ( "Rotation" , "Rotation of the stamper" ) ;
public static readonly GUIContent SCALE = new GUIContent ( "Scale" , "Scale of the stamper" ) ;
}
2023-12-30 17:37:48 +08:00
private void DrawTransformGUI ( )
{
2024-03-05 17:34:41 +08:00
GEditorCommon . Foldout ( GTransformGUI . LABEL , true , GTransformGUI . ID , ( ) = >
2023-12-30 17:37:48 +08:00
{
2024-03-05 17:34:41 +08:00
instance . Position = GEditorCommon . InlineVector3Field ( GTransformGUI . POSITION , instance . Position ) ;
instance . Rotation = Quaternion . Euler ( GEditorCommon . InlineVector3Field ( GTransformGUI . ROTATION , instance . Rotation . eulerAngles ) ) ;
instance . Scale = GEditorCommon . InlineVector3Field ( GTransformGUI . SCALE , instance . Scale ) ;
2023-12-30 17:37:48 +08:00
Vector3 euler = instance . Rotation . eulerAngles ;
euler = new Vector3 ( 0 , euler . y , 0 ) ;
instance . Rotation = Quaternion . Euler ( euler ) ;
} ) ;
}
2024-03-05 17:34:41 +08:00
private class GStampGUI
{
public static readonly string LABEL = "Stamp" ;
public static readonly string ID = "geo-stamper-stamp" ;
public static readonly GUIContent MASK = new GUIContent ( "Mask" , "A texture defines the geometry feature to stamp, only R channel is used" ) ;
public static readonly GUIContent CHANNEL = new GUIContent ( "Channel" , "Choose whether to stamp to height or visibility data" ) ;
public static readonly GUIContent FALLOFF = new GUIContent ( "Falloff" , "Gradually decrease the mask intensity over its edge" ) ;
public static readonly GUIContent OPERATION = new GUIContent ( "Operation" , "The math operation to perform on the terrain, please see the documentation for detail" ) ;
public static readonly GUIContent LERP_FACTOR = new GUIContent ( "Lerp Factor" , "The interpolation factor" ) ;
public static readonly GUIContent ADDITIONAL_MESH_RESOLUTION = new GUIContent ( "Additional Mesh Resolution" , "Add more polygons to the stamp area" ) ;
public static readonly GUIContent INVERSE = new GUIContent ( "Inverse the stamp mask" ) ;
public static readonly GUIContent BLEND_USING_FALLOFF = new GUIContent ( "Blend Using Falloff" , "Blend the stamp result with the current terrain using Falloff curve" ) ;
}
2023-12-30 17:37:48 +08:00
private void DrawStampGUI ( )
{
2024-03-05 17:34:41 +08:00
GEditorCommon . Foldout ( GStampGUI . LABEL , true , GStampGUI . ID , ( ) = >
2023-12-30 17:37:48 +08:00
{
2024-03-05 17:34:41 +08:00
instance . Stamp = EditorGUILayout . ObjectField ( GStampGUI . MASK , instance . Stamp , typeof ( Texture2D ) , false ) as Texture2D ;
instance . Channel = ( GGeometryStamper . GStampChannel ) EditorGUILayout . EnumPopup ( GStampGUI . CHANNEL , instance . Channel ) ;
2023-12-30 17:37:48 +08:00
EditorGUI . BeginChangeCheck ( ) ;
2024-03-05 17:34:41 +08:00
instance . Falloff = EditorGUILayout . CurveField ( GStampGUI . FALLOFF , instance . Falloff , Color . red , new Rect ( 0 , 0 , 1 , 1 ) ) ;
2023-12-30 17:37:48 +08:00
if ( EditorGUI . EndChangeCheck ( ) )
{
instance . Internal_UpdateFalloffTexture ( ) ;
}
2024-03-05 17:34:41 +08:00
instance . Operation = ( GStampOperation ) EditorGUILayout . EnumPopup ( GStampGUI . OPERATION , instance . Operation ) ;
2023-12-30 17:37:48 +08:00
if ( instance . Operation = = GStampOperation . Lerp )
{
2024-03-05 17:34:41 +08:00
instance . LerpFactor = EditorGUILayout . Slider ( GStampGUI . LERP_FACTOR , instance . LerpFactor , 0f , 1f ) ;
2023-12-30 17:37:48 +08:00
}
2024-03-05 17:34:41 +08:00
instance . AdditionalMeshResolution = EditorGUILayout . IntSlider ( GStampGUI . ADDITIONAL_MESH_RESOLUTION , instance . AdditionalMeshResolution , 0 , 10 ) ;
instance . InverseStamp = EditorGUILayout . Toggle ( GStampGUI . INVERSE , instance . InverseStamp ) ;
instance . UseFalloffAsBlendFactor = EditorGUILayout . Toggle ( GStampGUI . BLEND_USING_FALLOFF , instance . UseFalloffAsBlendFactor ) ;
2023-12-30 17:37:48 +08:00
} ) ;
}
2024-03-05 17:34:41 +08:00
private class GGizmosGUI
{
public static readonly string LABEL = "Gizmos" ;
public static readonly string ID = "geo-stamper-gizmos" ;
public static readonly GUIContent LIVE_PREVIEW = new GUIContent ( "Live Preview" , "Draw a preview in the scene view" ) ;
public static readonly GUIContent BOUNDS = new GUIContent ( "Bounds" , "Show the stamper bounds in the scene view" ) ;
}
2023-12-30 17:37:48 +08:00
private void DrawGizmosGUI ( )
{
2024-03-05 17:34:41 +08:00
GEditorCommon . Foldout ( GGizmosGUI . LABEL , true , GGizmosGUI . ID , ( ) = >
2023-12-30 17:37:48 +08:00
{
2024-03-05 17:34:41 +08:00
GEditorSettings . Instance . stampTools . showLivePreview = EditorGUILayout . Toggle ( GGizmosGUI . LIVE_PREVIEW , GEditorSettings . Instance . stampTools . showLivePreview ) ;
GEditorSettings . Instance . stampTools . showBounds = EditorGUILayout . Toggle ( GGizmosGUI . BOUNDS , GEditorSettings . Instance . stampTools . showBounds ) ;
2023-12-30 17:37:48 +08:00
} ) ;
}
2024-03-05 17:34:41 +08:00
private class GActionGUI
{
public static readonly string LABEL = "Action" ;
public static readonly string ID = "geo-stamper-action" ;
public static readonly GUIContent SNAP_TO_TERRAIN = new GUIContent ( "Snap To Terrain" , "Fit the stamper to the underneath terrain" ) ;
public static readonly GUIContent SNAP_TO_LEVEL_BOUNDS = new GUIContent ( "Snap To Level Bounds" , "Fit the stamper to cover all terrains in the level" ) ;
public static readonly GUIContent APPLY = new GUIContent ( "Apply" , "Stamp on the terrains" ) ;
}
2023-12-30 17:37:48 +08:00
private void DrawActionGUI ( )
{
2024-03-05 17:34:41 +08:00
GEditorCommon . Foldout ( GActionGUI . LABEL , true , GActionGUI . ID , ( ) = >
2023-12-30 17:37:48 +08:00
{
EditorGUILayout . BeginHorizontal ( ) ;
2024-03-05 17:34:41 +08:00
if ( GUILayout . Button ( GActionGUI . SNAP_TO_TERRAIN ) )
2023-12-30 17:37:48 +08:00
{
IEnumerator < GStylizedTerrain > terrains = GStylizedTerrain . ActiveTerrains . GetEnumerator ( ) ;
while ( terrains . MoveNext ( ) )
{
GStylizedTerrain t = terrains . Current ;
Bounds b = t . Bounds ;
Rect r = new Rect ( new Vector2 ( b . min . x , b . min . z ) , new Vector2 ( b . size . x , b . size . z ) ) ;
Vector2 p = new Vector2 ( instance . Position . x , instance . Position . z ) ;
if ( r . Contains ( p ) )
{
instance . Position = new Vector3 ( r . center . x , b . min . y , r . center . y ) ;
instance . Rotation = Quaternion . identity ;
instance . Scale = new Vector3 ( b . size . x , b . size . y , b . size . z ) ;
break ;
}
}
}
2024-03-05 17:34:41 +08:00
if ( GUILayout . Button ( GActionGUI . SNAP_TO_LEVEL_BOUNDS ) )
2023-12-30 17:37:48 +08:00
{
Bounds b = GCommon . GetLevelBounds ( ) ;
instance . Position = new Vector3 ( b . center . x , b . min . y , b . center . z ) ;
instance . Rotation = Quaternion . identity ;
instance . Scale = new Vector3 ( b . size . x , b . size . y , b . size . z ) ;
}
EditorGUILayout . EndHorizontal ( ) ;
2024-03-05 17:34:41 +08:00
if ( GUILayout . Button ( GActionGUI . APPLY ) )
2023-12-30 17:37:48 +08:00
{
2024-03-05 17:34:41 +08:00
List < GStylizedTerrain > terrains = GUtilities . ExtractTerrainsFromOverlapTest ( GCommon . OverlapTest ( instance . GroupId , instance . GetQuad ( ) ) ) ;
CreateInitialBackup ( terrains ) ;
2023-12-30 17:37:48 +08:00
ApplyStamp ( ) ;
2024-03-05 17:34:41 +08:00
CreateAfterStampBackup ( terrains ) ;
2023-12-30 17:37:48 +08:00
}
} ) ;
}
2024-03-05 17:34:41 +08:00
private void CreateInitialBackup ( List < GStylizedTerrain > terrains )
2023-12-30 17:37:48 +08:00
{
GBackupInternal . TryCreateAndMergeInitialBackup ( HISTORY_PREFIX , terrains , GCommon . HeightMapAndFoliageResourceFlags , true ) ;
}
2024-03-05 17:34:41 +08:00
private class GStampDialogGUI
{
public static readonly string TITLE = "Applying" ;
public static readonly string INFO = "Stamping terrain geometry..." ;
}
2023-12-30 17:37:48 +08:00
private void ApplyStamp ( )
{
2024-03-05 17:34:41 +08:00
EditorUtility . DisplayProgressBar ( GStampDialogGUI . TITLE , GStampDialogGUI . INFO , 1f ) ;
2023-12-30 17:37:48 +08:00
try
{
instance . Apply ( ) ;
}
catch ( System . Exception e )
{
Debug . LogError ( e . ToString ( ) ) ;
}
EditorUtility . ClearProgressBar ( ) ;
}
2024-03-05 17:34:41 +08:00
private void CreateAfterStampBackup ( List < GStylizedTerrain > terrains )
2023-12-30 17:37:48 +08:00
{
GBackupInternal . TryCreateAndMergeBackup ( HISTORY_PREFIX , terrains , GCommon . HeightMapAndFoliageResourceFlags , true ) ;
}
private void DuringSceneGUI ( SceneView sv )
{
EditorGUI . BeginChangeCheck ( ) ;
HandleEditingTransform ( ) ;
DrawStampBounds ( ) ;
if ( EditorGUI . EndChangeCheck ( ) )
{
UpdatePreview ( ) ;
}
}
private void HandleEditingTransform ( )
{
if ( Tools . current = = Tool . Move )
{
instance . Position = Handles . PositionHandle ( instance . Position , instance . Rotation ) ;
}
else if ( Tools . current = = Tool . Rotate )
{
instance . Rotation = Handles . RotationHandle ( instance . Rotation , instance . Position ) ;
Vector3 euler = instance . Rotation . eulerAngles ;
euler = new Vector3 ( 0 , euler . y , 0 ) ;
instance . Rotation = Quaternion . Euler ( euler ) ;
}
else if ( Tools . current = = Tool . Scale )
{
instance . Scale = Handles . ScaleHandle ( instance . Scale , instance . Position , instance . Rotation , HandleUtility . GetHandleSize ( instance . Position ) ) ;
}
}
private void OnCameraRender ( Camera cam )
{
2024-03-05 17:34:41 +08:00
if ( cam . cameraType ! = CameraType . SceneView )
return ;
if ( GEditorSettings . Instance . stampTools . showLivePreview )
2023-12-30 17:37:48 +08:00
DrawLivePreview ( cam ) ;
2024-03-05 17:34:41 +08:00
if ( instance . EnableTerrainMask & & GEditorSettings . Instance . stampTools . showTerrainMask )
{
DrawMask ( cam ) ;
}
2023-12-30 17:37:48 +08:00
}
private void OnCameraRenderSRP ( UnityEngine . Rendering . ScriptableRenderContext context , Camera cam )
{
OnCameraRender ( cam ) ;
}
private void DrawLivePreview ( Camera cam )
{
2024-03-05 17:34:41 +08:00
List < GOverlapTestResult > overlapTest = GCommon . OverlapTest ( instance . GroupId , instance . GetQuad ( ) ) ;
foreach ( GOverlapTestResult test in overlapTest )
2023-12-30 17:37:48 +08:00
{
2024-03-05 17:34:41 +08:00
if ( test . IsOverlapped )
{
DrawLivePreview ( test . Terrain , cam , test . IsChunkOverlapped ) ;
}
2023-12-30 17:37:48 +08:00
}
}
private void DrawMask ( Camera cam )
{
GCommon . ForEachTerrain ( instance . GroupId , ( t ) = >
{
GLivePreviewDrawer . DrawTerrainMask ( t , cam ) ;
} ) ;
}
2024-03-05 17:34:41 +08:00
private void DrawLivePreview ( GStylizedTerrain t , Camera cam , bool [ ] chunkCulling )
2023-12-30 17:37:48 +08:00
{
if ( t . transform . rotation ! = Quaternion . identity | |
t . transform . lossyScale ! = Vector3 . one )
return ;
RenderTexture rt = GetPreviewTexture ( t ) ;
if ( instance . Channel = = GGeometryStamper . GStampChannel . Elevation )
{
2024-03-05 17:34:41 +08:00
GLivePreviewDrawer . DrawGeometryLivePreview ( t , cam , rt , chunkCulling ) ;
2023-12-30 17:37:48 +08:00
}
else if ( instance . Channel = = GGeometryStamper . GStampChannel . Visibility )
{
Matrix4x4 worldToMaskMatrix = Matrix4x4 . TRS (
worldPoints [ 0 ] ,
instance . Rotation ,
instance . Scale ) . inverse ;
2024-03-05 17:34:41 +08:00
GLivePreviewDrawer . DrawVisibilityLivePreview ( t , cam , rt , chunkCulling , instance . Stamp , worldToMaskMatrix ) ;
2023-12-30 17:37:48 +08:00
}
}
private void UpdatePreview ( )
{
2024-03-05 17:34:41 +08:00
List < GStylizedTerrain > terrains = GUtilities . ExtractTerrainsFromOverlapTest ( GCommon . OverlapTest ( instance . GroupId , instance . GetQuad ( ) ) ) ;
foreach ( GStylizedTerrain t in terrains )
2023-12-30 17:37:48 +08:00
{
UpdatePreview ( t ) ;
}
}
private void UpdatePreview ( GStylizedTerrain t )
{
RenderTexture rt = GetPreviewTexture ( t ) ;
2024-03-05 17:34:41 +08:00
instance . Internal_DrawOnTexture ( t , rt ) ;
2023-12-30 17:37:48 +08:00
}
private RenderTexture GetPreviewTexture ( GStylizedTerrain t )
{
if ( previewTextures = = null )
{
previewTextures = new Dictionary < GStylizedTerrain , RenderTexture > ( ) ;
}
int resolution = t . TerrainData . Geometry . HeightMapResolution ;
if ( ! previewTextures . ContainsKey ( t ) | |
previewTextures [ t ] = = null )
{
RenderTexture rt = new RenderTexture ( resolution , resolution , 0 , GGeometry . HeightMapRTFormat , RenderTextureReadWrite . Linear ) ;
previewTextures [ t ] = rt ;
}
else if ( previewTextures [ t ] . width ! = resolution | |
previewTextures [ t ] . height ! = resolution | |
previewTextures [ t ] . format ! = GGeometry . HeightMapRTFormat )
{
previewTextures [ t ] . Release ( ) ;
Object . DestroyImmediate ( previewTextures [ t ] ) ;
RenderTexture rt = new RenderTexture ( resolution , resolution , 0 , GGeometry . HeightMapRTFormat , RenderTextureReadWrite . Linear ) ;
previewTextures [ t ] = rt ;
}
previewTextures [ t ] . wrapMode = TextureWrapMode . Clamp ;
return previewTextures [ t ] ;
}
private void DrawStampBounds ( )
{
2024-03-05 17:34:41 +08:00
if ( ! GEditorSettings . Instance . stampTools . showBounds )
2023-12-30 17:37:48 +08:00
return ;
instance . GetBox ( worldBox ) ;
Vector3 [ ] b = worldBox ;
Handles . color = Color . yellow ;
Handles . zTest = UnityEngine . Rendering . CompareFunction . LessEqual ;
Handles . DrawLines ( new Vector3 [ ]
{
//bottom quad
b [ 0 ] , b [ 1 ] ,
b [ 1 ] , b [ 2 ] ,
b [ 2 ] , b [ 3 ] ,
b [ 3 ] , b [ 0 ] ,
//top quad
b [ 4 ] , b [ 5 ] ,
b [ 5 ] , b [ 6 ] ,
b [ 6 ] , b [ 7 ] ,
b [ 7 ] , b [ 4 ] ,
//vertical lines
b [ 0 ] , b [ 4 ] ,
b [ 1 ] , b [ 5 ] ,
b [ 2 ] , b [ 6 ] ,
b [ 3 ] , b [ 7 ]
} ) ;
Handles . zTest = UnityEngine . Rendering . CompareFunction . Always ;
}
}
}
2024-03-05 17:34:41 +08:00
#endif