Exemple #1
0
        private void storage_RangeChangedPlanet(Vector3I minChanged, Vector3I maxChanged, MyStorageDataTypeFlags dataChanged)
        {
            ProfilerShort.Begin("MyVoxelMap::storage_RangeChanged");
            Vector3I minSector = minChanged / PHYSICS_SECTOR_SIZE_METERS;
            Vector3I maxSector = maxChanged / PHYSICS_SECTOR_SIZE_METERS;

            MyVoxelPhysics voxelMap;

            if (m_physicsShapes != null)
            {
                for (var it = new Vector3I.RangeIterator(ref minSector, ref maxSector);
                     it.IsValid(); it.MoveNext())
                {
                    if (m_physicsShapes.TryGetValue(it.Current, out voxelMap))
                    {
                        if (voxelMap != null)
                        {
                            voxelMap.OnStorageChanged(minChanged, maxChanged, dataChanged);
                        }
                    }
                }
            }

            if (Render is MyRenderComponentVoxelMap)
            {
                (Render as MyRenderComponentVoxelMap).InvalidateRange(minChanged, maxChanged);
            }

            OnRangeChanged(minChanged, maxChanged, dataChanged);
            ProfilerShort.End();
        }
Exemple #2
0
            private int GetDivideIndex(ref Vector3I renderCellCoord)
            {
                // TODO: Optimize
                int divideIndex = 0;

                if (m_lodDivisions > 1)
                {
                    BoundingBoxD lodAabb = m_boundingBoxes.GetAabb(m_boundingBoxes.GetRoot());
                    Vector3I     test    = Vector3I.Round(lodAabb.Size / (double)MyVoxelCoordSystems.RenderCellSizeInMeters(m_lod));
                    //Vector3I lodSizeMinusOne = m_parentClipmap.LodSizeMinusOne(m_lod);
                    //Vector3I lodSize = lodSizeMinusOne + Vector3I.One;
                    Vector3I lodSize         = test;
                    Vector3I lodSizeMinusOne = test - 1;
                    Vector3I lodDivision     = Vector3I.One * (m_lodDivisions - 1);

                    var cellIterator = new Vector3I.RangeIterator(ref Vector3I.Zero, ref lodDivision);
                    for (; cellIterator.IsValid(); cellIterator.MoveNext())
                    {
                        Vector3I currentDivision = cellIterator.Current;
                        Vector3I min             = currentDivision * lodSize / m_lodDivisions;
                        Vector3I max             = (currentDivision + Vector3I.One) * lodSize / m_lodDivisions;
                        if (renderCellCoord.IsInsideInclusive(ref min, ref max))
                        {
                            break;
                        }
                    }
                    Debug.Assert(cellIterator.IsValid(), "Valid division index not found!");
                    Vector3I foundCell = cellIterator.Current;
                    divideIndex = GetDivideIndexFromMergeCell(ref foundCell);
                }
                return(divideIndex);
            }
Exemple #3
0
        public void PrefetchShapeOnRay(ref LineD ray)
        {
            Vector3I minCorner, maxCorner;

            MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref ray.From, out minCorner);
            MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref ray.To, out maxCorner);

            minCorner /= PHYSICS_SECTOR_SIZE_METERS;
            maxCorner /= PHYSICS_SECTOR_SIZE_METERS;

            for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner);
                 it.IsValid(); it.MoveNext())
            {
                if (m_physicsShapes.ContainsKey(it.Current))
                {
                    m_physicsShapes[it.Current].PrefetchShapeOnRay(ref ray);
                }
            }
        }
Exemple #4
0
        private void storage_RangeChangedPlanet(Vector3I minChanged, Vector3I maxChanged, MyStorageDataTypeFlags dataChanged)
        {
            ProfilerShort.Begin("MyVoxelMap::storage_RangeChanged");
            Vector3I minSector = minChanged / PHYSICS_SECTOR_SIZE_METERS;
            Vector3I maxSector = maxChanged / PHYSICS_SECTOR_SIZE_METERS;

            Vector3I increment = m_storage.Size / (m_numCells + 1);

            for (var it = new Vector3I.RangeIterator(ref minSector, ref maxSector);
                 it.IsValid(); it.MoveNext())
            {
                MyVoxelPhysics voxelMap = CreatePhysicsShape(ref increment, ref it);

                voxelMap.OnStorageChanged(minChanged, maxChanged, dataChanged);
            }

            if (Render is MyRenderComponentVoxelMap)
            {
                (Render as MyRenderComponentVoxelMap).InvalidateRange(minChanged, maxChanged);
            }

            ProfilerShort.End();
        }
Exemple #5
0
            private bool FindFirstAcceptableEntry()
            {
                while (true)
                {
                    while (m_storageIndex != -1)
                    {
                        Entry current = m_parent.m_storage[m_storageIndex];
                        if ((current.Point - m_point).LengthSquared() < m_distSq)
                        {
                            return(true);
                        }
                        m_previousIndex = m_storageIndex;
                        m_storageIndex  = current.NextEntry;
                    }

                    m_rangeIterator.MoveNext();

                    if (!FindNextNonemptyBin())
                    {
                        return(false);
                    }
                }
            }
Exemple #6
0
        private void GeneratePhysicalShapeForBox(ref Vector3I increment, ref BoundingBoxD shapeBox)
        {
            if (!shapeBox.Intersects(PositionComp.WorldAABB))
            {
                return;
            }

            Vector3I minCorner, maxCorner;

            MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref shapeBox.Min, out minCorner);
            MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref shapeBox.Max, out maxCorner);

            minCorner /= PHYSICS_SECTOR_SIZE_METERS;
            maxCorner /= PHYSICS_SECTOR_SIZE_METERS;

            for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner);
                 it.IsValid(); it.MoveNext())
            {
                ProfilerShort.Begin("Myplanet::create physics shape");
                CreatePhysicsShape(ref increment, ref it);
                ProfilerShort.End();
            }
        }
Exemple #7
0
        private void GeneratePhysicalShapeForBox(ref Vector3I increment, ref BoundingBoxD shapeBox)
        {
            if (!shapeBox.Intersects(PositionComp.WorldAABB))
                return;

            Vector3I minCorner, maxCorner;
            MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref shapeBox.Min, out minCorner);
            MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref shapeBox.Max, out maxCorner);

            minCorner /= PHYSICS_SECTOR_SIZE_METERS;
            maxCorner /= PHYSICS_SECTOR_SIZE_METERS;

            for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner);
                it.IsValid(); it.MoveNext())
            {
                ProfilerShort.Begin("Myplanet::create physics shape");
                CreatePhysicsShape(ref increment, ref it);
                ProfilerShort.End();
            }
        }
Exemple #8
0
        private void storage_RangeChangedPlanet(Vector3I minChanged, Vector3I maxChanged, MyStorageDataTypeFlags dataChanged)
        {
            ProfilerShort.Begin("MyVoxelMap::storage_RangeChanged");
            Vector3I minSector = minChanged / PHYSICS_SECTOR_SIZE_METERS;
            Vector3I maxSector = maxChanged/PHYSICS_SECTOR_SIZE_METERS;

            Vector3I increment = m_storage.Size / (m_numCells+1);
            for (var it = new Vector3I.RangeIterator(ref minSector, ref maxSector);
                it.IsValid(); it.MoveNext())
            {
                MyVoxelPhysics voxelMap = CreatePhysicsShape(ref increment, ref it);

                voxelMap.OnStorageChanged(minChanged, maxChanged, dataChanged);
            }

            if (Render is MyRenderComponentVoxelMap)
            {
                (Render as MyRenderComponentVoxelMap).InvalidateRange(minChanged, maxChanged);
            }

            ProfilerShort.End();
        }
        public static void CutOutShapeWithProperties(
            MyVoxelBase voxelMap,
            MyShape shape,
            out float voxelsCountInPercent,
            out MyVoxelMaterialDefinition voxelMaterial,
            Dictionary<MyVoxelMaterialDefinition, int> exactCutOutMaterials = null,
            bool updateSync = false,
            bool onlyCheck = false)
        {
            if (MySession.Static.EnableVoxelDestruction == false)
            {
                voxelsCountInPercent = 0;
                voxelMaterial = null;
                return;
            }

            ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()");

            int originalSum = 0;
            int removedSum = 0;

            // Some shapes just ignore transforms so we round the bbox conservativelly by converting it to sphere
            var bbox = shape.GetWorldBoundaries();
            var center = bbox.Center;
            var radius = (center - bbox.Min).Length();

            MatrixD mat = voxelMap.PositionComp.WorldMatrix;
            MatrixD inverse;
            //Vector3D translation = mat.Translation;
            //mat.Translation = Vector3D.Zero;

            // invert is used to bring voxel coordinates back to world.
            inverse = voxelMap.PositionComp.WorldMatrixInvScaled;//MatrixD.Invert(ref mat, out inverse);

            Vector3 offset = voxelMap.StorageMin + voxelMap.SizeInMetresHalf;

            Vector3D.Transform(ref center, ref inverse, out center);
            
            // The transform is centered, but the code expects voxel local coordinates.
            center += voxelMap.SizeInMetresHalf;

            bbox = new BoundingBoxD(center - radius, center + radius);

            Vector3I minCorner, maxCorner;
            ComputeShapeBounds(voxelMap, ref bbox, Vector3.Zero, voxelMap.Storage.Size, out minCorner, out maxCorner);

            var cacheMin = minCorner - 1;
            var cacheMax = maxCorner + 1;
            voxelMap.Storage.ClampVoxelCoord(ref cacheMin);
            voxelMap.Storage.ClampVoxelCoord(ref cacheMax);
            m_cache.Resize(cacheMin, cacheMax);
            voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cacheMin, ref cacheMax);

            {
                var shapeCenter = bbox.Center;
                Vector3I exactCenter;
                MyVoxelCoordSystems.WorldPositionToVoxelCoord(Vector3.Zero, ref shapeCenter, out exactCenter);
                exactCenter -= cacheMin;
                exactCenter = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1);
                voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter));
            }

            ProfilerShort.Begin("Main loop");
            for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext())
            {
                var relPos   = it.Current - cacheMin; // get original amount
                var original = m_cache.Content(ref relPos);

                if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove
                    continue;

                Vector3D vpos;
                MyVoxelCoordSystems.VoxelCoordToLocalPosition(ref it.Current, out vpos);

                // center
                vpos -= offset;

                // transform back to world space.
                Vector3D.Transform(ref vpos, ref mat, out vpos);

                var volume = shape.GetVolume(ref vpos);

                if (volume == 0f) // if there is no intersection
                    continue;

                var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL);
                var voxelMat  = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref relPos));
                var toRemove  = (int)(maxRemove * voxelMat.DamageRatio);
                var newVal    = MathHelper.Clamp(original - toRemove, 0, original-maxRemove);
                var removed   = Math.Abs(original - newVal);

                if (!onlyCheck)
                    m_cache.Content(ref relPos, (byte)newVal);

                originalSum += original;
                removedSum  += removed;

                if (exactCutOutMaterials != null)
                {
                    int value = 0;
                    exactCutOutMaterials.TryGetValue(voxelMat, out value);
                    value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed);
                    exactCutOutMaterials[voxelMat] = value;
                }
            }

            if (removedSum > 0 && updateSync && Sync.IsServer)
            {
                shape.SendDrillCutOutRequest(voxelMap);
            }

            ProfilerShort.BeginNextBlock("Write");


            if (removedSum > 0 && !onlyCheck)
            {
                //  Clear all small voxel that may have been created during explosion. They can be created even outside the range of
                //  explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the
                //  explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we
                //  will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove
                //  B voxels too.
                //!! TODO AR & MK : check if this is needed !!
                RemoveSmallVoxelsUsingChachedVoxels();

                voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax);
            }
            ProfilerShort.End();
           

            voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f;

            if (removedSum > 0)
                CheckNeighbourStaticGridsAfterVoxelChanged(MyVoxelBase.OperationType.Cut, voxelMap, shape);

            ProfilerShort.End();
        }
Exemple #10
0
        private void storage_RangeChangedPlanet(Vector3I minChanged, Vector3I maxChanged, MyStorageDataTypeFlags dataChanged)
        {
            ProfilerShort.Begin("MyVoxelMap::storage_RangeChanged");
            Vector3I minSector = minChanged / PHYSICS_SECTOR_SIZE_METERS;
            Vector3I maxSector = maxChanged / PHYSICS_SECTOR_SIZE_METERS;

            MyVoxelPhysics voxelMap;

            if (m_physicsShapes != null)
            {
                for (var it = new Vector3I.RangeIterator(ref minSector, ref maxSector);
                    it.IsValid(); it.MoveNext())
                {
                    if (m_physicsShapes.TryGetValue(it.Current, out voxelMap))
                    {
                        if (voxelMap != null)
                            voxelMap.OnStorageChanged(minChanged, maxChanged, dataChanged);
                    }
                }
            }

            if (Render is MyRenderComponentVoxelMap)
            {
                (Render as MyRenderComponentVoxelMap).InvalidateRange(minChanged, maxChanged);
            }

            OnRangeChanged(minChanged, maxChanged, dataChanged);
            ProfilerShort.End();
        }
Exemple #11
0
        public void SpawnFlora(Vector3D pos)
        {
            if (m_planetEnvironmentSectors == null)
            {
                m_planetEnvironmentSectors = new Dictionary <Vector3I, MyPlanetEnvironmentSector>(500);
            }

            Vector3D gravity       = GetWorldGravityNormalized(ref pos);
            Vector3D perpedincular = MyUtils.GetRandomPerpendicularVector(ref gravity);
            Vector3D third         = Vector3D.Cross(gravity, perpedincular);

            perpedincular += third;

            Vector3I min = new Vector3I(-ENVIROMENT_EXTEND);
            Vector3I max = new Vector3I(ENVIROMENT_EXTEND);

            Vector3 offset = new Vector3(-MyPlanetEnvironmentSector.SECTOR_SIZE_METERS);

            for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.MoveNext())
            {
                Vector3D currentPos = pos + it.Current * offset * perpedincular;
                currentPos = PlaceToOrbit(currentPos, ref gravity);

                if (false == ChekPosition(currentPos))
                {
                    Vector3I newSector = Vector3I.Floor(currentPos / MyPlanetEnvironmentSector.SECTOR_SIZE_METERS);
                    if (m_planetSectorsPool == null)
                    {
                        m_planetSectorsPool = new MyDynamicObjectPool <MyPlanetEnvironmentSector>(400);
                    }


                    MyPlanetEnvironmentSector sector = m_planetSectorsPool.Allocate();

                    sector.Init(ref newSector, this);
                    m_planetEnvironmentSectors[newSector] = sector;
                    sector.PlaceItems();
                }
            }

            Vector3I sectorCoords = Vector3I.Floor(PlaceToOrbit(pos, ref gravity) / MyPlanetEnvironmentSector.SECTOR_SIZE_METERS);

            Vector3I keepMin = sectorCoords + new Vector3I(-ENVIROMENT_EXTEND_KEEP);
            Vector3I keepMax = sectorCoords + new Vector3I(ENVIROMENT_EXTEND_KEEP);

            foreach (var enviromentSector in m_planetEnvironmentSectors)
            {
                if (enviromentSector.Key.IsInsideInclusive(keepMin, keepMax))
                {
                    m_sectorsToKeep.Add(enviromentSector.Key);
                }
            }
        }
        public static ulong CutOutShape(MyVoxelBase voxelMap, MyShape shape)
        {
            Vector3I minCorner, maxCorner, numCells;

            GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells);
            ulong changedVolumeAmount = 0;

            for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext())
            {
                Vector3I cellMinCorner, cellMaxCorner;
                GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner);

                var cacheMin = cellMinCorner - 1;
                var cacheMax = cellMaxCorner + 1;
                voxelMap.Storage.ClampVoxelCoord(ref cacheMin);
                voxelMap.Storage.ClampVoxelCoord(ref cacheMax);

                ulong removedSum = 0;
                m_cache.Resize(cacheMin, cacheMax);
                voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, 0, ref cacheMin, ref cacheMax);

                for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext())
                {
                    var relPos   = it.Current - cacheMin; // get original amount
                    var original = m_cache.Content(ref relPos);

                    if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove
                    {
                        continue;
                    }

                    Vector3D vpos;
                    MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos);
                    var volume = shape.GetVolume(ref vpos);

                    if (volume == 0f) // if there is no intersection
                    {
                        continue;
                    }

                    var   toRemove = (int)(MyVoxelConstants.VOXEL_CONTENT_FULL - (volume * MyVoxelConstants.VOXEL_CONTENT_FULL));
                    var   newVal   = Math.Min(toRemove, original);
                    ulong removed  = (ulong)Math.Abs(original - newVal);

                    m_cache.Content(ref relPos, (byte)newVal);
                    removedSum += removed;
                }

                if (removedSum > 0)
                {
                    RemoveSmallVoxelsUsingChachedVoxels(); // must stay because of the around when filling voxels
                    voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax);
                }

                changedVolumeAmount += removedSum;
            }

            return(changedVolumeAmount);
        }
        public static ulong FillInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx)
        {
            Vector3I minCorner, maxCorner, numCells;
            ulong    retValue = 0;

            GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells);

            for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext())
            {
                Vector3I cellMinCorner, cellMaxCorner;
                GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner);

                Vector3I originalMinCorner = cellMinCorner;
                Vector3I originalMaxCorner = cellMaxCorner;

                voxelMap.Storage.ClampVoxelCoord(ref cellMinCorner, VOXEL_CLAMP_BORDER_DISTANCE);
                voxelMap.Storage.ClampVoxelCoord(ref cellMaxCorner, VOXEL_CLAMP_BORDER_DISTANCE);

                ClampingInfo minCornerClamping = CheckForClamping(originalMinCorner, cellMinCorner);
                ClampingInfo maxCornerClamping = CheckForClamping(originalMaxCorner, cellMaxCorner);

                m_cache.Resize(cellMinCorner, cellMaxCorner);
                voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cellMinCorner, ref cellMaxCorner);

                ulong filledSum = 0;

                for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext())
                {
                    var relPos   = it.Current - cellMinCorner; // get original amount
                    var original = m_cache.Content(ref relPos);

                    if (original == MyVoxelConstants.VOXEL_CONTENT_FULL) // if there is nothing to add
                    {
                        continue;
                    }

                    //if there was some claping, fill the clamp region with material
                    if ((it.Current.X == cellMinCorner.X && minCornerClamping.X) || (it.Current.X == cellMaxCorner.X && maxCornerClamping.X) ||
                        (it.Current.Y == cellMinCorner.Y && minCornerClamping.Y) || (it.Current.Y == cellMaxCorner.Y && maxCornerClamping.Y) ||
                        (it.Current.Z == cellMinCorner.Z && minCornerClamping.Z) || (it.Current.Z == cellMaxCorner.Z && maxCornerClamping.Z))
                    {
                        m_cache.Material(ref relPos, materialIdx);
                        continue;
                    }

                    Vector3D vpos;
                    MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos);
                    var volume = shape.GetVolume(ref vpos);


                    if (volume <= 0f) // there is nothing to fill
                    {
                        continue;
                    }

                    m_cache.Material(ref relPos, materialIdx); // set material

                    var  toFill = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL);
                    long newVal = MathHelper.Clamp(original + toFill, 0, Math.Max(original, toFill));

                    m_cache.Content(ref relPos, (byte)newVal);
                    filledSum += (ulong)(newVal - original);
                }
                if (filledSum > 0)
                {
                    RemoveSmallVoxelsUsingChachedVoxels();
                    voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, ref cellMinCorner, ref cellMaxCorner);
                }

                retValue += filledSum;
            }

            return(retValue);
        }
        private void EnsureMorphTargetExists(MyPrecalcJobRender.Args args, MyIsoMesh highResMesh)
        {
            // Ensure as many (ideally all) vertices have some mapping prepared.
            // This is here to resolve any missing parent only once for each vertex (main loop can visit vertices for each triangle they appear in).
            //var geometryData = highResMesh;
            for (int i = 0; i < highResMesh.VerticesCount; ++i)
            {
                Vector3 highResPosition = highResMesh.Positions[i];
                Vertex  lowResVertex;

                Vector3I vertexCell = highResMesh.Cells[i] >> 1;
                if (!m_morphMap.TryGetValue(vertexCell, out lowResVertex))
                {
                    float   scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << args.Cell.Lod);
                    Vector3 cell  = highResPosition / scale;
                    cell *= 0.5f;
                    scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << (args.Cell.Lod + 1));
                    Vector3  lowResPosition    = cell * scale;
                    var      cellMin           = vertexCell;
                    var      cellMax           = vertexCell + 1; // usually I need to find parent in this direction
                    float    nearestDist       = float.PositiveInfinity;
                    int      nearestDistManhat = int.MaxValue;
                    Vector3I?nearestCell       = null;
                    for (var it = new Vector3I.RangeIterator(ref cellMin, ref cellMax); it.IsValid(); it.MoveNext())
                    {
                        Vertex morph;
                        if (m_morphMap.TryGetValue(it.Current, out morph))
                        {
                            var   tmp        = it.Current - cellMin;
                            int   distManhat = tmp.X + tmp.Y + tmp.Z;
                            float dist       = (morph.Target.Position - lowResPosition).LengthSquared();
                            if (distManhat < nearestDistManhat ||
                                (distManhat == nearestDistManhat && dist < nearestDist))
                            {
                                nearestDist       = dist;
                                nearestDistManhat = distManhat;
                                nearestCell       = it.Current;
                            }
                        }
                    }

                    if (nearestCell.HasValue)
                    {
                        m_morphMap.Add(vertexCell, m_morphMap[nearestCell.Value]);
                    }
                    else
                    {
                        //Debug.Fail("I'm screwed");
                    }
                }
            }
        }
Exemple #15
0
        public void ReadRange(MyStorageData target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax, ref MyVoxelRequestFlags requestFlags)
        {
            ProfilerShort.Begin(GetType().Name + ".ReadRange");
            try
            {
                const int SUBRANGE_SIZE_SHIFT = 3;
                const int SUBRANGE_SIZE       = 1 << SUBRANGE_SIZE_SHIFT;
                var       threshold           = new Vector3I(SUBRANGE_SIZE);
                var       rangeSize           = lodVoxelRangeMax - lodVoxelRangeMin + 1;
                if ((dataToRead & MyStorageDataTypeFlags.Content) != 0)
                {
                    target.ClearContent(0);
                }

                if ((rangeSize.X <= threshold.X &&
                     rangeSize.Y <= threshold.Y &&
                     rangeSize.Z <= threshold.Z) || !MyFakes.ENABLE_SPLIT_VOXEL_READ_QUERIES)
                {
                    using (m_lock.AcquireSharedUsing())
                    {
                        ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags);
                    }
                }
                else
                {
                    // These optimizations don't work when splitting the range.
                    requestFlags &= ~(MyVoxelRequestFlags.OneMaterial | MyVoxelRequestFlags.ContentChecked);
                    MyVoxelRequestFlags flags = requestFlags;

                    // splitting to smaller ranges to make sure the lock is not held for too long, preventing write on update thread
                    // subranges could be aligned to multiple of their size for possibly better performance
                    var steps = (rangeSize - 1) >> SUBRANGE_SIZE_SHIFT;
                    for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref steps); it.IsValid(); it.MoveNext())
                    {
                        flags = requestFlags;
                        var offset = it.Current << SUBRANGE_SIZE_SHIFT;
                        var min    = lodVoxelRangeMin + offset;
                        var max    = min + SUBRANGE_SIZE - 1;
                        Vector3I.Min(ref max, ref lodVoxelRangeMax, out max);
                        Debug.Assert(min.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax));
                        Debug.Assert(max.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax));
                        using (m_lock.AcquireSharedUsing())
                        {
                            ReadRangeInternal(target, ref offset, dataToRead, lodIndex, ref min, ref max, ref flags);
                        }
                    }

                    // If the storage is consistent this should be fine.
                    requestFlags = flags;
                }
            }
            finally
            {
                ProfilerShort.End();
            }
        }
        public static void CutOutShapeWithProperties(
            MyVoxelBase voxelMap,
            MyShape shape,
            out float voxelsCountInPercent,
            out MyVoxelMaterialDefinition voxelMaterial,
            Dictionary <MyVoxelMaterialDefinition, int> exactCutOutMaterials = null,
            bool updateSync = false,
            bool onlyCheck  = false)
        {
            if (MySession.Static.EnableVoxelDestruction == false)
            {
                voxelsCountInPercent = 0;
                voxelMaterial        = null;
                return;
            }

            ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()");

            int originalSum = 0;
            int removedSum  = 0;

            // Some shapes just ignore transforms so we round the bbox conservativelly by converting it to sphere
            var bbox   = shape.GetWorldBoundaries();
            var center = bbox.Center;
            var radius = (center - bbox.Min).Length();

            MatrixD mat = voxelMap.PositionComp.WorldMatrix;
            MatrixD inverse;

            //Vector3D translation = mat.Translation;
            //mat.Translation = Vector3D.Zero;

            // invert is used to bring voxel coordinates back to world.
            inverse = voxelMap.PositionComp.WorldMatrixInvScaled;//MatrixD.Invert(ref mat, out inverse);

            Vector3 offset = voxelMap.StorageMin + voxelMap.SizeInMetresHalf;

            Vector3D.Transform(ref center, ref inverse, out center);

            // The transform is centered, but the code expects voxel local coordinates.
            center += voxelMap.SizeInMetresHalf;

            bbox = new BoundingBoxD(center - radius, center + radius);

            Vector3I minCorner, maxCorner;

            ComputeShapeBounds(voxelMap, ref bbox, Vector3.Zero, voxelMap.Storage.Size, out minCorner, out maxCorner);

            var cacheMin = minCorner - 1;
            var cacheMax = maxCorner + 1;

            voxelMap.Storage.ClampVoxelCoord(ref cacheMin);
            voxelMap.Storage.ClampVoxelCoord(ref cacheMax);
            m_cache.Resize(cacheMin, cacheMax);
            voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cacheMin, ref cacheMax);

            {
                var      shapeCenter = bbox.Center;
                Vector3I exactCenter;
                MyVoxelCoordSystems.WorldPositionToVoxelCoord(Vector3.Zero, ref shapeCenter, out exactCenter);
                exactCenter  -= cacheMin;
                exactCenter   = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1);
                voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter));
            }

            ProfilerShort.Begin("Main loop");
            for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext())
            {
                var relPos   = it.Current - cacheMin; // get original amount
                var original = m_cache.Content(ref relPos);

                if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove
                {
                    continue;
                }

                Vector3D vpos;
                MyVoxelCoordSystems.VoxelCoordToLocalPosition(ref it.Current, out vpos);

                // center
                vpos -= offset;

                // transform back to world space.
                Vector3D.Transform(ref vpos, ref mat, out vpos);

                var volume = shape.GetVolume(ref vpos);

                if (volume == 0f) // if there is no intersection
                {
                    continue;
                }

                var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL);
                var voxelMat  = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref relPos));
                var toRemove  = (int)(maxRemove * voxelMat.DamageRatio);
                var newVal    = MathHelper.Clamp(original - toRemove, 0, original - maxRemove);
                var removed   = Math.Abs(original - newVal);

                if (!onlyCheck)
                {
                    m_cache.Content(ref relPos, (byte)newVal);
                }

                originalSum += original;
                removedSum  += removed;

                if (exactCutOutMaterials != null)
                {
                    int value = 0;
                    exactCutOutMaterials.TryGetValue(voxelMat, out value);
                    value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed);
                    exactCutOutMaterials[voxelMat] = value;
                }
            }

            if (removedSum > 0 && updateSync && Sync.IsServer)
            {
                shape.SendDrillCutOutRequest(voxelMap);
            }

            ProfilerShort.BeginNextBlock("Write");


            if (removedSum > 0 && !onlyCheck)
            {
                //  Clear all small voxel that may have been created during explosion. They can be created even outside the range of
                //  explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the
                //  explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we
                //  will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove
                //  B voxels too.
                //!! TODO AR & MK : check if this is needed !!
                RemoveSmallVoxelsUsingChachedVoxels();

                voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax);
            }
            ProfilerShort.End();


            voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f;

            if (removedSum > 0)
            {
                CheckNeighbourStaticGridsAfterVoxelChanged(MyVoxelBase.OperationType.Cut, voxelMap, shape);
            }

            ProfilerShort.End();
        }
        public void ReadRange(MyStorageDataCache target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax)
        {
            ProfilerShort.Begin(GetType().Name + ".ReadRange");
            try
            {
                const int SUBRANGE_SIZE_SHIFT = 3;
                const int SUBRANGE_SIZE = 1 << SUBRANGE_SIZE_SHIFT;
                var threshold = new Vector3I(SUBRANGE_SIZE);
                var rangeSize = lodVoxelRangeMax - lodVoxelRangeMin + 1;
                if ((dataToRead & MyStorageDataTypeFlags.Content) != 0)
                {
                    target.ClearContent(0);
                }
                if ((dataToRead & MyStorageDataTypeFlags.Material) != 0)
                {
                    //target.ClearMaterials(m_defaultMaterial);
                }

                if (rangeSize.X <= threshold.X &&
                    rangeSize.Y <= threshold.Y &&
                    rangeSize.Z <= threshold.Z)
                {
                    using (m_lock.AcquireSharedUsing())
                    {
                        ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax);
                    }
                }
                else
                {
                    // splitting to smaller ranges to make sure the lock is not held for too long, preventing write on update thread
                    // subranges could be aligned to multiple of their size for possibly better performance
                    var steps = (rangeSize - 1) >> SUBRANGE_SIZE_SHIFT;
                    for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref steps); it.IsValid(); it.MoveNext())
                    {
                        var offset = it.Current << SUBRANGE_SIZE_SHIFT;
                        var min = lodVoxelRangeMin + offset;
                        var max = min + SUBRANGE_SIZE - 1;
                        Vector3I.Min(ref max, ref lodVoxelRangeMax, out max);
                        Debug.Assert(min.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax));
                        Debug.Assert(max.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax));
                        using (m_lock.AcquireSharedUsing())
                        {
                            ReadRangeInternal(target, ref offset, dataToRead, lodIndex, ref min, ref max);
                        }
                    }
                }
            }
            finally
            {
                ProfilerShort.End();
            }
        }
        private void ProcessMorphTargetCollisions(MyPrecalcJobRender.Args args, float vertexCellSizeInParentLod)
        {
            // Process collisions.
            // Remove collided vertices from map and add them to the list of collisions.
            for (int i = 0; i < m_collisionList.Count; ++i)
            {
                var vertexA = m_collisionList[i];
                Vertex vertexB;
                if (m_morphMap.TryGetValue(vertexA.Cell, out vertexB))
                {
                    m_morphMap.Remove(vertexA.Cell);
                    m_collisionList.Add(vertexB);
                }
            }

            // Try find better position for each vertex involved in collision.
            // mk:TODO This would ideally be done wthout MyVoxelCoordSystems
            float vertexHalfExpand = 0.25f * vertexCellSizeInParentLod;
            for (int i = 0; i < m_collisionList.Count; ++i)
            {
                var vertex = m_collisionList[i];
                var center = vertex.Target.Position;
                var min = center - vertexHalfExpand;
                var max = center + vertexHalfExpand;
                Vector3I minVertexCell, maxVertexCell;
                MyVoxelCoordSystems.LocalPositionToVertexCell(args.Cell.Lod + 1, ref min, out minVertexCell);
                MyVoxelCoordSystems.LocalPositionToVertexCell(args.Cell.Lod + 1, ref max, out maxVertexCell);
                if (minVertexCell == maxVertexCell)
                {
                    m_morphMap[minVertexCell] = vertex;
                }
                else
                {
                    for (var it = new Vector3I.RangeIterator(ref minVertexCell, ref maxVertexCell); it.IsValid(); it.MoveNext())
                    {
                        if (!m_morphMap.ContainsKey(it.Current))
                            m_morphMap[it.Current] = vertex;
                    }
                }
            }
            m_collisionList.Clear();
        }
        private void EnsureMorphTargetExists(MyPrecalcJobRender.Args args, MyIsoMesh highResMesh)
        {
            // Ensure as many (ideally all) vertices have some mapping prepared.
            // This is here to resolve any missing parent only once for each vertex (main loop can visit vertices for each triangle they appear in).
            //var geometryData = highResMesh;
            for (int i = 0; i < highResMesh.VerticesCount; ++i)
            {
                Vector3 highResPosition = highResMesh.Positions[i];
                Vertex lowResVertex;

                Vector3I vertexCell = highResMesh.Cells[i] >> 1;
                if (!m_morphMap.TryGetValue(vertexCell, out lowResVertex))
                {
                    float scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << args.Cell.Lod);
                    Vector3 cell = highResPosition / scale;
                    cell *= 0.5f;
                    scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << (args.Cell.Lod + 1));
                    Vector3 lowResPosition = cell * scale;
                    var cellMin = vertexCell;
                    var cellMax = vertexCell + 1; // usually I need to find parent in this direction
                    float nearestDist = float.PositiveInfinity;
                    int nearestDistManhat = int.MaxValue;
                    Vector3I? nearestCell = null;
                    for (var it = new Vector3I.RangeIterator(ref cellMin, ref cellMax); it.IsValid(); it.MoveNext())
                    {
                        Vertex morph;
                        if (m_morphMap.TryGetValue(it.Current, out morph))
                        {
                            var tmp = it.Current - cellMin;
                            int distManhat = tmp.X + tmp.Y + tmp.Z;
                            float dist = (morph.Target.Position - lowResPosition).LengthSquared();
                            if (distManhat < nearestDistManhat ||
                                (distManhat == nearestDistManhat && dist < nearestDist))
                            {
                                nearestDist = dist;
                                nearestDistManhat = distManhat;
                                nearestCell = it.Current;
                            }
                        }
                    }

                    if (nearestCell.HasValue)
                    {
                        m_morphMap.Add(vertexCell, m_morphMap[nearestCell.Value]);
                    }
                    else
                    {
                        //Debug.Fail("I'm screwed");
                    }
                }
            }
        }
            private int GetDivideIndex(ref Vector3I renderCellCoord)
            {
                // TODO: Optimize
                int divideIndex = 0;
                if (m_lodDivisions > 1)
                {
                    BoundingBoxD lodAabb = m_boundingBoxes.GetAabb(m_boundingBoxes.GetRoot());
                    Vector3I test = Vector3I.Round(lodAabb.Size / (double)MyVoxelCoordSystems.RenderCellSizeInMeters(m_lod));
                    //Vector3I lodSizeMinusOne = m_parentClipmap.LodSizeMinusOne(m_lod);
                    //Vector3I lodSize = lodSizeMinusOne + Vector3I.One;
                    Vector3I lodSize = test;
                    Vector3I lodSizeMinusOne = test - 1;
                    Vector3I lodDivision = Vector3I.One * (m_lodDivisions - 1);

                    var cellIterator = new Vector3I.RangeIterator(ref Vector3I.Zero, ref lodDivision);
                    for (; cellIterator.IsValid(); cellIterator.MoveNext())
                    {
                        Vector3I currentDivision = cellIterator.Current;
                        Vector3I min = currentDivision * lodSize / m_lodDivisions;
                        Vector3I max = (currentDivision + Vector3I.One) * lodSize / m_lodDivisions;
                        if (renderCellCoord.IsInsideInclusive(ref min, ref max))
                            break;
                    }
                    Debug.Assert(cellIterator.IsValid(), "Valid division index not found!");
                    Vector3I foundCell = cellIterator.Current;
                    divideIndex = GetDivideIndexFromMergeCell(ref foundCell);
                }
                return divideIndex;
            }
        public static void CutOutShapeWithProperties(
            MyVoxelBase voxelMap,
            MyShape shape,
            out float voxelsCountInPercent,
            out MyVoxelMaterialDefinition voxelMaterial,
            Dictionary <MyVoxelMaterialDefinition, int> exactCutOutMaterials = null,
            bool updateSync = false,
            bool onlyCheck  = false)
        {
            ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()");

            int originalSum = 0;
            int removedSum  = 0;

            var      bbox = shape.GetWorldBoundaries();
            Vector3I minCorner, maxCorner;

            ComputeShapeBounds(ref bbox, voxelMap.PositionLeftBottomCorner, voxelMap.Storage.Size, out minCorner, out maxCorner);

            var cacheMin = minCorner - 1;
            var cacheMax = maxCorner + 1;

            voxelMap.Storage.ClampVoxelCoord(ref cacheMin);
            voxelMap.Storage.ClampVoxelCoord(ref cacheMax);
            m_cache.Resize(cacheMin, cacheMax);
            voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cacheMin, ref cacheMax);

            {
                var      shapeCenter = bbox.Center;
                Vector3I exactCenter;
                MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref shapeCenter, out exactCenter);
                exactCenter  -= cacheMin;
                exactCenter   = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1);
                voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter));
            }

            for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext())
            {
                var relPos   = it.Current - cacheMin; // get original amount
                var original = m_cache.Content(ref relPos);

                if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove
                {
                    continue;
                }

                Vector3D vpos;
                MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos);
                var volume = shape.GetVolume(ref vpos);

                if (volume == 0f) // if there is no intersection
                {
                    continue;
                }

                var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL);
                var voxelMat  = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref relPos));
                var toRemove  = (int)(maxRemove * voxelMat.DamageRatio);
                var newVal    = MathHelper.Clamp(original - toRemove, 0, maxRemove);
                var removed   = Math.Abs(original - newVal);

                if (!onlyCheck)
                {
                    m_cache.Content(ref relPos, (byte)newVal);
                }

                originalSum += original;
                removedSum  += removed;

                if (exactCutOutMaterials != null)
                {
                    int value = 0;
                    exactCutOutMaterials.TryGetValue(voxelMat, out value);
                    value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed);
                    exactCutOutMaterials[voxelMat] = value;
                }
            }

            if (removedSum > 0 && !onlyCheck)
            {
                //  Clear all small voxel that may have been created during explosion. They can be created even outside the range of
                //  explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the
                //  explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we
                //  will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove
                //  B voxels too.
                //!! TODO AR & MK : check if this is needed !!
                RemoveSmallVoxelsUsingChachedVoxels();

                voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax);
            }

            if (removedSum > 0 && updateSync && Sync.IsServer)
            {
                shape.SendDrillCutOutRequest(voxelMap.SyncObject);
            }

            voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f;
            ProfilerShort.End();
        }
        private void ProcessMorphTargetCollisions(MyPrecalcJobRender.Args args, float vertexCellSizeInParentLod)
        {
            // Process collisions.
            // Remove collided vertices from map and add them to the list of collisions.
            for (int i = 0; i < m_collisionList.Count; ++i)
            {
                var    vertexA = m_collisionList[i];
                Vertex vertexB;
                if (m_morphMap.TryGetValue(vertexA.Cell, out vertexB))
                {
                    m_morphMap.Remove(vertexA.Cell);
                    m_collisionList.Add(vertexB);
                }
            }

            // Try find better position for each vertex involved in collision.
            // mk:TODO This would ideally be done wthout MyVoxelCoordSystems
            float vertexHalfExpand = 0.25f * vertexCellSizeInParentLod;

            for (int i = 0; i < m_collisionList.Count; ++i)
            {
                var      vertex = m_collisionList[i];
                var      center = vertex.Target.Position;
                var      min = center - vertexHalfExpand;
                var      max = center + vertexHalfExpand;
                Vector3I minVertexCell, maxVertexCell;
                MyVoxelCoordSystems.LocalPositionToVertexCell(args.Cell.Lod + 1, ref min, out minVertexCell);
                MyVoxelCoordSystems.LocalPositionToVertexCell(args.Cell.Lod + 1, ref max, out maxVertexCell);
                if (minVertexCell == maxVertexCell)
                {
                    m_morphMap[minVertexCell] = vertex;
                }
                else
                {
                    for (var it = new Vector3I.RangeIterator(ref minVertexCell, ref maxVertexCell); it.IsValid(); it.MoveNext())
                    {
                        if (!m_morphMap.ContainsKey(it.Current))
                        {
                            m_morphMap[it.Current] = vertex;
                        }
                    }
                }
            }
            m_collisionList.Clear();
        }
        public static void PaintInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx)
        {
            Vector3I minCorner, maxCorner, numCells;

            GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells);

            for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext())
            {
                Vector3I cellMinCorner, cellMaxCorner;
                GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner);

                m_cache.Resize(cellMinCorner, cellMaxCorner);
                voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, 0, ref cellMinCorner, ref cellMaxCorner);

                for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext())
                {
                    var relPos = it.Current - cellMinCorner;

                    Vector3D vpos;
                    MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos);
                    float volume = shape.GetVolume(ref vpos);
                    if (volume > 0.5f)
                    {
                        m_cache.Material(ref relPos, materialIdx); // set material
                    }
                }

                voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Material, ref cellMinCorner, ref cellMaxCorner);
            }
        }
        public static void CutOutShapeWithProperties(
            MyVoxelBase voxelMap,
            MyShape shape,
            out float voxelsCountInPercent,
            out MyVoxelMaterialDefinition voxelMaterial,
            Dictionary<MyVoxelMaterialDefinition, int> exactCutOutMaterials = null,
            bool updateSync = false,
            bool onlyCheck = false)
        {
            ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()");

            int originalSum = 0;
            int removedSum = 0;

            var bbox = shape.GetWorldBoundaries();
            Vector3I minCorner, maxCorner;
            ComputeShapeBounds(ref bbox, voxelMap.PositionLeftBottomCorner, voxelMap.Storage.Size, out minCorner, out maxCorner);

            var cacheMin = minCorner - 1;
            var cacheMax = maxCorner + 1;
            voxelMap.Storage.ClampVoxelCoord(ref cacheMin);
            voxelMap.Storage.ClampVoxelCoord(ref cacheMax);
            m_cache.Resize(cacheMin, cacheMax);
            voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cacheMin, ref cacheMax);

            {
                var shapeCenter = bbox.Center;
                Vector3I exactCenter;
                MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref shapeCenter, out exactCenter);
                exactCenter -= cacheMin;
                exactCenter = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1);
                voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter));
            }

            for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext())
            {
                var relPos   = it.Current - cacheMin; // get original amount
                var original = m_cache.Content(ref relPos);

                if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove
                    continue;

                Vector3D vpos;
                MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos);
                var volume = shape.GetVolume(ref vpos);

                if (volume == 0f) // if there is no intersection
                    continue;

                var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL);
                var voxelMat  = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref relPos));
                var toRemove  = (int)(maxRemove * voxelMat.DamageRatio);
                var newVal    = MathHelper.Clamp(original - toRemove, 0, maxRemove);
                var removed   = Math.Abs(original - newVal);

                if (!onlyCheck)
                    m_cache.Content(ref relPos, (byte)newVal);

                originalSum += original;
                removedSum  += removed;

                if (exactCutOutMaterials != null)
                {
                    int value = 0;
                    exactCutOutMaterials.TryGetValue(voxelMat, out value);
                    value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed);
                    exactCutOutMaterials[voxelMat] = value;
                }
            }

            if (removedSum > 0 && !onlyCheck)
            {
                //  Clear all small voxel that may have been created during explosion. They can be created even outside the range of
                //  explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the
                //  explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we
                //  will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove
                //  B voxels too.
                //!! TODO AR & MK : check if this is needed !!
                RemoveSmallVoxelsUsingChachedVoxels();

                voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax);
            }

            if (removedSum > 0 && updateSync && Sync.IsServer)
            {
                shape.SendDrillCutOutRequest(voxelMap.SyncObject);
            }

            voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f;
            ProfilerShort.End();
        }
Exemple #25
0
        public void GenerateFloraGraphics(Vector3D pos)
        {
            Debug.Assert(m_planetEnvironmentSectors != null, "null environment sector");
            if (m_planetEnvironmentSectors == null)
            {
                return;
            }

            Vector3D gravity       = GetWorldGravityNormalized(ref pos);
            Vector3D perpedincular = MyUtils.GetRandomPerpendicularVector(ref gravity);
            Vector3D third         = Vector3D.Cross(gravity, perpedincular);

            perpedincular += third;

            Vector3I min = new Vector3I(-ENVIROMENT_EXTEND);
            Vector3I max = new Vector3I(ENVIROMENT_EXTEND);

            Vector3 offset = new Vector3(-MyPlanetEnvironmentSector.SECTOR_SIZE_METERS);

            for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.MoveNext())
            {
                Vector3D currentPos = pos + it.Current * offset * perpedincular;
                currentPos = PlaceToOrbit(currentPos, ref gravity);

                Vector3I newSector = Vector3I.Floor(currentPos / MyPlanetEnvironmentSector.SECTOR_SIZE_METERS);
                MyPlanetEnvironmentSector sector;
                if (true == m_planetEnvironmentSectors.TryGetValue(newSector, out sector) && sector.HasGraphics == false)
                {
                    sector.UpdateSectorGraphics();
                }
            }
        }
        public static void PaintInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx)
        {
            Vector3I minCorner, maxCorner, numCells;
            GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells);

            for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext())
            {
                Vector3I cellMinCorner, cellMaxCorner;
                GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner);

                m_cache.Resize(cellMinCorner, cellMaxCorner);
                voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, 0, ref cellMinCorner, ref cellMaxCorner);

                for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext())
                {
                    var relPos = it.Current - cellMinCorner;

                    Vector3D vpos;
                    MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos);
                    float volume = shape.GetVolume(ref vpos);
                    if (volume > 0.5f)
                        m_cache.Material(ref relPos, materialIdx); // set material
                }

                voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Material, ref cellMinCorner, ref cellMaxCorner);
            }
        }
        public void ReadRange(MyStorageDataCache target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax)
        {
            ProfilerShort.Begin(GetType().Name + ".ReadRange");
            try
            {
                const int SUBRANGE_SIZE_SHIFT = 3;
                const int SUBRANGE_SIZE       = 1 << SUBRANGE_SIZE_SHIFT;
                var       threshold           = new Vector3I(SUBRANGE_SIZE);
                var       rangeSize           = lodVoxelRangeMax - lodVoxelRangeMin + 1;
                if ((dataToRead & MyStorageDataTypeFlags.Content) != 0)
                {
                    target.ClearContent(0);
                }
                if ((dataToRead & MyStorageDataTypeFlags.Material) != 0)
                {
                    target.ClearMaterials(m_defaultMaterial);
                }

                if (rangeSize.X <= threshold.X &&
                    rangeSize.Y <= threshold.Y &&
                    rangeSize.Z <= threshold.Z)
                {
                    using (m_lock.AcquireSharedUsing())
                    {
                        ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax);
                    }
                }
                else
                {
                    // splitting to smaller ranges to make sure the lock is not held for too long, preventing write on update thread
                    // subranges could be aligned to multiple of their size for possibly better performance
                    var steps = (rangeSize - 1) >> SUBRANGE_SIZE_SHIFT;
                    for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref steps); it.IsValid(); it.MoveNext())
                    {
                        var offset = it.Current << SUBRANGE_SIZE_SHIFT;
                        var min    = lodVoxelRangeMin + offset;
                        var max    = min + SUBRANGE_SIZE - 1;
                        Vector3I.Min(ref max, ref lodVoxelRangeMax, out max);
                        Debug.Assert(min.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax));
                        Debug.Assert(max.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax));
                        using (m_lock.AcquireSharedUsing())
                        {
                            ReadRangeInternal(target, ref offset, dataToRead, lodIndex, ref min, ref max);
                        }
                    }
                }
            }
            finally
            {
                ProfilerShort.End();
            }
        }
Exemple #28
0
        public void PrefetchShapeOnRay(ref LineD ray)
        {
            Vector3I minCorner, maxCorner;
            MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref ray.From, out minCorner);
            MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref ray.To, out maxCorner);

            minCorner /= PHYSICS_SECTOR_SIZE_METERS;
            maxCorner /= PHYSICS_SECTOR_SIZE_METERS;

            for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner);
                it.IsValid(); it.MoveNext())
            {
               if(m_physicsShapes.ContainsKey(it.Current))
               {
                   m_physicsShapes[it.Current].PrefetchShapeOnRay(ref ray);
               }
            }
        }
Exemple #29
0
        private void FindForestInitialCandidate()
        {
            BoundingBoxD groundBox = m_ground.PositionComp.WorldAABB;
            Vector3D boxSize = groundBox.Size;
            boxSize *= 0.1f;
            groundBox.Inflate(-boxSize);
            MyBBSetSampler sampler = new MyBBSetSampler(groundBox.Min, groundBox.Max);

            bool posIsValid = true;
            Vector3D worldPos = default(Vector3D);
            int counter = 0;
            do
            {
                // find random position for starting 
                worldPos = sampler.Sample();
                var worldPosProjected = worldPos;
                worldPosProjected.Y = 0.5f;
                posIsValid = true;
                counter++;
                Vector3D areaCheck = new Vector3D(20, 20, 20);
                foreach (var enqueued in m_initialForestLocations)
                {
                    // only interested in XZ plane
                    BoundingBoxD tmp = new BoundingBoxD(enqueued - areaCheck, enqueued + areaCheck);
                    tmp.Min.Y = 0;
                    tmp.Max.Y = 1;

                    if (tmp.Contains(worldPosProjected) == ContainmentType.Contains)
                    {
                        posIsValid = false;
                        break;
                    }
                }
            } while (!posIsValid && counter != 10);

            if (!posIsValid)
            {
                // could not find any position
                return;
            }

            var lineStart = new Vector3D(worldPos.X, groundBox.Max.Y, worldPos.Z);
            var lineEnd = new Vector3D(worldPos.X, groundBox.Min.Y, worldPos.Z);
            LineD line = new LineD(lineStart, lineEnd);
            MyIntersectionResultLineTriangleEx? result = null;
            var correctGroundDefinition = MyDefinitionManager.Static.GetVoxelMaterialDefinition("Grass");
            var materialId = correctGroundDefinition.Index;

            if (m_ground.GetIntersectionWithLine(ref line, out result, VRage.Components.IntersectionFlags.DIRECT_TRIANGLES))
            {
                Vector3D intersectionPoint = result.Value.IntersectionPointInWorldSpace;
                Vector3I voxelCoord, minRead, maxRead;
                MyVoxelCoordSystems.WorldPositionToVoxelCoord(m_ground.PositionLeftBottomCorner, ref intersectionPoint, out voxelCoord);
                minRead = voxelCoord - Vector3I.One;
                maxRead = voxelCoord + Vector3I.One;
                m_ground.Storage.ReadRange(m_voxelCache, MyStorageDataTypeFlags.Material, 0, ref minRead, ref maxRead);

                var minLocal = Vector3I.Zero;
                var maxLocal = Vector3I.One * 2;
                var it = new Vector3I.RangeIterator(ref minLocal, ref maxLocal);
                while (it.IsValid())
                {
                    var vec = it.Current;
                    var material = m_voxelCache.Material(ref vec);
                    if (material == materialId)
                    {
                        // found a location
                        var desired = voxelCoord - Vector3I.One + vec;
                        Vector3D desiredWorldPosition = default(Vector3D);
                        MyVoxelCoordSystems.VoxelCoordToWorldPosition(m_ground.PositionLeftBottomCorner, ref desired, out desiredWorldPosition);
                        m_initialForestLocations.Enqueue(desiredWorldPosition);
                        break;
                    }

                    it.MoveNext();
                }
            }
        }
Exemple #30
0
        public void GenerateFloraGraphics(Vector3D pos)
        {
            Debug.Assert(m_planetEnvironmentSectors != null, "null environment sector");
            if (m_planetEnvironmentSectors == null)
            {
                return;
            }

            Vector3D gravity = GetWorldGravityNormalized(ref pos);
            Vector3D perpedincular = MyUtils.GetRandomPerpendicularVector(ref gravity);
            Vector3D third = Vector3D.Cross(gravity, perpedincular);

            perpedincular += third;

            Vector3I min = new Vector3I(-ENVIROMENT_EXTEND);
            Vector3I max = new Vector3I(ENVIROMENT_EXTEND);

            Vector3 offset = new Vector3(-MyPlanetEnvironmentSector.SECTOR_SIZE_METERS);
            for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.MoveNext())
            {
                Vector3D currentPos = pos + it.Current * offset * perpedincular;
                currentPos = PlaceToOrbit(currentPos, ref gravity);

                Vector3I newSector = Vector3I.Floor(currentPos / MyPlanetEnvironmentSector.SECTOR_SIZE_METERS);
                MyPlanetEnvironmentSector sector;
                if (true == m_planetEnvironmentSectors.TryGetValue(newSector, out sector) && sector.HasGraphics == false)
                {
                    sector.UpdateSectorGraphics();
                }
            }

        }
        public static ulong FillInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx)
        {
            Vector3I minCorner, maxCorner, numCells;
            ulong retValue = 0;
            GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells);

            for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext())
            {
                Vector3I cellMinCorner, cellMaxCorner;
                GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner);

                Vector3I originalMinCorner = cellMinCorner;
                Vector3I originalMaxCorner = cellMaxCorner;

                voxelMap.Storage.ClampVoxelCoord(ref cellMinCorner, VOXEL_CLAMP_BORDER_DISTANCE);
                voxelMap.Storage.ClampVoxelCoord(ref cellMaxCorner, VOXEL_CLAMP_BORDER_DISTANCE);

                ClampingInfo minCornerClamping = CheckForClamping(originalMinCorner, cellMinCorner);
                ClampingInfo maxCornerClamping = CheckForClamping(originalMaxCorner, cellMaxCorner);

                m_cache.Resize(cellMinCorner, cellMaxCorner);
                voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cellMinCorner, ref cellMaxCorner);

                ulong filledSum = 0;

                for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext())
                {
                    var relPos = it.Current - cellMinCorner; // get original amount
                    var original = m_cache.Content(ref relPos);

                    if (original == MyVoxelConstants.VOXEL_CONTENT_FULL) // if there is nothing to add
                        continue;

                    //if there was some claping, fill the clamp region with material 
                    if ((it.Current.X == cellMinCorner.X && minCornerClamping.X) || (it.Current.X == cellMaxCorner.X && maxCornerClamping.X) ||
                        (it.Current.Y == cellMinCorner.Y && minCornerClamping.Y) || (it.Current.Y == cellMaxCorner.Y && maxCornerClamping.Y) ||
                        (it.Current.Z == cellMinCorner.Z && minCornerClamping.Z) || (it.Current.Z == cellMaxCorner.Z && maxCornerClamping.Z))
                    {
                        m_cache.Material(ref relPos, materialIdx);
                        continue;
                    }

                    Vector3D vpos;
                    MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos);
                    var volume = shape.GetVolume(ref vpos);


                    if (volume <= 0f) // there is nothing to fill
                        continue;

                    m_cache.Material(ref relPos, materialIdx); // set material

                    var toFill = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL);
                    long newVal = MathHelper.Clamp(original + toFill, 0, Math.Max(original, toFill));

                    m_cache.Content(ref relPos, (byte)newVal);
                    filledSum += (ulong)(newVal - original);
                }
                if (filledSum > 0)
                {
                    RemoveSmallVoxelsUsingChachedVoxels();
                    voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, ref cellMinCorner, ref cellMaxCorner);
                }

                retValue += filledSum;
            }

            return retValue;
        }
