using System; using System.Collections.Generic; using UnityEngine; namespace ErosionBrushPlugin { [ExecuteInEditMode] public class ErosionBrush : MonoBehaviour { public struct UndoStep { private float[,] heights; private int heightsOffsetX; private int heightsOffsetZ; private float[,,] splats; private int splatsOffsetX; private int splatsOffsetZ; public UndoStep(float[,] heights, float[,,] splats, int heightsOffsetX, int heightsOffsetZ, int splatsOffsetX, int splatsOffsetZ) { if (heightsOffsetX < 0) { heightsOffsetX = 0; } if (heightsOffsetZ < 0) { heightsOffsetZ = 0; } if (splatsOffsetX < 0) { splatsOffsetX = 0; } if (splatsOffsetZ < 0) { splatsOffsetZ = 0; } this.heightsOffsetX = heightsOffsetX; this.heightsOffsetZ = heightsOffsetZ; this.splatsOffsetX = splatsOffsetX; this.splatsOffsetZ = splatsOffsetZ; this.heights = heights.Clone() as float[,]; if (splats != null) { this.splats = splats.Clone() as float[,,]; } else { this.splats = null; } } public void Perform(TerrainData data) { data.SetHeights(heightsOffsetX, heightsOffsetZ, heights); if (splats != null) { data.SetAlphamaps(splatsOffsetX, splatsOffsetZ, splats); } } } private Terrain _terrain; public Preset preset = new Preset(); public Preset[] presets = new Preset[0]; public int guiSelectedPreset; public bool paint; public bool wasPaint; public bool moveDown; public Transform moveTfm; public bool gen; public bool undo; [NonSerialized] public Texture2D guiHydraulicIcon; [NonSerialized] public Texture2D guiWindIcon; [NonSerialized] public Texture2D guiPluginIcon; public int guiApplyIterations = 1; public int[] guiChannels; public string[] guiChannelNames; public Color guiBrushColor = new Color(1f, 0.7f, 0.3f); public float guiBrushThickness = 4f; public int guiBrushNumCorners = 32; public bool recordUndo = true; public bool unity5positioning; public bool focusOnBrush = true; public bool preserveDetail = true; public bool guiShowPreset = true; public bool guiShowBrush = true; public bool guiShowGenerator = true; public bool guiShowTextures = true; public bool guiShowGlobal; public bool guiShowSettings; public bool guiShowAbout; public int guiMaxBrushSize = 300; public bool guiSelectPresetsUsingNumkeys = true; [NonSerialized] private Matrix.Stacker heights; [NonSerialized] private Matrix.Stacker splats; [NonSerialized] private Matrix.Stacker sediments; public List> undoList = new List>(); public bool allowUndo; public Terrain terrain { get { if (_terrain == null) { _terrain = GetComponent(); } return _terrain; } set { _terrain = value; } } public void ApplyBrush(Rect worldRect, bool useFallof = true, bool newUndo = false) { TerrainData terrainData = terrain.terrainData; bool flag = preset.paintSplat; if (terrainData.alphamapLayers == 0) { flag = false; } int a = Mathf.Min(terrainData.heightmapResolution - 1, terrainData.alphamapResolution); int num = Mathf.Max(terrainData.heightmapResolution - 1, terrainData.alphamapResolution); int num2 = num / preset.downscale; int num3 = Mathf.Min(a, num2); int num4 = (terrainData.heightmapResolution - 1) / num3; int num5 = terrainData.alphamapResolution / num3; int num6 = num2 / num3; CoordRect coordRect = new CoordRect(worldRect.x * (float)num3, worldRect.y * (float)num3, worldRect.width * (float)num3, worldRect.height * (float)num3); CoordRect coordRect2 = coordRect * num4; CoordRect coordRect3 = coordRect * num5; CoordRect coordRect4 = coordRect * num6; if (heights == null || heights.smallRect != coordRect4 || heights.bigRect != coordRect2) { heights = new Matrix.Stacker(coordRect4, coordRect2); } if (splats == null || splats.smallRect != coordRect4 || splats.bigRect != coordRect3) { splats = new Matrix.Stacker(coordRect4, coordRect3); } if (sediments == null || sediments.smallRect != coordRect4 || sediments.bigRect != coordRect3) { sediments = new Matrix.Stacker(coordRect4, coordRect3); } heights.preserveDetail = preserveDetail; splats.preserveDetail = preserveDetail; sediments.preserveDetail = preserveDetail; heights.matrix.ChangeRect(coordRect2); float[,] array = heights.matrix.ReadHeighmap(terrainData); splats.matrix.ChangeRect(coordRect3); sediments.matrix.ChangeRect(coordRect3); float[,,] array2 = null; if (flag) { array2 = splats.matrix.ReadSplatmap(terrainData, preset.foreground.num); sediments.matrix.ReadSplatmap(terrainData, preset.background.num, array2); } heights.ToSmall(); if (flag) { splats.ToSmall(); sediments.ToSmall(); } heights.ToBig(); splats.ToBig(); sediments.ToBig(); if (recordUndo) { if (newUndo) { if (undoList.Count > 10) { undoList.RemoveAt(0); } undoList.Add(new List()); } if (undoList.Count == 0) { undoList.Add(new List()); } undoList[undoList.Count - 1].Add(new UndoStep(array, array2, coordRect2.offset.x, coordRect2.offset.z, coordRect3.offset.x, coordRect3.offset.z)); } heights.matrix.WriteHeightmap(terrainData, array, (!useFallof) ? (-1f) : preset.brushFallof); if (flag) { TerrainData data = terrainData; Matrix[] matrices = new Matrix[2] { splats.matrix, sediments.matrix }; int[] channels = new int[2] { preset.foreground.num, preset.background.num }; float[] opacity = new float[2] { (!preset.foreground.apply) ? 0f : preset.foreground.opacity, (!preset.background.apply) ? 0f : preset.background.opacity }; float brushFallof = ((!useFallof) ? (-1f) : preset.brushFallof); Matrix.AddSplatmaps(data, matrices, channels, opacity, array2, brushFallof); } } } }