using System; using System.Collections.Generic; using UnityEngine; namespace Assets.ThoMagic.Renderer { public class CellLayout { public Vector3 Origin; private readonly int _cellsX; private readonly int _cellsZ; private readonly float _cellSizeX; private readonly float _cellSizeZ; private readonly Cell[] _cells; private readonly Dictionary _cameraPlanes = new Dictionary(); private const int _planeCount = 6; private int _cachedFrameId; private Camera _cachedCamera; private Plane[] _planes = new Plane[6]; private Double3[] _absNormals = new Double3[6]; private Double3[] _planeNormal = new Double3[6]; private double[] _planeDistance = new double[6]; public CellLayout(float cellSizeX, float cellSizeZ, Bounds worldBounds) { Origin = worldBounds.min; _cellSizeX = cellSizeX; _cellSizeZ = cellSizeZ; _cellsX = Mathf.CeilToInt(worldBounds.size.x / _cellSizeX); _cellsZ = Mathf.CeilToInt(worldBounds.size.z / _cellSizeZ); _cells = new Cell[_cellsX * _cellsZ]; float num1 = _cellSizeX * 0.5f; float num2 = _cellSizeZ * 0.5f; for (int index1 = 0; index1 < _cellsZ; ++index1) { for (int index2 = 0; index2 < _cellsX; ++index2) { int index3 = index1 * _cellsX + index2; float num3 = (float)index2 * _cellSizeX + num1; float num4 = (float)index1 * _cellSizeZ + num2; _cells[index3].HeightMin = double.MaxValue; _cells[index3].HeightMax = double.MinValue; _cells[index3].Center = new Double3((double)num3, 0.0, (double)num4); _cells[index3].Extends = new Double3((double)num1, double.NaN, (double)num2); } } } public Cell[] GetCells() => _cells; public int GetCellCount() => _cells.Length; public void OverwriteCellHeightBounds() { int length = _cells.Length; for (int index = 0; index < length; ++index) _cells[index].HeightOverwrite = true; } public void SetCellHeightBounds(int cellIndex, double min, double max) { ref Cell local = ref _cells[cellIndex]; if (local.HeightOverwrite) { local.HeightOverwrite = false; local.HeightMax = max; local.HeightMin = min; } else { local.HeightMax = Math.Max(local.HeightMax, max); local.HeightMin = Math.Min(local.HeightMin, min); } local.Center = new Double3(local.Center.x, (local.HeightMax + local.HeightMin) * 0.5, local.Center.z); local.Extends = new Double3(local.Extends.x, (local.HeightMax + local.HeightMin) * 0.5, local.Extends.z); } public void Update(Camera camera, int frameId, bool frustumCulling) { if (camera == _cachedCamera && frameId == _cachedFrameId) return; _cachedCamera = camera; _cachedFrameId = frameId; Plane[] planes; if (!_cameraPlanes.TryGetValue(((object)camera).GetHashCode(), out planes)) _cameraPlanes[((object)camera).GetHashCode()] = planes = new Plane[6]; GeometryUtility.CalculateFrustumPlanes(camera, planes); SetPlanes(planes); double x1 = camera.transform.position.x; double z1 = camera.transform.position.z; Double3 absNormal1 = _absNormals[0]; Double3 absNormal2 = _absNormals[1]; Double3 absNormal3 = _absNormals[2]; Double3 absNormal4 = _absNormals[3]; Double3 absNormal5 = _absNormals[4]; Double3 absNormal6 = _absNormals[5]; Double3 double3_1 = _planeNormal[0]; Double3 double3_2 = _planeNormal[1]; Double3 double3_3 = _planeNormal[2]; Double3 double3_4 = _planeNormal[3]; Double3 double3_5 = _planeNormal[4]; Double3 double3_6 = _planeNormal[5]; double num1 = _planeDistance[0]; double num2 = _planeDistance[1]; double num3 = _planeDistance[2]; double num4 = _planeDistance[3]; double num5 = _planeDistance[4]; double num6 = _planeDistance[5]; double x2 = (double)Origin.x; double y = (double)Origin.y; double z2 = (double)Origin.z; int length = _cells.Length; for (int index = 0; index < length; ++index) { ref Cell local = ref _cells[index]; double num7 = local.Center.x + x2; double num8 = local.Center.y + y; double num9 = local.Center.z + z2; Double3 extends = local.Extends; local.DistanceX = Math.Abs(x1 - num7); local.DistanceZ = Math.Abs(z1 - num9); if (frustumCulling && !double.IsNaN(extends.y)) { bool flag = extends.x * absNormal1.x + extends.y * absNormal1.y + extends.z * absNormal1.z + (double3_1.x * num7 + double3_1.y * num8 + double3_1.z * num9) < -num1 || extends.x * absNormal2.x + extends.y * absNormal2.y + extends.z * absNormal2.z + (double3_2.x * num7 + double3_2.y * num8 + double3_2.z * num9) < -num2 || extends.x * absNormal3.x + extends.y * absNormal3.y + extends.z * absNormal3.z + (double3_3.x * num7 + double3_3.y * num8 + double3_3.z * num9) < -num3 || extends.x * absNormal4.x + extends.y * absNormal4.y + extends.z * absNormal4.z + (double3_4.x * num7 + double3_4.y * num8 + double3_4.z * num9) < -num4 || extends.x * absNormal5.x + extends.y * absNormal5.y + extends.z * absNormal5.z + (double3_5.x * num7 + double3_5.y * num8 + double3_5.z * num9) < -num5 || extends.x * absNormal6.x + extends.y * absNormal6.y + extends.z * absNormal6.z + (double3_6.x * num7 + double3_6.y * num8 + double3_6.z * num9) < -num6; local.InFrustum = !flag; } else local.InFrustum = true; } } private void SetPlanes(Plane[] planes) { _planes = planes; for (int index = 0; index < 6; ++index) { Plane plane = _planes[index]; Vector3 vector = plane.normal; Double3 double3 = new Double3(in vector); _absNormals[index] = new Double3(Math.Abs(double3.x), Math.Abs(double3.y), Math.Abs(double3.z)); _planeNormal[index] = double3; _planeDistance[index] = plane.distance; } } public struct Cell { public double DistanceX; public double DistanceZ; public bool InFrustum; public Double3 Center; public Double3 Extends; public double HeightMin; public double HeightMax; public bool HeightOverwrite; } public readonly struct Double3 { public readonly double x; public readonly double y; public readonly double z; public Double3(in Vector3 vector) { x = (double)vector.x; y = (double)vector.y; z = (double)vector.z; } public Double3(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } } } }