1154 lines
23 KiB
C#
1154 lines
23 KiB
C#
using System;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
|
|
namespace CTS
|
|
{
|
|
public class CTSHeightMap
|
|
{
|
|
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];
|
|
|
|
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 - 1f;
|
|
z *= (float)m_depthZ - 1f;
|
|
m_heights[(int)x, (int)z] = value;
|
|
m_isDirty = true;
|
|
}
|
|
}
|
|
|
|
public CTSHeightMap()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
public CTSHeightMap(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 = Math_IsPowerOf2(m_widthX) && Math_IsPowerOf2(m_depthZ);
|
|
m_statMinVal = (m_statMaxVal = 0f);
|
|
m_statSumVals = 0.0;
|
|
m_metaData = new byte[0];
|
|
m_isDirty = false;
|
|
}
|
|
|
|
public CTSHeightMap(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 = Math_IsPowerOf2(m_widthX) && 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 CTSHeightMap(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 = Math_IsPowerOf2(m_widthX) && 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 CTSHeightMap(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 = Math_IsPowerOf2(m_widthX) && 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 CTSHeightMap(CTSHeightMap 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;
|
|
m_metaData = new byte[source.m_metaData.Length];
|
|
for (int i = 0; i < source.m_metaData.Length; i++)
|
|
{
|
|
m_metaData[i] = source.m_metaData[i];
|
|
}
|
|
Buffer.BlockCopy(source.m_heights, 0, m_heights, 0, m_widthX * m_depthZ * 4);
|
|
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 int GetBufferSize()
|
|
{
|
|
return m_widthX * m_depthZ;
|
|
}
|
|
|
|
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 - 1f;
|
|
z *= (float)m_depthZ - 1f;
|
|
int num = (int)x;
|
|
int num2 = (int)z;
|
|
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 CTSHeightMap SetHeight(float height)
|
|
{
|
|
float num = 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 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 CTSHeightMap 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] = 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 CTSHeightMap SmoothRadius(int radius)
|
|
{
|
|
radius = Mathf.Max(5, radius);
|
|
CTSHeightMap cTSHeightMap = new CTSHeightMap(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++)
|
|
{
|
|
cTSHeightMap[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 += cTSHeightMap[k + m, num2 + l];
|
|
}
|
|
}
|
|
for (num2++; num2 < m_depthZ - radius; num2++)
|
|
{
|
|
for (int n = -radius; n < radius + 1; n++)
|
|
{
|
|
num3 -= cTSHeightMap[k + n, num2 - radius - 1];
|
|
num3 += cTSHeightMap[k + n, num2 + radius];
|
|
}
|
|
m_heights[k, num2] = num3;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public CTSHeightMap GetSlopeMap()
|
|
{
|
|
CTSHeightMap cTSHeightMap = new CTSHeightMap(this);
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
cTSHeightMap[i, j] = GetSlope(i, j);
|
|
}
|
|
}
|
|
return cTSHeightMap;
|
|
}
|
|
|
|
public CTSHeightMap Copy(CTSHeightMap CTSHeightMap)
|
|
{
|
|
if (m_widthX != CTSHeightMap.m_widthX || m_depthZ != CTSHeightMap.m_depthZ)
|
|
{
|
|
Debug.LogError("Can not copy different sized CTSHeightMap");
|
|
return this;
|
|
}
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] = CTSHeightMap.m_heights[i, j];
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public CTSHeightMap CopyClamped(CTSHeightMap CTSHeightMap, float min, float max)
|
|
{
|
|
if (m_widthX != CTSHeightMap.m_widthX || m_depthZ != CTSHeightMap.m_depthZ)
|
|
{
|
|
Debug.LogError("Can not copy different sized CTSHeightMap");
|
|
return this;
|
|
}
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = CTSHeightMap.m_heights[i, j];
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public CTSHeightMap Duplicate()
|
|
{
|
|
return new CTSHeightMap(this);
|
|
}
|
|
|
|
public CTSHeightMap 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 CTSHeightMap 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 = Math_IsPowerOf2(m_widthX) && Math_IsPowerOf2(m_depthZ);
|
|
m_statMinVal = (m_statMaxVal = 0f);
|
|
m_statSumVals = 0.0;
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public CTSHeightMap 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 CTSHeightMap 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 CTSHeightMap Add(CTSHeightMap CTSHeightMap)
|
|
{
|
|
if (m_widthX != CTSHeightMap.m_widthX || m_depthZ != CTSHeightMap.m_depthZ)
|
|
{
|
|
Debug.LogError("Can not add different sized CTSHeightMap");
|
|
return this;
|
|
}
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] += CTSHeightMap.m_heights[i, j];
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public CTSHeightMap 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 CTSHeightMap AddClamped(CTSHeightMap CTSHeightMap, float min, float max)
|
|
{
|
|
if (m_widthX != CTSHeightMap.m_widthX || m_depthZ != CTSHeightMap.m_depthZ)
|
|
{
|
|
Debug.LogError("Can not add different sized CTSHeightMap");
|
|
return this;
|
|
}
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j] + CTSHeightMap.m_heights[i, j];
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public CTSHeightMap 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 CTSHeightMap Subtract(CTSHeightMap CTSHeightMap)
|
|
{
|
|
if (m_widthX != CTSHeightMap.m_widthX || m_depthZ != CTSHeightMap.m_depthZ)
|
|
{
|
|
Debug.LogError("Can not subtract different sized CTSHeightMap");
|
|
return this;
|
|
}
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] -= CTSHeightMap.m_heights[i, j];
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public CTSHeightMap 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 CTSHeightMap SubtractClamped(CTSHeightMap CTSHeightMap, float min, float max)
|
|
{
|
|
if (m_widthX != CTSHeightMap.m_widthX || m_depthZ != CTSHeightMap.m_depthZ)
|
|
{
|
|
Debug.LogError("Can not add different sized CTSHeightMap");
|
|
return this;
|
|
}
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j] - CTSHeightMap.m_heights[i, j];
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public CTSHeightMap 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 CTSHeightMap Multiply(CTSHeightMap CTSHeightMap)
|
|
{
|
|
if (m_widthX != CTSHeightMap.m_widthX || m_depthZ != CTSHeightMap.m_depthZ)
|
|
{
|
|
Debug.LogError("Can not multiply different sized CTSHeightMap");
|
|
return this;
|
|
}
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] *= CTSHeightMap.m_heights[i, j];
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public CTSHeightMap 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 CTSHeightMap MultiplyClamped(CTSHeightMap CTSHeightMap, float min, float max)
|
|
{
|
|
if (m_widthX != CTSHeightMap.m_widthX || m_depthZ != CTSHeightMap.m_depthZ)
|
|
{
|
|
Debug.LogError("Can not multiply different sized CTSHeightMap");
|
|
return this;
|
|
}
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j] * CTSHeightMap.m_heights[i, j];
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public CTSHeightMap 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 CTSHeightMap Divide(CTSHeightMap CTSHeightMap)
|
|
{
|
|
if (m_widthX != CTSHeightMap.m_widthX || m_depthZ != CTSHeightMap.m_depthZ)
|
|
{
|
|
Debug.LogError("Can not divide different sized CTSHeightMap");
|
|
return this;
|
|
}
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
m_heights[i, j] /= CTSHeightMap.m_heights[i, j];
|
|
}
|
|
}
|
|
m_isDirty = true;
|
|
return this;
|
|
}
|
|
|
|
public CTSHeightMap 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 CTSHeightMap DivideClamped(CTSHeightMap CTSHeightMap, float min, float max)
|
|
{
|
|
if (m_widthX != CTSHeightMap.m_widthX || m_depthZ != CTSHeightMap.m_depthZ)
|
|
{
|
|
Debug.LogError("Can not divide different sized CTSHeightMap");
|
|
return this;
|
|
}
|
|
for (int i = 0; i < m_widthX; i++)
|
|
{
|
|
for (int j = 0; j < m_depthZ; j++)
|
|
{
|
|
float num = m_heights[i, j] / CTSHeightMap.m_heights[i, j];
|
|
if (num < min)
|
|
{
|
|
num = min;
|
|
}
|
|
else if (num > max)
|
|
{
|
|
num = max;
|
|
}
|
|
m_heights[i, j] = num;
|
|
}
|
|
}
|
|
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 CTSHeightMap 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 CTSHeightMap 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;
|
|
}
|
|
|
|
private bool Math_IsPowerOf2(int value)
|
|
{
|
|
return (value & (value - 1)) == 0;
|
|
}
|
|
|
|
private float Math_Clamp(float min, float max, float value)
|
|
{
|
|
if (value < min)
|
|
{
|
|
return min;
|
|
}
|
|
if (value > max)
|
|
{
|
|
return max;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
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());
|
|
}
|
|
}
|
|
}
|