2332 lines
53 KiB
C#
2332 lines
53 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
|
|
namespace Gaia
|
|
{
|
|
public class HeightMap
|
|
{
|
|
public enum CopyType
|
|
{
|
|
AlwaysCopy = 0,
|
|
CopyIfLessThan = 1,
|
|
CopyIfGreaterThan = 2
|
|
}
|
|
|
|
protected int m_widthX;
|
|
|
|
protected int m_depthZ;
|
|
|
|
protected float[,] m_heights;
|
|
|
|
protected bool m_isPowerOf2;
|
|
|
|
protected float m_widthInvX;
|
|
|
|
protected float m_depthInvZ;
|
|
|
|
protected float m_statMinVal;
|
|
|
|
protected float m_statMaxVal;
|
|
|
|
protected double m_statSumVals;
|
|
|
|
protected bool m_isDirty;
|
|
|
|
protected byte[] m_metaData = new byte[0];
|
|
|
|
private const int LEFT = 0;
|
|
|
|
private const int RIGHT = 1;
|
|
|
|
private const int BOTTOM = 2;
|
|
|
|
private const int TOP = 3;
|
|
|
|
private const float TIME = 0.2f;
|
|
|
|
public float this[int x, int z]
|
|
{
|
|
get
|
|
{
|
|
return m_heights[x, z];
|
|
}
|
|
set
|
|
{
|
|
m_heights[x, z] = value;
|
|
m_isDirty = true;
|
|
}
|
|
}
|
|
|
|
public float this[float x, float z]
|
|
{
|
|
get
|
|
{
|
|
return GetInterpolatedHeight(x, z);
|
|
}
|
|
set
|
|
{
|
|
x *= (float)m_widthX;
|
|
z *= (float)m_depthZ;
|
|
int num = (int)x;
|
|
if (num == m_widthX)
|
|
{
|
|
num = m_widthX - 1;
|
|
}
|
|
int num2 = (int)z;
|
|
if (num2 == m_depthZ)
|
|
{
|
|
num2 = m_depthZ - 1;
|
|
}
|
|
m_heights[num, num2] = value;
|
|
m_isDirty = true;
|
|
}
|
|
}
|
|
|
|
public HeightMap()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
public HeightMap(int width, int depth)
|
|
{
|
|
m_widthX = width;
|
|
m_depthZ = depth;
|
|
m_widthInvX = 1f / (float)m_widthX;
|
|
m_depthInvZ = 1f / (float)m_depthZ;
|
|
m_heights = new float[m_widthX, m_depthZ];
|
|
m_isPowerOf2 = GaiaUtils.Math_IsPowerOf2(m_widthX) && GaiaUtils.Math_IsPowerOf2(m_depthZ);
|
|
m_statMinVal = (m_statMaxVal = 0f);
|
|
m_statSumVals = 0.0;
|
|
m_metaData = new byte[0];
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public HeightMap(float[,] source)
|
|
{
|
|
m_widthX = source.GetLength(0);
|
|
m_depthZ = source.GetLength(1);
|
|
m_widthInvX = 1f / (float)m_widthX;
|
|
m_depthInvZ = 1f / (float)m_depthZ;
|
|
m_heights = new float[m_widthX, m_depthZ];
|
|
m_isPowerOf2 = GaiaUtils.Math_IsPowerOf2(m_widthX) && GaiaUtils.Math_IsPowerOf2(m_depthZ);
|
|
m_statMinVal = (m_statMaxVal = 0f);
|
|
m_statSumVals = 0.0;
|
|
m_metaData = new byte[0];
|
|
Buffer.BlockCopy(source, 0, m_heights, 0, m_widthX * m_depthZ * 4);
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public HeightMap(float[,,] source, int slice)
|
|
{
|
|
m_widthX = source.GetLength(0);
|
|
m_depthZ = source.GetLength(1);
|
|
m_widthInvX = 1f / (float)m_widthX;
|
|
m_depthInvZ = 1f / (float)m_depthZ;
|
|
m_heights = new float[m_widthX, m_depthZ];
|
|
m_isPowerOf2 = GaiaUtils.Math_IsPowerOf2(m_widthX) && GaiaUtils.Math_IsPowerOf2(m_depthZ);
|
|
m_statMinVal = (m_statMaxVal = 0f);
|
|
m_statSumVals = 0.0;
|
|
m_metaData = new byte[0];
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] = source[i, j, slice];
|
|
}
|
|
}
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public HeightMap(int[,] source)
|
|
{
|
|
m_widthX = source.GetLength(0);
|
|
m_depthZ = source.GetLength(1);
|
|
m_widthInvX = 1f / (float)m_widthX;
|
|
m_depthInvZ = 1f / (float)m_depthZ;
|
|
m_heights = new float[m_widthX, m_depthZ];
|
|
m_isPowerOf2 = GaiaUtils.Math_IsPowerOf2(m_widthX) && GaiaUtils.Math_IsPowerOf2(m_depthZ);
|
|
m_statMinVal = (m_statMaxVal = 0f);
|
|
m_statSumVals = 0.0;
|
|
m_metaData = new byte[0];
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] = source[i, j];
|
|
}
|
|
}
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public HeightMap(HeightMap source)
|
|
{
|
|
Reset();
|
|
m_widthX = source.m_widthX;
|
|
m_depthZ = source.m_depthZ;
|
|
m_widthInvX = 1f / (float)m_widthX;
|
|
m_depthInvZ = 1f / (float)m_depthZ;
|
|
m_heights = new float[m_widthX, m_depthZ];
|
|
m_isPowerOf2 = source.m_isPowerOf2;
|
|
SetMetaData(source.m_metaData);
|
|
Buffer.BlockCopy(source.m_heights, 0, m_heights, 0, m_widthX * m_depthZ * 4);
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public HeightMap(string sourceFile)
|
|
{
|
|
Reset();
|
|
LoadFromBinaryFile(sourceFile);
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public HeightMap(byte[] sourceBytes)
|
|
{
|
|
Reset();
|
|
LoadFromByteArray(sourceBytes);
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public int Width()
|
|
{
|
|
return m_widthX;
|
|
}
|
|
|
|
public int Depth()
|
|
{
|
|
return m_depthZ;
|
|
}
|
|
|
|
public float MinVal()
|
|
{
|
|
return m_statMinVal;
|
|
}
|
|
|
|
public float MaxVal()
|
|
{
|
|
return m_statMaxVal;
|
|
}
|
|
|
|
public double SumVal()
|
|
{
|
|
return m_statSumVals;
|
|
}
|
|
|
|
public byte[] GetMetaData()
|
|
{
|
|
return m_metaData;
|
|
}
|
|
|
|
public bool IsDirty()
|
|
{
|
|
return m_isDirty;
|
|
}
|
|
|
|
public void SetDirty(bool dirty = true)
|
|
{
|
|
m_isDirty = dirty;
|
|
}
|
|
|
|
public void ClearDirty()
|
|
{
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public void SetMetaData(byte[] metadata)
|
|
{
|
|
m_metaData = new byte[metadata.Length];
|
|
Buffer.BlockCopy(metadata, 0, m_metaData, 0, metadata.Length);
|
|
m_isDirty = true;
|
|
}
|
|
|
|
public float[,] Heights()
|
|
{
|
|
return m_heights;
|
|
}
|
|
|
|
public float[] Heights1D()
|
|
{
|
|
float[] array = new float[m_widthX * m_depthZ];
|
|
Buffer.BlockCopy(m_heights, 0, array, 0, array.Length * 4);
|
|
return array;
|
|
}
|
|
|
|
public void SetHeights(float[] heights)
|
|
{
|
|
int num = (int)Mathf.Sqrt(heights.Length);
|
|
if (num != m_widthX || num != m_depthZ)
|
|
{
|
|
Debug.LogError("SetHeights: Heights do not match. Aborting.");
|
|
return;
|
|
}
|
|
Buffer.BlockCopy(heights, 0, m_heights, 0, heights.Length * 4);
|
|
m_isDirty = true;
|
|
}
|
|
|
|
public void SetHeights(float[,] heights)
|
|
{
|
|
if (m_widthX != heights.GetLength(0) || m_depthZ != heights.GetLength(1))
|
|
{
|
|
Debug.LogError("SetHeights: Sizes do not match. Aborting.");
|
|
return;
|
|
}
|
|
int num = heights.GetLength(0) * heights.GetLength(1);
|
|
Buffer.BlockCopy(heights, 0, m_heights, 0, num * 4);
|
|
m_isDirty = true;
|
|
}
|
|
|
|
public float GetSafeHeight(int x, int z)
|
|
{
|
|
if (x < 0)
|
|
{
|
|
x = 0;
|
|
}
|
|
if (z < 0)
|
|
{
|
|
z = 0;
|
|
}
|
|
if (x >= m_widthX)
|
|
{
|
|
x = m_widthX - 1;
|
|
}
|
|
if (z >= m_depthZ)
|
|
{
|
|
z = m_depthZ - 1;
|
|
}
|
|
return m_heights[x, z];
|
|
}
|
|
|
|
public void SetSafeHeight(int x, int z, float height)
|
|
{
|
|
if (x < 0)
|
|
{
|
|
x = 0;
|
|
}
|
|
if (z < 0)
|
|
{
|
|
z = 0;
|
|
}
|
|
if (x >= m_widthX)
|
|
{
|
|
x = m_widthX - 1;
|
|
}
|
|
if (z >= m_depthZ)
|
|
{
|
|
z = m_depthZ - 1;
|
|
}
|
|
m_heights[x, z] = height;
|
|
m_isDirty = true;
|
|
}
|
|
|
|
protected float GetInterpolatedHeight(float x, float z)
|
|
{
|
|
x *= (float)m_widthX;
|
|
z *= (float)m_depthZ;
|
|
int num = (int)x;
|
|
if (num == m_widthX)
|
|
{
|
|
num = m_widthX - 1;
|
|
}
|
|
int num2 = (int)z;
|
|
if (num2 == m_depthZ)
|
|
{
|
|
num2 = m_depthZ - 1;
|
|
}
|
|
int num3 = num + 1;
|
|
int num4 = num2 + 1;
|
|
if (num3 == m_widthX)
|
|
{
|
|
num3 = num;
|
|
}
|
|
if (num4 == m_depthZ)
|
|
{
|
|
num4 = num2;
|
|
}
|
|
float num5 = x - (float)num;
|
|
float num6 = z - (float)num2;
|
|
float num7 = 1f - num5;
|
|
float num8 = 1f - num6;
|
|
return num7 * num8 * m_heights[num, num2] + num7 * num6 * m_heights[num, num4] + num5 * num8 * m_heights[num3, num2] + num5 * num6 * m_heights[num3, num4];
|
|
}
|
|
|
|
public HeightMap SetHeight(float height)
|
|
{
|
|
float num = GaiaUtils.Math_Clamp(0f, 1f, height);
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public void GetHeightRange(ref float minHeight, ref float maxHeight)
|
|
{
|
|
maxHeight = float.MinValue;
|
|
minHeight = float.MaxValue;
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j];
|
|
if (num > maxHeight)
|
|
{
|
|
maxHeight = num;
|
|
}
|
|
if (num < minHeight)
|
|
{
|
|
minHeight = num;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public float GetSlope(int x, int z)
|
|
{
|
|
float num = m_heights[x, z];
|
|
float num2 = m_heights[x + 1, z] - num;
|
|
float num3 = m_heights[x, z + 1] - num;
|
|
return (float)Math.Sqrt(num2 * num2 + num3 * num3);
|
|
}
|
|
|
|
public float GetSlope(float x, float z)
|
|
{
|
|
float num = GetInterpolatedHeight(x + m_widthInvX * 0.9f, z) - GetInterpolatedHeight(x - m_widthInvX * 0.9f, z);
|
|
float num2 = GetInterpolatedHeight(x, z + m_depthInvZ * 0.9f) - GetInterpolatedHeight(x, z - m_depthInvZ * 0.9f);
|
|
return GaiaUtils.Math_Clamp(0f, 90f, (float)(Math.Sqrt(num * num + num2 * num2) * 10000.0));
|
|
}
|
|
|
|
public float GetSlope_a(float x, float z)
|
|
{
|
|
float interpolatedHeight = GetInterpolatedHeight(x, z);
|
|
float num = Math.Abs(GetInterpolatedHeight(x - m_widthInvX, z) - interpolatedHeight);
|
|
float num2 = Math.Abs(GetInterpolatedHeight(x + m_widthInvX, z) - interpolatedHeight);
|
|
float num3 = Math.Abs(GetInterpolatedHeight(x, z - m_depthInvZ) - interpolatedHeight);
|
|
float num4 = Math.Abs(GetInterpolatedHeight(x, z + m_depthInvZ) - interpolatedHeight);
|
|
return (num + num2 + num3 + num4) / 4f * 400f;
|
|
}
|
|
|
|
public float GetBaseLevel()
|
|
{
|
|
float num = 0f;
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
if (m_heights[i, 0] > num)
|
|
{
|
|
num = m_heights[i, 0];
|
|
}
|
|
if (m_heights[i, m_depthZ - 1] > num)
|
|
{
|
|
num = m_heights[i, m_depthZ - 1];
|
|
}
|
|
}
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
if (m_heights[0, j] > num)
|
|
{
|
|
num = m_heights[0, j];
|
|
}
|
|
if (m_heights[m_widthX - 1, j] > num)
|
|
{
|
|
num = m_heights[m_widthX - 1, j];
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public bool HasData()
|
|
{
|
|
if (m_widthX <= 0 || m_depthZ <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
if (m_heights == null)
|
|
{
|
|
return false;
|
|
}
|
|
if (m_heights.GetLength(0) != m_widthX || m_heights.GetLength(1) != m_depthZ)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public float[] GetRow(int rowX)
|
|
{
|
|
float[] array = new float[m_depthZ];
|
|
for (int i = 0; i < m_depthZ; i++)
|
|
{
|
|
array[i] = m_heights[rowX, i];
|
|
}
|
|
return array;
|
|
}
|
|
|
|
public void SetRow(int rowX, float[] values)
|
|
{
|
|
for (int i = 0; i < m_depthZ; i++)
|
|
{
|
|
m_heights[rowX, i] = values[i];
|
|
}
|
|
}
|
|
|
|
public float[] GetColumn(int columnZ)
|
|
{
|
|
float[] array = new float[m_widthX];
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
array[i] = m_heights[i, columnZ];
|
|
}
|
|
return array;
|
|
}
|
|
|
|
public void SetColumn(int columnZ, float[] values)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
m_heights[i, columnZ] = values[i];
|
|
}
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
m_widthX = (m_depthZ = 0);
|
|
m_widthInvX = (m_depthInvZ = 0f);
|
|
m_heights = null;
|
|
m_statMinVal = (m_statMaxVal = 0f);
|
|
m_statSumVals = 0.0;
|
|
m_metaData = new byte[0];
|
|
m_heights = new float[0, 0];
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public void UpdateStats()
|
|
{
|
|
m_statMinVal = 1f;
|
|
m_statMaxVal = 0f;
|
|
m_statSumVals = 0.0;
|
|
float num = 0f;
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
num = m_heights[i, j];
|
|
if (num < m_statMinVal)
|
|
{
|
|
m_statMinVal = num;
|
|
}
|
|
if (num > m_statMaxVal)
|
|
{
|
|
m_statMaxVal = num;
|
|
}
|
|
m_statSumVals += num;
|
|
}
|
|
}
|
|
}
|
|
|
|
public HeightMap Smooth(int iterations)
|
|
{
|
|
for (int i = 0; i < iterations; i++)
|
|
{
|
|
for (int j = 0; j < m_widthX; j++)
|
|
{
|
|
for (int k = 0; k < m_depthZ; k++)
|
|
{
|
|
m_heights[j, k] = GaiaUtils.Math_Clamp(0f, 1f, (GetSafeHeight(j - 1, k) + GetSafeHeight(j + 1, k) + GetSafeHeight(j, k - 1) + GetSafeHeight(j, k + 1)) / 4f);
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap SmoothRadius(int radius)
|
|
{
|
|
radius = Mathf.Max(5, radius);
|
|
HeightMap heightMap = new HeightMap(m_widthX, m_depthZ);
|
|
float num = 1f / (float)((2 * radius + 1) * (2 * radius + 1));
|
|
for (int i = 0; i < m_depthZ; i++)
|
|
{
|
|
for (int j = 0; j < m_widthX; j++)
|
|
{
|
|
heightMap[j, i] = num * m_heights[j, i];
|
|
}
|
|
}
|
|
for (int k = radius; k < m_widthX - radius; k++)
|
|
{
|
|
int num2 = radius;
|
|
float num3 = 0f;
|
|
for (int l = -radius; l < radius + 1; l++)
|
|
{
|
|
for (int m = -radius; m < radius + 1; m++)
|
|
{
|
|
num3 += heightMap[k + m, num2 + l];
|
|
}
|
|
}
|
|
for (num2++; num2 < m_depthZ - radius; num2++)
|
|
{
|
|
for (int n = -radius; n < radius + 1; n++)
|
|
{
|
|
num3 -= heightMap[k + n, num2 - radius - 1];
|
|
num3 += heightMap[k + n, num2 + radius];
|
|
}
|
|
m_heights[k, num2] = num3;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Convolve(float[,] kernel)
|
|
{
|
|
float num = 0f;
|
|
int num2 = Mathf.FloorToInt((float)kernel.GetLength(0) / 2f);
|
|
int length = kernel.GetLength(0);
|
|
int length2 = kernel.GetLength(1);
|
|
int num3 = length * length2;
|
|
int num4 = 0;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
for (int j = 0; j < length2; j++)
|
|
{
|
|
num += kernel[i, j];
|
|
}
|
|
}
|
|
if (GaiaUtils.Math_ApproximatelyEqual(num, 0f))
|
|
{
|
|
num = 1f;
|
|
}
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
float num5 = 0f;
|
|
float num6 = 0f;
|
|
num4 = 0;
|
|
for (int m = -num2; m <= num2; m++)
|
|
{
|
|
int num7 = k + m;
|
|
if (num7 < 0 || num7 >= m_widthX)
|
|
{
|
|
continue;
|
|
}
|
|
for (int n = -num2; n <= num2; n++)
|
|
{
|
|
int num8 = l + n;
|
|
if (num8 >= 0 && num8 < m_depthZ)
|
|
{
|
|
float num9 = kernel[m + num2, n + num2];
|
|
num6 += num9;
|
|
num5 += m_heights[num7, num8] * num9;
|
|
num4++;
|
|
}
|
|
}
|
|
}
|
|
if (num4 == num3)
|
|
{
|
|
m_heights[k, l] = Mathf.Clamp01(num5 / num);
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap DeNoise(int radius)
|
|
{
|
|
float num = 0f;
|
|
for (int i = radius; i < m_widthX - radius; i++)
|
|
{
|
|
for (int j = radius; j < m_depthZ - radius; j++)
|
|
{
|
|
float num2 = float.MaxValue;
|
|
float num3 = float.MinValue;
|
|
for (int k = -radius; k <= radius; k++)
|
|
{
|
|
for (int l = -radius; l <= radius; l++)
|
|
{
|
|
if (k != 0 || l != 0)
|
|
{
|
|
num = m_heights[i + k, j + l];
|
|
if (num < num2)
|
|
{
|
|
num2 = num;
|
|
}
|
|
if (num > num3)
|
|
{
|
|
num3 = num;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
num = m_heights[i, j];
|
|
if (num > num3)
|
|
{
|
|
m_heights[i, j] = num3;
|
|
}
|
|
else if (num < num2)
|
|
{
|
|
m_heights[i, j] = num2;
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap GrowEdges(int radius)
|
|
{
|
|
float num = 0f;
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num2 = float.MaxValue;
|
|
float num3 = float.MinValue;
|
|
for (int k = -radius; k <= radius; k++)
|
|
{
|
|
for (int l = -radius; l <= radius; l++)
|
|
{
|
|
int num4 = i + k;
|
|
if (num4 < 0 || num4 >= m_widthX || (k == 0 && l == 0))
|
|
{
|
|
continue;
|
|
}
|
|
int num5 = j + l;
|
|
if (num5 >= 0 && num5 < m_depthZ)
|
|
{
|
|
num = m_heights[num4, num5];
|
|
if (num < num2)
|
|
{
|
|
num2 = num;
|
|
}
|
|
if (num > num3)
|
|
{
|
|
num3 = num;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
num = m_heights[i, j];
|
|
if (num3 > num)
|
|
{
|
|
m_heights[i, j] = (num3 + num) / 2f;
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap ShrinkEdges(int radius)
|
|
{
|
|
float num = 0f;
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num2 = float.MaxValue;
|
|
float num3 = float.MinValue;
|
|
for (int k = -radius; k <= radius; k++)
|
|
{
|
|
int num4 = i + k;
|
|
if (num4 < 0 || num4 == m_widthX)
|
|
{
|
|
continue;
|
|
}
|
|
for (int l = -radius; l <= radius; l++)
|
|
{
|
|
if (k == 0 && l == 0)
|
|
{
|
|
continue;
|
|
}
|
|
int num5 = j + l;
|
|
if (num5 >= 0 && num5 < m_depthZ)
|
|
{
|
|
num = m_heights[num4, num5];
|
|
if (num < num2)
|
|
{
|
|
num2 = num;
|
|
}
|
|
if (num > num3)
|
|
{
|
|
num3 = num;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
num = m_heights[i, j];
|
|
if (num2 < num)
|
|
{
|
|
m_heights[i, j] = (num2 + num) / 2f;
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap GetSlopeMap()
|
|
{
|
|
HeightMap heightMap = new HeightMap(this);
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
heightMap[i, j] = GetSlope(i, j);
|
|
}
|
|
}
|
|
return heightMap;
|
|
}
|
|
|
|
public HeightMap Copy(HeightMap heightMap, CopyType copyType = CopyType.AlwaysCopy)
|
|
{
|
|
switch (copyType)
|
|
{
|
|
case CopyType.AlwaysCopy:
|
|
{
|
|
if (m_widthX != heightMap.m_widthX || m_depthZ != heightMap.m_depthZ)
|
|
{
|
|
for (int num11 = 0; num11 < m_widthX; num11++)
|
|
{
|
|
for (int num12 = 0; num12 < m_depthZ; num12++)
|
|
{
|
|
m_heights[num11, num12] = heightMap[m_widthInvX * (float)num11, m_depthInvZ * (float)num12];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
for (int num13 = 0; num13 < m_widthX; num13++)
|
|
{
|
|
for (int num14 = 0; num14 < m_depthZ; num14++)
|
|
{
|
|
m_heights[num13, num14] = heightMap.m_heights[num13, num14];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case CopyType.CopyIfLessThan:
|
|
{
|
|
if (m_widthX != heightMap.m_widthX || m_depthZ != heightMap.m_depthZ)
|
|
{
|
|
for (int m = 0; m < m_widthX; m++)
|
|
{
|
|
for (int n = 0; n < m_depthZ; n++)
|
|
{
|
|
float num5 = m_heights[m, n];
|
|
float num6 = heightMap[m_widthInvX * (float)m, m_depthInvZ * (float)n];
|
|
if (num6 < num5)
|
|
{
|
|
m_heights[m, n] = num6;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
for (int num7 = 0; num7 < m_widthX; num7++)
|
|
{
|
|
for (int num8 = 0; num8 < m_depthZ; num8++)
|
|
{
|
|
float num9 = m_heights[num7, num8];
|
|
float num10 = heightMap[num7, num8];
|
|
if (num10 < num9)
|
|
{
|
|
m_heights[num7, num8] = num10;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case CopyType.CopyIfGreaterThan:
|
|
{
|
|
if (m_widthX != heightMap.m_widthX || m_depthZ != heightMap.m_depthZ)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j];
|
|
float num2 = heightMap[m_widthInvX * (float)i, m_depthInvZ * (float)j];
|
|
if (num2 > num)
|
|
{
|
|
m_heights[i, j] = num2;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
float num3 = m_heights[k, l];
|
|
float num4 = heightMap[k, l];
|
|
if (num4 > num3)
|
|
{
|
|
m_heights[k, l] = num4;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap CopyClamped(HeightMap heightMap, float min, float max)
|
|
{
|
|
if (m_widthX != heightMap.m_widthX || m_depthZ != heightMap.m_depthZ)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = heightMap[m_widthInvX * (float)i, m_depthInvZ * (float)j];
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
float num2 = heightMap.m_heights[k, l];
|
|
if (num2 < min)
|
|
{
|
|
num2 = min;
|
|
}
|
|
else if (num2 > max)
|
|
{
|
|
num2 = max;
|
|
}
|
|
m_heights[k, l] = num2;
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Duplicate()
|
|
{
|
|
return new HeightMap(this);
|
|
}
|
|
|
|
public HeightMap Invert()
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] = 1f - m_heights[i, j];
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Flip()
|
|
{
|
|
float[,] array = new float[m_depthZ, m_widthX];
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
array[j, i] = m_heights[i, j];
|
|
}
|
|
}
|
|
m_heights = array;
|
|
m_widthX = array.GetLength(0);
|
|
m_depthZ = array.GetLength(1);
|
|
m_widthInvX = 1f / (float)m_widthX;
|
|
m_depthInvZ = 1f / (float)m_depthZ;
|
|
m_isPowerOf2 = GaiaUtils.Math_IsPowerOf2(m_widthX) && GaiaUtils.Math_IsPowerOf2(m_depthZ);
|
|
m_statMinVal = (m_statMaxVal = 0f);
|
|
m_statSumVals = 0.0;
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Normalise()
|
|
{
|
|
float num = float.MinValue;
|
|
float num2 = float.MaxValue;
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num3 = m_heights[i, j];
|
|
if (num3 > num)
|
|
{
|
|
num = num3;
|
|
}
|
|
if (num3 < num2)
|
|
{
|
|
num2 = num3;
|
|
}
|
|
}
|
|
}
|
|
float num4 = num - num2;
|
|
if (num4 > 0f)
|
|
{
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
m_heights[k, l] = (m_heights[k, l] - num2) / num4;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public HeightMap ErodeThermal(int iterations, float talusMin, float talusMax, HeightMap hardnessMask)
|
|
{
|
|
for (int i = 0; i < iterations; i++)
|
|
{
|
|
for (int j = 1; j < m_widthX - 1; j++)
|
|
{
|
|
for (int k = 1; k < m_depthZ - 1; k++)
|
|
{
|
|
float num = m_heights[j, k];
|
|
float num2 = m_heights[j, k + 1];
|
|
float num3 = m_heights[j - 1, k];
|
|
float num4 = m_heights[j + 1, k];
|
|
float num5 = m_heights[j, k - 1];
|
|
float num6 = num - num2;
|
|
float num7 = num - num3;
|
|
float num8 = num - num4;
|
|
float num9 = num - num5;
|
|
int num10 = 0;
|
|
int num11 = 0;
|
|
float num12 = 0f;
|
|
if (num6 > num12)
|
|
{
|
|
num12 = num6;
|
|
num11 = 1;
|
|
}
|
|
if (num7 > num12)
|
|
{
|
|
num12 = num7;
|
|
num10 = -1;
|
|
num11 = 0;
|
|
}
|
|
if (num8 > num12)
|
|
{
|
|
num12 = num8;
|
|
num10 = 1;
|
|
num11 = 0;
|
|
}
|
|
if (num9 > num12)
|
|
{
|
|
num12 = num9;
|
|
num10 = 0;
|
|
num11 = -1;
|
|
}
|
|
if (!(num12 < talusMin) && !(num12 > talusMax))
|
|
{
|
|
num12 *= 1f - hardnessMask[m_widthInvX * (float)j, m_depthInvZ * (float)k];
|
|
num12 *= 0.5f;
|
|
m_heights[j, k] -= num12;
|
|
m_heights[j + num10, k + num11] = m_heights[j + num10, k + num11] + num12;
|
|
m_isDirty = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Quantize(float divisor)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] = Mathf.Round(m_heights[i, j] / divisor) * divisor;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Quantize(float[] startHeights, AnimationCurve[] curves)
|
|
{
|
|
int length = startHeights.GetLength(0);
|
|
if (length == 0)
|
|
{
|
|
Debug.LogWarning("Quantize : must supply heights!");
|
|
return this;
|
|
}
|
|
if (curves.GetLength(0) != length)
|
|
{
|
|
Debug.LogWarning("Quantize : startHeights and curves do not match!");
|
|
return this;
|
|
}
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
int num = 0;
|
|
float num2 = 0f;
|
|
float num3 = 1f;
|
|
float num4 = m_heights[i, j];
|
|
for (num = length - 1; num >= 0; num--)
|
|
{
|
|
num2 = startHeights[num];
|
|
num3 = ((num != length - 1) ? startHeights[num + 1] : 1f);
|
|
if (num2 <= num4 && num4 <= num3)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
m_heights[i, j] = num2 + (num4 - num2) * curves[num].Evaluate((num4 - num2) / (num3 - num2));
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap CurvatureMap(GaiaConstants.CurvatureType curvatureType)
|
|
{
|
|
float limit = 10000f;
|
|
int depthZ = m_depthZ;
|
|
int widthX = m_widthX;
|
|
float num = 1f / ((float)widthX - 1f);
|
|
float num2 = 1f / ((float)depthZ - 1f);
|
|
float[] array = Heights1D();
|
|
HeightMap heightMap = Duplicate();
|
|
for (int i = 0; i < depthZ; i++)
|
|
{
|
|
for (int j = 0; j < widthX; j++)
|
|
{
|
|
int num3 = ((j == widthX - 1) ? j : (j + 1));
|
|
int num4 = ((j == 0) ? j : (j - 1));
|
|
int num5 = ((i == depthZ - 1) ? i : (i + 1));
|
|
int num6 = ((i == 0) ? i : (i - 1));
|
|
float num7 = array[j + i * widthX];
|
|
float num8 = array[num4 + i * widthX];
|
|
float num9 = array[num3 + i * widthX];
|
|
float num10 = array[j + num6 * widthX];
|
|
float num11 = array[j + num5 * widthX];
|
|
float num12 = array[num4 + num6 * widthX];
|
|
float num13 = array[num4 + num5 * widthX];
|
|
float num14 = array[num3 + num6 * widthX];
|
|
float num15 = array[num3 + num5 * widthX];
|
|
float dx = (num9 - num8) / (2f * num);
|
|
float dy = (num11 - num10) / (2f * num2);
|
|
float dxx = (num9 - 2f * num7 + num8) / (num * num);
|
|
float dyy = (num11 - 2f * num7 + num10) / (num2 * num2);
|
|
float dxy = (num15 - num14 - num13 + num12) / (4f * num * num2);
|
|
float value = 0f;
|
|
switch (curvatureType)
|
|
{
|
|
case GaiaConstants.CurvatureType.Horizontal:
|
|
value = HorizontalCurve(limit, dx, dy, dxx, dyy, dxy);
|
|
break;
|
|
case GaiaConstants.CurvatureType.Vertical:
|
|
value = VerticalCurve(limit, dx, dy, dxx, dyy, dxy);
|
|
break;
|
|
case GaiaConstants.CurvatureType.Average:
|
|
value = AverageCurve(limit, dx, dy, dxx, dyy, dxy);
|
|
break;
|
|
}
|
|
heightMap[j, i] = value;
|
|
}
|
|
}
|
|
return heightMap;
|
|
}
|
|
|
|
private float HorizontalCurve(float limit, float dx, float dy, float dxx, float dyy, float dxy)
|
|
{
|
|
float num = -2f * (dy * dy * dxx + dx * dx * dyy - dx * dy * dxy);
|
|
num /= dx * dx + dy * dy;
|
|
if (float.IsInfinity(num) || float.IsNaN(num))
|
|
{
|
|
num = 0f;
|
|
}
|
|
if (num < 0f - limit)
|
|
{
|
|
num = 0f - limit;
|
|
}
|
|
if (num > limit)
|
|
{
|
|
num = limit;
|
|
}
|
|
num /= limit;
|
|
return num * 0.5f + 0.5f;
|
|
}
|
|
|
|
private float VerticalCurve(float limit, float dx, float dy, float dxx, float dyy, float dxy)
|
|
{
|
|
float num = -2f * (dx * dx * dxx + dy * dy * dyy + dx * dy * dxy);
|
|
num /= dx * dx + dy * dy;
|
|
if (float.IsInfinity(num) || float.IsNaN(num))
|
|
{
|
|
num = 0f;
|
|
}
|
|
if (num < 0f - limit)
|
|
{
|
|
num = 0f - limit;
|
|
}
|
|
if (num > limit)
|
|
{
|
|
num = limit;
|
|
}
|
|
num /= limit;
|
|
return num * 0.5f + 0.5f;
|
|
}
|
|
|
|
private float AverageCurve(float limit, float dx, float dy, float dxx, float dyy, float dxy)
|
|
{
|
|
float num = HorizontalCurve(limit, dx, dy, dxx, dyy, dxy);
|
|
float num2 = VerticalCurve(limit, dx, dy, dxx, dyy, dxy);
|
|
return (num + num2) * 0.5f;
|
|
}
|
|
|
|
public HeightMap Aspect(GaiaConstants.AspectType aspectType)
|
|
{
|
|
int depthZ = m_depthZ;
|
|
int widthX = m_widthX;
|
|
float[] array = Heights1D();
|
|
float num = 1f / ((float)widthX - 1f);
|
|
float num2 = 1f / ((float)depthZ - 1f);
|
|
for (int i = 0; i < depthZ; i++)
|
|
{
|
|
for (int j = 0; j < widthX; j++)
|
|
{
|
|
int num3 = ((j == widthX - 1) ? j : (j + 1));
|
|
int num4 = ((j == 0) ? j : (j - 1));
|
|
int num5 = ((i == depthZ - 1) ? i : (i + 1));
|
|
int num6 = ((i == 0) ? i : (i - 1));
|
|
float num7 = array[num4 + i * widthX];
|
|
float num8 = array[num3 + i * widthX];
|
|
float num9 = array[j + num6 * widthX];
|
|
float num10 = array[j + num5 * widthX];
|
|
float num11 = (num8 - num7) / (2f * num);
|
|
float num12 = (num10 - num9) / (2f * num2);
|
|
float num13 = Mathf.Sqrt(num11 * num11 + num12 * num12);
|
|
float num14 = Mathf.Acos((0f - num12) / num13) * 57.29578f;
|
|
if (float.IsInfinity(num14) || float.IsNaN(num14))
|
|
{
|
|
num14 = 0f;
|
|
}
|
|
float num15 = 180f * (1f + Sign(num11)) - Sign(num11) * num14;
|
|
switch (aspectType)
|
|
{
|
|
case GaiaConstants.AspectType.Northerness:
|
|
num15 = Mathf.Cos(num15 * (MathF.PI / 180f));
|
|
num15 = num15 * 0.5f + 0.5f;
|
|
break;
|
|
case GaiaConstants.AspectType.Easterness:
|
|
num15 = Mathf.Sin(num15 * (MathF.PI / 180f));
|
|
num15 = num15 * 0.5f + 0.5f;
|
|
break;
|
|
default:
|
|
num15 /= 360f;
|
|
break;
|
|
}
|
|
m_heights[j, i] = num15;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
private float Sign(float v)
|
|
{
|
|
if (v > 0f)
|
|
{
|
|
return 1f;
|
|
}
|
|
if (v < 0f)
|
|
{
|
|
return -1f;
|
|
}
|
|
return 0f;
|
|
}
|
|
|
|
public HeightMap ErodeHydraulic(int iterations, HeightMap hardnessMap, HeightMap rainMap, int rainFrequency, float sedimentDisolveRate, ref HeightMap sedimentMap)
|
|
{
|
|
HeightMap heightMap = new HeightMap(m_widthX, m_depthZ);
|
|
float[,,] outFlow = new float[m_widthX, m_depthZ, 4];
|
|
HeightMap heightMap2 = new HeightMap(m_widthX, m_depthZ);
|
|
HeightMap heightMap3 = new HeightMap(m_widthX, m_depthZ);
|
|
float value = 1f / (float)rainFrequency;
|
|
for (int i = 0; i < iterations; i++)
|
|
{
|
|
if (i % rainFrequency == 0)
|
|
{
|
|
heightMap.Add(rainMap);
|
|
}
|
|
CalculateWaterOutflow(this, heightMap, outFlow);
|
|
UpdateWaterMap(heightMap, outFlow);
|
|
for (int j = 0; j < m_widthX; j++)
|
|
{
|
|
for (int k = 0; k < m_depthZ; k++)
|
|
{
|
|
float num = m_heights[j, k];
|
|
float num2 = heightMap[j, k];
|
|
float num3 = hardnessMap[j, k];
|
|
float num4 = 0f;
|
|
int num5 = 0;
|
|
for (int l = j - 1; l <= j + 1; l++)
|
|
{
|
|
if (l < 0 || l == m_widthX)
|
|
{
|
|
continue;
|
|
}
|
|
for (int m = k - 1; m <= k + 1; m++)
|
|
{
|
|
if (m >= 0 && m != m_depthZ)
|
|
{
|
|
float num6 = num - m_heights[l, m];
|
|
if (num6 > 0f)
|
|
{
|
|
num4 += num6;
|
|
num5++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (num5 <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
float num7 = num2 * num4 * sedimentDisolveRate * (1f - num3);
|
|
heightMap3[j, k] -= num7;
|
|
for (int n = j - 1; n <= j + 1; n++)
|
|
{
|
|
if (n < 0 || n == m_widthX)
|
|
{
|
|
continue;
|
|
}
|
|
for (int num8 = k - 1; num8 <= k + 1; num8++)
|
|
{
|
|
if (num8 >= 0 && num8 != m_depthZ)
|
|
{
|
|
float num9 = num - m_heights[n, num8];
|
|
if (num9 > 0f)
|
|
{
|
|
float num10 = num7 * (num9 / num4);
|
|
heightMap3[n, num8] += num10;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sedimentMap.Add(heightMap3);
|
|
AddClamped(heightMap3, 0f, 1f);
|
|
heightMap.SubtractClamped(value, 0f, 1f);
|
|
heightMap2.SetHeight(0f);
|
|
heightMap3.SetHeight(0f);
|
|
m_isDirty = true;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
private void CalculateWaterOutflow(HeightMap heightMap, HeightMap waterMap, float[,,] outFlow)
|
|
{
|
|
int num = heightMap.Width();
|
|
int num2 = heightMap.Depth();
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
for (int j = 0; j < num2; j++)
|
|
{
|
|
int x = ((i != 0) ? (i - 1) : 0);
|
|
int x2 = ((i == num - 1) ? (num - 1) : (i + 1));
|
|
int z = ((j != 0) ? (j - 1) : 0);
|
|
int z2 = ((j == num2 - 1) ? (num2 - 1) : (j + 1));
|
|
float num3 = waterMap[i, j];
|
|
float num4 = waterMap[x, j];
|
|
float num5 = waterMap[x2, j];
|
|
float num6 = waterMap[i, z];
|
|
float num7 = waterMap[i, z2];
|
|
float num8 = heightMap[i, j];
|
|
float num9 = heightMap[x, j];
|
|
float num10 = heightMap[x2, j];
|
|
float num11 = heightMap[i, z];
|
|
float num12 = heightMap[i, z2];
|
|
float num13 = num3 + num8 - (num4 + num9);
|
|
float num14 = num3 + num8 - (num5 + num10);
|
|
float num15 = num3 + num8 - (num6 + num11);
|
|
float num16 = num3 + num8 - (num7 + num12);
|
|
float num17 = Mathf.Max(0f, outFlow[i, j, 0] + num13);
|
|
float num18 = Mathf.Max(0f, outFlow[i, j, 1] + num14);
|
|
float num19 = Mathf.Max(0f, outFlow[i, j, 2] + num15);
|
|
float num20 = Mathf.Max(0f, outFlow[i, j, 3] + num16);
|
|
float num21 = num17 + num18 + num19 + num20;
|
|
if (num21 > 0f)
|
|
{
|
|
float num22 = num3 / (num21 * 0.2f);
|
|
if (num22 > 1f)
|
|
{
|
|
num22 = 1f;
|
|
}
|
|
if (num22 < 0f)
|
|
{
|
|
num22 = 0f;
|
|
}
|
|
outFlow[i, j, 0] = num17 * num22;
|
|
outFlow[i, j, 1] = num18 * num22;
|
|
outFlow[i, j, 2] = num19 * num22;
|
|
outFlow[i, j, 3] = num20 * num22;
|
|
}
|
|
else
|
|
{
|
|
outFlow[i, j, 0] = 0f;
|
|
outFlow[i, j, 1] = 0f;
|
|
outFlow[i, j, 2] = 0f;
|
|
outFlow[i, j, 3] = 0f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdateWaterMap(HeightMap waterMap, float[,,] outFlow)
|
|
{
|
|
int num = waterMap.Width();
|
|
int num2 = waterMap.Depth();
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
for (int j = 0; j < num2; j++)
|
|
{
|
|
float num3 = outFlow[i, j, 0] + outFlow[i, j, 1] + outFlow[i, j, 2] + outFlow[i, j, 3];
|
|
float num4 = 0f;
|
|
num4 += ((i == 0) ? 0f : outFlow[i - 1, j, 1]);
|
|
num4 += ((i == num - 1) ? 0f : outFlow[i + 1, j, 0]);
|
|
num4 += ((j == 0) ? 0f : outFlow[i, j - 1, 3]);
|
|
num4 += ((j == num2 - 1) ? 0f : outFlow[i, j + 1, 2]);
|
|
float num5 = waterMap[i, j] + (num4 - num3) * 0.2f;
|
|
if (num5 < 0f)
|
|
{
|
|
num5 = 0f;
|
|
}
|
|
waterMap[i, j] = num5;
|
|
}
|
|
}
|
|
}
|
|
|
|
public HeightMap FlowMap(int iterations)
|
|
{
|
|
int depthZ = m_depthZ;
|
|
int widthX = m_widthX;
|
|
float[] heightMap = Heights1D();
|
|
float[,] waterMap = new float[widthX, depthZ];
|
|
float[,,] outFlow = new float[widthX, depthZ, 4];
|
|
FillWaterMap(0.0001f, waterMap, widthX, depthZ);
|
|
for (int i = 0; i < iterations; i++)
|
|
{
|
|
ComputeOutflow(waterMap, outFlow, heightMap, widthX, depthZ);
|
|
UpdateWaterMap(waterMap, outFlow, widthX, depthZ);
|
|
}
|
|
float[,] array = new float[widthX, depthZ];
|
|
CalculateVelocityField(array, outFlow, widthX, depthZ);
|
|
NormalizeMap(array, widthX, depthZ);
|
|
return new HeightMap(array);
|
|
}
|
|
|
|
private void FillWaterMap(float amount, float[,] waterMap, int width, int height)
|
|
{
|
|
for (int i = 0; i < height; i++)
|
|
{
|
|
for (int j = 0; j < width; j++)
|
|
{
|
|
waterMap[j, i] = amount;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ComputeOutflow(float[,] waterMap, float[,,] outFlow, float[] heightMap, int width, int height)
|
|
{
|
|
for (int i = 0; i < height; i++)
|
|
{
|
|
for (int j = 0; j < width; j++)
|
|
{
|
|
int num = ((j != 0) ? (j - 1) : 0);
|
|
int num2 = ((j == width - 1) ? (width - 1) : (j + 1));
|
|
int num3 = ((i != 0) ? (i - 1) : 0);
|
|
int num4 = ((i == height - 1) ? (height - 1) : (i + 1));
|
|
float num5 = waterMap[j, i];
|
|
float num6 = waterMap[num, i];
|
|
float num7 = waterMap[num2, i];
|
|
float num8 = waterMap[j, num3];
|
|
float num9 = waterMap[j, num4];
|
|
float num10 = heightMap[j + i * width];
|
|
float num11 = heightMap[num + i * width];
|
|
float num12 = heightMap[num2 + i * width];
|
|
float num13 = heightMap[j + num3 * width];
|
|
float num14 = heightMap[j + num4 * width];
|
|
float num15 = num5 + num10 - (num6 + num11);
|
|
float num16 = num5 + num10 - (num7 + num12);
|
|
float num17 = num5 + num10 - (num8 + num13);
|
|
float num18 = num5 + num10 - (num9 + num14);
|
|
float num19 = Mathf.Max(0f, outFlow[j, i, 0] + num15);
|
|
float num20 = Mathf.Max(0f, outFlow[j, i, 1] + num16);
|
|
float num21 = Mathf.Max(0f, outFlow[j, i, 2] + num17);
|
|
float num22 = Mathf.Max(0f, outFlow[j, i, 3] + num18);
|
|
float num23 = num19 + num20 + num21 + num22;
|
|
if (num23 > 0f)
|
|
{
|
|
float num24 = num5 / (num23 * 0.2f);
|
|
if (num24 > 1f)
|
|
{
|
|
num24 = 1f;
|
|
}
|
|
if (num24 < 0f)
|
|
{
|
|
num24 = 0f;
|
|
}
|
|
outFlow[j, i, 0] = num19 * num24;
|
|
outFlow[j, i, 1] = num20 * num24;
|
|
outFlow[j, i, 2] = num21 * num24;
|
|
outFlow[j, i, 3] = num22 * num24;
|
|
}
|
|
else
|
|
{
|
|
outFlow[j, i, 0] = 0f;
|
|
outFlow[j, i, 1] = 0f;
|
|
outFlow[j, i, 2] = 0f;
|
|
outFlow[j, i, 3] = 0f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdateWaterMap(float[,] waterMap, float[,,] outFlow, int width, int height)
|
|
{
|
|
for (int i = 0; i < height; i++)
|
|
{
|
|
for (int j = 0; j < width; j++)
|
|
{
|
|
float num = outFlow[j, i, 0] + outFlow[j, i, 1] + outFlow[j, i, 2] + outFlow[j, i, 3];
|
|
float num2 = 0f;
|
|
num2 += ((j == 0) ? 0f : outFlow[j - 1, i, 1]);
|
|
num2 += ((j == width - 1) ? 0f : outFlow[j + 1, i, 0]);
|
|
num2 += ((i == 0) ? 0f : outFlow[j, i - 1, 3]);
|
|
num2 += ((i == height - 1) ? 0f : outFlow[j, i + 1, 2]);
|
|
float num3 = waterMap[j, i] + (num2 - num) * 0.2f;
|
|
if (num3 < 0f)
|
|
{
|
|
num3 = 0f;
|
|
}
|
|
waterMap[j, i] = num3;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CalculateVelocityField(float[,] velocityMap, float[,,] outFlow, int width, int height)
|
|
{
|
|
for (int i = 0; i < height; i++)
|
|
{
|
|
for (int j = 0; j < width; j++)
|
|
{
|
|
float num = ((j == 0) ? 0f : (outFlow[j - 1, i, 1] - outFlow[j, i, 0]));
|
|
float num2 = ((j == width - 1) ? 0f : (outFlow[j, i, 1] - outFlow[j + 1, i, 0]));
|
|
float num3 = ((i == height - 1) ? 0f : (outFlow[j, i + 1, 2] - outFlow[j, i, 3]));
|
|
float num4 = ((i == 0) ? 0f : (outFlow[j, i, 2] - outFlow[j, i - 1, 3]));
|
|
float num5 = (num + num2) * 0.5f;
|
|
float num6 = (num4 + num3) * 0.5f;
|
|
velocityMap[j, i] = Mathf.Sqrt(num5 * num5 + num6 * num6);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void NormalizeMap(float[,] map, int width, int height)
|
|
{
|
|
float num = float.PositiveInfinity;
|
|
float num2 = float.NegativeInfinity;
|
|
for (int i = 0; i < height; i++)
|
|
{
|
|
for (int j = 0; j < width; j++)
|
|
{
|
|
float num3 = map[j, i];
|
|
if (num3 < num)
|
|
{
|
|
num = num3;
|
|
}
|
|
if (num3 > num2)
|
|
{
|
|
num2 = num3;
|
|
}
|
|
}
|
|
}
|
|
float num4 = num2 - num;
|
|
for (int k = 0; k < height; k++)
|
|
{
|
|
for (int l = 0; l < width; l++)
|
|
{
|
|
float num5 = map[l, k];
|
|
num5 = ((!(num4 < 1E-12f)) ? ((num5 - num) / num4) : 0f);
|
|
map[l, k] = num5;
|
|
}
|
|
}
|
|
}
|
|
|
|
public HeightMap SlopeMap()
|
|
{
|
|
int depthZ = m_depthZ;
|
|
int widthX = m_widthX;
|
|
float[] array = Heights1D();
|
|
float num = 1f / ((float)widthX - 1f);
|
|
float num2 = 1f / ((float)depthZ - 1f);
|
|
float num3 = 0.5f;
|
|
float num4 = 0.5f;
|
|
HeightMap heightMap = new HeightMap(widthX, depthZ);
|
|
for (int i = 0; i < depthZ; i++)
|
|
{
|
|
for (int j = 0; j < widthX; j++)
|
|
{
|
|
int num5 = ((j == widthX - 1) ? j : (j + 1));
|
|
int num6 = ((j == 0) ? j : (j - 1));
|
|
int num7 = ((i == depthZ - 1) ? i : (i + 1));
|
|
int num8 = ((i == 0) ? i : (i - 1));
|
|
float num9 = array[num6 + i * widthX] * num3;
|
|
float num10 = array[num5 + i * widthX] * num3;
|
|
float num11 = array[j + num8 * widthX] * num4;
|
|
float num12 = array[j + num7 * widthX] * num4;
|
|
float num13 = (num10 - num9) / (2f * num);
|
|
float num14 = (num12 - num11) / (2f * num2);
|
|
float num15 = Mathf.Sqrt(num13 * num13 + num14 * num14);
|
|
float value = num15 / Mathf.Sqrt(1f + num15 * num15);
|
|
heightMap[j, i] = value;
|
|
}
|
|
}
|
|
return heightMap;
|
|
}
|
|
|
|
public HeightMap Add(float value)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] += value;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Add(HeightMap heightMap)
|
|
{
|
|
if (m_widthX != heightMap.m_widthX || m_depthZ != heightMap.m_depthZ)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] += heightMap[m_widthInvX * (float)i, m_depthInvZ * (float)j];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
m_heights[k, l] += heightMap.m_heights[k, l];
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap AddClamped(float value, float min, float max)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j] + value;
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap AddClamped(HeightMap heightMap, float min, float max)
|
|
{
|
|
if (m_widthX != heightMap.m_widthX || m_depthZ != heightMap.m_depthZ)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j] + heightMap[m_widthInvX * (float)i, m_depthInvZ * (float)j];
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
float num2 = m_heights[k, l] + heightMap.m_heights[k, l];
|
|
if (num2 < min)
|
|
{
|
|
num2 = min;
|
|
}
|
|
else if (num2 > max)
|
|
{
|
|
num2 = max;
|
|
}
|
|
m_heights[k, l] = num2;
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Subtract(float value)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] -= value;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Subtract(HeightMap heightMap)
|
|
{
|
|
if (m_widthX != heightMap.m_widthX || m_depthZ != heightMap.m_depthZ)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] -= heightMap[m_widthInvX * (float)i, m_depthInvZ * (float)j];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
m_heights[k, l] -= heightMap.m_heights[k, l];
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap SubtractClamped(float value, float min, float max)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j] - value;
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap SubtractClamped(HeightMap heightMap, float min, float max)
|
|
{
|
|
if (m_widthX != heightMap.m_widthX || m_depthZ != heightMap.m_depthZ)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j] - heightMap[m_widthInvX * (float)i, m_depthInvZ * (float)j];
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
float num2 = m_heights[k, l] - heightMap.m_heights[k, l];
|
|
if (num2 < min)
|
|
{
|
|
num2 = min;
|
|
}
|
|
else if (num2 > max)
|
|
{
|
|
num2 = max;
|
|
}
|
|
m_heights[k, l] = num2;
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Multiply(float value)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] *= value;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Multiply(HeightMap heightMap)
|
|
{
|
|
if (m_widthX != heightMap.m_widthX || m_depthZ != heightMap.m_depthZ)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] *= heightMap[m_widthInvX * (float)i, m_depthInvZ * (float)j];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
m_heights[k, l] *= heightMap.m_heights[k, l];
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap MultiplyClamped(float value, float min, float max)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j] * value;
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap MultiplyClamped(HeightMap heightMap, float min, float max)
|
|
{
|
|
if (m_widthX != heightMap.m_widthX || m_depthZ != heightMap.m_depthZ)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j] * heightMap[m_widthInvX * (float)i, m_depthInvZ * (float)j];
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
float num2 = m_heights[k, l] * heightMap.m_heights[k, l];
|
|
if (num2 < min)
|
|
{
|
|
num2 = min;
|
|
}
|
|
else if (num2 > max)
|
|
{
|
|
num2 = max;
|
|
}
|
|
m_heights[k, l] = num2;
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Divide(float value)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] /= value;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Divide(HeightMap heightMap)
|
|
{
|
|
if (m_widthX != heightMap.m_widthX || m_depthZ != heightMap.m_depthZ)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] /= heightMap[m_widthInvX * (float)i, m_depthInvZ * (float)j];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
m_heights[k, l] /= heightMap.m_heights[k, l];
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap DivideClamped(float value, float min, float max)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j] / value;
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap DivideClamped(HeightMap heightMap, float min, float max)
|
|
{
|
|
if (m_widthX != heightMap.m_widthX || m_depthZ != heightMap.m_depthZ)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j] / heightMap[m_widthInvX * (float)i, m_depthInvZ * (float)j];
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
float num2 = m_heights[k, l] / heightMap.m_heights[k, l];
|
|
if (num2 < min)
|
|
{
|
|
num2 = min;
|
|
}
|
|
else if (num2 > max)
|
|
{
|
|
num2 = max;
|
|
}
|
|
m_heights[k, l] = num2;
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Lerp(HeightMap hmNewValues, HeightMap hmLerpMask)
|
|
{
|
|
if (m_widthX != hmNewValues.m_widthX || m_depthZ != hmNewValues.m_depthZ)
|
|
{
|
|
if (m_widthX != hmLerpMask.m_widthX || m_depthZ != hmLerpMask.m_depthZ)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] = Mathf.Lerp(m_heights[i, j], hmNewValues[m_widthInvX * (float)i, m_depthInvZ * (float)j], hmLerpMask[m_widthInvX * (float)i, m_depthInvZ * (float)j]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
m_heights[k, l] = Mathf.Lerp(m_heights[k, l], hmNewValues[m_widthInvX * (float)k, m_depthInvZ * (float)l], hmLerpMask[k, l]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (m_widthX != hmLerpMask.m_widthX || m_depthZ != hmLerpMask.m_depthZ)
|
|
{
|
|
for (int m = 0; m < m_widthX; m++)
|
|
{
|
|
for (int n = 0; n < m_depthZ; n++)
|
|
{
|
|
m_heights[m, n] = Mathf.Lerp(m_heights[m, n], hmNewValues[m, n], hmLerpMask[m_widthInvX * (float)m, m_depthInvZ * (float)n]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int num = 0; num < m_widthX; num++)
|
|
{
|
|
for (int num2 = 0; num2 < m_depthZ; num2++)
|
|
{
|
|
m_heights[num, num2] = Mathf.Lerp(m_heights[num, num2], hmNewValues[num, num2], hmLerpMask[num, num2]);
|
|
}
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public float Sum()
|
|
{
|
|
float num = 0f;
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
num += m_heights[i, j];
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public float Average()
|
|
{
|
|
return Sum() / (float)(m_widthX * m_depthZ);
|
|
}
|
|
|
|
public HeightMap Power(float exponent)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] = Mathf.Pow(m_heights[i, j], exponent);
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public HeightMap Contrast(float contrast)
|
|
{
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] = (m_heights[i, j] - 0.5f) * contrast + 0.5f;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public void SaveToBinaryFile(string fileName)
|
|
{
|
|
BinaryFormatter binaryFormatter = new BinaryFormatter();
|
|
Stream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
|
|
binaryFormatter.Serialize(stream, m_widthX);
|
|
binaryFormatter.Serialize(stream, m_depthZ);
|
|
binaryFormatter.Serialize(stream, m_metaData);
|
|
binaryFormatter.Serialize(stream, m_heights);
|
|
stream.Close();
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public void LoadFromBinaryFile(string fileName)
|
|
{
|
|
if (!File.Exists(fileName))
|
|
{
|
|
Debug.LogError("Could not locate file : " + fileName);
|
|
return;
|
|
}
|
|
Reset();
|
|
BinaryFormatter binaryFormatter = new BinaryFormatter();
|
|
Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
|
m_widthX = (int)binaryFormatter.Deserialize(stream);
|
|
m_depthZ = (int)binaryFormatter.Deserialize(stream);
|
|
m_metaData = (byte[])binaryFormatter.Deserialize(stream);
|
|
m_heights = (float[,])binaryFormatter.Deserialize(stream);
|
|
stream.Close();
|
|
m_widthInvX = 1f / (float)m_widthX;
|
|
m_depthInvZ = 1f / (float)m_depthZ;
|
|
m_isPowerOf2 = GaiaUtils.Math_IsPowerOf2(m_widthX) && GaiaUtils.Math_IsPowerOf2(m_depthZ);
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public void LoadFromByteArray(byte[] source)
|
|
{
|
|
if (source == null)
|
|
{
|
|
Debug.LogError("No data provided");
|
|
return;
|
|
}
|
|
Reset();
|
|
BinaryFormatter binaryFormatter = new BinaryFormatter();
|
|
Stream stream = new MemoryStream(source);
|
|
m_widthX = (int)binaryFormatter.Deserialize(stream);
|
|
m_depthZ = (int)binaryFormatter.Deserialize(stream);
|
|
m_metaData = (byte[])binaryFormatter.Deserialize(stream);
|
|
m_heights = (float[,])binaryFormatter.Deserialize(stream);
|
|
stream.Close();
|
|
m_widthInvX = 1f / (float)m_widthX;
|
|
m_depthInvZ = 1f / (float)m_depthZ;
|
|
m_isPowerOf2 = GaiaUtils.Math_IsPowerOf2(m_widthX) && GaiaUtils.Math_IsPowerOf2(m_depthZ);
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public void LoadFromRawFile(string fileName, GaiaConstants.RawByteOrder byteOrder, ref GaiaConstants.RawBitDepth bitDepth, ref int resolution)
|
|
{
|
|
if (!File.Exists(fileName))
|
|
{
|
|
Debug.LogError("Could not locate raw file : " + fileName);
|
|
return;
|
|
}
|
|
Reset();
|
|
using (FileStream fileStream = File.OpenRead(fileName))
|
|
{
|
|
using (BinaryReader binaryReader = ((byteOrder == GaiaConstants.RawByteOrder.IBM) ? new BinaryReader(fileStream) : new BinaryReaderMac(fileStream)))
|
|
{
|
|
if (bitDepth == GaiaConstants.RawBitDepth.Sixteen)
|
|
{
|
|
if (fileStream.Length % 2 == 0L)
|
|
{
|
|
resolution = (m_widthX = (m_depthZ = Mathf.CeilToInt(Mathf.Sqrt(fileStream.Length / 2))));
|
|
m_heights = new float[m_widthX, m_depthZ];
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] = (float)(int)binaryReader.ReadUInt16() / 65535f;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_widthX = (m_depthZ = Mathf.CeilToInt(Mathf.Sqrt(fileStream.Length)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
resolution = (m_widthX = (m_depthZ = Mathf.CeilToInt(Mathf.Sqrt(fileStream.Length))));
|
|
m_heights = new float[m_widthX, m_depthZ];
|
|
for (int k = 0; k < m_widthX; k++)
|
|
{
|
|
for (int l = 0; l < m_depthZ; l++)
|
|
{
|
|
m_heights[k, l] = (float)(int)binaryReader.ReadByte() / 255f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fileStream.Close();
|
|
}
|
|
m_widthInvX = 1f / (float)m_widthX;
|
|
m_depthInvZ = 1f / (float)m_depthZ;
|
|
m_isPowerOf2 = GaiaUtils.Math_IsPowerOf2(m_widthX) && GaiaUtils.Math_IsPowerOf2(m_depthZ);
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public void DumpMap(float scaleValue, int precision, string spacer, bool flip)
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
string text = "";
|
|
if (precision == 0)
|
|
{
|
|
text = "{0:0}";
|
|
}
|
|
else
|
|
{
|
|
text = "{0:0.";
|
|
for (int i = 0; i < precision; i++)
|
|
{
|
|
text += "0";
|
|
}
|
|
text += "}";
|
|
}
|
|
if (!string.IsNullOrEmpty(spacer))
|
|
{
|
|
text += spacer;
|
|
}
|
|
for (int j = 0; j < m_widthX; j++)
|
|
{
|
|
for (int k = 0; k < m_depthZ; k++)
|
|
{
|
|
if (!flip)
|
|
{
|
|
stringBuilder.AppendFormat(text, m_heights[j, k] * scaleValue);
|
|
}
|
|
else
|
|
{
|
|
stringBuilder.AppendFormat(text, m_heights[k, j] * scaleValue);
|
|
}
|
|
}
|
|
stringBuilder.AppendLine();
|
|
}
|
|
Debug.Log(stringBuilder.ToString());
|
|
}
|
|
|
|
public void DumpRow(int rowX, float scaleValue, int precision, string spacer)
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
string text = "";
|
|
if (precision == 0)
|
|
{
|
|
text = "{0:0}";
|
|
}
|
|
else
|
|
{
|
|
text = "{0:0.";
|
|
for (int i = 0; i < precision; i++)
|
|
{
|
|
text += "0";
|
|
}
|
|
text += "}";
|
|
}
|
|
if (!string.IsNullOrEmpty(spacer))
|
|
{
|
|
text += spacer;
|
|
}
|
|
float[] row = GetRow(rowX);
|
|
for (int j = 0; j < row.Length; j++)
|
|
{
|
|
stringBuilder.AppendFormat(text, row[j] * scaleValue);
|
|
}
|
|
Debug.Log(stringBuilder.ToString());
|
|
}
|
|
|
|
public void DumpColumn(int columnZ, float scaleValue, int precision, string spacer)
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
string text = "";
|
|
if (precision == 0)
|
|
{
|
|
text = "{0:0}";
|
|
}
|
|
else
|
|
{
|
|
text = "{0:0.";
|
|
for (int i = 0; i < precision; i++)
|
|
{
|
|
text += "0";
|
|
}
|
|
text += "}";
|
|
}
|
|
if (!string.IsNullOrEmpty(spacer))
|
|
{
|
|
text += spacer;
|
|
}
|
|
float[] column = GetColumn(columnZ);
|
|
for (int j = 0; j < column.Length; j++)
|
|
{
|
|
stringBuilder.AppendFormat(text, column[j] * scaleValue);
|
|
}
|
|
Debug.Log(stringBuilder.ToString());
|
|
}
|
|
}
|
|
}
|