Heroes_of_Hiis/Assets/Polaris - Low Poly Ecosystem/Polaris - Low Poly Terrain .../Runtime/Scripts/TerrainData/GGrassPatch.cs

346 lines
11 KiB
C#

#if GRIFFIN
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using Pinwheel.Griffin.Rendering;
using Pinwheel.Griffin.Compression;
using System;
using UnityEngine.Serialization;
namespace Pinwheel.Griffin
{
[System.Serializable]
public class GGrassPatch
{
[SerializeField]
private GFoliage foliage;
public GFoliage Foliage
{
get
{
return foliage;
}
private set
{
foliage = value;
}
}
[SerializeField]
private Vector2 index;
public Vector2 Index
{
get
{
return index;
}
set
{
index = value;
}
}
#pragma warning disable 0649
//Old container that get serialized as raw values and should be retired for now
//However, it should still be here to prevent data lost when upgrading from lower version
//This container will be empty after the manual upgrade
[SerializeField]
private List<GGrassInstance> instances;
#pragma warning restore 0649
internal int InstanceCount
{
get
{
if (instances_NonSerialized == null)
return 0;
else
return instances_NonSerialized.Count;
}
}
[NonSerialized]
private List<GGrassInstance> instances_NonSerialized;
internal List<GGrassInstance> Instances
{
get
{
if (instances_NonSerialized == null)
{
instances_NonSerialized = new List<GGrassInstance>();
}
return instances_NonSerialized;
}
set
{
instances_NonSerialized = value;
}
}
private bool requireFullUpdate;
internal bool RequireFullUpdate
{
get
{
return requireFullUpdate;
}
set
{
requireFullUpdate = value;
}
}
[SerializeField]
internal Bounds bounds;
public Bounds Bounds
{
get
{
return bounds;
}
private set
{
bounds = value;
}
}
[SerializeField]
private byte[] prototypeIndexSerializeData;
[SerializeField]
private byte[] positionSerializeData;
[SerializeField]
private byte[] rotationSerializeData;
[SerializeField]
private byte[] scaleSerializeData;
internal GGrassPatch(GFoliage owner, int indexX, int indexY)
{
foliage = owner;
Index = new Vector2(indexX, indexY);
}
public void Changed()
{
if (Foliage != null && Foliage.TerrainData != null)
{
Foliage.TerrainData.InvokeGrassChange(Index);
}
}
public void AddInstances(IEnumerable<GGrassInstance> newInstances)
{
Instances.AddRange(newInstances);
RecalculateBounds();
Changed();
}
public int RemoveInstances(Predicate<GGrassInstance> match)
{
int count = Instances.RemoveAll(match);
if (count > 0)
{
RecalculateBounds();
Changed();
}
return count;
}
public void ClearInstances()
{
Instances.Clear();
RecalculateBounds();
Changed();
}
public Rect GetUvRange()
{
return GCommon.GetUvRange(foliage.PatchGridSize, (int)Index.x, (int)Index.y);
}
public void RecalculateBounds()
{
if (Instances.Count == 0)
{
Rect r = GetUvRange();
Vector3 center = new Vector3(r.x, 0, r.y);
Vector3 size = Vector3.zero;
Bounds b = new Bounds();
b.center = center;
b.size = size;
Bounds = b;
}
else
{
float minX = float.MaxValue;
float maxX = float.MinValue;
float minY = float.MaxValue;
float maxY = float.MinValue;
float minZ = float.MaxValue;
float maxZ = float.MinValue;
int instanceCount = Instances.Count;
for (int i = 0; i < instanceCount; ++i)
{
Vector3 pos = Instances[i].Position;
minX = Mathf.Min(minX, pos.x);
maxX = Mathf.Max(maxX, pos.x);
minY = Mathf.Min(minY, pos.y);
maxY = Mathf.Max(maxY, pos.y);
minZ = Mathf.Min(minZ, pos.z);
maxZ = Mathf.Max(maxZ, pos.z);
}
Vector3 p = Vector3.Lerp(
new Vector3(minX, minY, minZ),
new Vector3(maxX, maxY, maxZ),
0.5f);
Vector3 s = new Vector3(
maxX - minX,
Mathf.Max(0.001f, maxY - minY),
maxZ - minZ);
Bounds = new Bounds(p, s);
}
}
internal void Serialize()
{
int[] protoIndices = new int[Instances.Count];
float[] positions = new float[Instances.Count * 3];
float[] rotations = new float[Instances.Count * 4];
float[] scales = new float[Instances.Count * 3];
for (int i = 0; i < Instances.Count; ++i)
{
GGrassInstance grass = Instances[i];
protoIndices[i] = grass.PrototypeIndex;
positions[i * 3 + 0] = grass.Position.x;
positions[i * 3 + 1] = grass.Position.y;
positions[i * 3 + 2] = grass.Position.z;
rotations[i * 4 + 0] = grass.Rotation.x;
rotations[i * 4 + 1] = grass.Rotation.y;
rotations[i * 4 + 2] = grass.Rotation.z;
rotations[i * 4 + 3] = grass.Rotation.w;
scales[i * 3 + 0] = grass.Scale.x;
scales[i * 3 + 1] = grass.Scale.y;
scales[i * 3 + 2] = grass.Scale.z;
}
prototypeIndexSerializeData = new byte[Buffer.ByteLength(protoIndices)];
Buffer.BlockCopy(protoIndices, 0, prototypeIndexSerializeData, 0, prototypeIndexSerializeData.Length);
prototypeIndexSerializeData = GCompressor.Compress(prototypeIndexSerializeData);
positionSerializeData = new byte[Buffer.ByteLength(positions)];
Buffer.BlockCopy(positions, 0, positionSerializeData, 0, positionSerializeData.Length);
positionSerializeData = GCompressor.Compress(positionSerializeData);
rotationSerializeData = new byte[Buffer.ByteLength(rotations)];
Buffer.BlockCopy(rotations, 0, rotationSerializeData, 0, rotationSerializeData.Length);
rotationSerializeData = GCompressor.Compress(rotationSerializeData);
scaleSerializeData = new byte[Buffer.ByteLength(scales)];
Buffer.BlockCopy(scales, 0, scaleSerializeData, 0, scaleSerializeData.Length);
scaleSerializeData = GCompressor.Compress(scaleSerializeData);
GCompressor.CleanUp();
}
internal void Deserialize()
{
if (prototypeIndexSerializeData != null &&
positionSerializeData != null &&
rotationSerializeData != null &&
scaleSerializeData != null)
{
prototypeIndexSerializeData = GCompressor.Decompress(prototypeIndexSerializeData);
positionSerializeData = GCompressor.Decompress(positionSerializeData);
rotationSerializeData = GCompressor.Decompress(rotationSerializeData);
scaleSerializeData = GCompressor.Decompress(scaleSerializeData);
int[] indices = new int[prototypeIndexSerializeData.Length / sizeof(int)];
float[] positions = new float[positionSerializeData.Length / sizeof(float)];
float[] rotations = new float[rotationSerializeData.Length / sizeof(float)];
float[] scales = new float[scaleSerializeData.Length / sizeof(float)];
Buffer.BlockCopy(prototypeIndexSerializeData, 0, indices, 0, prototypeIndexSerializeData.Length);
Buffer.BlockCopy(positionSerializeData, 0, positions, 0, positionSerializeData.Length);
Buffer.BlockCopy(rotationSerializeData, 0, rotations, 0, rotationSerializeData.Length);
Buffer.BlockCopy(scaleSerializeData, 0, scales, 0, scaleSerializeData.Length);
Instances.Clear();
for (int i = 0; i < indices.Length; ++i)
{
GGrassInstance grass = GGrassInstance.Create(indices[i]);
grass.Position = new Vector3(
positions[i * 3 + 0],
positions[i * 3 + 1],
positions[i * 3 + 2]);
grass.Rotation = new Quaternion(
rotations[i * 4 + 0],
rotations[i * 4 + 1],
rotations[i * 4 + 2],
rotations[i * 4 + 3]);
grass.Scale = new Vector3(
scales[i * 3 + 0],
scales[i * 3 + 1],
scales[i * 3 + 2]);
Instances.Add(grass);
}
GCompressor.CleanUp();
}
}
internal void UpgradeSerializeVersion()
{
//v250: Compressed serialization
if (instances != null && instances.Count > 0)
{
if (instances_NonSerialized != null)
{
instances_NonSerialized.AddRange(instances);
RecalculateBounds();
Changed();
}
}
}
public int GetMemStats()
{
int mem = 0;
if (prototypeIndexSerializeData != null)
{
mem += prototypeIndexSerializeData.Length;
mem += positionSerializeData.Length;
mem += rotationSerializeData.Length;
mem += scaleSerializeData.Length;
}
return mem;
}
public NativeArray<Vector2> GetGrassPositionArray(Allocator allocator = Allocator.TempJob)
{
int instanceCount = InstanceCount;
List<GGrassInstance> instances = Instances;
NativeArray<Vector2> positions = new NativeArray<Vector2>(instanceCount, allocator, NativeArrayOptions.UninitializedMemory);
Vector2 pos = Vector2.zero;
for (int i = 0; i < instanceCount; ++i)
{
GGrassInstance g = instances[i];
pos.Set(g.position.x, g.position.z);
positions[i] = pos;
}
return positions;
}
}
}
#endif