This commit is contained in:
CortexCore
2025-03-14 21:04:19 +08:00
parent ff8670c453
commit 757ffe79ee
1282 changed files with 104378 additions and 3 deletions

View File

@@ -0,0 +1,323 @@
#if GRIFFIN
using Pinwheel.Griffin.BackupTool;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
namespace Pinwheel.Griffin.SplineTool
{
[CustomEditor(typeof(GFoliageRemover))]
public class GFoliageRemoverInspector : Editor
{
private GFoliageRemover instance;
private Dictionary<GStylizedTerrain, RenderTexture> previewTextures;
private bool isUrp;
private ScriptableRenderContext urpContext;
private const string HISTORY_PREFIX = "Remove Foliage Along Path";
private void OnEnable()
{
Undo.undoRedoPerformed += OnUndoRedo;
instance = target as GFoliageRemover;
instance.Internal_UpdateFalloffTexture();
GCommon.RegisterBeginRender(OnCameraRender);
GCommon.RegisterBeginRenderSRP(OnCameraRenderSRP);
}
private void OnDisable()
{
Undo.undoRedoPerformed -= OnUndoRedo;
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);
}
public override void OnInspectorGUI()
{
DrawBaseGUI();
if (instance.SplineCreator == null)
return;
DrawFalloffGUI();
DrawMaskGUI();
DrawTreesGUI();
DrawGrassesGUI();
DrawActionGUI();
}
private class GBaseGUI
{
public static readonly GUIContent SPLINE_CREATOR = new GUIContent("Spline Creator", "The Spline Creator component which this modifier belongs to");
public static readonly GUIContent LIVE_PREVIEW = new GUIContent("Live Preview", "Draw a preview on the terrain");
}
private void DrawBaseGUI()
{
instance.SplineCreator = EditorGUILayout.ObjectField(GBaseGUI.SPLINE_CREATOR, instance.SplineCreator, typeof(GSplineCreator), true) as GSplineCreator;
EditorGUI.BeginChangeCheck();
GEditorSettings.Instance.splineTools.livePreview.foliageRemover = EditorGUILayout.Toggle(GBaseGUI.LIVE_PREVIEW, GEditorSettings.Instance.splineTools.livePreview.foliageRemover);
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(GEditorSettings.Instance);
}
}
private class GFalloffGUI
{
public static readonly string LABEL = "Falloff";
public static readonly string ID = "spline-foliage-remover-falloff";
public static readonly GUIContent FALL_OFF = new GUIContent("Falloff", "Falloff factor of the spline effect, from the center to the edge");
public static readonly GUIContent FALL_OFF_NOISE = new GUIContent("Falloff Noise", "Noise map in world space to blend with the falloff curve");
public static readonly GUIContent FALL_OFF_NOISE_SIZE = new GUIContent("Falloff Noise Size", "Size of the falloff noise in world space");
}
private void DrawFalloffGUI()
{
GEditorCommon.Foldout(GFalloffGUI.LABEL, false, GFalloffGUI.ID, () =>
{
EditorGUI.BeginChangeCheck();
instance.Falloff = EditorGUILayout.CurveField(GFalloffGUI.FALL_OFF, instance.Falloff, Color.red, new Rect(0, 0, 1, 1));
if (EditorGUI.EndChangeCheck())
{
instance.Internal_UpdateFalloffTexture();
}
instance.FalloffNoise = EditorGUILayout.ObjectField(GFalloffGUI.FALL_OFF_NOISE, instance.FalloffNoise, typeof(Texture2D), false) as Texture2D;
if (instance.FalloffNoise != null)
instance.FalloffNoiseSize = GEditorCommon.InlineVector2Field(GFalloffGUI.FALL_OFF_NOISE_SIZE, instance.FalloffNoiseSize);
});
}
private class GMaskGUI
{
public static readonly string LABEL = "Mask";
public static readonly string ID = "spline-foliage-remover-mask";
public static readonly GUIContent MASK_RESOLUTION = new GUIContent("Mask Resolution", "Resolution of the mask which is rendered by the spline, this mask will be used for sample foliage instances");
}
private void DrawMaskGUI()
{
GEditorCommon.Foldout(GMaskGUI.LABEL, false, GMaskGUI.ID, () =>
{
instance.MaskResolution = EditorGUILayout.DelayedIntField(GMaskGUI.MASK_RESOLUTION, instance.MaskResolution);
});
}
private class GTreesGUI
{
public static readonly string LABEL = "Trees";
public static readonly string ID = "spline-foliage-remover-trees";
public static readonly GUIContent REMOVE_TREES = new GUIContent("Remove Trees", "Toggle trees removing along the spline");
public static readonly GUIContent PROTOTYPES = new GUIContent("Prototypes", "The tree types to remove");
}
private void DrawTreesGUI()
{
GEditorCommon.Foldout(GTreesGUI.LABEL, false, GTreesGUI.ID, () =>
{
instance.RemoveTrees = EditorGUILayout.Toggle(GTreesGUI.REMOVE_TREES, instance.RemoveTrees);
if (instance.RemoveTrees)
{
EditorGUILayout.LabelField(GTreesGUI.PROTOTYPES);
instance.TreePrototypeIndices = GEditorCommon.TreeSetMultiSelectionGrid(instance.SplineCreator.GroupId, instance.TreePrototypeIndices);
}
});
}
private class GGrassesGUI
{
public static readonly string LABEL = "Grasses";
public static readonly string ID = "spline-foliage-remover-grasses";
public static readonly GUIContent REMOVE_GRASSES = new GUIContent("Remove Grasses", "Toggle grasses removing along the spline");
public static readonly GUIContent PROTOTYPES = new GUIContent("Prototypes", "The grass types to remove");
}
private void DrawGrassesGUI()
{
GEditorCommon.Foldout(GGrassesGUI.LABEL, false, GGrassesGUI.ID, () =>
{
instance.RemoveGrasses = EditorGUILayout.Toggle(GGrassesGUI.REMOVE_GRASSES, instance.RemoveGrasses);
if (instance.RemoveGrasses)
{
EditorGUILayout.LabelField(GGrassesGUI.PROTOTYPES);
instance.GrassPrototypeIndices = GEditorCommon.GrassSetMultiSelectionGrid(instance.SplineCreator.GroupId, instance.GrassPrototypeIndices);
}
});
}
private class GActionGUI
{
public static readonly string LABEL = "Action";
public static readonly string ID = "spline-foliage-remover-action";
public static readonly GUIContent REMOVE_TREES = new GUIContent("Remove Trees");
public static readonly GUIContent REMOVE_GRASSES = new GUIContent("Remove Grasses");
public static readonly GUIContent REMOVE_TREES_GRASSES = new GUIContent("Remove Trees & Grasses");
}
private void DrawActionGUI()
{
GEditorCommon.ExpandFoldout(GActionGUI.ID);
GEditorCommon.Foldout(GActionGUI.LABEL, true, GActionGUI.ID, () =>
{
GUIContent btnLabel;
if (instance.RemoveTrees && instance.RemoveGrasses)
{
btnLabel = GActionGUI.REMOVE_TREES_GRASSES;
}
else if (instance.RemoveTrees && !instance.RemoveGrasses)
{
btnLabel = GActionGUI.REMOVE_TREES;
}
else if (!instance.RemoveTrees && instance.RemoveGrasses)
{
btnLabel = GActionGUI.REMOVE_GRASSES;
}
else
{
btnLabel = GActionGUI.REMOVE_TREES_GRASSES;
}
GUI.enabled = instance.RemoveTrees || instance.RemoveGrasses;
if (GUILayout.Button(btnLabel))
{
List<GStylizedTerrain> terrains = GUtilities.ExtractTerrainsFromOverlapTest(instance.SplineCreator.SweepTest());
CreateInitialBackup(terrains);
Apply();
CreateBackupAfterApply(terrains);
}
GUI.enabled = true;
});
}
private void CreateInitialBackup(List<GStylizedTerrain> terrains)
{
GBackupInternal.TryCreateAndMergeInitialBackup(HISTORY_PREFIX, terrains, GCommon.FoliageInstancesResourceFlags, true);
}
private void Apply()
{
EditorUtility.DisplayProgressBar("Applying", "Removing foliage...", 1f);
try
{
instance.Apply();
}
catch (System.Exception e)
{
Debug.LogError(e.ToString());
}
EditorUtility.ClearProgressBar();
}
private void CreateBackupAfterApply(List<GStylizedTerrain> terrains)
{
GBackupInternal.TryCreateAndMergeBackup(HISTORY_PREFIX, terrains, GCommon.FoliageInstancesResourceFlags, true);
}
private void OnCameraRender(Camera cam)
{
isUrp = false;
urpContext = default;
if (cam.cameraType != CameraType.SceneView)
return;
if (GEditorSettings.Instance.splineTools.livePreview.foliageRemover)
DrawLivePreview(cam);
}
private void OnCameraRenderSRP(UnityEngine.Rendering.ScriptableRenderContext context, Camera cam)
{
OnCameraRender(cam);
}
private IEnumerator IDrawLivePreviewEndOfFrameURP(Camera cam)
{
yield return new WaitForEndOfFrame();
if (cam != null)
{
DrawLivePreview(cam);
}
}
private void DrawLivePreview(Camera cam)
{
List<GOverlapTestResult> sweepTests = instance.SplineCreator.SweepTest();
foreach (GOverlapTestResult st in sweepTests)
{
if (!st.IsOverlapped)
continue;
DrawLivePreview(st.Terrain, cam, st.IsChunkOverlapped);
}
}
private void DrawLivePreview(GStylizedTerrain t, Camera cam, bool[] chunkCulling)
{
if (t.transform.rotation != Quaternion.identity ||
t.transform.lossyScale != Vector3.one)
return;
RenderTexture rt = GetPreviewTexture(t);
instance.Internal_Apply(t, rt);
GLivePreviewDrawer.DrawMasksLivePreview(
t, cam,
new Texture[] { rt },
new Color[] { GEditorSettings.Instance.splineTools.negativeHighlightColor },
chunkCulling);
}
private RenderTexture GetPreviewTexture(GStylizedTerrain t)
{
if (previewTextures == null)
{
previewTextures = new Dictionary<GStylizedTerrain, RenderTexture>();
}
int resolution = instance.MaskResolution;
if (!previewTextures.ContainsKey(t) ||
previewTextures[t] == null)
{
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
previewTextures[t] = rt;
}
else if (previewTextures[t].width != resolution || previewTextures[t].height != resolution)
{
previewTextures[t].Release();
Object.DestroyImmediate(previewTextures[t]);
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
previewTextures[t] = rt;
}
previewTextures[t].wrapMode = TextureWrapMode.Clamp;
return previewTextures[t];
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2193db762e1d63142b706eb944248806
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,352 @@
#if GRIFFIN
using Pinwheel.Griffin.BackupTool;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
namespace Pinwheel.Griffin.SplineTool
{
[CustomEditor(typeof(GFoliageSpawner))]
public class GFoliageSpawnerInspector : Editor
{
private GFoliageSpawner instance;
private Dictionary<GStylizedTerrain, RenderTexture> previewTextures;
private MaterialPropertyBlock previewPropertyBlock;
private bool isUrp;
private ScriptableRenderContext urpContext;
private const string HISTORY_PREFIX = "Spawn Foliage Along Path";
private void OnEnable()
{
Undo.undoRedoPerformed += OnUndoRedo;
instance = target as GFoliageSpawner;
instance.Internal_UpdateFalloffTexture();
previewPropertyBlock = new MaterialPropertyBlock();
GCommon.RegisterBeginRender(OnCameraRender);
GCommon.RegisterBeginRenderSRP(OnCameraRenderSRP);
}
private void OnDisable()
{
Undo.undoRedoPerformed -= OnUndoRedo;
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);
}
public override void OnInspectorGUI()
{
DrawBaseGUI();
if (instance.SplineCreator == null)
return;
DrawFalloffGUI();
DrawMaskGUI();
DrawRotationScaleGUI();
DrawTreesGUI();
DrawGrassesGUI();
DrawActionGUI();
}
private class GBaseGUI
{
public static readonly GUIContent SPLINE_CREATOR = new GUIContent("Spline Creator", "The Spline Creator component which this modifier belongs to");
public static readonly GUIContent LIVE_PREVIEW = new GUIContent("Live Preview", "Draw a preview on the terrain");
}
private void DrawBaseGUI()
{
instance.SplineCreator = EditorGUILayout.ObjectField(GBaseGUI.SPLINE_CREATOR, instance.SplineCreator, typeof(GSplineCreator), true) as GSplineCreator;
EditorGUI.BeginChangeCheck();
GEditorSettings.Instance.splineTools.livePreview.foliageSpawner = EditorGUILayout.Toggle(GBaseGUI.LIVE_PREVIEW, GEditorSettings.Instance.splineTools.livePreview.foliageSpawner);
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(GEditorSettings.Instance);
}
}
private class GFalloffGUI
{
public static readonly string LABEL = "Falloff";
public static readonly string ID = "spline-foliage-spawner-falloff";
public static readonly GUIContent FALL_OFF = new GUIContent("Falloff", "Falloff factor of the spline effect, from the center to the edge");
public static readonly GUIContent FALL_OFF_NOISE = new GUIContent("Falloff Noise", "Noise map in world space to blend with the falloff curve");
public static readonly GUIContent FALL_OFF_NOISE_SIZE = new GUIContent("Falloff Noise Size", "Size of the falloff noise in world space");
}
private void DrawFalloffGUI()
{
GEditorCommon.Foldout(GFalloffGUI.LABEL, false, GFalloffGUI.ID, () =>
{
EditorGUI.BeginChangeCheck();
instance.Falloff = EditorGUILayout.CurveField(GFalloffGUI.FALL_OFF, instance.Falloff, Color.red, new Rect(0, 0, 1, 1));
if (EditorGUI.EndChangeCheck())
{
instance.Internal_UpdateFalloffTexture();
}
instance.FalloffNoise = EditorGUILayout.ObjectField(GFalloffGUI.FALL_OFF_NOISE, instance.FalloffNoise, typeof(Texture2D), false) as Texture2D;
if (instance.FalloffNoise != null)
instance.FalloffNoiseSize = GEditorCommon.InlineVector2Field(GFalloffGUI.FALL_OFF_NOISE_SIZE, instance.FalloffNoiseSize);
});
}
private class GMaskGUI
{
public static readonly string LABEL = "Mask";
public static readonly string ID = "spline-foliage-spawner-mask";
public static readonly GUIContent MASK_RESOLUTION = new GUIContent("Mask Resolution", "Resolution of the mask which is rendered by the spline, this mask will be used for sample foliage instances");
}
private void DrawMaskGUI()
{
GEditorCommon.Foldout(GMaskGUI.LABEL, false, GMaskGUI.ID, () =>
{
instance.MaskResolution = EditorGUILayout.DelayedIntField(GMaskGUI.MASK_RESOLUTION, instance.MaskResolution);
});
}
private class GTreesGUI
{
public static readonly string LABEL = "Trees";
public static readonly string ID = "spline-foliage-spawner-trees";
public static readonly GUIContent SPAWN_TREES = new GUIContent("Spawn Trees", "Toggle trees spawning along the spline");
public static readonly GUIContent PROTOTYPES = new GUIContent("Prototypes", "The tree types to spawn");
public static readonly GUIContent DENSITY = new GUIContent("Density", "Number of instances per a meter-squared");
}
private void DrawTreesGUI()
{
GEditorCommon.Foldout(GTreesGUI.LABEL, false, GTreesGUI.ID, () =>
{
instance.SpawnTrees = EditorGUILayout.Toggle(GTreesGUI.SPAWN_TREES, instance.SpawnTrees);
if (instance.SpawnTrees)
{
EditorGUILayout.LabelField(GTreesGUI.PROTOTYPES);
instance.TreePrototypeIndices = GEditorCommon.TreeSetMultiSelectionGrid(instance.SplineCreator.GroupId, instance.TreePrototypeIndices);
instance.TreeDensity = EditorGUILayout.FloatField(GTreesGUI.DENSITY, instance.TreeDensity);
}
});
}
private class GGrassesGUI
{
public static readonly string LABEL = "Grasses";
public static readonly string ID = "spline-foliage-spawner-grasses";
public static readonly GUIContent SPAWN_GRASSES = new GUIContent("Spawn Grasses", "Toggle grasses spawning along the spline");
public static readonly GUIContent PROTOTYPES = new GUIContent("Prototypes", "The grass types to spawn");
public static readonly GUIContent DENSITY = new GUIContent("Density", "Number of instances per a meter-squared");
}
private void DrawGrassesGUI()
{
GEditorCommon.Foldout(GGrassesGUI.LABEL, false, GGrassesGUI.ID, () =>
{
instance.SpawnGrasses = EditorGUILayout.Toggle(GGrassesGUI.SPAWN_GRASSES, instance.SpawnGrasses);
if (instance.SpawnGrasses)
{
EditorGUILayout.LabelField(GGrassesGUI.PROTOTYPES);
instance.GrassPrototypeIndices = GEditorCommon.GrassSetMultiSelectionGrid(instance.SplineCreator.GroupId, instance.GrassPrototypeIndices);
instance.GrassDensity = EditorGUILayout.FloatField(GGrassesGUI.DENSITY, instance.GrassDensity);
}
});
}
private class GRotationScaleGUI
{
public static readonly string LABEL = "Rotation & Scale";
public static readonly string ID = "spline-foliage-spawner-rotation-scale";
public static readonly GUIContent MIN_ROTATION = new GUIContent("Min Rotation", "Minimum rotation of each instance, in degree, on Y axis");
public static readonly GUIContent MAX_ROTATION = new GUIContent("Max Rotation", "Maximum rotation of each instance, in degree, on Y axis");
public static readonly GUIContent MIN_SCALE = new GUIContent("Min Scale", "Minimum scale of each instance");
public static readonly GUIContent MAX_SCALE = new GUIContent("Max Scale", "Maximum scale of each instance");
}
private void DrawRotationScaleGUI()
{
GEditorCommon.Foldout(GRotationScaleGUI.LABEL, false, GRotationScaleGUI.ID, () =>
{
instance.MinRotation = EditorGUILayout.FloatField(GRotationScaleGUI.MIN_ROTATION, instance.MinRotation);
instance.MaxRotation = EditorGUILayout.FloatField(GRotationScaleGUI.MAX_ROTATION, instance.MaxRotation);
instance.MinScale = GEditorCommon.InlineVector3Field(GRotationScaleGUI.MIN_SCALE, instance.MinScale);
instance.MaxScale = GEditorCommon.InlineVector3Field(GRotationScaleGUI.MAX_SCALE, instance.MaxScale);
});
}
private class GActionGUI
{
public static readonly string LABEL = "Action";
public static readonly string ID = "spline-foliage-spawner-action";
public static readonly GUIContent SPAWN_TREES = new GUIContent("Spawn Trees");
public static readonly GUIContent SPAWN_GRASSES = new GUIContent("Spawn Grasses");
public static readonly GUIContent SPAWN_TREES_GRASSES = new GUIContent("Spawn Trees & Grasses");
}
private void DrawActionGUI()
{
GEditorCommon.ExpandFoldout(GActionGUI.ID);
GEditorCommon.Foldout(GActionGUI.LABEL, true, GActionGUI.ID, () =>
{
GUIContent btnLabel;
if (instance.SpawnTrees && instance.SpawnGrasses)
{
btnLabel = GActionGUI.SPAWN_TREES_GRASSES;
}
else if (instance.SpawnTrees && !instance.SpawnGrasses)
{
btnLabel = GActionGUI.SPAWN_TREES;
}
else if (!instance.SpawnTrees && instance.SpawnGrasses)
{
btnLabel = GActionGUI.SPAWN_GRASSES;
}
else
{
btnLabel = GActionGUI.SPAWN_TREES_GRASSES;
}
GUI.enabled = instance.SpawnTrees || instance.SpawnGrasses;
if (GUILayout.Button(btnLabel))
{
List<GStylizedTerrain> terrains = GUtilities.ExtractTerrainsFromOverlapTest(instance.SplineCreator.SweepTest());
CreateInitialBackup(terrains);
Apply();
CreateBackupAfterApply(terrains);
}
GUI.enabled = true;
});
}
private void CreateInitialBackup(List<GStylizedTerrain> terrains)
{
GBackupInternal.TryCreateAndMergeInitialBackup(HISTORY_PREFIX, terrains, GCommon.FoliageInstancesResourceFlags, true);
}
private void Apply()
{
EditorUtility.DisplayProgressBar("Applying", "Spawning foliage...", 1f);
try
{
instance.Apply();
}
catch (System.Exception e)
{
Debug.LogError(e.ToString());
}
EditorUtility.ClearProgressBar();
}
private void CreateBackupAfterApply(List<GStylizedTerrain> terrains)
{
GBackupInternal.TryCreateAndMergeBackup(HISTORY_PREFIX, terrains, GCommon.FoliageInstancesResourceFlags, true);
}
private void OnCameraRender(Camera cam)
{
isUrp = false;
urpContext = default;
if (cam.cameraType != CameraType.SceneView)
return;
if (GEditorSettings.Instance.splineTools.livePreview.foliageSpawner)
DrawLivePreview(cam);
}
private void OnCameraRenderSRP(UnityEngine.Rendering.ScriptableRenderContext context, Camera cam)
{
OnCameraRender(cam);
}
private IEnumerator IDrawLivePreviewEndOfFrameURP(Camera cam)
{
yield return new WaitForEndOfFrame();
if (cam != null)
{
DrawLivePreview(cam);
}
}
private void DrawLivePreview(Camera cam)
{
List<GOverlapTestResult> sweepTests = instance.SplineCreator.SweepTest();
foreach (GOverlapTestResult st in sweepTests)
{
if (!st.IsOverlapped)
continue;
DrawLivePreview(st.Terrain, cam, st.IsChunkOverlapped);
}
}
private void DrawLivePreview(GStylizedTerrain t, Camera cam, bool[] chunkCulling)
{
if (t.transform.rotation != Quaternion.identity ||
t.transform.lossyScale != Vector3.one)
return;
RenderTexture rt = GetPreviewTexture(t);
instance.Internal_Apply(t, rt);
GLivePreviewDrawer.DrawMasksLivePreview(
t, cam,
new Texture[] { rt },
new Color[] { GEditorSettings.Instance.splineTools.positiveHighlightColor },
chunkCulling);
}
private RenderTexture GetPreviewTexture(GStylizedTerrain t)
{
if (previewTextures == null)
{
previewTextures = new Dictionary<GStylizedTerrain, RenderTexture>();
}
int resolution = instance.MaskResolution;
if (!previewTextures.ContainsKey(t) ||
previewTextures[t] == null)
{
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
previewTextures[t] = rt;
}
else if (previewTextures[t].width != resolution || previewTextures[t].height != resolution)
{
previewTextures[t].Release();
Object.DestroyImmediate(previewTextures[t]);
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
previewTextures[t] = rt;
}
previewTextures[t].wrapMode = TextureWrapMode.Clamp;
return previewTextures[t];
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 614c28b376274cc47ae3afad00ad3139
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,305 @@
#if GRIFFIN
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
namespace Pinwheel.Griffin.SplineTool
{
[CustomEditor(typeof(GObjectRemover))]
public class GObjectRemoverInspector : Editor
{
private GObjectRemover instance;
private Dictionary<GStylizedTerrain, RenderTexture> previewTextures;
private bool isUrp;
private ScriptableRenderContext urpContext;
private const string HISTORY_PREFIX = "Remove Foliage Along Path";
private void OnEnable()
{
instance = target as GObjectRemover;
instance.Internal_UpdateFalloffTexture();
GCommon.RegisterBeginRender(OnCameraRender);
GCommon.RegisterBeginRenderSRP(OnCameraRenderSRP);
}
private void OnDisable()
{
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);
}
}
}
public override void OnInspectorGUI()
{
DrawBaseGUI();
if (instance.SplineCreator == null)
return;
DrawFalloffGUI();
DrawMaskGUI();
DrawObjectGUI();
DrawActionGUI();
}
private class GBaseGUI
{
public static readonly GUIContent SPLINE_CREATOR = new GUIContent("Spline Creator", "The Spline Creator component which this modifier belongs to");
public static readonly GUIContent LIVE_PREVIEW = new GUIContent("Live Preview", "Draw a preview on the terrain");
}
private void DrawBaseGUI()
{
instance.SplineCreator = EditorGUILayout.ObjectField(GBaseGUI.SPLINE_CREATOR, instance.SplineCreator, typeof(GSplineCreator), true) as GSplineCreator;
EditorGUI.BeginChangeCheck();
GEditorSettings.Instance.splineTools.livePreview.objectRemover = EditorGUILayout.Toggle(GBaseGUI.LIVE_PREVIEW, GEditorSettings.Instance.splineTools.livePreview.objectRemover);
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(GEditorSettings.Instance);
}
}
private class GFalloffGUI
{
public static readonly string LABEL = "Falloff";
public static readonly string ID = "spline-object-remover-falloff";
public static readonly GUIContent FALL_OFF = new GUIContent("Falloff", "Falloff factor of the spline effect, from the center to the edge");
public static readonly GUIContent FALL_OFF_NOISE = new GUIContent("Falloff Noise", "Noise map in world space to blend with the falloff curve");
public static readonly GUIContent FALL_OFF_NOISE_SIZE = new GUIContent("Falloff Noise Size", "Size of the falloff noise in world space");
}
private void DrawFalloffGUI()
{
GEditorCommon.Foldout(GFalloffGUI.LABEL, false, GFalloffGUI.ID, () =>
{
EditorGUI.BeginChangeCheck();
instance.Falloff = EditorGUILayout.CurveField(GFalloffGUI.FALL_OFF, instance.Falloff, Color.red, new Rect(0, 0, 1, 1));
if (EditorGUI.EndChangeCheck())
{
instance.Internal_UpdateFalloffTexture();
}
instance.FalloffNoise = EditorGUILayout.ObjectField(GFalloffGUI.FALL_OFF_NOISE, instance.FalloffNoise, typeof(Texture2D), false) as Texture2D;
if (instance.FalloffNoise != null)
instance.FalloffNoiseSize = GEditorCommon.InlineVector2Field(GFalloffGUI.FALL_OFF_NOISE_SIZE, instance.FalloffNoiseSize);
});
}
private class GMaskGUI
{
public static readonly string LABEL = "Mask";
public static readonly string ID = "spline-object-remover-mask";
public static readonly GUIContent MASK_RESOLUTION = new GUIContent("Mask Resolution", "Resolution of the mask which is rendered by the spline, this mask will be used for sample object instances");
}
private void DrawMaskGUI()
{
GEditorCommon.Foldout(GMaskGUI.LABEL, false, GMaskGUI.ID, () =>
{
instance.MaskResolution = EditorGUILayout.DelayedIntField(GMaskGUI.MASK_RESOLUTION, instance.MaskResolution);
});
}
private class GObjectGUI
{
public static readonly string LABEL = "Objects";
public static readonly string ID = "spline-object-remover-objects";
public static readonly GUIContent MIN_ROTATION = new GUIContent("Min Rotation", "Minimum rotation of each instance, in degree, on Y axis");
public static readonly GUIContent MAX_ROTATION = new GUIContent("Max Rotation", "Maximum rotation of each instance, in degree, on Y axis");
public static readonly GUIContent MIN_SCALE = new GUIContent("Min Scale", "Minimum scale of each instance");
public static readonly GUIContent MAX_SCALE = new GUIContent("Max Scale", "Maximum scale of each instance");
public static readonly GUIContent RAYCAST_LAYER = new GUIContent("Raycast Layer", "Object layer to perform raycast for snapping");
public static readonly GUIContent ALIGN_TO_SURFACE = new GUIContent("Align To Surface", "Align the object for terrain surface");
public static readonly GUIContent DENSITY = new GUIContent("Density", "Number of object instances per a meter-squared");
}
private void DrawObjectGUI()
{
GEditorCommon.Foldout(GObjectGUI.LABEL, false, GObjectGUI.ID, () =>
{
DrawObjectSelectorGUI();
});
}
private void DrawObjectSelectorGUI()
{
if (instance.Prototypes.Count > 0)
{
GSelectionGridArgs args = new GSelectionGridArgs();
args.collection = instance.Prototypes;
args.selectedIndices = instance.PrototypeIndices;
args.itemSize = GEditorCommon.selectionGridTileSizeSmall;
args.itemPerRow = 4;
args.drawPreviewFunction = GEditorCommon.DrawGameObjectPreview;
args.contextClickFunction = OnObjectSelectorContextClick;
instance.PrototypeIndices = GEditorCommon.MultiSelectionGrid(args);
}
else
{
EditorGUILayout.LabelField("No Game Object found!", GEditorCommon.WordWrapItalicLabel);
}
GEditorCommon.Separator();
Rect r1 = EditorGUILayout.GetControlRect(GUILayout.Height(GEditorCommon.objectSelectorDragDropHeight));
GameObject prefab = GEditorCommon.ObjectSelectorDragDrop<GameObject>(r1, "Drop a Game Object here!", "t:GameObject");
if (prefab != null)
{
instance.Prototypes.AddIfNotContains(prefab);
}
GEditorCommon.SpacePixel(0);
Rect r2 = EditorGUILayout.GetControlRect(GUILayout.Height(GEditorCommon.objectSelectorDragDropHeight));
GPrefabPrototypeGroup group = GEditorCommon.ObjectSelectorDragDrop<GPrefabPrototypeGroup>(r2, "Drop a Prefab Prototype Group here!", "t:GPrefabPrototypeGroup");
if (group != null)
{
instance.Prototypes.AddIfNotContains(group.Prototypes);
}
}
private void OnObjectSelectorContextClick(Rect r, int index, ICollection collection)
{
GenericMenu menu = new GenericMenu();
menu.AddItem(
new GUIContent("Remove"),
false,
() =>
{
instance.Prototypes.RemoveAt(index);
});
menu.ShowAsContext();
}
private class GActionGUI
{
public static readonly string LABEL = "Action";
public static readonly string ID = "spline-object-remover-action";
public static readonly GUIContent SPAWN = new GUIContent("Remove");
}
private void DrawActionGUI()
{
GEditorCommon.ExpandFoldout(GActionGUI.ID);
GEditorCommon.Foldout(GActionGUI.LABEL, true, GActionGUI.ID, () =>
{
if (GUILayout.Button(GActionGUI.SPAWN))
{
Apply();
}
});
}
private void Apply()
{
EditorUtility.DisplayProgressBar("Applying", "Removing objects...", 1f);
try
{
instance.Apply();
}
catch (System.Exception e)
{
Debug.LogError(e.ToString());
}
EditorUtility.ClearProgressBar();
}
private void OnCameraRender(Camera cam)
{
isUrp = false;
urpContext = default;
if (cam.cameraType != CameraType.SceneView)
return;
if (GEditorSettings.Instance.splineTools.livePreview.objectRemover)
DrawLivePreview(cam);
}
private void OnCameraRenderSRP(UnityEngine.Rendering.ScriptableRenderContext context, Camera cam)
{
OnCameraRender(cam);
}
private IEnumerator IDrawLivePreviewEndOfFrameURP(Camera cam)
{
yield return new WaitForEndOfFrame();
if (cam != null)
{
DrawLivePreview(cam);
}
}
private void DrawLivePreview(Camera cam)
{
List<GOverlapTestResult> sweepTests = instance.SplineCreator.SweepTest();
foreach (GOverlapTestResult st in sweepTests)
{
if (!st.IsOverlapped)
{
continue;
}
DrawLivePreview(st.Terrain, cam, st.IsChunkOverlapped);
}
}
private void DrawLivePreview(GStylizedTerrain t, Camera cam, bool[] chunkCulling)
{
if (t.transform.rotation != Quaternion.identity ||
t.transform.lossyScale != Vector3.one)
return;
RenderTexture rt = GetPreviewTexture(t);
instance.Internal_Apply(t, rt);
GLivePreviewDrawer.DrawMasksLivePreview(
t, cam,
new Texture[] { rt },
new Color[] { GEditorSettings.Instance.splineTools.negativeHighlightColor },
chunkCulling);
}
private RenderTexture GetPreviewTexture(GStylizedTerrain t)
{
if (previewTextures == null)
{
previewTextures = new Dictionary<GStylizedTerrain, RenderTexture>();
}
int resolution = instance.MaskResolution;
if (!previewTextures.ContainsKey(t) ||
previewTextures[t] == null)
{
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
previewTextures[t] = rt;
}
else if (previewTextures[t].width != resolution || previewTextures[t].height != resolution)
{
previewTextures[t].Release();
Object.DestroyImmediate(previewTextures[t]);
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
previewTextures[t] = rt;
}
previewTextures[t].wrapMode = TextureWrapMode.Clamp;
return previewTextures[t];
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 14435b783456cd14680d1acdb4dd62c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,306 @@
#if GRIFFIN
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
namespace Pinwheel.Griffin.SplineTool
{
[CustomEditor(typeof(GObjectSpawner))]
public class GObjectSpawnerInspector : Editor
{
private GObjectSpawner instance;
private Dictionary<GStylizedTerrain, RenderTexture> previewTextures;
private bool isUrp;
private ScriptableRenderContext urpContext;
private void OnEnable()
{
instance = target as GObjectSpawner;
instance.Internal_UpdateFalloffTexture();
GCommon.RegisterBeginRender(OnCameraRender);
GCommon.RegisterBeginRenderSRP(OnCameraRenderSRP);
}
private void OnDisable()
{
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);
}
}
}
public override void OnInspectorGUI()
{
DrawBaseGUI();
if (instance.SplineCreator == null)
return;
DrawFalloffGUI();
DrawMaskGUI();
DrawObjectGUI();
DrawActionGUI();
}
private class GBaseGUI
{
public static readonly GUIContent SPLINE_CREATOR = new GUIContent("Spline Creator", "The Spline Creator component which this modifier belongs to");
public static readonly GUIContent LIVE_PREVIEW = new GUIContent("Live Preview", "Draw a preview on the terrain");
}
private void DrawBaseGUI()
{
instance.SplineCreator = EditorGUILayout.ObjectField(GBaseGUI.SPLINE_CREATOR, instance.SplineCreator, typeof(GSplineCreator), true) as GSplineCreator;
EditorGUI.BeginChangeCheck();
GEditorSettings.Instance.splineTools.livePreview.objectSpawner = EditorGUILayout.Toggle(GBaseGUI.LIVE_PREVIEW, GEditorSettings.Instance.splineTools.livePreview.objectSpawner);
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(GEditorSettings.Instance);
}
}
private class GFalloffGUI
{
public static readonly string LABEL = "Falloff";
public static readonly string ID = "spline-object-spawner-falloff";
public static readonly GUIContent FALL_OFF = new GUIContent("Falloff", "Falloff factor of the spline effect, from the center to the edge");
public static readonly GUIContent FALL_OFF_NOISE = new GUIContent("Falloff Noise", "Noise map in world space to blend with the falloff curve");
public static readonly GUIContent FALL_OFF_NOISE_SIZE = new GUIContent("Falloff Noise Size", "Size of the falloff noise in world space");
}
private void DrawFalloffGUI()
{
GEditorCommon.Foldout(GFalloffGUI.LABEL, false, GFalloffGUI.ID, () =>
{
EditorGUI.BeginChangeCheck();
instance.Falloff = EditorGUILayout.CurveField(GFalloffGUI.FALL_OFF, instance.Falloff, Color.red, new Rect(0, 0, 1, 1));
if (EditorGUI.EndChangeCheck())
{
instance.Internal_UpdateFalloffTexture();
}
instance.FalloffNoise = EditorGUILayout.ObjectField(GFalloffGUI.FALL_OFF_NOISE, instance.FalloffNoise, typeof(Texture2D), false) as Texture2D;
if (instance.FalloffNoise != null)
instance.FalloffNoiseSize = GEditorCommon.InlineVector2Field(GFalloffGUI.FALL_OFF_NOISE_SIZE, instance.FalloffNoiseSize);
});
}
private class GMaskGUI
{
public static readonly string LABEL = "Mask";
public static readonly string ID = "spline-object-spawner-mask";
public static readonly GUIContent MASK_RESOLUTION = new GUIContent("Mask Resolution", "Resolution of the mask which is rendered by the spline, this mask will be used for sample object instances");
}
private void DrawMaskGUI()
{
GEditorCommon.Foldout(GMaskGUI.LABEL, false, GMaskGUI.ID, () =>
{
instance.MaskResolution = EditorGUILayout.DelayedIntField(GMaskGUI.MASK_RESOLUTION, instance.MaskResolution);
});
}
private class GObjectGUI
{
public static readonly string LABEL = "Objects";
public static readonly string ID = "spline-object-spawner-objects";
public static readonly GUIContent MIN_ROTATION = new GUIContent("Min Rotation", "Minimum rotation of each instance, in degree, on Y axis");
public static readonly GUIContent MAX_ROTATION = new GUIContent("Max Rotation", "Maximum rotation of each instance, in degree, on Y axis");
public static readonly GUIContent MIN_SCALE = new GUIContent("Min Scale", "Minimum scale of each instance");
public static readonly GUIContent MAX_SCALE = new GUIContent("Max Scale", "Maximum scale of each instance");
public static readonly GUIContent RAYCAST_LAYER = new GUIContent("Raycast Layer", "Object layer to perform raycast for snapping");
public static readonly GUIContent ALIGN_TO_SURFACE = new GUIContent("Align To Surface", "Align the object for terrain surface");
public static readonly GUIContent DENSITY = new GUIContent("Density", "Number of object instances per a meter-squared");
}
private void DrawObjectGUI()
{
GEditorCommon.Foldout(GObjectGUI.LABEL, false, GObjectGUI.ID, () =>
{
DrawObjectSelectorGUI();
instance.Density = EditorGUILayout.FloatField(GObjectGUI.DENSITY, instance.Density);
instance.MinRotation = EditorGUILayout.FloatField(GObjectGUI.MIN_ROTATION, instance.MinRotation);
instance.MaxRotation = EditorGUILayout.FloatField(GObjectGUI.MAX_ROTATION, instance.MaxRotation);
instance.MinScale = GEditorCommon.InlineVector3Field(GObjectGUI.MIN_SCALE, instance.MinScale);
instance.MaxScale = GEditorCommon.InlineVector3Field(GObjectGUI.MAX_SCALE, instance.MaxScale);
instance.WorldRaycastMask = GEditorCommon.LayerMaskField(GObjectGUI.RAYCAST_LAYER, instance.WorldRaycastMask);
instance.AlignToSurface = EditorGUILayout.Toggle(GObjectGUI.ALIGN_TO_SURFACE, instance.AlignToSurface);
});
}
private void DrawObjectSelectorGUI()
{
if (instance.Prototypes.Count > 0)
{
GSelectionGridArgs args = new GSelectionGridArgs();
args.collection = instance.Prototypes;
args.selectedIndices = instance.PrototypeIndices;
args.itemSize = GEditorCommon.selectionGridTileSizeSmall;
args.itemPerRow = 4;
args.drawPreviewFunction = GEditorCommon.DrawGameObjectPreview;
args.contextClickFunction = OnObjectSelectorContextClick;
instance.PrototypeIndices = GEditorCommon.MultiSelectionGrid(args);
}
else
{
EditorGUILayout.LabelField("No Game Object found!", GEditorCommon.WordWrapItalicLabel);
}
GEditorCommon.Separator();
Rect r1 = EditorGUILayout.GetControlRect(GUILayout.Height(GEditorCommon.objectSelectorDragDropHeight));
GameObject prefab = GEditorCommon.ObjectSelectorDragDrop<GameObject>(r1, "Drop a Game Object here!", "t:GameObject");
if (prefab != null)
{
instance.Prototypes.AddIfNotContains(prefab);
}
GEditorCommon.SpacePixel(0);
Rect r2 = EditorGUILayout.GetControlRect(GUILayout.Height(GEditorCommon.objectSelectorDragDropHeight));
GPrefabPrototypeGroup group = GEditorCommon.ObjectSelectorDragDrop<GPrefabPrototypeGroup>(r2, "Drop a Prefab Prototype Group here!", "t:GPrefabPrototypeGroup");
if (group != null)
{
instance.Prototypes.AddIfNotContains(group.Prototypes);
}
}
private void OnObjectSelectorContextClick(Rect r, int index, ICollection collection)
{
GenericMenu menu = new GenericMenu();
menu.AddItem(
new GUIContent("Remove"),
false,
() =>
{
instance.Prototypes.RemoveAt(index);
});
menu.ShowAsContext();
}
private class GActionGUI
{
public static readonly string LABEL = "Action";
public static readonly string ID = "spline-object-spawner-action";
public static readonly GUIContent SPAWN = new GUIContent("Spawn");
}
private void DrawActionGUI()
{
GEditorCommon.ExpandFoldout(GActionGUI.ID);
GEditorCommon.Foldout(GActionGUI.LABEL, true, GActionGUI.ID, () =>
{
if (GUILayout.Button(GActionGUI.SPAWN))
{
Apply();
}
});
}
private void Apply()
{
EditorUtility.DisplayProgressBar("Applying", "Spawning objects...", 1f);
try
{
instance.Apply();
}
catch (System.Exception e)
{
Debug.LogError(e.ToString());
}
EditorUtility.ClearProgressBar();
}
private void OnCameraRender(Camera cam)
{
isUrp = false;
urpContext = default;
if (cam.cameraType != CameraType.SceneView)
return;
if (GEditorSettings.Instance.splineTools.livePreview.objectSpawner)
DrawLivePreview(cam);
}
private void OnCameraRenderSRP(UnityEngine.Rendering.ScriptableRenderContext context, Camera cam)
{
OnCameraRender(cam);
}
private IEnumerator IDrawLivePreviewEndOfFrameURP(Camera cam)
{
yield return new WaitForEndOfFrame();
if (cam != null)
{
DrawLivePreview(cam);
}
}
private void DrawLivePreview(Camera cam)
{
List<GOverlapTestResult> sweepTests = instance.SplineCreator.SweepTest();
foreach (GOverlapTestResult st in sweepTests)
{
if (!st.IsOverlapped)
continue;
DrawLivePreview(st.Terrain, cam, st.IsChunkOverlapped);
}
}
private void DrawLivePreview(GStylizedTerrain t, Camera cam, bool[] chunkCulling)
{
if (t.transform.rotation != Quaternion.identity ||
t.transform.lossyScale != Vector3.one)
return;
RenderTexture rt = GetPreviewTexture(t);
instance.Internal_Apply(t, rt);
GLivePreviewDrawer.DrawMasksLivePreview(
t, cam,
new Texture[] { rt },
new Color[] { GEditorSettings.Instance.splineTools.positiveHighlightColor },
chunkCulling);
}
private RenderTexture GetPreviewTexture(GStylizedTerrain t)
{
if (previewTextures == null)
{
previewTextures = new Dictionary<GStylizedTerrain, RenderTexture>();
}
int resolution = instance.MaskResolution;
if (!previewTextures.ContainsKey(t) ||
previewTextures[t] == null)
{
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
previewTextures[t] = rt;
}
else if (previewTextures[t].width != resolution || previewTextures[t].height != resolution)
{
previewTextures[t].Release();
Object.DestroyImmediate(previewTextures[t]);
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
previewTextures[t] = rt;
}
previewTextures[t].wrapMode = TextureWrapMode.Clamp;
return previewTextures[t];
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f1222651ce344a240b32a91b9329f727
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,343 @@
#if GRIFFIN
using Pinwheel.Griffin.BackupTool;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
namespace Pinwheel.Griffin.SplineTool
{
[CustomEditor(typeof(GPathPainter))]
public class GPathPainterInspector : Editor
{
private GPathPainter instance;
private Dictionary<string, RenderTexture> previewTextures;
private bool isUrp;
private ScriptableRenderContext urpContext;
private static readonly string HISTORY_PREFIX_ALBEDO_METALLIC = "Make Path Albedo Metallic";
private static readonly string HISTORY_PREFIX_SPLAT = "Make Path Splat";
public void OnEnable()
{
Undo.undoRedoPerformed += OnUndoRedo;
instance = (GPathPainter)target;
instance.Internal_UpdateFalloffTexture();
GCommon.RegisterBeginRender(OnCameraRender);
GCommon.RegisterBeginRenderSRP(OnCameraRenderSRP);
GCommon.UpdateMaterials(instance.SplineCreator.GroupId);
}
private void OnDisable()
{
Undo.undoRedoPerformed -= OnUndoRedo;
GCommon.UnregisterBeginRender(OnCameraRender);
GCommon.UnregisterBeginRenderSRP(OnCameraRenderSRP);
if (previewTextures != null)
{
foreach (string k in previewTextures.Keys)
{
RenderTexture rt = previewTextures[k];
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);
}
public override void OnInspectorGUI()
{
DrawBaseGUI();
if (instance.SplineCreator == null)
return;
DrawFalloffGUI();
DrawPathGUI();
DrawActionGUI();
}
private class GBaseGUI
{
public static readonly GUIContent SPLINE_CREATOR = new GUIContent("Spline Creator", "The Spline Creator component this modifier belongs to");
public static readonly GUIContent LIVE_PREVIEW = new GUIContent("Live Preview", "Draw a preview over the terrain");
}
private void DrawBaseGUI()
{
instance.SplineCreator = EditorGUILayout.ObjectField(GBaseGUI.SPLINE_CREATOR, instance.SplineCreator, typeof(GSplineCreator), true) as GSplineCreator;
EditorGUI.BeginChangeCheck();
GEditorSettings.Instance.splineTools.livePreview.pathPainter = EditorGUILayout.Toggle(GBaseGUI.LIVE_PREVIEW, GEditorSettings.Instance.splineTools.livePreview.pathPainter);
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(GEditorSettings.Instance);
}
}
private class GFalloffGUI
{
public static readonly string LABEL = "Falloff";
public static readonly string ID = "spline-path-painter-falloff";
public static readonly GUIContent FALL_OFF = new GUIContent("Falloff", "Falloff factor of the spline effect, from the center to the edge");
public static readonly GUIContent FALL_OFF_NOISE = new GUIContent("Falloff Noise", "Noise map in world space to blend with the falloff curve");
public static readonly GUIContent FALL_OFF_NOISE_SIZE = new GUIContent("Falloff Noise Size", "Size of the falloff noise in world space");
}
private void DrawFalloffGUI()
{
GEditorCommon.Foldout(GFalloffGUI.LABEL, false, GFalloffGUI.ID, () =>
{
EditorGUI.BeginChangeCheck();
instance.Falloff = EditorGUILayout.CurveField(GFalloffGUI.FALL_OFF, instance.Falloff, Color.red, new Rect(0, 0, 1, 1));
if (EditorGUI.EndChangeCheck())
{
instance.Internal_UpdateFalloffTexture();
}
instance.FalloffNoise = EditorGUILayout.ObjectField(GFalloffGUI.FALL_OFF_NOISE, instance.FalloffNoise, typeof(Texture2D), false) as Texture2D;
if (instance.FalloffNoise != null)
instance.FalloffNoiseSize = GEditorCommon.InlineVector2Field(GFalloffGUI.FALL_OFF_NOISE_SIZE, instance.FalloffNoiseSize);
});
}
private class GPathGUI
{
public static readonly string LABEL = "Path";
public static readonly string ID = "spline-path-painter-path";
public static readonly GUIContent CHANNEL = new GUIContent("Channel", "The target texture to paint the path on");
public static readonly GUIContent COLOR = new GUIContent("Color", "Color of the path");
public static readonly GUIContent METALLIC = new GUIContent("Metallic", "Metallic value of the path");
public static readonly GUIContent SMOOTHNESS = new GUIContent("Smoothness", "Smoothness value of the path");
public static readonly GUIContent AMS_NOTE = new GUIContent("Use a material that utilizes Albedo & Metallic map to see the result!");
public static readonly GUIContent SPLAT_PROTOTYPE = new GUIContent("Prototype");
public static readonly GUIContent SPLAT_NOTE = new GUIContent("Use a material that utilizes Splat map to see the result!");
}
private void DrawPathGUI()
{
GEditorCommon.Foldout(GPathGUI.LABEL, false, GPathGUI.ID, () =>
{
instance.Channel = (GPathPainter.PaintChannel)EditorGUILayout.EnumPopup(GPathGUI.CHANNEL, instance.Channel);
if (instance.Channel == GPathPainter.PaintChannel.AlbedoAndMetallic)
{
instance.Color = EditorGUILayout.ColorField(GPathGUI.COLOR, instance.Color);
instance.Metallic = EditorGUILayout.Slider(GPathGUI.METALLIC, instance.Metallic, 0f, 1f);
instance.Smoothness = EditorGUILayout.Slider(GPathGUI.SMOOTHNESS, instance.Smoothness, 0f, 1f);
EditorGUILayout.Space();
EditorGUILayout.LabelField(GPathGUI.AMS_NOTE, GEditorCommon.WordWrapItalicLabel);
}
else if (instance.Channel == GPathPainter.PaintChannel.Splat)
{
EditorGUILayout.LabelField(GPathGUI.SPLAT_PROTOTYPE);
instance.SplatIndex = GEditorCommon.SplatSetSelectionGrid(instance.SplineCreator.GroupId, instance.SplatIndex);
EditorGUILayout.Space();
EditorGUILayout.LabelField(GPathGUI.SPLAT_NOTE, GEditorCommon.WordWrapItalicLabel);
}
});
}
private class GActionGUI
{
public static readonly string LABEL = "Action";
public static readonly string ID = "spline-path-painter-action";
public static readonly GUIContent APPLY_BTN = new GUIContent("Apply");
}
private void DrawActionGUI()
{
GEditorCommon.ExpandFoldout(GActionGUI.ID);
GEditorCommon.Foldout(GActionGUI.LABEL, true, GActionGUI.ID, () =>
{
if (GUILayout.Button(GActionGUI.APPLY_BTN))
{
List<GStylizedTerrain> terrains = GUtilities.ExtractTerrainsFromOverlapTest(instance.SplineCreator.SweepTest());
CreateInitialBackup(terrains);
ApplyPath();
CreateBackupAfterApplyPath(terrains);
}
});
}
private void CreateInitialBackup(List<GStylizedTerrain> terrains)
{
string historyPrefix =
instance.Channel == GPathPainter.PaintChannel.AlbedoAndMetallic ? HISTORY_PREFIX_ALBEDO_METALLIC :
instance.Channel == GPathPainter.PaintChannel.Splat ? HISTORY_PREFIX_SPLAT : "Unknown Action";
List<GTerrainResourceFlag> resourceFlag = new List<GTerrainResourceFlag>();
if (instance.Channel == GPathPainter.PaintChannel.AlbedoAndMetallic)
{
resourceFlag.Add(GTerrainResourceFlag.AlbedoMap);
resourceFlag.Add(GTerrainResourceFlag.MetallicMap);
}
else if (instance.Channel == GPathPainter.PaintChannel.Splat)
{
resourceFlag.Add(GTerrainResourceFlag.SplatControlMaps);
}
GBackupInternal.TryCreateAndMergeInitialBackup(historyPrefix, terrains, resourceFlag, true);
}
private void ApplyPath()
{
EditorUtility.DisplayProgressBar("Applying", "Creating path...", 1f);
try
{
instance.Apply();
}
catch (System.Exception e)
{
Debug.LogError(e.ToString());
}
EditorUtility.ClearProgressBar();
}
private void CreateBackupAfterApplyPath(List<GStylizedTerrain> terrains)
{
string historyPrefix =
instance.Channel == GPathPainter.PaintChannel.AlbedoAndMetallic ? HISTORY_PREFIX_ALBEDO_METALLIC :
instance.Channel == GPathPainter.PaintChannel.Splat ? HISTORY_PREFIX_SPLAT : "Unknown Action";
List<GTerrainResourceFlag> resourceFlag = new List<GTerrainResourceFlag>();
if (instance.Channel == GPathPainter.PaintChannel.AlbedoAndMetallic)
{
resourceFlag.Add(GTerrainResourceFlag.AlbedoMap);
resourceFlag.Add(GTerrainResourceFlag.MetallicMap);
}
else if (instance.Channel == GPathPainter.PaintChannel.Splat)
{
resourceFlag.Add(GTerrainResourceFlag.SplatControlMaps);
}
GBackupInternal.TryCreateAndMergeBackup(historyPrefix, terrains, resourceFlag, true);
}
private void OnCameraRender(Camera cam)
{
isUrp = false;
urpContext = default;
if (cam.cameraType != CameraType.SceneView)
return;
if (GEditorSettings.Instance.splineTools.livePreview.pathPainter)
DrawLivePreview(cam);
}
private void OnCameraRenderSRP(UnityEngine.Rendering.ScriptableRenderContext context, Camera cam)
{
OnCameraRender(cam);
}
private IEnumerator IDrawLivePreviewEndOfFrameURP(Camera cam)
{
yield return new WaitForEndOfFrame();
if (cam != null)
{
DrawLivePreview(cam);
}
}
private void DrawLivePreview(Camera cam)
{
List<GOverlapTestResult> sweepTest = instance.SplineCreator.SweepTest();
for (int i = 0; i < sweepTest.Count; ++i)
{
GOverlapTestResult st = sweepTest[i];
if (!st.IsOverlapped)
continue;
DrawLivePreview(st.Terrain, cam, st.IsChunkOverlapped);
}
}
private void DrawLivePreview(GStylizedTerrain t, Camera cam, bool[] chunkCulling)
{
if (instance.Channel == GPathPainter.PaintChannel.AlbedoAndMetallic)
{
SetupAlbedoMetallicPreview(t, cam, chunkCulling);
}
else if (instance.Channel == GPathPainter.PaintChannel.Splat)
{
SetupSplatPreview(t, cam, chunkCulling);
}
}
private void SetupAlbedoMetallicPreview(GStylizedTerrain t, Camera cam, bool[] chunkCulling)
{
Material mat = t.TerrainData.Shading.MaterialToRender;
if (mat == null)
return;
int albedoResolution = t.TerrainData.Shading.AlbedoMapResolution;
FilterMode albedoFilter = t.TerrainData.Shading.AlbedoMapOrDefault.filterMode;
RenderTexture rtAlbedo = GetPreviewTexture(t, "albedo", albedoResolution, albedoFilter);
instance.Internal_ApplyAlbedo(t, rtAlbedo);
int metallicResolution = t.TerrainData.Shading.MetallicMapResolution;
FilterMode metallicFilter = t.TerrainData.Shading.MetallicMapOrDefault.filterMode;
RenderTexture rtMetallic = GetPreviewTexture(t, "metallic", metallicResolution, metallicFilter);
instance.Internal_ApplyMetallic(t, rtMetallic);
GLivePreviewDrawer.DrawAMSLivePreview(t, cam, rtAlbedo, rtMetallic, chunkCulling);
}
private void SetupSplatPreview(GStylizedTerrain t, Camera cam, bool[] chunkCulling)
{
Material mat = t.TerrainData.Shading.MaterialToRender;
if (mat == null)
return;
int controlMapResolution = t.TerrainData.Shading.SplatControlResolution;
int controlMapCount = t.TerrainData.Shading.SplatControlMapCount;
if (controlMapCount == 0)
return;
RenderTexture[] rtControls = new RenderTexture[controlMapCount];
for (int i = 0; i < controlMapCount; ++i)
{
rtControls[i] = GetPreviewTexture(t, "splatControl" + i, controlMapResolution, t.TerrainData.Shading.GetSplatControlOrDefault(i).filterMode);
}
instance.Internal_ApplySplat(t, rtControls);
GLivePreviewDrawer.DrawSplatLivePreview(t, cam, rtControls, chunkCulling);
}
private RenderTexture GetPreviewTexture(GStylizedTerrain t, string mapName, int resolution, FilterMode filter)
{
if (previewTextures == null)
{
previewTextures = new Dictionary<string, RenderTexture>();
}
string key = string.Format("{0}_{1}", t.GetInstanceID(), mapName);
if (!previewTextures.ContainsKey(key) ||
previewTextures[key] == null)
{
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
rt.wrapMode = TextureWrapMode.Clamp;
previewTextures[key] = rt;
}
else if (previewTextures[key].width != resolution || previewTextures[key].height != resolution)
{
previewTextures[key].Release();
Object.DestroyImmediate(previewTextures[key]);
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
rt.wrapMode = TextureWrapMode.Clamp;
previewTextures[key] = rt;
}
previewTextures[key].filterMode = filter;
return previewTextures[key];
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 92073657896cefc45a0745cd4318e7c8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,258 @@
#if GRIFFIN
using Pinwheel.Griffin.BackupTool;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
namespace Pinwheel.Griffin.SplineTool
{
[CustomEditor(typeof(GRampMaker))]
public class GRampMakerInspector : Editor
{
private GRampMaker instance;
private Dictionary<GStylizedTerrain, RenderTexture> previewTextures;
private static readonly string HISTORY_PREFIX = "Make Ramp";
private void OnEnable()
{
Undo.undoRedoPerformed += OnUndoRedo;
instance = (GRampMaker)target;
instance.Internal_UpdateFalloffTexture();
GCommon.RegisterBeginRender(OnCameraRender);
GCommon.RegisterBeginRenderSRP(OnCameraRenderSRP);
}
private void OnDisable()
{
Undo.undoRedoPerformed -= OnUndoRedo;
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);
}
public override void OnInspectorGUI()
{
DrawBaseGUI();
if (instance.SplineCreator == null)
return;
DrawFalloffGUI();
DrawRampGUI();
DrawActionGUI();
#if GRIFFIN_VEGETATION_STUDIO_PRO
GEditorCommon.DrawVspIntegrationGUI();
#endif
}
private class GBaseGUI
{
public static readonly GUIContent SPLINE_CREATOR = new GUIContent("Spline Creator", "The Spline Creator component this modifier belongs to");
public static readonly GUIContent LIVE_PREVIEW = new GUIContent("Live Preview", "Draw a preview over the terrain");
}
private void DrawBaseGUI()
{
instance.SplineCreator = EditorGUILayout.ObjectField(GBaseGUI.SPLINE_CREATOR, instance.SplineCreator, typeof(GSplineCreator), true) as GSplineCreator;
EditorGUI.BeginChangeCheck();
GEditorSettings.Instance.splineTools.livePreview.rampMaker = EditorGUILayout.Toggle(GBaseGUI.LIVE_PREVIEW, GEditorSettings.Instance.splineTools.livePreview.rampMaker);
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(GEditorSettings.Instance);
}
}
private class GFalloffGUI
{
public static readonly string LABEL = "Falloff";
public static readonly string ID = "spline-ramp-maker-falloff";
public static readonly GUIContent FALL_OFF = new GUIContent("Falloff", "Falloff factor of the spline effect, from the center to the edge");
public static readonly GUIContent FALL_OFF_NOISE = new GUIContent("Falloff Noise", "Noise map in world space to blend with the falloff curve");
public static readonly GUIContent FALL_OFF_NOISE_SIZE = new GUIContent("Falloff Noise Size", "Size of the falloff noise in world space");
}
private void DrawFalloffGUI()
{
GEditorCommon.Foldout(GFalloffGUI.LABEL, false, GFalloffGUI.ID, () =>
{
EditorGUI.BeginChangeCheck();
instance.Falloff = EditorGUILayout.CurveField(GFalloffGUI.FALL_OFF, instance.Falloff, Color.red, new Rect(0, 0, 1, 1));
if (EditorGUI.EndChangeCheck())
{
instance.Internal_UpdateFalloffTexture();
}
instance.FalloffNoise = EditorGUILayout.ObjectField(GFalloffGUI.FALL_OFF_NOISE, instance.FalloffNoise, typeof(Texture2D), false) as Texture2D;
if (instance.FalloffNoise != null)
instance.FalloffNoiseSize = GEditorCommon.InlineVector2Field(GFalloffGUI.FALL_OFF_NOISE_SIZE, instance.FalloffNoiseSize);
});
}
private class GRampGUI
{
public static readonly string LABEL = "Ramp";
public static readonly string ID = "spline-ramp-maker-ramp";
public static readonly GUIContent ADDITIONAL_MESH_RESOLUTION = new GUIContent("Additional Mesh Resolution", "Add more mesh detail to the ramp");
public static readonly GUIContent HEIGHT_OFFSET = new GUIContent("Height Offset", "Offset the ramp height on Y axis, useful for making rivers");
public static readonly GUIContent STEP_COUNT = new GUIContent("Step Count", "Adding a quantize/step effect to the ramp");
public static readonly GUIContent RAISE_HEIGHT = new GUIContent("Raise Height", "Toggle height raising");
public static readonly GUIContent LOWER_HEIGHT = new GUIContent("Lower Height", "Toggle height lowering");
}
private void DrawRampGUI()
{
GEditorCommon.Foldout(GRampGUI.LABEL, false, GRampGUI.ID, () =>
{
instance.AdditionalMeshResolution = EditorGUILayout.IntField(GRampGUI.ADDITIONAL_MESH_RESOLUTION, instance.AdditionalMeshResolution);
instance.HeightOffset = EditorGUILayout.FloatField(GRampGUI.HEIGHT_OFFSET, instance.HeightOffset);
instance.StepCount = EditorGUILayout.IntField(GRampGUI.STEP_COUNT, instance.StepCount);
instance.RaiseHeight = EditorGUILayout.Toggle(GRampGUI.RAISE_HEIGHT, instance.RaiseHeight);
instance.LowerHeight = EditorGUILayout.Toggle(GRampGUI.LOWER_HEIGHT, instance.LowerHeight);
});
}
private class GActionGUI
{
public static readonly string LABEL = "Action";
public static readonly string ID = "spline-ramp-maker-action";
public static readonly GUIContent APPLY_BTN = new GUIContent("Apply");
}
private void DrawActionGUI()
{
GEditorCommon.ExpandFoldout(GActionGUI.ID);
GEditorCommon.Foldout(GActionGUI.LABEL, true, GActionGUI.ID, () =>
{
if (GUILayout.Button(GActionGUI.APPLY_BTN))
{
List<GStylizedTerrain> terrains = GUtilities.ExtractTerrainsFromOverlapTest(instance.SplineCreator.SweepTest());
CreateInitialBackup(terrains);
ApplyRamp();
CreateBackupAfterApplyRamp(terrains);
}
});
}
private void CreateInitialBackup(List<GStylizedTerrain> terrains)
{
GBackupInternal.TryCreateAndMergeInitialBackup(HISTORY_PREFIX, terrains, GCommon.HeightMapAndFoliageResourceFlags, true);
}
private void ApplyRamp()
{
EditorUtility.DisplayProgressBar("Applying", "Creating ramp...", 1f);
try
{
instance.Apply();
}
catch (System.Exception e)
{
Debug.LogError(e.ToString());
}
EditorUtility.ClearProgressBar();
}
private void CreateBackupAfterApplyRamp(List<GStylizedTerrain> terrains)
{
GBackupInternal.TryCreateAndMergeBackup(HISTORY_PREFIX, terrains, GCommon.HeightMapAndFoliageResourceFlags, true);
}
private void OnCameraRender(Camera cam)
{
if (cam.cameraType != CameraType.SceneView)
return;
if (GEditorSettings.Instance.splineTools.livePreview.rampMaker)
DrawLivePreview(cam);
}
private void OnCameraRenderSRP(ScriptableRenderContext context, Camera cam)
{
OnCameraRender(cam);
}
private IEnumerator IDrawLivePreviewEndOfFrameURP(Camera cam)
{
yield return new WaitForEndOfFrame();
if (cam != null)
{
DrawLivePreview(cam);
}
}
private void DrawLivePreview(Camera cam)
{
List<GOverlapTestResult> sweepTests = instance.SplineCreator.SweepTest();
for (int i = 0; i < sweepTests.Count; ++i)
{
GOverlapTestResult st = sweepTests[i];
if (st.IsOverlapped)
{
GStylizedTerrain t = st.Terrain;
if (t.transform.rotation != Quaternion.identity ||
t.transform.lossyScale != Vector3.one)
return;
RenderTexture rt = GetPreviewTexture(t);
instance.Internal_DrawOnTexture(t, rt);
GLivePreviewDrawer.DrawGeometryLivePreview(t, cam, rt, st.IsChunkOverlapped);
}
}
}
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];
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f3daaf52765c3c48a47d9027af674b9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
#if GRIFFIN
using UnityEditor;
using UnityEngine;
namespace Pinwheel.Griffin.SplineTool
{
public class GSplineAnchorInspectorDrawer
{
private GSplineAnchor instance;
public GSplineAnchorInspectorDrawer(GSplineAnchor anchor)
{
instance = anchor;
}
public static GSplineAnchorInspectorDrawer Create(GSplineAnchor anchor)
{
return new GSplineAnchorInspectorDrawer(anchor);
}
public void DrawGUI()
{
EditorGUIUtility.wideMode = true;
instance.Position = EditorGUILayout.Vector3Field("Position", instance.Position);
instance.Rotation = Quaternion.Euler(EditorGUILayout.Vector3Field("Rotation", instance.Rotation.eulerAngles));
instance.Scale = EditorGUILayout.Vector3Field("Scale", instance.Scale);
EditorGUIUtility.wideMode = false;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c4d774cb54e8dcc40b5416112355a269
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,457 @@
#if GRIFFIN
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using Type = System.Type;
namespace Pinwheel.Griffin.SplineTool
{
[CustomEditor(typeof(GSplineCreator))]
public class GSplineCreatorInspector : Editor
{
private List<Type> modifierTypes;
public List<Type> ModifierTypes
{
get
{
if (modifierTypes == null)
{
modifierTypes = new List<Type>();
}
return modifierTypes;
}
set
{
modifierTypes = value;
}
}
private GSplineCreator instance;
private int selectedAnchorIndex = -1;
private int selectedSegmentIndex = -1;
private Rect addModifierButtonRect;
private GSplineEditingGUIDrawer splineEditingDrawer;
private void OnEnable()
{
instance = (GSplineCreator)target;
InitModifierClasses();
Tools.hidden = true;
splineEditingDrawer = new GSplineEditingGUIDrawer(instance);
GCommon.RegisterBeginRender(OnBeginRender);
GCommon.RegisterBeginRenderSRP(OnBeginRenderSRP);
SceneView.duringSceneGui += DuringSceneGUI;
GLayerInitializer.SetupSplineLayer();
}
private void OnDisable()
{
Tools.hidden = false;
GCommon.UnregisterBeginRender(OnBeginRender);
GCommon.UnregisterBeginRenderSRP(OnBeginRenderSRP);
SceneView.duringSceneGui -= DuringSceneGUI;
}
private void InitModifierClasses()
{
List<Type> loadedTypes = GCommon.GetAllLoadedTypes();
ModifierTypes = loadedTypes.FindAll(
t => t.IsSubclassOf(typeof(GSplineModifier)));
}
public override bool RequiresConstantRepaint()
{
return false;
}
private class GBaseGUI
{
public static readonly GUIContent GROUP_ID = new GUIContent("Group Id", "Id of the terrain group this tool will work on");
public static readonly GUIContent RAYCAST_LAYER = new GUIContent("Raycast Layers", "Game object layers to perform raycast when adding anchors");
public static readonly GUIContent RAYCAST_LAYER_WARNING = new GUIContent("You can't edit the spline with Raycast Layers set to Nothing");
public static readonly GUIContent AUTO_TANGENT = new GUIContent("Auto Tangent", "Smooth the spline automatically");
public static readonly GUIContent ENABLE_TERRAIN_MASK = new GUIContent("Enable Terrain Mask", "Use the terrain Mask texture (R) to lock particular regions from being edited");
public static readonly GUIContent ENABLE_TOPOGRAPHIC = new GUIContent("Enable Topographic", "Draw an overlay topographic view for better sense of elevation");
}
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
GUI.enabled = !GEditorSettings.Instance.splineTools.showTransformGizmos;
instance.GroupId = GEditorCommon.ActiveTerrainGroupPopupWithAllOption(GBaseGUI.GROUP_ID, instance.GroupId);
GEditorSettings.Instance.splineTools.raycastLayers = GEditorCommon.LayerMaskField(GBaseGUI.RAYCAST_LAYER, GEditorSettings.Instance.splineTools.raycastLayers);
if (GEditorSettings.Instance.splineTools.raycastLayers == 0)
{
EditorGUILayout.LabelField(GBaseGUI.RAYCAST_LAYER_WARNING, GEditorCommon.WarningLabel);
}
GEditorSettings.Instance.splineTools.autoTangent = EditorGUILayout.Toggle(GBaseGUI.AUTO_TANGENT, GEditorSettings.Instance.splineTools.autoTangent);
instance.EnableTerrainMask = EditorGUILayout.Toggle(GBaseGUI.ENABLE_TERRAIN_MASK, instance.EnableTerrainMask);
GEditorSettings.Instance.topographic.enable = EditorGUILayout.Toggle(GBaseGUI.ENABLE_TOPOGRAPHIC, GEditorSettings.Instance.topographic.enable);
DrawInstructionGUI();
GUI.enabled = true;
DrawTransformGUI();
GUI.enabled = !GEditorSettings.Instance.splineTools.showTransformGizmos;
DrawAnchorDefaultValueGUI();
DrawSelectedAnchorGUI();
DrawSegmentDefaultValueGUI();
DrawSelectedSegmentGUI();
//DrawGizmosGUI();
DrawModifiersGUI();
GEditorCommon.DrawBackupHelpBox();
//DrawDebugGUI();
if (EditorGUI.EndChangeCheck())
{
GSplineCreator.MarkSplineChanged(instance);
GUtilities.MarkCurrentSceneDirty();
}
GEditorCommon.DrawCommonLinks();
}
private class GInstructionGUI
{
public static readonly string LABEL = "Instruction";
public static readonly string ID = "spline-creator-instruction";
public static readonly GUIContent INSTRUCTION = new GUIContent(
string.Format(
"Create a edit bezier spline.\n" +
" - Left Click to select element.\n" +
" - Ctrl & Left Click to delete element.\n" +
" - Shift & Left Click to add element.\n" +
"Use Add Modifier to do specific tasks with spline data."));
}
private void DrawInstructionGUI()
{
GEditorCommon.Foldout(GInstructionGUI.LABEL, true, GInstructionGUI.ID, () =>
{
EditorGUILayout.LabelField(GInstructionGUI.INSTRUCTION, GEditorCommon.WordWrapItalicLabel);
});
}
private class GTransformGUI
{
public static readonly string LABEL = "Transform";
public static readonly string ID = "spline-creator-transform";
public static readonly GUIContent SET_PIVOT_TO_MEDIAN_POINT = new GUIContent("Set Pivot To Median Point");
public static readonly GUIContent POSITION = new GUIContent("Position", "Position of the Spline object");
public static readonly GUIContent ROTATION = new GUIContent("Rotation", "Rotation of the Spline object");
public static readonly GUIContent SCALE = new GUIContent("Scale", "Scale of the Spline object");
public static readonly GUIContent SHOW_TRANSFORM_GIZMOS = new GUIContent("Show Transform Gizmos", "Show gizmos to move, rotate and scale the Spline object");
}
private void DrawTransformGUI()
{
if (GEditorSettings.Instance.splineTools.showTransformGizmos)
{
GEditorCommon.ExpandFoldout(GTransformGUI.ID);
}
GenericMenu menu = new GenericMenu();
menu.AddItem(
GTransformGUI.SET_PIVOT_TO_MEDIAN_POINT,
false,
() => { SetPivotToMedianPoint(); });
GEditorCommon.Foldout(GTransformGUI.LABEL, true, GTransformGUI.ID, () =>
{
instance.transform.localPosition = GEditorCommon.InlineVector3Field(GTransformGUI.POSITION, instance.transform.localPosition);
instance.transform.localRotation = GEditorCommon.InlineEulerRotationField(GTransformGUI.ROTATION, instance.transform.localRotation);
instance.transform.localScale = GEditorCommon.InlineVector3Field(GTransformGUI.SCALE, instance.transform.localScale);
GEditorSettings.Instance.splineTools.showTransformGizmos = EditorGUILayout.Toggle(GTransformGUI.SHOW_TRANSFORM_GIZMOS, GEditorSettings.Instance.splineTools.showTransformGizmos);
},
menu);
}
private class GAnchorDefaultGUI
{
public static readonly string LABEL = "Anchor Defaults";
public static readonly string ID = "spline-creator-anchor-defaults";
public static readonly GUIContent POSITION_OFFSET = new GUIContent("Position Offset", "Offset from the raycast point of the anchor");
public static readonly GUIContent INITIAL_ROTATION = new GUIContent("Rotation", "Initial rotation of the new anchor");
public static readonly GUIContent INITIAL_SCALE = new GUIContent("Scale", "Initial scale of the new anchor");
}
private void DrawAnchorDefaultValueGUI()
{
GEditorCommon.Foldout(GAnchorDefaultGUI.LABEL, true, GAnchorDefaultGUI.ID, () =>
{
instance.PositionOffset = GEditorCommon.InlineVector3Field(GAnchorDefaultGUI.POSITION_OFFSET, instance.PositionOffset);
instance.InitialRotation = GEditorCommon.InlineEulerRotationField(GAnchorDefaultGUI.INITIAL_ROTATION, instance.InitialRotation);
instance.InitialScale = GEditorCommon.InlineVector3Field(GAnchorDefaultGUI.INITIAL_SCALE, instance.InitialScale);
});
}
private class GSelectedAnchorGUI
{
public static readonly string LABEL = "Selected Anchor";
public static readonly string ID = "spline-creator-selected-anchor";
public static readonly GUIContent POSITION = new GUIContent("Position", "Position of the anchor");
public static readonly GUIContent ROTATION = new GUIContent("Rotation", "Rotation of the anchor, you can't change this if Auto Tangent is enable");
public static readonly GUIContent SCALE = new GUIContent("Scale", "Scale of the anchor");
public static readonly GUIContent NO_ANCHOR_SELECTED = new GUIContent("No Anchor selected!");
}
private void DrawSelectedAnchorGUI()
{
GEditorCommon.Foldout(GSelectedAnchorGUI.LABEL, true, GSelectedAnchorGUI.ID, () =>
{
selectedAnchorIndex = splineEditingDrawer.selectedAnchorIndex;
if (selectedAnchorIndex >= 0 && selectedAnchorIndex < instance.Spline.Anchors.Count)
{
GSplineAnchor a = instance.Spline.Anchors[selectedAnchorIndex];
EditorGUI.BeginChangeCheck();
a.Position = GEditorCommon.InlineVector3Field(GSelectedAnchorGUI.POSITION, a.Position);
GUI.enabled = !GEditorSettings.Instance.splineTools.autoTangent;
a.Rotation = GEditorCommon.InlineEulerRotationField(GSelectedAnchorGUI.ROTATION, a.Rotation);
GUI.enabled = true;
a.Scale = GEditorCommon.InlineVector3Field(GSelectedAnchorGUI.SCALE, a.Scale);
if (EditorGUI.EndChangeCheck())
{
if (GEditorSettings.Instance.splineTools.autoTangent)
{
instance.Spline.SmoothTangents(selectedAnchorIndex);
}
List<int> segmentIndices = instance.Spline.FindSegments(selectedAnchorIndex);
instance.UpdateMesh(segmentIndices);
}
}
else
{
EditorGUILayout.LabelField(GSelectedAnchorGUI.NO_ANCHOR_SELECTED, GEditorCommon.ItalicLabel);
}
});
}
private class GSegmentDefaultGUI
{
public static readonly string LABEL = "Segment Defaults";
public static readonly string ID = "spline-creator-segment-defaults";
public static readonly GUIContent SMOOTHNESS = new GUIContent("Smoothness", "Spline subdivision factor, larger number produces smoother spline");
public static readonly GUIContent WIDTH = new GUIContent("Width", "Width of the inner part of the spline body where there is no falloff");
public static readonly GUIContent FALLOFF_WIDTH = new GUIContent("Falloff Width", "Width of the outer part of the spline body where falloff takes into account");
}
private void DrawSegmentDefaultValueGUI()
{
GEditorCommon.Foldout(GSegmentDefaultGUI.LABEL, true, GSegmentDefaultGUI.ID, () =>
{
EditorGUIUtility.wideMode = true;
EditorGUI.BeginChangeCheck();
instance.Smoothness = EditorGUILayout.IntField(GSegmentDefaultGUI.SMOOTHNESS, instance.Smoothness);
instance.Width = EditorGUILayout.FloatField(GSegmentDefaultGUI.WIDTH, instance.Width);
instance.FalloffWidth = EditorGUILayout.FloatField(GSegmentDefaultGUI.FALLOFF_WIDTH, instance.FalloffWidth);
if (EditorGUI.EndChangeCheck())
{
instance.UpdateMeshes();
}
EditorGUIUtility.wideMode = false;
});
}
private class GSelectedSegmentGUI
{
public static readonly string LABEL = "Selected Segment";
public static readonly string ID = "spline-creator-selected-segment";
public static readonly GUIContent START_TANGENT = new GUIContent("Start Tangent", "Position of the first tangent, you can't change this if Auto Tangent is on");
public static readonly GUIContent END_TANGENT = new GUIContent("End Tangent", "Position of the second tangent, you can't change this if Auto Tangent is on");
public static readonly GUIContent FLIP_DIRECTION_BTN = new GUIContent("Flip Direction", "Flip the direction of this segment");
public static readonly GUIContent NO_SEGMENT_SELECTED = new GUIContent("No Segment selected!");
}
private void DrawSelectedSegmentGUI()
{
GEditorCommon.Foldout(GSelectedSegmentGUI.LABEL, true, GSelectedSegmentGUI.ID, () =>
{
selectedSegmentIndex = splineEditingDrawer.selectedSegmentIndex;
if (selectedSegmentIndex >= 0 && selectedSegmentIndex < instance.Spline.Segments.Count)
{
GSplineSegment s = instance.Spline.Segments[selectedSegmentIndex];
GUI.enabled = !GEditorSettings.Instance.splineTools.autoTangent;
s.StartTangent = GEditorCommon.InlineVector3Field(GSelectedSegmentGUI.START_TANGENT, s.StartTangent);
s.EndTangent = GEditorCommon.InlineVector3Field(GSelectedSegmentGUI.END_TANGENT, s.EndTangent);
GUI.enabled = true;
if (GUILayout.Button(GSelectedSegmentGUI.FLIP_DIRECTION_BTN))
{
s.FlipDirection();
if (GEditorSettings.Instance.splineTools.autoTangent)
{
instance.Spline.SmoothTangents(s.StartIndex, s.EndIndex);
}
instance.UpdateMesh(selectedSegmentIndex);
}
}
else
{
EditorGUILayout.LabelField(GSelectedSegmentGUI.NO_SEGMENT_SELECTED, GEditorCommon.ItalicLabel);
}
});
}
private class GGizmosGUI
{
}
private void DrawGizmosGUI()
{
string label = "Gizmos";
string id = "gizmos" + instance.GetInstanceID().ToString();
GEditorCommon.Foldout(label, true, id, () =>
{
EditorUtility.SetDirty(GEditorSettings.Instance);
});
}
private class GModifiersGUI
{
public static readonly string LABEL = "Modifiers";
public static readonly string ID = "spline-creator-modifiers";
public static readonly GUIContent ADD_MODIFIER_BTN = new GUIContent("Add Modifier");
}
private void DrawModifiersGUI()
{
GEditorCommon.Foldout(GModifiersGUI.LABEL, true, GModifiersGUI.ID, () =>
{
if (ModifierTypes.Count == 0)
return;
Rect r = EditorGUILayout.GetControlRect();
if (Event.current.type == EventType.Repaint)
addModifierButtonRect = r;
if (GUI.Button(r, GModifiersGUI.ADD_MODIFIER_BTN))
{
GenericMenu menu = new GenericMenu();
for (int i = 0; i < ModifierTypes.Count; ++i)
{
Type t = ModifierTypes[i];
string menuLabel = string.Empty;
object[] alternativeClassNameAttributes = t.GetCustomAttributes(typeof(GDisplayName), false);
if (alternativeClassNameAttributes != null && alternativeClassNameAttributes.Length > 0)
{
GDisplayName att = alternativeClassNameAttributes[0] as GDisplayName;
if (att.DisplayName == null ||
att.DisplayName.Equals(string.Empty))
menuLabel = t.Name;
else
menuLabel = att.DisplayName;
}
else
{
menuLabel = t.Name;
}
menu.AddItem(
new GUIContent(ObjectNames.NicifyVariableName(menuLabel)),
false,
() =>
{
AddModifier(t);
});
}
menu.DropDown(addModifierButtonRect);
}
});
}
private void AddModifier(Type t)
{
GSplineModifier modifier = instance.gameObject.AddComponent(t) as GSplineModifier;
modifier.SplineCreator = instance;
}
private void DuringSceneGUI(SceneView sv)
{
if (!instance.isActiveAndEnabled)
return;
EditorGUI.BeginChangeCheck();
splineEditingDrawer.Draw();
if (EditorGUI.EndChangeCheck())
{
GSplineCreator.MarkSplineChanged(instance);
GUtilities.MarkCurrentSceneDirty();
}
}
private void SetPivotToMedianPoint()
{
Vector3 localMedian = Vector3.zero;
List<GSplineAnchor> anchors = instance.Spline.Anchors;
if (anchors.Count == 0)
return;
for (int i = 0; i < anchors.Count; ++i)
{
localMedian += anchors[i].Position;
}
localMedian = localMedian / anchors.Count;
Vector3 worldMedian = instance.transform.TransformPoint(localMedian);
Matrix4x4 medianToLocal = Matrix4x4.TRS(
worldMedian,
instance.transform.rotation,
instance.transform.lossyScale).inverse;
Matrix4x4 localToWorld = instance.transform.localToWorldMatrix;
Matrix4x4 transformationMatrix = medianToLocal * localToWorld;
for (int i = 0; i < anchors.Count; ++i)
{
anchors[i].Position = transformationMatrix.MultiplyPoint(anchors[i].Position);
}
List<GSplineSegment> segments = instance.Spline.Segments;
for (int i = 0; i < segments.Count; ++i)
{
segments[i].StartTangent = transformationMatrix.MultiplyPoint(segments[i].StartTangent);
segments[i].EndTangent = transformationMatrix.MultiplyPoint(segments[i].EndTangent);
}
instance.transform.position = worldMedian;
instance.UpdateMeshes();
GSplineCreator.MarkSplineChanged(instance);
}
private void OnBeginRender(Camera cam)
{
if (cam.cameraType != CameraType.SceneView)
return;
if (instance.EnableTerrainMask)
{
DrawTerrainMask(cam);
}
}
private void OnBeginRenderSRP(ScriptableRenderContext context, Camera cam)
{
OnBeginRender(cam);
}
private void DrawTerrainMask(Camera cam)
{
GCommon.ForEachTerrain(instance.GroupId, (t) =>
{
GLivePreviewDrawer.DrawTerrainMask(t, cam);
});
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5183558bccf9aa644b43209408435eb9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,376 @@
#if GRIFFIN
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.EditorTools;
using UnityEditor;
namespace Pinwheel.Griffin.SplineTool
{
public class GSplineEditingGUIDrawer
{
private const float BEZIER_SELECT_DISTANCE = 10;
private const float BEZIER_WIDTH = 5;
public int selectedAnchorIndex = -1;
public int selectedSegmentIndex = -1;
private GSplineCreator splineCreator;
bool autoTangent;
bool showTransformGizmos;
public GSplineEditingGUIDrawer(GSplineCreator splineCreator)
{
this.splineCreator = splineCreator;
}
public void Draw()
{
if (Event.current == null)
return;
autoTangent = GEditorSettings.Instance.splineTools.autoTangent;
showTransformGizmos = GEditorSettings.Instance.splineTools.showTransformGizmos;
//DrawDebug();
HandleSelectTransformRemoveAnchor();
HandleSelectTransformRemoveSegment();
HandleAddAnchor();
//DrawMesh();
DrawPivot();
//DrawInstruction();
CatchHotControl();
}
private void HandleSelectTransformRemoveAnchor()
{
List<GSplineAnchor> anchors = splineCreator.Spline.Anchors;
for (int i = 0; i < anchors.Count; ++i)
{
GSplineAnchor a = anchors[i];
Vector3 localPos = a.Position;
Vector3 worldPos = splineCreator.transform.TransformPoint(localPos);
float handleSize = HandleUtility.GetHandleSize(worldPos) * 0.2f;
if (i == selectedAnchorIndex && !showTransformGizmos)
{
Handles.color = GEditorSettings.Instance.splineTools.selectedElementColor;
Handles.SphereHandleCap(0, worldPos, Quaternion.identity, handleSize, EventType.Repaint);
bool isGlobalRotation = Tools.pivotRotation == PivotRotation.Global;
EditorGUI.BeginChangeCheck();
if (Tools.current == Tool.Move)
{
worldPos = Handles.PositionHandle(worldPos, isGlobalRotation ? Quaternion.identity : a.Rotation);
localPos = splineCreator.transform.InverseTransformPoint(worldPos);
a.Position = localPos;
}
else if (Tools.current == Tool.Rotate && !GEditorSettings.Instance.splineTools.autoTangent)
{
a.Rotation = Handles.RotationHandle(a.Rotation, worldPos);
}
else if (Tools.current == Tool.Scale)
{
a.Scale = Handles.ScaleHandle(a.Scale, worldPos, isGlobalRotation ? Quaternion.identity : a.Rotation, HandleUtility.GetHandleSize(worldPos));
}
anchors[i] = a;
if (EditorGUI.EndChangeCheck())
{
if (autoTangent)
{
splineCreator.Spline.SmoothTangents(selectedAnchorIndex);
GUI.changed = true;
}
List<int> segmentIndices = splineCreator.Spline.FindSegments(selectedAnchorIndex);
splineCreator.UpdateMesh(segmentIndices);
}
}
else
{
Handles.color = GEditorSettings.Instance.splineTools.anchorColor;
if (Handles.Button(worldPos, Quaternion.identity, handleSize, handleSize * 0.5f, Handles.SphereHandleCap) && !showTransformGizmos)
{
if (!Event.current.alt)
{
if (Event.current.control)
{
selectedAnchorIndex = -1;
selectedSegmentIndex = -1;
splineCreator.Spline.RemoveAnchor(i);
GUI.changed = true;
}
else if (Event.current.shift)
{
if (selectedAnchorIndex != i &&
selectedAnchorIndex >= 0 &&
selectedAnchorIndex < anchors.Count)
{
splineCreator.Spline.AddSegment(selectedAnchorIndex, i);
if (autoTangent)
{
int[] segmentsIndices = splineCreator.Spline.SmoothTangents(selectedAnchorIndex, i);
splineCreator.UpdateMesh(segmentsIndices);
}
else
{
splineCreator.UpdateMesh(splineCreator.Spline.Segments.Count - 1);
}
selectedAnchorIndex = i;
selectedSegmentIndex = -1;
GUI.changed = true;
}
}
else
{
selectedAnchorIndex = i;
selectedSegmentIndex = -1;
GUI.changed = true;
}
Event.current.Use();
}
}
}
}
}
private void HandleAddAnchor()
{
if (showTransformGizmos)
return;
bool isLeftMouseUp = Event.current.type == EventType.MouseUp && Event.current.button == 0;
bool isShift = Event.current.shift;
bool isAlt = Event.current.alt;
if (!isLeftMouseUp)
return;
LayerMask raycastLayers = GEditorSettings.Instance.splineTools.raycastLayers;
Ray r = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
RaycastHit hit;
if (Physics.Raycast(r, out hit, 10000, raycastLayers))
{
if (isAlt)
{
return;
}
if (!isShift)
{
selectedAnchorIndex = -1;
return;
}
Vector3 offset = splineCreator.PositionOffset;
Vector3 worldPos = hit.point + offset;
Vector3 localPos = splineCreator.transform.InverseTransformPoint(worldPos);
GSplineAnchor a = new GSplineAnchor(localPos);
splineCreator.Spline.AddAnchor(a);
if (selectedAnchorIndex >= 0 && selectedAnchorIndex < splineCreator.Spline.Anchors.Count - 1)
{
splineCreator.Spline.AddSegment(selectedAnchorIndex, splineCreator.Spline.Anchors.Count - 1);
if (autoTangent)
{
int[] segmentIndices = splineCreator.Spline.SmoothTangents(selectedAnchorIndex, splineCreator.Spline.Anchors.Count - 1);
splineCreator.UpdateMesh(segmentIndices);
}
else
{
splineCreator.UpdateMesh(splineCreator.Spline.Segments.Count - 1);
}
}
selectedAnchorIndex = splineCreator.Spline.Anchors.Count - 1;
GUI.changed = true;
Event.current.Use();
}
else
{
selectedAnchorIndex = -1;
}
}
private void HandleSelectTransformRemoveSegment()
{
List<GSplineSegment> segments = splineCreator.Spline.Segments;
List<GSplineAnchor> anchors = splineCreator.Spline.Anchors;
for (int i = 0; i < segments.Count; ++i)
{
if (!splineCreator.Spline.IsSegmentValid(i))
continue;
if (i == selectedSegmentIndex && !autoTangent && !showTransformGizmos)
HandleSelectedSegmentModifications();
int i0 = segments[i].StartIndex;
int i1 = segments[i].EndIndex;
GSplineAnchor a0 = anchors[i0];
GSplineAnchor a1 = anchors[i1];
Vector3 startPosition = splineCreator.transform.TransformPoint(a0.Position);
Vector3 endPosition = splineCreator.transform.TransformPoint(a1.Position);
Vector3 startTangent = splineCreator.transform.TransformPoint(segments[i].StartTangent);
Vector3 endTangent = splineCreator.transform.TransformPoint(segments[i].EndTangent);
Color color = (i == selectedSegmentIndex) ?
GEditorSettings.Instance.splineTools.selectedElementColor :
GEditorSettings.Instance.splineTools.segmentColor; ;
Color colorFade = new Color(color.r, color.g, color.b, color.a * 0.3f);
Vector3[] bezierPoints = Handles.MakeBezierPoints(startPosition, endPosition, startTangent, endTangent, Mathf.Min(5, splineCreator.Smoothness));
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
Handles.color = color;
Handles.DrawPolyLine(bezierPoints);
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
Handles.color = colorFade;
Handles.DrawPolyLine(bezierPoints);
if (Event.current.type == EventType.MouseUp && Event.current.button == 0 && !showTransformGizmos && !Event.current.alt)
{
float d0 = DistanceMouseToSpline(Event.current.mousePosition, bezierPoints);
float d1 = DistanceMouseToPoint(Event.current.mousePosition, bezierPoints[0]);
float d2 = DistanceMouseToPoint(Event.current.mousePosition, bezierPoints[bezierPoints.Length - 1]);
if (d0 <= BEZIER_SELECT_DISTANCE &&
d1 > BEZIER_SELECT_DISTANCE &&
d2 > BEZIER_SELECT_DISTANCE)
{
selectedSegmentIndex = i;
if (Event.current.control)
{
splineCreator.Spline.RemoveSegment(selectedSegmentIndex);
selectedSegmentIndex = -1;
GUI.changed = true;
}
//don't Use() the event here
}
else
{
if (selectedSegmentIndex == i)
{
selectedSegmentIndex = -1;
}
}
}
}
Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
}
private void HandleSelectedSegmentModifications()
{
if (selectedSegmentIndex < 0 || selectedSegmentIndex >= splineCreator.Spline.Segments.Count)
return;
if (!splineCreator.Spline.IsSegmentValid(selectedSegmentIndex))
return;
GSplineSegment segment = splineCreator.Spline.Segments[selectedSegmentIndex];
GSplineAnchor startAnchor = splineCreator.Spline.Anchors[segment.StartIndex];
GSplineAnchor endAnchor = splineCreator.Spline.Anchors[segment.EndIndex];
Vector3 worldStartPosition = splineCreator.transform.TransformPoint(startAnchor.Position);
Vector3 worldEndPosition = splineCreator.transform.TransformPoint(endAnchor.Position);
Vector3 worldStartTangent = splineCreator.transform.TransformPoint(segment.StartTangent);
Vector3 worldEndTangent = splineCreator.transform.TransformPoint(segment.EndTangent);
EditorGUI.BeginChangeCheck();
Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
worldStartTangent = Handles.PositionHandle(worldStartTangent, Quaternion.identity);
worldEndTangent = Handles.PositionHandle(worldEndTangent, Quaternion.identity);
segment.StartTangent = splineCreator.transform.InverseTransformPoint(worldStartTangent);
segment.EndTangent = splineCreator.transform.InverseTransformPoint(worldEndTangent);
if (EditorGUI.EndChangeCheck())
{
splineCreator.UpdateMesh(selectedSegmentIndex);
GUI.changed = true;
}
Handles.color = Color.white;
Handles.DrawLine(worldStartPosition, worldStartTangent);
Handles.DrawLine(worldEndPosition, worldEndTangent);
}
private void DrawPivot()
{
if (!showTransformGizmos)
{
Vector3 pivot = splineCreator.transform.position;
float size = HandleUtility.GetHandleSize(pivot);
Vector3 xStart = pivot + Vector3.left * size;
Vector3 xEnd = pivot + Vector3.right * size;
Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
Handles.color = Handles.xAxisColor;
Handles.DrawLine(xStart, xEnd);
Vector3 yStart = pivot + Vector3.down * size;
Vector3 yEnd = pivot + Vector3.up * size;
Handles.color = Handles.yAxisColor;
Handles.DrawLine(yStart, yEnd);
Vector3 zStart = pivot + Vector3.back * size;
Vector3 zEnd = pivot + Vector3.forward * size;
Handles.color = Handles.zAxisColor;
Handles.DrawLine(zStart, zEnd);
}
else
{
if (Tools.current == Tool.Move)
{
splineCreator.transform.position = Handles.PositionHandle(splineCreator.transform.position, splineCreator.transform.rotation);
}
else if (Tools.current == Tool.Rotate)
{
splineCreator.transform.rotation = Handles.RotationHandle(splineCreator.transform.rotation, splineCreator.transform.position);
}
else if (Tools.current == Tool.Scale)
{
splineCreator.transform.localScale = Handles.ScaleHandle(splineCreator.transform.localScale, splineCreator.transform.position, splineCreator.transform.rotation, HandleUtility.GetHandleSize(splineCreator.transform.position));
}
}
}
private void CatchHotControl()
{
if (Event.current.alt)
return;
int controlId = GUIUtility.GetControlID(this.GetHashCode(), FocusType.Passive);
if (Event.current.type == EventType.MouseDown)
{
if (Event.current.button == 0)
{
GUIUtility.hotControl = controlId;
//OnMouseDown(Event.current);
}
}
else if (Event.current.type == EventType.MouseUp)
{
if (GUIUtility.hotControl == controlId)
{
//OnMouseUp(Event.current);
//Return the hot control back to Unity, use the default
GUIUtility.hotControl = 0;
}
}
else if (Event.current.type == EventType.KeyDown)
{
//OnKeyDown(Event.current);
}
}
public static float DistanceMouseToSpline(Vector2 mousePosition, params Vector3[] splinePoint)
{
float d = float.MaxValue;
for (int i = 0; i < splinePoint.Length - 1; ++i)
{
float d1 = HandleUtility.DistancePointToLineSegment(
mousePosition,
HandleUtility.WorldToGUIPoint(splinePoint[i]),
HandleUtility.WorldToGUIPoint(splinePoint[i + 1]));
if (d1 < d)
d = d1;
}
return d;
}
public static float DistanceMouseToPoint(Vector2 mousePosition, Vector3 worldPoint)
{
float d = Vector2.Distance(
mousePosition,
HandleUtility.WorldToGUIPoint(worldPoint));
return d;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a260f948ec7700f4cbadbb102203e139
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
#if GRIFFIN
using UnityEditor;
using UnityEngine;
namespace Pinwheel.Griffin.SplineTool
{
[CustomEditor(typeof(GSplineModifier), true)]
public class GSplineModifierInspector : Editor
{
private GSplineModifier instance;
public void OnEnable()
{
instance = (GSplineModifier)target;
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
if (instance.SplineCreator == null)
return;
EditorGUILayout.Space();
if (GUILayout.Button("Apply"))
{
instance.Apply();
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 672f37962a8bbbd4a896b3826b4b222a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
#if GRIFFIN
using UnityEditor;
namespace Pinwheel.Griffin.SplineTool
{
public class GSplineSegmentInspectorDrawer
{
private GSplineSegment instance;
public GSplineSegmentInspectorDrawer(GSplineSegment s)
{
instance = s;
}
public static GSplineSegmentInspectorDrawer Create(GSplineSegment s)
{
return new GSplineSegmentInspectorDrawer(s);
}
public void DrawGUI()
{
EditorGUIUtility.wideMode = true;
instance.StartTangent = EditorGUILayout.Vector3Field("Start Tangent", instance.StartTangent);
instance.EndTangent = EditorGUILayout.Vector3Field("End Tangent", instance.EndTangent);
EditorGUIUtility.wideMode = false;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 66f9ccfb9144d5d4d884c72e1c267058
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: