void PushCuboid(Octree cuboid)
        {
            if (chunkRequestLast >= chunkRequests.Length - 1)
            {
                ShowMessage("Chunk creation buffer exhausted. Delaying creation...");
                return;
            }

            // Compare distances from last cuboid
            if (chunkRequestLast >= 0)
            {
                Octree prev       = chunkRequests [chunkRequestLast];
                float  distCuboid = (cuboid.center.x - currentCamPos.x) * (cuboid.center.x - currentCamPos.x) + (cuboid.center.y - currentCamPos.y) * (cuboid.center.y - currentCamPos.y);
                float  distPrev   = (prev.center.x - currentCamPos.x) * (prev.center.x - currentCamPos.x) + (prev.center.y - currentCamPos.y) * (prev.center.y - currentCamPos.y);
                if (distPrev < distCuboid)
                {
                    chunkRequests [chunkRequestLast] = cuboid;
                    cuboid = prev;
                }
            }
            chunkRequests [++chunkRequestLast] = cuboid;
        }
        void CheckCuboidVisibility(Octree cuboid)
        {
            if (cuboid.exploredChildren >= 8)
            {
                return;
            }

            Vector3 cuboidCenter = cuboid.center;
            float   dx           = cuboidCenter.x - currentCamPos.x;

            if (dx < 0)
            {
                dx = -dx;                 // simple abs()
            }
            dx -= cuboid.extents;
            dx /= 16f;
            if (dx > _visibleChunksDistance)
            {
                return;
            }
            float dy = cuboidCenter.y - currentCamPos.y;

            if (dy < 0)
            {
                dy = -dy;
            }
            dy -= cuboid.extents;
            dy /= 16f;
            int chunksYDistance = _visibleChunksDistance >= 8 ? 8 : _visibleChunksDistance;

            if (dy > chunksYDistance)
            {
                return;
            }
            float dz = cuboidCenter.z - currentCamPos.z;

            if (dz < 0)
            {
                dz = -dz;
            }
            dz -= cuboid.extents;
            dz /= 16f;
            if (dz > _visibleChunksDistance)
            {
                return;
            }

            Vector3 cuboidMin, cuboidMax;

            cuboidMin.x = cuboidCenter.x - cuboid.extents;
            cuboidMin.y = cuboidCenter.y - cuboid.extents;
            cuboidMin.z = cuboidCenter.z - cuboid.extents;
            cuboidMax.x = cuboidCenter.x + cuboid.extents;
            cuboidMax.y = cuboidCenter.y + cuboid.extents;
            cuboidMax.z = cuboidCenter.z + cuboid.extents;

            bool inFrustum;

            if (onlyRenderInFrustum)
            {
                inFrustum = GeometryUtilityNonAlloc.TestPlanesAABB(frustumPlanesNormals, frustumPlanesDistances, ref cuboidMin, ref cuboidMax);
            }
            else
            {
                inFrustum = true;
            }
            if (inFrustum)
            {
                int cuboidSize = cuboid.extents * 2;
                if (cuboidSize > 16)
                {
                    if (cuboid.children == null)
                    {
                        cuboid.Explode();
                    }
                    for (int k = 0; k < 8; k++)
                    {
                        if (!cuboid.children [k].explored)
                        {
                            PushCuboid(cuboid.children [k]);
                        }
                    }
                    return;
                }

                // cuboid is less than a chunk - use that chunk
                int chunkX, chunkY, chunkZ;
                GetChunkCoordinates(cuboid.center, out chunkX, out chunkY, out chunkZ);
                int hash = GetChunkHash(chunkX, chunkY, chunkZ);

                CachedChunk cachedChunk;
                if (cachedChunks.TryGetValue(hash, out cachedChunk))
                {
                    cachedChunk.octree = cuboid;
                    cuboid.parent.exploredChildren++;
                    cuboid.explored = true;
                    VoxelChunk chunk = cachedChunk.chunk;
                    if (chunk == null)
                    {
                        return;
                    }
                    if (chunk.isPopulated)
                    {
                        // If this chunk has been created but not rendered yet, request it
                        //	if (chunk.renderState == ChunkRenderState.Pending && !chunk.inqueue) {
                        if (chunk.renderState != ChunkRenderState.RenderingComplete || !chunk.mr.enabled)
                        {
                            if (chunk.inqueue)
                            {
                                chunk.needsMeshRebuild = true;
                            }
                            else
                            {
                                ChunkRequestRefresh(chunk, false, true);
                            }
                        }
                        return;
                    }
                }

                CreateChunk(hash, chunkX, chunkY, chunkZ, false);
                chunkCreationCountThisFrame++;
            }
        }
 public Octree(Octree parent, Vector3 center, int extents)
 {
     this.parent  = parent;
     this.center  = center;
     this.extents = extents;
 }