using System; using System.Collections.Generic; using UnityEngine; namespace Obi { public class ObiHeightFieldHandle : ObiResourceHandle { public ObiHeightFieldHandle(TerrainData data, int index = -1) : base(index) { owner = data; } } public struct HeightFieldHeader //we need to use the header in the backend, so it must be a struct. { public int firstSample; public int sampleCount; public HeightFieldHeader(int firstSample, int sampleCount) { this.firstSample = firstSample; this.sampleCount = sampleCount; } } public class ObiHeightFieldContainer { public Dictionary handles; /**< dictionary indexed by asset, so that we don't generate data for the same distance field multiple times.*/ public ObiNativeHeightFieldHeaderList headers; /**< One header per distance field.*/ public ObiNativeFloatList samples; public ObiHeightFieldContainer() { handles = new Dictionary(); headers = new ObiNativeHeightFieldHeaderList(); samples = new ObiNativeFloatList(); } public ObiHeightFieldHandle GetOrCreateHeightField(TerrainData source) { ObiHeightFieldHandle handle; if (!handles.TryGetValue(source, out handle)) { // Get the heighfield into a 1d array: int width = source.heightmapResolution; int height = source.heightmapResolution; float[,] heights = source.GetHeights(0, 0, width, height); bool[,] holes = source.GetHoles(0, 0, width-1, height-1); float[] buffer = new float[width * height]; for (int y = 0; y < height; ++y) for (int x = 0; x < width; ++x) buffer[y * width + x] = heights[y, x] * (holes[Mathf.Min(y,height - 2), Mathf.Min(x, width - 2)] ? 1:-1); handle = new ObiHeightFieldHandle(source, headers.count); handles.Add(source, handle); headers.Add(new HeightFieldHeader(samples.count, buffer.Length)); samples.AddRange(buffer); } return handle; } public void DestroyHeightField(ObiHeightFieldHandle handle) { if (handle != null && handle.isValid && handle.index < handles.Count) { var header = headers[handle.index]; // Update headers: for (int i = 0; i < headers.count; ++i) { var h = headers[i]; if (h.firstSample > header.firstSample) { h.firstSample -= header.sampleCount; headers[i] = h; } } // update handles: foreach (var pair in handles) { if (pair.Value.index > handle.index) pair.Value.index--; } // Remove nodes samples.RemoveRange(header.firstSample, header.sampleCount); // remove header: headers.RemoveAt(handle.index); // remove the heightfield from the dictionary: handles.Remove(handle.owner); // Invalidate our handle: handle.Invalidate(); } } public void Dispose() { if (headers != null) headers.Dispose(); if (samples != null) samples.Dispose(); } } }