#if GRIFFIN using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; using Unity.Collections; using Pinwheel.Griffin.Rendering; namespace Pinwheel.Griffin { public class GFoliage : ScriptableObject, ISerializationCallbackReceiver { [SerializeField] private GTerrainData terrainData; public GTerrainData TerrainData { get { return terrainData; } internal set { terrainData = value; } } [SerializeField] private GTreePrototypeGroup trees; public GTreePrototypeGroup Trees { get { return trees; } set { trees = value; } } [SerializeField] private List treeInstances; public List TreeInstances { get { if (treeInstances == null) treeInstances = new List(); return treeInstances; } set { treeInstances = value; } } [SerializeField] private GSnapMode treeSnapMode; public GSnapMode TreeSnapMode { get { return treeSnapMode; } set { treeSnapMode = value; } } [SerializeField] private LayerMask treeSnapLayerMask; public LayerMask TreeSnapLayerMask { get { return treeSnapLayerMask; } set { treeSnapLayerMask = value; } } [SerializeField] private GGrassPrototypeGroup grasses; public GGrassPrototypeGroup Grasses { get { return grasses; } set { GGrassPrototypeGroup oldValue = grasses; GGrassPrototypeGroup newValue = value; grasses = newValue; if (oldValue != newValue) { if (TerrainData != null) { TerrainData.InvokeGrassPrototypeGroupChanged(); } } } } [SerializeField] private GSnapMode grassSnapMode; public GSnapMode GrassSnapMode { get { return grassSnapMode; } set { grassSnapMode = value; } } [SerializeField] private LayerMask grassSnapLayerMask; public LayerMask GrassSnapLayerMask { get { return grassSnapLayerMask; } set { grassSnapLayerMask = value; } } [SerializeField] private int patchGridSize; public int PatchGridSize { get { return patchGridSize; } set { int oldValue = patchGridSize; int newValue = Mathf.Clamp(value, 2, 20); patchGridSize = newValue; if (oldValue != newValue) { if (grassPatches != null) { ResampleGrassPatches(); } if (TerrainData != null) { TerrainData.InvokeGrassPatchGridSizeChange(); } } } } [SerializeField] private GGrassPatch[] grassPatches; public GGrassPatch[] GrassPatches { get { if (grassPatches == null) { grassPatches = new GGrassPatch[PatchGridSize * PatchGridSize]; for (int x = 0; x < PatchGridSize; ++x) { for (int z = 0; z < patchGridSize; ++z) { GGrassPatch patch = new GGrassPatch(this, x, z); grassPatches[GUtilities.To1DIndex(x, z, PatchGridSize)] = patch; } } } if (grassPatches.Length != PatchGridSize * PatchGridSize) { ResampleGrassPatches(); } return grassPatches; } } private List treeDirtyRegions; private List TreeDirtyRegions { get { if (treeDirtyRegions == null) { treeDirtyRegions = new List(); } return treeDirtyRegions; } set { treeDirtyRegions = value; } } private List grassDirtyRegions; private List GrassDirtyRegions { get { if (grassDirtyRegions == null) { grassDirtyRegions = new List(); } return grassDirtyRegions; } set { grassDirtyRegions = value; } } [SerializeField] private bool enableInteractiveGrass; public bool EnableInteractiveGrass { get { return enableInteractiveGrass; } set { enableInteractiveGrass = value; } } [SerializeField] private int vectorFieldMapResolution; public int VectorFieldMapResolution { get { return vectorFieldMapResolution; } set { vectorFieldMapResolution = Mathf.Clamp(Mathf.ClosestPowerOfTwo(value), GCommon.TEXTURE_SIZE_MIN, GCommon.TEXTURE_SIZE_MAX); } } [SerializeField] private float bendSensitive; public float BendSensitive { get { return bendSensitive; } set { bendSensitive = Mathf.Clamp01(value); } } [SerializeField] private float restoreSensitive; public float RestoreSensitive { get { return restoreSensitive; } set { restoreSensitive = Mathf.Clamp01(value); } } public int GrassInstanceCount { get { int count = 0; for (int i = 0; i < GrassPatches.Length; ++i) { count += GrassPatches[i].Instances.Count; } return count; } } public float grassVersion; public const float GRASS_VERSION_COMPRESSED = 2020.1f; public void Reset() { name = "Foliage"; Trees = GRuntimeSettings.Instance.foliageDefault.trees; TreeSnapMode = GRuntimeSettings.Instance.foliageDefault.treeSnapMode; TreeSnapLayerMask = GRuntimeSettings.Instance.foliageDefault.treeSnapLayerMask; Grasses = GRuntimeSettings.Instance.foliageDefault.grasses; GrassSnapMode = GRuntimeSettings.Instance.foliageDefault.grassSnapMode; GrassSnapLayerMask = GRuntimeSettings.Instance.foliageDefault.grassSnapLayerMask; PatchGridSize = GRuntimeSettings.Instance.foliageDefault.patchGridSize; EnableInteractiveGrass = GRuntimeSettings.Instance.foliageDefault.enableInteractiveGrass; VectorFieldMapResolution = GRuntimeSettings.Instance.foliageDefault.vectorFieldMapResolution; BendSensitive = GRuntimeSettings.Instance.foliageDefault.bendSensitive; RestoreSensitive = GRuntimeSettings.Instance.foliageDefault.restoreSensitive; ClearGrassInstances(); ClearTreeInstances(); grassVersion = GVersionInfo.Number; } public void ResetFull() { Reset(); } public void Refresh() { //if (Trees != null) //{ // List prototypes = Trees.Prototypes; // //for (int i = 0; i < prototypes.Count; ++i) // //{ // // prototypes[i].Refresh(); // //} // RemoveTreeInstances(t => t.PrototypeIndex < 0 || t.PrototypeIndex >= Trees.Prototypes.Count); //} //if (Grasses != null) //{ // for (int i = 0; i < GrassPatches.Length; ++i) // { // GrassPatches[i].RemoveInstances(g => g.PrototypeIndex < 0 || g.PrototypeIndex >= Grasses.Prototypes.Count); // } //} } private void ResampleGrassPatches() { List grassInstances = new List(); for (int i = 0; i < grassPatches.Length; ++i) { grassInstances.AddRange(grassPatches[i].Instances); } grassPatches = new GGrassPatch[PatchGridSize * PatchGridSize]; for (int x = 0; x < PatchGridSize; ++x) { for (int z = 0; z < patchGridSize; ++z) { int index = GUtilities.To1DIndex(x, z, PatchGridSize); GGrassPatch patch = new GGrassPatch(this, x, z); grassPatches[index] = patch; } } AddGrassInstances(grassInstances); } public void AddGrassInstances(List instances) { Rect[] uvRects = new Rect[GrassPatches.Length]; for (int r = 0; r < uvRects.Length; ++r) { uvRects[r] = GrassPatches[r].GetUvRange(); } bool[] dirty = new bool[GrassPatches.Length]; for (int i = 0; i < instances.Count; ++i) { GGrassInstance grass = instances[i]; for (int r = 0; r < uvRects.Length; ++r) { if (uvRects[r].Contains(new Vector2(grass.position.x, grass.position.z))) { grassPatches[r].Instances.Add(grass); dirty[r] = true; break; } } } for (int i = 0; i < dirty.Length; ++i) { if (dirty[i] == true) { GrassPatches[i].RecalculateBounds(); GrassPatches[i].Changed(); } } } public List GetGrassInstances() { List instances = new List(); for (int i = 0; i < GrassPatches.Length; ++i) { instances.AddRange(GrassPatches[i].Instances); } return instances; } public void ClearGrassInstances() { for (int i = 0; i < GrassPatches.Length; ++i) { GrassPatches[i].ClearInstances(); } } public void SetTreeRegionDirty(Rect uvRect) { TreeDirtyRegions.Add(uvRect); } public void SetTreeRegionDirty(IEnumerable uvRects) { TreeDirtyRegions.AddRange(uvRects); } public Rect[] GetTreeDirtyRegions() { return TreeDirtyRegions.ToArray(); } public void ClearTreeDirtyRegions() { TreeDirtyRegions.Clear(); } public void SetGrassRegionDirty(Rect uvRect) { GrassDirtyRegions.Add(uvRect); } public void SetGrassRegionDirty(IEnumerable uvRects) { GrassDirtyRegions.AddRange(uvRects); } public Rect[] GetGrassDirtyRegions() { return GrassDirtyRegions.ToArray(); } public void ClearGrassDirtyRegions() { GrassDirtyRegions.Clear(); } public void CopyTo(GFoliage des) { des.Trees = Trees; des.TreeSnapMode = TreeSnapMode; des.TreeSnapLayerMask = TreeSnapLayerMask; des.Grasses = Grasses; des.GrassSnapMode = GrassSnapMode; des.GrassSnapLayerMask = GrassSnapLayerMask; des.PatchGridSize = PatchGridSize; } public void OnBeforeSerialize() { for (int i = 0; i < GrassPatches.Length; ++i) { GrassPatches[i].Serialize(); } } public void OnAfterDeserialize() { for (int i = 0; i < GrassPatches.Length; ++i) { GrassPatches[i].Deserialize(); } } public void Internal_UpgradeGrassSerializeVersion() { for (int i = 0; i < GrassPatches.Length; ++i) { GrassPatches[i].UpgradeSerializeVersion(); } grassVersion = GVersionInfo.Number; Debug.Log("Successfully upgrade grass serialize to newer version!"); } public void GrassAllChanged() { for (int i = 0; i < GrassPatches.Length; ++i) { GrassPatches[i].Changed(); } } public void TreeAllChanged() { if (TerrainData != null) { TerrainData.InvokeTreeChanged(); } } public void AddTreeInstances(IEnumerable newInstances) { TreeInstances.AddRange(newInstances); TreeAllChanged(); } public void RemoveTreeInstances(System.Predicate condition) { int removedCount = TreeInstances.RemoveAll(condition); if (removedCount > 0) { TreeAllChanged(); } } public void ClearTreeInstances() { TreeInstances.Clear(); TreeAllChanged(); } public int GetTreeMemStats() { return TreeInstances.Count * GTreeInstance.GetStructSize(); } public int GetGrassMemStats() { int memory = 0; if (grassPatches != null) { for (int i = 0; i < grassPatches.Length; ++i) { if (grassPatches[i] != null) { memory += grassPatches[i].GetMemStats(); } } } return memory; } public NativeArray GetTreesPositionArray(Allocator allocator = Allocator.TempJob) { List trees = TreeInstances; int treeCount = trees.Count; NativeArray positions = new NativeArray(treeCount, allocator, NativeArrayOptions.UninitializedMemory); Vector2 pos = Vector2.zero; for (int i = 0; i < treeCount; ++i) { GTreeInstance t = trees[i]; pos.Set(t.position.x, t.position.z); positions[i] = pos; } return positions; } } } #endif