Exemple #32
0
        public void SpawnFlora(Vector3D pos)
        {
            if (m_planetEnvironmentSectors == null)
            {
                m_planetEnvironmentSectors = new Dictionary<Vector3I, MyPlanetEnvironmentSector>(500);
            }

            Vector3D gravity = GetWorldGravityNormalized(ref pos);
            Vector3D perpedincular = MyUtils.GetRandomPerpendicularVector(ref gravity);
            Vector3D third = Vector3D.Cross(gravity, perpedincular);

            perpedincular += third;

            Vector3I min = new Vector3I(-ENVIROMENT_EXTEND);
            Vector3I max = new Vector3I(ENVIROMENT_EXTEND);

            Vector3 offset = new Vector3(-MyPlanetEnvironmentSector.SECTOR_SIZE_METERS);

            for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.MoveNext())
            {
                Vector3D currentPos = pos + it.Current * offset * perpedincular;
                currentPos = PlaceToOrbit(currentPos, ref gravity);

                if (false == ChekPosition(currentPos))
                {
                    Vector3I newSector = Vector3I.Floor(currentPos / MyPlanetEnvironmentSector.SECTOR_SIZE_METERS);
                    if (m_planetSectorsPool == null)
                    {
                        m_planetSectorsPool = new MyDynamicObjectPool<MyPlanetEnvironmentSector>(400);
                    }
                   

                    MyPlanetEnvironmentSector sector = m_planetSectorsPool.Allocate();

                    sector.Init(ref newSector, this);
                    m_planetEnvironmentSectors[newSector] = sector;
                    sector.PlaceItems();
                }
            }

            Vector3I sectorCoords = Vector3I.Floor(PlaceToOrbit(pos, ref gravity) / MyPlanetEnvironmentSector.SECTOR_SIZE_METERS);

            Vector3I keepMin = sectorCoords + new Vector3I(-ENVIROMENT_EXTEND_KEEP);
            Vector3I keepMax = sectorCoords + new Vector3I(ENVIROMENT_EXTEND_KEEP);

            foreach (var enviromentSector in m_planetEnvironmentSectors)
            {
                if (enviromentSector.Key.IsInsideInclusive(keepMin, keepMax))
                {
                    m_sectorsToKeep.Add(enviromentSector.Key);
                }
            }
        }
        public static ulong CutOutShape(MyVoxelBase voxelMap, MyShape shape)
        {
            Vector3I minCorner, maxCorner, numCells;
            GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells);
            ulong changedVolumeAmount = 0;

            for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext())
            {
                Vector3I cellMinCorner, cellMaxCorner;
                GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner);

                var cacheMin = cellMinCorner - 1;
                var cacheMax = cellMaxCorner + 1;
                voxelMap.Storage.ClampVoxelCoord(ref cacheMin);
                voxelMap.Storage.ClampVoxelCoord(ref cacheMax);

                ulong removedSum = 0;
                m_cache.Resize(cacheMin, cacheMax);
                voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, 0, ref cacheMin, ref cacheMax);

                for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext())
                {
                    var relPos = it.Current - cacheMin; // get original amount
                    var original = m_cache.Content(ref relPos);

                    if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove
                        continue;

                    Vector3D vpos;
                    MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos);
                    var volume = shape.GetVolume(ref vpos);

                    if (volume == 0f) // if there is no intersection
                        continue;

                    var toRemove = (int)(MyVoxelConstants.VOXEL_CONTENT_FULL - (volume * MyVoxelConstants.VOXEL_CONTENT_FULL));
                    var newVal = Math.Min(toRemove, original);
                    ulong removed = (ulong)Math.Abs(original - newVal);

                    m_cache.Content(ref relPos, (byte)newVal);
                    removedSum += removed;
                }

                if (removedSum > 0)
                {
                    RemoveSmallVoxelsUsingChachedVoxels(); // must stay because of the around when filling voxels
                    voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax);
                }

                changedVolumeAmount += removedSum;
            }

            return changedVolumeAmount;
        }
        public void ReadRange(MyStorageData target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax, ref MyVoxelRequestFlags requestFlags)
        {
            ProfilerShort.Begin(GetType().Name + ".ReadRange");
            try
            {
                const int SUBRANGE_SIZE_SHIFT = 3;
                const int SUBRANGE_SIZE = 1 << SUBRANGE_SIZE_SHIFT;
                var threshold = new Vector3I(SUBRANGE_SIZE);
                var rangeSize = lodVoxelRangeMax - lodVoxelRangeMin + 1;
                if ((dataToRead & MyStorageDataTypeFlags.Content) != 0)
                {
                    target.ClearContent(0);
                }

                if ((rangeSize.X <= threshold.X &&
                    rangeSize.Y <= threshold.Y &&
                    rangeSize.Z <= threshold.Z) || !MyFakes.ENABLE_SPLIT_VOXEL_READ_QUERIES)
                {
                    using (m_lock.AcquireSharedUsing())
                    {
                        ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags);
                    }
                }
                else
                {
                    // These optimizations don't work when splitting the range.
                    requestFlags &= ~(MyVoxelRequestFlags.OneMaterial | MyVoxelRequestFlags.ContentChecked);
                    MyVoxelRequestFlags flags = requestFlags;

                    // splitting to smaller ranges to make sure the lock is not held for too long, preventing write on update thread
                    // subranges could be aligned to multiple of their size for possibly better performance
                    var steps = (rangeSize - 1) >> SUBRANGE_SIZE_SHIFT;
                    for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref steps); it.IsValid(); it.MoveNext())
                    {
                        flags = requestFlags;
                        var offset = it.Current << SUBRANGE_SIZE_SHIFT;
                        var min = lodVoxelRangeMin + offset;
                        var max = min + SUBRANGE_SIZE - 1;
                        Vector3I.Min(ref max, ref lodVoxelRangeMax, out max);
                        Debug.Assert(min.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax));
                        Debug.Assert(max.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax));
                        using (m_lock.AcquireSharedUsing())
                        {
                            ReadRangeInternal(target, ref offset, dataToRead, lodIndex, ref min, ref max, ref flags);
                        }
                    }

                    // If the storage is consistent this should be fine.
                    requestFlags = flags;
                }
            }
            finally
            {
                ProfilerShort.End();
            }
        }