2024-03-05 17:34:41 +08:00
|
|
|
#if GRIFFIN
|
2023-12-30 17:37:48 +08:00
|
|
|
using UnityEngine;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using Type = System.Type;
|
|
|
|
using Rand = System.Random;
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
using Pinwheel.Griffin.BackupTool;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace Pinwheel.Griffin.PaintTool
|
|
|
|
{
|
|
|
|
[System.Serializable]
|
|
|
|
[ExecuteInEditMode]
|
|
|
|
public class GTerrainTexturePainter : MonoBehaviour
|
|
|
|
{
|
|
|
|
public const float GEOMETRY_OPACITY_EXPONENT = 3;
|
|
|
|
|
|
|
|
private static readonly List<string> BUILTIN_PAINTER_NAME = new List<string>(new string[]
|
|
|
|
{
|
|
|
|
"GElevationPainter",
|
|
|
|
"GHeightSamplingPainter",
|
|
|
|
"GTerracePainter",
|
|
|
|
"GRemapPainter",
|
|
|
|
"GNoisePainter",
|
|
|
|
"GSubDivPainter",
|
|
|
|
"GVisibilityPainter",
|
|
|
|
"GAlbedoPainter",
|
|
|
|
"GMetallicPainter",
|
|
|
|
"GSmoothnessPainter",
|
|
|
|
"GSplatPainter",
|
|
|
|
"GMaskPainter"
|
|
|
|
});
|
|
|
|
|
|
|
|
private static List<Type> customPainterTypes;
|
|
|
|
private static List<Type> CustomPainterTypes
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (customPainterTypes == null)
|
|
|
|
customPainterTypes = new List<Type>();
|
|
|
|
return customPainterTypes;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
customPainterTypes = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static string TexturePainterInterfaceName
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return typeof(IGTexturePainter).Name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static GTerrainTexturePainter()
|
|
|
|
{
|
|
|
|
RefreshCustomPainterTypes();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void RefreshCustomPainterTypes()
|
|
|
|
{
|
|
|
|
List<Type> loadedTypes = GCommon.GetAllLoadedTypes();
|
|
|
|
CustomPainterTypes = loadedTypes.FindAll(
|
|
|
|
t => t.GetInterface(TexturePainterInterfaceName) != null &&
|
|
|
|
!BUILTIN_PAINTER_NAME.Contains(t.Name));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static List<Type> GetCustomPainterTypes()
|
|
|
|
{
|
|
|
|
return CustomPainterTypes;
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private int groupId;
|
|
|
|
public int GroupId
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return groupId;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
groupId = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private GTexturePaintingMode mode;
|
|
|
|
public GTexturePaintingMode Mode
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return mode;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
mode = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private int customPainterIndex;
|
|
|
|
public int CustomPainterIndex
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return customPainterIndex;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
customPainterIndex = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private string customPainterArgs;
|
|
|
|
public string CustomPainterArgs
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return customPainterArgs;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
customPainterArgs = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private bool enableTerrainMask = true;
|
|
|
|
public bool EnableTerrainMask
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return enableTerrainMask;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
enableTerrainMask = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private bool forceUpdateGeometry;
|
|
|
|
public bool ForceUpdateGeometry
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return forceUpdateGeometry;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
forceUpdateGeometry = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public IGTexturePainter ActivePainter
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (Mode == GTexturePaintingMode.Elevation)
|
|
|
|
{
|
|
|
|
return new GElevationPainter();
|
|
|
|
}
|
|
|
|
else if (Mode == GTexturePaintingMode.HeightSampling)
|
|
|
|
{
|
|
|
|
return new GHeightSamplingPainter();
|
|
|
|
}
|
|
|
|
else if (Mode == GTexturePaintingMode.Terrace)
|
|
|
|
{
|
|
|
|
return new GTerracePainter();
|
|
|
|
}
|
|
|
|
else if (Mode == GTexturePaintingMode.Remap)
|
|
|
|
{
|
|
|
|
return new GRemapPainter();
|
|
|
|
}
|
|
|
|
else if (Mode == GTexturePaintingMode.Noise)
|
|
|
|
{
|
|
|
|
return new GNoisePainter();
|
|
|
|
}
|
|
|
|
else if (Mode == GTexturePaintingMode.SubDivision)
|
|
|
|
{
|
|
|
|
return new GSubDivPainter();
|
|
|
|
}
|
|
|
|
else if (Mode == GTexturePaintingMode.Visibility)
|
|
|
|
{
|
|
|
|
return new GVisibilityPainter();
|
|
|
|
}
|
|
|
|
else if (Mode == GTexturePaintingMode.Albedo)
|
|
|
|
{
|
|
|
|
return new GAlbedoPainter();
|
|
|
|
}
|
|
|
|
else if (Mode == GTexturePaintingMode.Metallic)
|
|
|
|
{
|
|
|
|
return new GMetallicPainter();
|
|
|
|
}
|
|
|
|
else if (Mode == GTexturePaintingMode.Smoothness)
|
|
|
|
{
|
|
|
|
return new GSmoothnessPainter();
|
|
|
|
}
|
|
|
|
else if (Mode == GTexturePaintingMode.Splat)
|
|
|
|
{
|
|
|
|
return new GSplatPainter();
|
|
|
|
}
|
|
|
|
else if (Mode == GTexturePaintingMode.Mask)
|
|
|
|
{
|
|
|
|
return new GMaskPainter();
|
|
|
|
}
|
|
|
|
else if (mode == GTexturePaintingMode.Custom)
|
|
|
|
{
|
|
|
|
if (CustomPainterIndex >= 0 && CustomPainterIndex < CustomPainterTypes.Count)
|
|
|
|
return System.Activator.CreateInstance(CustomPainterTypes[CustomPainterIndex]) as IGTexturePainter;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private float brushRadius;
|
|
|
|
public float BrushRadius
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return brushRadius;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
brushRadius = Mathf.Max(0.01f, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private float brushRadiusJitter;
|
|
|
|
public float BrushRadiusJitter
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return brushRadiusJitter;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
brushRadiusJitter = Mathf.Clamp01(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private float brushRotation;
|
|
|
|
public float BrushRotation
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return brushRotation;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
brushRotation = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private float brushRotationJitter;
|
|
|
|
public float BrushRotationJitter
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return brushRotationJitter;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
brushRotationJitter = Mathf.Clamp01(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private float brushOpacity;
|
|
|
|
public float BrushOpacity
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return brushOpacity;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
brushOpacity = Mathf.Clamp01(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private float brushOpacityJitter;
|
|
|
|
public float BrushOpacityJitter
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return brushOpacityJitter;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
brushOpacityJitter = Mathf.Clamp01(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private float brushTargetStrength = 1;
|
|
|
|
public float BrushTargetStrength
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return brushTargetStrength;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
brushTargetStrength = Mathf.Clamp01(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private float brushScatter;
|
|
|
|
public float BrushScatter
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return brushScatter;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
brushScatter = Mathf.Clamp01(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private float brushScatterJitter;
|
|
|
|
public float BrushScatterJitter
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return brushScatterJitter;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
brushScatterJitter = Mathf.Clamp01(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private Color brushColor;
|
|
|
|
public Color BrushColor
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return brushColor;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
brushColor = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private List<Texture2D> brushMasks;
|
|
|
|
public List<Texture2D> BrushMasks
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (brushMasks == null)
|
|
|
|
brushMasks = new List<Texture2D>();
|
|
|
|
return brushMasks;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
brushMasks = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private int selectedBrushMaskIndex;
|
|
|
|
public int SelectedBrushMaskIndex
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return selectedBrushMaskIndex;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
if (BrushMasks.Count > 0)
|
|
|
|
selectedBrushMaskIndex = Mathf.Clamp(value, 0, BrushMasks.Count);
|
|
|
|
else
|
|
|
|
selectedBrushMaskIndex = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public int SelectedSplatIndex
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (SelectedSplatIndices.Count == 0)
|
|
|
|
{
|
|
|
|
SelectedSplatIndices.Add(0);
|
|
|
|
}
|
|
|
|
return SelectedSplatIndices[0];
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
SelectedSplatIndices.Clear();
|
|
|
|
SelectedSplatIndices.Add(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private List<int> selectedSplatIndices;
|
|
|
|
public List<int> SelectedSplatIndices
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (selectedSplatIndices == null)
|
|
|
|
{
|
|
|
|
selectedSplatIndices = new List<int>();
|
|
|
|
}
|
|
|
|
return selectedSplatIndices;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
selectedSplatIndices = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
private Vector3 samplePoint;
|
|
|
|
public Vector3 SamplePoint
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return samplePoint;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
samplePoint = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-05 17:34:41 +08:00
|
|
|
[SerializeField]
|
|
|
|
private GConditionalPaintingConfigs conditionalPaintingConfigs;
|
|
|
|
public GConditionalPaintingConfigs ConditionalPaintingConfigs
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return conditionalPaintingConfigs;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
conditionalPaintingConfigs = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-30 17:37:48 +08:00
|
|
|
internal static Dictionary<string, RenderTexture> internal_RenderTextures;
|
|
|
|
|
|
|
|
private void OnEnable()
|
|
|
|
{
|
|
|
|
ReloadBrushMasks();
|
2024-03-05 17:34:41 +08:00
|
|
|
|
|
|
|
if (conditionalPaintingConfigs != null)
|
|
|
|
{
|
|
|
|
conditionalPaintingConfigs.UpdateCurveTextures();
|
|
|
|
}
|
2023-12-30 17:37:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private void OnDisable()
|
|
|
|
{
|
2024-03-05 17:34:41 +08:00
|
|
|
CleanUp();
|
2023-12-30 17:37:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private void Reset()
|
|
|
|
{
|
|
|
|
GroupId = 0;
|
|
|
|
Mode = GTexturePaintingMode.Elevation;
|
|
|
|
BrushRadius = 50;
|
|
|
|
BrushRadiusJitter = 0;
|
|
|
|
BrushOpacity = 0.5f;
|
|
|
|
BrushOpacityJitter = 0;
|
|
|
|
BrushTargetStrength = 1;
|
|
|
|
BrushRotation = 0;
|
|
|
|
BrushRotationJitter = 0;
|
|
|
|
BrushColor = Color.white;
|
2024-03-05 17:34:41 +08:00
|
|
|
|
|
|
|
if (conditionalPaintingConfigs != null)
|
|
|
|
{
|
|
|
|
conditionalPaintingConfigs.CleanUp();
|
|
|
|
}
|
|
|
|
conditionalPaintingConfigs = new GConditionalPaintingConfigs();
|
|
|
|
conditionalPaintingConfigs.UpdateCurveTextures();
|
2023-12-30 17:37:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public void ReloadBrushMasks()
|
|
|
|
{
|
|
|
|
BrushMasks = new List<Texture2D>(Resources.LoadAll<Texture2D>(GCommon.BRUSH_MASK_RESOURCES_PATH));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Paint(GTexturePainterArgs args)
|
|
|
|
{
|
|
|
|
IGTexturePainter p = ActivePainter;
|
|
|
|
if (p == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
FillArgs(ref args);
|
|
|
|
|
2024-03-05 17:34:41 +08:00
|
|
|
List<GStylizedTerrain> overlappedTerrain = GUtilities.ExtractTerrainsFromOverlapTest(GPaintToolUtilities.OverlapTest(GroupId, args.HitPoint, args.Radius, args.Rotation));
|
2023-12-30 17:37:48 +08:00
|
|
|
#if UNITY_EDITOR
|
|
|
|
if (args.MouseEventType == GPainterMouseEventType.Down ||
|
|
|
|
args.MouseEventType == GPainterMouseEventType.Drag)
|
|
|
|
{
|
|
|
|
Editor_CreateInitialHistoryEntry(args, overlappedTerrain);
|
|
|
|
}
|
|
|
|
#endif
|
2024-03-05 17:34:41 +08:00
|
|
|
foreach (GStylizedTerrain t in overlappedTerrain)
|
|
|
|
{
|
|
|
|
p.BeginPainting(t, args);
|
|
|
|
}
|
2023-12-30 17:37:48 +08:00
|
|
|
|
2024-03-05 17:34:41 +08:00
|
|
|
foreach (GStylizedTerrain t in overlappedTerrain)
|
2023-12-30 17:37:48 +08:00
|
|
|
{
|
2024-03-05 17:34:41 +08:00
|
|
|
p.EndPainting(t, args);
|
2023-12-30 17:37:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
EditedTerrains.UnionWith(overlappedTerrain);
|
|
|
|
if (args.MouseEventType == GPainterMouseEventType.Up)
|
|
|
|
{
|
|
|
|
Editor_CreateHistory(args);
|
|
|
|
currentInitialBackupName = null;
|
|
|
|
InitialRecordedTerrains.Clear();
|
|
|
|
EditedTerrains.Clear();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
private HashSet<GStylizedTerrain> initialRecordedTerrains;
|
|
|
|
private HashSet<GStylizedTerrain> InitialRecordedTerrains
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (initialRecordedTerrains == null)
|
|
|
|
{
|
|
|
|
initialRecordedTerrains = new HashSet<GStylizedTerrain>();
|
|
|
|
}
|
|
|
|
return initialRecordedTerrains;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private HashSet<GStylizedTerrain> editedTerrains;
|
|
|
|
private HashSet<GStylizedTerrain> EditedTerrains
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (editedTerrains == null)
|
|
|
|
{
|
|
|
|
editedTerrains = new HashSet<GStylizedTerrain>();
|
|
|
|
}
|
|
|
|
return editedTerrains;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private string currentInitialBackupName;
|
|
|
|
|
|
|
|
private void Editor_CreateInitialHistoryEntry(GTexturePainterArgs args, List<GStylizedTerrain> overlappedTerrains)
|
|
|
|
{
|
2024-03-05 17:34:41 +08:00
|
|
|
if (!GEditorSettings.Instance.paintTools.enableHistory)
|
2023-12-30 17:37:48 +08:00
|
|
|
return;
|
|
|
|
if (overlappedTerrains.Count == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
List<GTerrainResourceFlag> flags = new List<GTerrainResourceFlag>();
|
|
|
|
flags.AddRange(ActivePainter.GetResourceFlagForHistory(args));
|
|
|
|
|
|
|
|
if (InitialRecordedTerrains.Count == 0)
|
|
|
|
{
|
|
|
|
currentInitialBackupName = GBackup.TryCreateInitialBackup(ActivePainter.HistoryPrefix, overlappedTerrains[0], flags, false);
|
|
|
|
if (!string.IsNullOrEmpty(currentInitialBackupName))
|
|
|
|
{
|
|
|
|
InitialRecordedTerrains.Add(overlappedTerrains[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!string.IsNullOrEmpty(currentInitialBackupName))
|
|
|
|
{
|
|
|
|
for (int i = 0; i < overlappedTerrains.Count; ++i)
|
|
|
|
{
|
|
|
|
if (InitialRecordedTerrains.Contains(overlappedTerrains[i]))
|
|
|
|
continue;
|
|
|
|
GBackup.BackupTerrain(overlappedTerrains[i], currentInitialBackupName, flags);
|
|
|
|
InitialRecordedTerrains.Add(overlappedTerrains[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void Editor_CreateHistory(GTexturePainterArgs args)
|
|
|
|
{
|
2024-03-05 17:34:41 +08:00
|
|
|
if (!GEditorSettings.Instance.paintTools.enableHistory)
|
2023-12-30 17:37:48 +08:00
|
|
|
return;
|
|
|
|
if (EditedTerrains.Count == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
List<GTerrainResourceFlag> flags = new List<GTerrainResourceFlag>();
|
|
|
|
flags.AddRange(ActivePainter.GetResourceFlagForHistory(args));
|
|
|
|
|
|
|
|
List<GStylizedTerrain> terrainList = new List<GStylizedTerrain>(EditedTerrains);
|
|
|
|
string backupName = GBackup.TryCreateBackup(ActivePainter.HistoryPrefix, terrainList[0], flags, false);
|
|
|
|
if (!string.IsNullOrEmpty(backupName))
|
|
|
|
{
|
|
|
|
for (int i = 1; i < terrainList.Count; ++i)
|
|
|
|
{
|
|
|
|
GBackup.BackupTerrain(terrainList[i], backupName, flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
internal static RenderTexture Internal_GetRenderTexture(GStylizedTerrain t, int resolution, int id = 0)
|
|
|
|
{
|
|
|
|
if (internal_RenderTextures == null)
|
|
|
|
{
|
|
|
|
internal_RenderTextures = new Dictionary<string, RenderTexture>();
|
|
|
|
}
|
|
|
|
|
|
|
|
string key = string.Format("{0}_{1}", t != null ? t.GetInstanceID() : 0, id);
|
|
|
|
if (!internal_RenderTextures.ContainsKey(key) ||
|
|
|
|
internal_RenderTextures[key] == null)
|
|
|
|
{
|
2024-03-05 17:34:41 +08:00
|
|
|
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
|
2023-12-30 17:37:48 +08:00
|
|
|
internal_RenderTextures[key] = rt;
|
|
|
|
}
|
|
|
|
else if (internal_RenderTextures[key].width != resolution ||
|
|
|
|
internal_RenderTextures[key].height != resolution ||
|
|
|
|
internal_RenderTextures[key].format != GGeometry.HeightMapRTFormat)
|
|
|
|
{
|
|
|
|
internal_RenderTextures[key].Release();
|
|
|
|
Object.DestroyImmediate(internal_RenderTextures[key]);
|
2024-03-05 17:34:41 +08:00
|
|
|
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
|
2023-12-30 17:37:48 +08:00
|
|
|
internal_RenderTextures[key] = rt;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal_RenderTextures[key].wrapMode = TextureWrapMode.Clamp;
|
|
|
|
|
|
|
|
return internal_RenderTextures[key];
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void Internal_ReleaseRenderTextures()
|
|
|
|
{
|
|
|
|
if (internal_RenderTextures != null)
|
|
|
|
{
|
|
|
|
foreach (string k in internal_RenderTextures.Keys)
|
|
|
|
{
|
|
|
|
RenderTexture rt = internal_RenderTextures[k];
|
|
|
|
if (rt == null)
|
|
|
|
continue;
|
|
|
|
rt.Release();
|
|
|
|
Object.DestroyImmediate(rt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Rand GetRandomGenerator()
|
|
|
|
{
|
|
|
|
return new Rand(System.DateTime.Now.Millisecond);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void ProcessBrushDynamic(ref GTexturePainterArgs args)
|
|
|
|
{
|
|
|
|
Rand rand = GetRandomGenerator();
|
|
|
|
args.Radius -= BrushRadius * BrushRadiusJitter * (float)rand.NextDouble();
|
|
|
|
args.Rotation += Mathf.Sign((float)rand.NextDouble() - 0.5f) * BrushRotation * BrushRotationJitter * (float)rand.NextDouble();
|
|
|
|
args.Opacity -= BrushOpacity * BrushOpacityJitter * (float)rand.NextDouble();
|
|
|
|
|
|
|
|
Vector3 scatterDir = new Vector3((float)(rand.NextDouble() * 2 - 1), 0, (float)(rand.NextDouble() * 2 - 1)).normalized;
|
|
|
|
float scatterLengthMultiplier = BrushScatter - (float)rand.NextDouble() * BrushScatterJitter;
|
|
|
|
float scatterLength = args.Radius * scatterLengthMultiplier;
|
|
|
|
|
|
|
|
args.HitPoint += scatterDir * scatterLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void FillArgs(ref GTexturePainterArgs args, bool useBrushDynamic = true)
|
|
|
|
{
|
|
|
|
args.Radius = BrushRadius;
|
|
|
|
args.Rotation = BrushRotation;
|
|
|
|
args.Opacity = BrushOpacity * BrushTargetStrength;
|
|
|
|
args.Color = BrushColor;
|
|
|
|
if (SelectedSplatIndices.Count > 0)
|
|
|
|
{
|
|
|
|
args.SplatIndex = SelectedSplatIndices[Random.Range(0, SelectedSplatIndices.Count)];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
args.SplatIndex = -1;
|
|
|
|
}
|
|
|
|
args.SamplePoint = SamplePoint;
|
|
|
|
args.CustomArgs = CustomPainterArgs;
|
|
|
|
args.ForceUpdateGeometry = ForceUpdateGeometry;
|
|
|
|
args.EnableTerrainMask = EnableTerrainMask;
|
|
|
|
if (SelectedBrushMaskIndex >= 0 && SelectedBrushMaskIndex < BrushMasks.Count)
|
|
|
|
{
|
|
|
|
args.BrushMask = BrushMasks[SelectedBrushMaskIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (args.ActionType == GPainterActionType.Alternative &&
|
|
|
|
args.MouseEventType == GPainterMouseEventType.Down)
|
|
|
|
{
|
|
|
|
SamplePoint = args.HitPoint;
|
|
|
|
args.SamplePoint = args.HitPoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (useBrushDynamic)
|
|
|
|
{
|
|
|
|
ProcessBrushDynamic(ref args);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3[] corners = GCommon.GetBrushQuadCorners(args.HitPoint, args.Radius, args.Rotation);
|
|
|
|
args.WorldPointCorners = corners;
|
2024-03-05 17:34:41 +08:00
|
|
|
|
|
|
|
args.ConditionalPaintingConfigs = this.ConditionalPaintingConfigs;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void CleanUp()
|
|
|
|
{
|
|
|
|
Internal_ReleaseRenderTextures();
|
|
|
|
if (conditionalPaintingConfigs != null)
|
|
|
|
{
|
|
|
|
conditionalPaintingConfigs.CleanUp();
|
|
|
|
}
|
2023-12-30 17:37:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-05 17:34:41 +08:00
|
|
|
#endif
|