public void InitEnvironment()
        {
            EnvironmentDefinition = Planet.Generator.EnvironmentDefinition;

            PlanetTranslation = Planet.WorldMatrix.Translation;

            m_InstanceHash = Planet.GetInstanceHash();

            double radius    = Planet.AverageRadius;
            double faceSize  = radius * Math.Sqrt(2);
            double faceSize2 = faceSize / 2;

            double sectorSize = EnvironmentDefinition.SectorSize;

            // Prepare each clipmap
            for (int i = 0; i < 6; ++i)
            {
                // get forward and up
                Vector3D forward, up;
                MyPlanetCubemapHelper.GetForwardUp((Base6Directions.Direction)i, out forward, out up);

                var translation = forward * faceSize2 + PlanetTranslation;

                forward = -forward;

                // prepare matrix
                MatrixD worldMatrix;
                MatrixD.CreateWorld(ref translation, ref forward, ref up, out worldMatrix);

                // Setup origins
                Vector3D origin = new Vector3D(-faceSize2, -faceSize2, 0);
                Vector3D.Transform(ref origin, ref worldMatrix, out origin);

                // Basis vectors
                Vector3D basisX = new Vector3D(1, 0, 0), basisY = new Vector3D(0, 1, 0);
                Vector3D.RotateAndScale(ref basisX, ref worldMatrix, out basisX);
                Vector3D.RotateAndScale(ref basisY, ref worldMatrix, out basisY);

                // Create and init the clipmap.
                m_clipmaps[i] = new My2DClipmap <MyPlanetEnvironmentClipmapProxy>();
                ActiveClipmap = m_clipmaps[i];
                ActiveFace    = i;

                m_clipmaps[i].Init(this, ref worldMatrix, sectorSize, faceSize);
                ActiveFace = -1;

                // Prepare the provider for the face
                var provider = new MyProceduralEnvironmentProvider {
                    ProviderId = i
                };

                provider.Init(this, ref origin, ref basisX, ref basisY, ActiveClipmap.LeafSize, m_providerData[i]);

                Providers[i] = provider;
            }
        }
        private void UpdateClipmaps()
        {
            // This avoids the clipmap from overruning and going bad
            if (m_sectorsToWorkParallel.Count > 0)
            {
                return;
            }

            Vector3D camera = MySector.MainCamera.Position - PlanetTranslation;

            double distance = camera.Length();

            // Update only if relevant
            if (distance > Planet.AverageRadius + m_clipmaps[0].FaceHalf && Proxies.Count == 0)
            {
                return;
            }

            distance = Math.Abs(Planet.Provider.Shape.GetDistanceToSurfaceCacheless(camera));

            // Get cubemap coordinates
            Vector2D texcoords;
            int      direction;

            MyPlanetCubemapHelper.ProjectToCube(ref camera, out direction, out texcoords);

            // Update each clipmap accordingly.
            for (int face = 0; face < 6; ++face)
            {
                ActiveFace    = face;
                ActiveClipmap = m_clipmaps[face];

                Vector2D localCoords;
                MyPlanetCubemapHelper.TranslateTexcoordsToFace(ref texcoords, direction, face, out localCoords);

                Vector3D pos;
                pos.X = localCoords.X * ActiveClipmap.FaceHalf;
                pos.Y = localCoords.Y * ActiveClipmap.FaceHalf;

                if ((face ^ direction) == 1)
                {
                    pos.Z = distance + Planet.AverageRadius * 2;
                }
                else
                {
                    pos.Z = distance;
                }

                //pos.Z = 0;

                ActiveClipmap.Update(pos);
                EvaluateOperations(); // Enqueue operations from this clipmap.
            }

            ActiveFace = -1;
        }
        public MyEnvironmentSector GetSectorForPosition(Vector3D positionWorld)
        {
            var positionLocal = positionWorld - PlanetTranslation;

            int      face;
            Vector2D texcoords;

            MyPlanetCubemapHelper.ProjectToCube(ref positionLocal, out face, out texcoords);

            texcoords *= m_clipmaps[face].FaceHalf;

            var handler = m_clipmaps[face].GetHandler(texcoords);

            if (handler != null)
            {
                return(handler.EnvironmentSector);
            }
            return(null);
        }
        // Iterate over sector boxes in a range.
        // TODO: Dumb version of this for small boxes
        private unsafe void RasterSectorsForPhysics(BoundingBoxD range)
        {
            range.InflateToMinimum(EnvironmentDefinition.SectorSize);

            Vector2I top = new Vector2I(1 << m_clipmaps[0].Depth) - 1;

            Vector3D *pos = stackalloc Vector3D[8];

            range.GetCornersUnsafe(pos);

            // bitmask for faces, 7th bit is simple bit
            int markedFaces = 0;
            int firstFace   = 0;

            for (var i = 0; i < 8; ++i)
            {
                Vector3D copy = pos[i];

                int index = MyPlanetCubemapHelper.FindCubeFace(ref copy);
                firstFace = index;
                index     = 1 << index;

                if ((markedFaces & ~index) != 0)
                {
                    markedFaces |= 0x40;
                }

                markedFaces |= index;
            }

            // This way we can ensure a single code path.
            int startFace = 0;
            int endFace   = 5;

            // If we only encounter one face we narrow it down.
            if ((markedFaces & 0x40) == 0)
            {
                startFace = endFace = firstFace;
            }

            for (int face = startFace; face <= endFace; ++face)
            {
                if (((1 << face) & markedFaces) == 0)
                {
                    continue;
                }

                double size = m_clipmaps[face].LeafSize;

                // Offset
                var offset = 1 << m_clipmaps[face].Depth - 1;

                BoundingBox2D bounds = BoundingBox2D.CreateInvalid();
                for (int i = 0; i < 8; ++i)
                {
                    Vector3D copy = pos[i];

                    Vector2D normCoords;
                    MyPlanetCubemapHelper.ProjectForFace(ref copy, face, out normCoords);
                    bounds.Include(normCoords);
                }

                bounds.Min += 1;
                bounds.Min *= offset;

                bounds.Max += 1;
                bounds.Max *= offset;

                // Calculate bounds in sectors.
                var start = new Vector2I((int)bounds.Min.X, (int)bounds.Min.Y);
                var end   = new Vector2I((int)bounds.Max.X, (int)bounds.Max.Y);

                Vector2I.Max(ref start, ref Vector2I.Zero, out start);
                Vector2I.Min(ref end, ref top, out end);

                for (int x = start.X; x <= end.X; ++x)
                {
                    for (int y = start.Y; y <= end.Y; ++y)
                    {
                        EnsurePhysicsSector(x, y, face);
                    }
                }
            }
        }
        private unsafe void RasterSectorsForCollision(MyEntity entity)
        {
            if (!(entity is MyCubeGrid))
            {
                return;
            }

            BoundingBoxD range = entity.PositionComp.WorldAABB;

            range.Inflate(8);
            range.Translate(-PlanetTranslation);

            Vector2I top = new Vector2I(1 << m_clipmaps[0].Depth) - 1;

            Vector3D *pos = stackalloc Vector3D[8];

            range.GetCornersUnsafe(pos);

            // bitmask for faces, 7th bit is simple bit
            int markedFaces = 0;
            int firstFace   = 0;

            for (var i = 0; i < 8; ++i)
            {
                Vector3D copy = pos[i];

                int index = MyPlanetCubemapHelper.FindCubeFace(ref copy);
                firstFace = index;
                index     = 1 << index;

                if ((markedFaces & ~index) != 0)
                {
                    markedFaces |= 0x40;
                }

                markedFaces |= index;
            }

            // This way we can ensure a single code path.
            int startFace = 0;
            int endFace   = 5;

            // If we only encounter one face we narrow it down.
            if ((markedFaces & 0x40) == 0)
            {
                startFace = endFace = firstFace;
            }

            for (int face = startFace; face <= endFace; ++face)
            {
                if (((1 << face) & markedFaces) == 0)
                {
                    continue;
                }

                // Offset
                var offset = 1 << m_clipmaps[face].Depth - 1;

                BoundingBox2D bounds = BoundingBox2D.CreateInvalid();
                for (int i = 0; i < 8; ++i)
                {
                    Vector3D copy = pos[i];

                    Vector2D normCoords;
                    MyPlanetCubemapHelper.ProjectForFace(ref copy, face, out normCoords);
                    bounds.Include(normCoords);
                }

                bounds.Min += 1;
                bounds.Min *= offset;

                bounds.Max += 1;
                bounds.Max *= offset;

                // Calculate bounds in sectors.
                var start = new Vector2I((int)bounds.Min.X, (int)bounds.Min.Y);
                var end   = new Vector2I((int)bounds.Max.X, (int)bounds.Max.Y);

                Vector2I.Max(ref start, ref Vector2I.Zero, out start);
                Vector2I.Min(ref end, ref top, out end);

                for (int x = start.X; x <= end.X; ++x)
                {
                    for (int y = start.Y; y <= end.Y; ++y)
                    {
                        long sect = MyPlanetSectorId.MakeSectorId(x, y, face);

                        List <MyOrientedBoundingBoxD> boxes;
                        if (!m_obstructorsPerSector.TryGetValue(sect, out boxes))
                        {
                            boxes = new List <MyOrientedBoundingBoxD>();
                            m_obstructorsPerSector.Add(sect, boxes);
                        }

                        var bb = entity.PositionComp.LocalAABB;
                        bb.Inflate(8); // inflate by 8m to increase the likellyhood of overlap with trees' roots.

                        boxes.Add(new MyOrientedBoundingBoxD((BoundingBoxD)bb, entity.PositionComp.WorldMatrix));
                    }
                }
            }
        }