// Actually, this function marks even cubes around the block to make sure that any changes caused in their triangles
        // will be reflected in the navigation mesh.
        public void MarkBlockChanged(MySlimBlock block)
        {
            Vector3I min = block.Min - Vector3I.One;
            Vector3I max = block.Max + Vector3I.One;

            Vector3I pos = min;

            for (var it = new Vector3I.RangeIterator(ref block.Min, ref block.Max); it.IsValid(); it.GetNext(out pos))
            {
                m_changedCubes.Add(pos);
            }

            Vector3I minCell = CubeToCell(ref min);
            Vector3I maxCell = CubeToCell(ref max);

            pos = minCell;
            for (var it = new Vector3I.RangeIterator(ref minCell, ref maxCell); it.IsValid(); it.GetNext(out pos))
            {
                m_changedCells.Add(pos);

                MyCellCoord cellCoord  = new MyCellCoord(0, pos);
                ulong       packedCell = cellCoord.PackId64();

                TryClearCell(packedCell);
            }
        }
Exemple #2
0
        protected override void Init(MyObjectBuilder_DefinitionBase ob)
        {
            base.Init(ob);

            var objectBuilder = ob as MyObjectBuilder_BlockNavigationDefinition;

            Debug.Assert(ob != null);
            if (ob == null)
            {
                return;
            }

            if (objectBuilder.NoEntry || objectBuilder.Triangles == null)
            {
                NoEntry = true;
            }
            else
            {
                NoEntry = false;
                var newMesh = new MyGridNavigationMesh(null, null, objectBuilder.Triangles.Length);

                Vector3I maxPos = objectBuilder.Size - Vector3I.One - objectBuilder.Center;
                Vector3I minPos = -(Vector3I)(objectBuilder.Center);

                foreach (var triOb in objectBuilder.Triangles)
                {
                    Vector3 pa = (Vector3)triOb.Points[0];
                    Vector3 pb = (Vector3)triOb.Points[1];
                    Vector3 pc = (Vector3)triOb.Points[2];

                    var tri = newMesh.AddTriangle(ref pa, ref pb, ref pc);

                    var center = (pa + pb + pc) / 3.0f;

                    // We want to move the triangle vertices more towards the triangle center to ensure correct calculation of containing cube
                    Vector3  cvA      = (center - pa) * 0.0001f;
                    Vector3  cvB      = (center - pb) * 0.0001f;
                    Vector3  cvC      = (center - pc) * 0.0001f;
                    Vector3I gridPosA = Vector3I.Round(pa + cvA);
                    Vector3I gridPosB = Vector3I.Round(pb + cvB);
                    Vector3I gridPosC = Vector3I.Round(pc + cvC);
                    Vector3I.Clamp(ref gridPosA, ref minPos, ref maxPos, out gridPosA);
                    Vector3I.Clamp(ref gridPosB, ref minPos, ref maxPos, out gridPosB);
                    Vector3I.Clamp(ref gridPosC, ref minPos, ref maxPos, out gridPosC);
                    Vector3I min, max;
                    Vector3I.Min(ref gridPosA, ref gridPosB, out min);
                    Vector3I.Min(ref min, ref gridPosC, out min);
                    Vector3I.Max(ref gridPosA, ref gridPosB, out max);
                    Vector3I.Max(ref max, ref gridPosC, out max);

                    Vector3I pos = min;
                    for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.GetNext(out pos))
                    {
                        newMesh.RegisterTriangle(tri, ref pos);
                    }
                }

                m_mesh = newMesh;
            }
        }
Exemple #3
0
        private MyVoxelPhysics CreatePhysicsShape(ref Vector3I increment, ref Vector3I.RangeIterator it)
        {
            if (m_physicsShapes == null)
            {
                m_physicsShapes = new Dictionary <Vector3I, MyVoxelPhysics>();
            }

            MyVoxelPhysics voxelMap = null;

            if (m_physicsShapes.TryGetValue(it.Current, out voxelMap) == false)
            {
                if (m_hasGeneratedTexture == false)
                {
                    m_storage.DataProvider.GenerateNoiseHelpTexture(m_storage.Size.X);
                    m_hasGeneratedTexture = true;
                }

                voxelMap = new MyVoxelPhysics();

                Vector3I storageMin = it.Current * increment;
                Vector3I storageMax = storageMin + increment;

                voxelMap.EntityId = 0;
                voxelMap.Init(m_storage, this.PositionLeftBottomCorner + storageMin * MyVoxelConstants.VOXEL_SIZE_IN_METRES, storageMin, storageMax, this);
                voxelMap.Save = false;
                m_physicsShapes.Add(it.Current, voxelMap);
                MyEntities.Add(voxelMap);
            }
            return(voxelMap);
        }
Exemple #4
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);
            }
        private Vector3I FindTriangleCube(int triIndex, ref Vector3I edgePositionA, ref Vector3I edgePositionB)
        {
            Vector3I min, max;

            Vector3I.Min(ref edgePositionA, ref edgePositionB, out min);
            Vector3I.Max(ref edgePositionA, ref edgePositionB, out max);
            min = Vector3I.Round(new Vector3(min) / 256.0f - Vector3.Half);
            max = Vector3I.Round(new Vector3(max) / 256.0f + Vector3.Half);

            for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.GetNext(out min))
            {
                List <int> list;
                m_smallTriangleRegistry.TryGetValue(min, out list);
                if (list == null)
                {
                    continue;
                }

                if (list.Contains(triIndex))
                {
                    return(min);
                }
            }

            Debug.Assert(false, "Could not find navmesh triangle cube. Shouldn't get here!");
            return(Vector3I.Zero);
        }
Exemple #6
0
            /// <summary>
            /// Checks only immediate children (any deeper would take too long).
            /// </summary>
            private static bool ChildrenWereLoaded(LodLevel childLod, ref MyCellCoord thisLodCell)
            {
                if (childLod == null)
                {
                    return(false);
                }

                Debug.Assert(thisLodCell.Lod == childLod.m_lodIndex + 1);

                var childLodCell = new MyCellCoord();

                childLodCell.Lod = childLod.m_lodIndex;
                var shiftToChild = MyVoxelCoordSystems.RenderCellSizeShiftToMoreDetailed(thisLodCell.Lod);
                var start        = thisLodCell.CoordInLod << shiftToChild;
                var end          = start + ((1 << shiftToChild) >> 1);

                Vector3I.Max(ref childLod.m_lodSizeMinusOne, ref Vector3I.Zero, out childLod.m_lodSizeMinusOne);
                Vector3I.Min(ref end, ref childLod.m_lodSizeMinusOne, out end);
                childLodCell.CoordInLod = start;
                for (var it = new Vector3I.RangeIterator(ref start, ref end);
                     it.IsValid(); it.GetNext(out childLodCell.CoordInLod))
                {
                    var      key = childLodCell.PackId64();
                    CellData data;
                    if (!childLod.m_storedCellData.TryGetValue(key, out data) || !data.WasLoaded)
                    {
                        return(false);
                    }
                }

                return(true);
            }
Exemple #7
0
        internal void GenerateAllShapes()
        {
            var min = Vector3I.Zero;

            Vector3I storageSize = m_voxelMap.Size;
            Vector3I max         = new Vector3I(0, 0, 0);

            max.X = storageSize.X >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS;
            max.Y = storageSize.Y >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS;
            max.Z = storageSize.Z >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS;

            max += min;

            var args = new MyPrecalcJobPhysicsPrefetch.Args
            {
                GeometryCell  = new MyCellCoord(0, min),
                Storage       = m_voxelMap.Storage,
                TargetPhysics = this,
                Tracker       = m_workTracker,
            };

            for (var it = new Vector3I.RangeIterator(ref min, ref max);
                 it.IsValid();
                 it.GetNext(out args.GeometryCell.CoordInLod))
            {
                MyPrecalcJobPhysicsPrefetch.Start(args);
            }
        }
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;

            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();
        }
        public void InvalidateRange(Vector3I minVoxelChanged, Vector3I maxVoxelChanged)
        {
            minVoxelChanged -= MyPrecalcComponent.InvalidatedRangeInflate;
            maxVoxelChanged += MyPrecalcComponent.InvalidatedRangeInflate;

            m_voxelMap.Storage.ClampVoxelCoord(ref minVoxelChanged);
            m_voxelMap.Storage.ClampVoxelCoord(ref maxVoxelChanged);

            Vector3I minCell, maxCell;

            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref minVoxelChanged, out minCell);
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxVoxelChanged, out maxCell);

            Vector3I currentCell = minCell;

            for (var it = new Vector3I.RangeIterator(ref minCell, ref maxCell); it.IsValid(); it.GetNext(out currentCell))
            {
                if (m_processedCells.Contains(ref currentCell))
                {
                    RemoveCell(currentCell);
                }

                MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, currentCell);
                m_higherLevelHelper.TryClearCell(coord.PackId64());
            }
        }
        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);
            }
        }
Exemple #11
0
        private MyVoxelPhysics CreateVoxelPhysics(ref Vector3I increment, ref Vector3I.RangeIterator it)
        {
            if (m_physicsShapes == null)
            {
                m_physicsShapes = new Dictionary <Vector3I, MyVoxelPhysics>();
            }

            MyVoxelPhysics voxelMap = null;

            if (!m_physicsShapes.TryGetValue(it.Current, out voxelMap))
            {
                Vector3I storageMin = it.Current * increment;
                Vector3I storageMax = storageMin + increment;

                BoundingBox check = new BoundingBox(storageMin, storageMax);

                if (Storage.Intersect(ref check, false) == ContainmentType.Intersects)
                {
                    voxelMap = new MyVoxelPhysics();

                    voxelMap.Init(m_storage,
                                  this.PositionLeftBottomCorner + storageMin * MyVoxelConstants.VOXEL_SIZE_IN_METRES, storageMin,
                                  storageMax, this);
                    voxelMap.Save = false;
                    MyEntities.Add(voxelMap);
                }

                m_physicsShapes.Add(it.Current, voxelMap);
            }
            return(voxelMap);
        }
Exemple #12
0
            internal void InvalidateRange(Vector3I lodMin, Vector3I lodMax)
            {
                //              MyLog.Default.WriteLine("InvalidateRange Lod: " + m_lodIndex + " Min: " + lodMin + " Max: " + lodMax);

                var cell = new MyCellCoord(m_lodIndex, lodMin);

                for (var it = new Vector3I.RangeIterator(ref lodMin, ref lodMax);
                     it.IsValid(); it.GetNext(out cell.CoordInLod))
                {
                    CellData data;
                    var      id = cell.PackId64();
//                    MyLog.Default.WriteLine("Setting to: m_lodIndex " + cell.Lod + " Coord: " + cell.CoordInLod);


                    if (m_storedCellData.TryGetValue(id, out data))
                    {
                        data.State = CellState.Invalid;
                        //MyLog.Default.WriteLine("Really set to: m_lodIndex " + cell.Lod + " Coord: " + cell.CoordInLod);
                    }

                    if (MyClipmap.UseCache)
                    {
                        var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, id);
                        var cachedCell    = MyClipmap.CellsCache.Read(clipmapCellId);
                        if (cachedCell != null)
                        {
                            cachedCell.State = CellState.Invalid;
                        }
                    }
                }
            }
        // Actually, this function marks even cubes around the block to make sure that any changes caused in their triangles
        // will be reflected in the navigation mesh.
        public void MarkBlockChanged(MySlimBlock block)
        {
            Vector3I min = block.Min - Vector3I.One;
            Vector3I max = block.Max + Vector3I.One;

            Vector3I pos = min;
            for (var it = new Vector3I.RangeIterator(ref block.Min, ref block.Max); it.IsValid(); it.GetNext(out pos))
            {
                m_changedCubes.Add(pos);
            }

            Vector3I minCell = CubeToCell(ref min);
            Vector3I maxCell = CubeToCell(ref max);

            pos = minCell;
            for (var it = new Vector3I.RangeIterator(ref minCell, ref maxCell); it.IsValid(); it.GetNext(out pos))
            {
                m_changedCells.Add(pos);

                MyCellCoord cellCoord = new MyCellCoord(0, pos);
                ulong packedCell = cellCoord.PackId64();

                TryClearCell(packedCell);
            }
        }
        private void Segment()
        {
            m_segmentation.ClearInput();

            foreach (var block in m_grid.CubeBlocks)
            {
                Vector3I begin = block.Min;
                Vector3I end   = block.Max;
                Vector3I pos   = begin;
                for (var it = new Vector3I.RangeIterator(ref begin, ref end); it.IsValid(); it.GetNext(out pos))
                {
                    m_segmentation.AddInput(pos);
                }
            }

            var segmentList = m_segmentation.FindSegments(MyVoxelSegmentationType.Simple2);

            m_segments = new List <BoundingBox>(segmentList.Count);
            for (int i = 0; i < segmentList.Count; ++i)
            {
                BoundingBox bb = new BoundingBox();
                bb.Min = (new Vector3(segmentList[i].Min) - Vector3.Half) * m_grid.GridSize - Vector3.Half; // The another half is here to just add some head space
                bb.Max = (new Vector3(segmentList[i].Max) + Vector3.Half) * m_grid.GridSize + Vector3.Half;
                m_segments.Add(bb);
            }

            m_segmentation.ClearInput();
        }
Exemple #15
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 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);
        }
Exemple #17
0
        private MyShipMergeBlock GetOtherMergeBlock()
        {
            Vector3I minI, maxI;

            CalculateMergeArea(out minI, out maxI);

            Vector3I pos = minI;

            for (Vector3I.RangeIterator it = new Vector3I.RangeIterator(ref minI, ref maxI); it.IsValid(); it.GetNext(out pos))
            {
                var block = this.CubeGrid.GetCubeBlock(pos);
                if (block != null && block.FatBlock != null)
                {
                    var mergeBlock = block.FatBlock as MyShipMergeBlock;
                    if (mergeBlock == null)
                    {
                        continue;
                    }

                    Vector3I otherMinI, otherMaxI;
                    mergeBlock.CalculateMergeArea(out otherMinI, out otherMaxI);
                    Vector3I faceNormal = Base6Directions.GetIntVector(this.Orientation.TransformDirection(m_forward));

                    // Bounding box test of minI <-> maxI and otherMinI(shifted by faceNormal) <-> otherMaxI(shifted by faceNormal)
                    otherMinI = maxI - (otherMinI + faceNormal);
                    otherMaxI = otherMaxI + faceNormal - minI;
                    if (otherMinI.X < 0)
                    {
                        continue;
                    }
                    if (otherMinI.Y < 0)
                    {
                        continue;
                    }
                    if (otherMinI.Z < 0)
                    {
                        continue;
                    }
                    if (otherMaxI.X < 0)
                    {
                        continue;
                    }
                    if (otherMaxI.Y < 0)
                    {
                        continue;
                    }
                    if (otherMaxI.Z < 0)
                    {
                        continue;
                    }

                    return(mergeBlock);
                }
            }

            return(null);
        }
Exemple #18
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();
            }
        }
Exemple #19
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 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 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 #22
0
        private MyProceduralCell GenerateObjectSeedsCell(ref Vector3I cellId)
        {
            MyProceduralCell cell = new MyProceduralCell(cellId);

            ProfilerShort.Begin("GenerateObjectSeedsCell");
            IMyModule cellDensityFunction = CalculateCellDensityFunction(ref cellId);

            if (cellDensityFunction == null)
            {
                ProfilerShort.End();
                return(null);
            }
            int cellSeed = GetCellSeed(ref cellId);

            using (MyRandom.Instance.PushSeed(cellSeed))
            {
                var random = MyRandom.Instance;

                int      index     = 0;
                Vector3I subCellId = Vector3I.Zero;
                Vector3I max       = new Vector3I(SUBCELLS - 1);
                for (var iter = new Vector3I.RangeIterator(ref Vector3I.Zero, ref max); iter.IsValid(); iter.GetNext(out subCellId))
                {
                    Vector3D position = new Vector3D(random.NextDouble(), random.NextDouble(), random.NextDouble());
                    position += (Vector3D)subCellId / SUBCELL_SIZE;
                    position += cellId;
                    position *= CELL_SIZE;

                    if (!MyEntities.IsInsideWorld(position))
                    {
                        continue;
                    }

                    ProfilerShort.Begin("GetValue");
                    var value = cellDensityFunction.GetValue(position.X, position.Y, position.Z);
                    ProfilerShort.End();

                    if (value < m_objectDensity) // -1..+1
                    {
                        var objectSeed = new MyObjectSeed(cell, position, GetObjectSize(random.NextDouble()));
                        objectSeed.Type  = GetSeedType(random.NextDouble());
                        objectSeed.Seed  = random.Next();
                        objectSeed.Index = index++;

                        GenerateObject(cell, objectSeed, ref index, random, cellDensityFunction);
                    }
                }
            }

            ProfilerShort.End();
            return(cell);
        }
Exemple #23
0
 internal void InvalidateRange(Vector3I lodMin, Vector3I lodMax)
 {
     var cell = new MyCellCoord(m_lodIndex, lodMin);
     for (var it = new Vector3I.RangeIterator(ref lodMin, ref lodMax);
         it.IsValid(); it.GetNext(out cell.CoordInLod))
     {
         CellData data;
         var id = cell.PackId64();
         if (m_storedCellData.TryGetValue(id, out data))
         {
             data.State = CellState.Invalid;
         }
     }
 }
Exemple #24
0
        /// <summary>
        /// Whether connection is allowed to any of the positions between otherBlockMinPos and otherBlockMaxPos (both inclusive).
        /// Default implementation calls ConnectionAllowed(ref Vector3I otherBlockPos, ref Vector3I faceNormal) in a for loop.
        /// Override this in a subclass if this is not needed (for example, because all calls would return the same value for the same face)
        /// </summary>
        public virtual bool ConnectionAllowed(ref Vector3I otherBlockMinPos, ref Vector3I otherBlockMaxPos, ref Vector3I faceNormal, MyCubeBlockDefinition def)
        {
            Vector3I pos = otherBlockMinPos;

            for (Vector3I.RangeIterator it = new Vector3I.RangeIterator(ref otherBlockMinPos, ref otherBlockMaxPos); it.IsValid(); it.GetNext(out pos))
            {
                if (ConnectionAllowed(ref pos, ref faceNormal, def))
                {
                    return(true);
                }
            }

            return(false);
        }
        private void AddBlock(MySlimBlock block)
        {
            Vector3I start = block.Min;
            Vector3I end   = block.Max;

            for (var it = new Vector3I.RangeIterator(ref start, ref end); it.IsValid(); it.GetNext(out start))
            {
                Debug.Assert(!m_cubeSet.Contains(ref start));
                m_cubeSet.Add(ref start);
            }

            MatrixI transform = new MatrixI(block.Position, block.Orientation.Forward, block.Orientation.Up);

            MergeFromAnotherMesh(block.BlockDefinition.NavigationDefinition.Mesh, ref transform);
        }
Exemple #26
0
            public Enumerator(MyVector3DGrid <T> parent, ref Vector3D point, double dist)
            {
                m_parent = parent;
                m_point  = point;
                m_distSq = dist * dist;

                Vector3D offset = new Vector3D(dist);
                Vector3I start  = Vector3I.Floor((point - offset) * parent.m_divisor);
                Vector3I end    = Vector3I.Floor((point + offset) * parent.m_divisor);

                m_rangeIterator = new Vector3I.RangeIterator(ref start, ref end);

                m_previousIndex = -1;
                m_storageIndex  = -1;
            }
Exemple #27
0
            public SphereQuery(MyVector3Grid <T> parent, ref Vector3 point, float dist)
            {
                m_parent = parent;
                m_point  = point;
                m_distSq = dist * dist;

                Vector3  offset = new Vector3(dist);
                Vector3I start  = m_parent.GetBinIndex(point - offset);
                Vector3I end    = m_parent.GetBinIndex(point + offset);

                m_rangeIterator = new Vector3I.RangeIterator(ref start, ref end);

                m_previousIndex = -1;
                m_storageIndex  = -1;
            }
Exemple #28
0
        /// <param name="minVoxelChanged">Inclusive min.</param>
        /// <param name="maxVoxelChanged">Inclusive max.</param>
        internal void InvalidateRange(Vector3I minChanged, Vector3I maxChanged)
        {
            minChanged -= MyVoxelPrecalc.InvalidatedRangeInflate;
            maxChanged += MyVoxelPrecalc.InvalidatedRangeInflate;
            m_voxelMap.FixVoxelCoord(ref minChanged);
            m_voxelMap.FixVoxelCoord(ref maxChanged);
            var      minCellChanged = minChanged >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS;
            var      maxCellChanged = maxChanged >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS;
            Vector3I cellCoord      = minCellChanged;

            for (var it = new Vector3I.RangeIterator(ref minCellChanged, ref maxCellChanged); it.IsValid(); it.GetNext(out cellCoord))
            {
                RemoveCell(ref cellCoord);
            }
        }
        public void MarkBoxForAddition(BoundingBoxD box)
        {
            ProfilerShort.Begin("VoxelNavMesh.MarkBoxForAddition");
            Vector3I pos, end;

            MyVoxelCoordSystems.WorldPositionToVoxelCoord(m_voxelMap.PositionLeftBottomCorner, ref box.Min, out pos);
            MyVoxelCoordSystems.WorldPositionToVoxelCoord(m_voxelMap.PositionLeftBottomCorner, ref box.Max, out end);

            m_voxelMap.Storage.ClampVoxelCoord(ref pos);
            m_voxelMap.Storage.ClampVoxelCoord(ref end);

            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref pos, out pos);
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref end, out end);

            Vector3 center = pos + end;

            center = center * 0.5f;

            pos /= 1 << NAVMESH_LOD;
            end /= 1 << NAVMESH_LOD;

            for (var it = new Vector3I.RangeIterator(ref pos, ref end); it.IsValid(); it.GetNext(out pos))
            {
                if (!m_processedCells.Contains(ref pos) && !m_markedForAddition.Contains(ref pos))
                {
                    float weight = 1.0f / (0.01f + Vector3.RectangularDistance(pos, center));

                    if (!m_toAdd.Full)
                    {
                        m_toAdd.Insert(pos, weight);
                        m_markedForAddition.Add(ref pos);
                    }
                    else
                    {
                        float min = m_toAdd.MinKey();
                        if (weight > min)
                        {
                            Vector3I posRemoved = m_toAdd.RemoveMin();
                            m_markedForAddition.Remove(ref posRemoved);

                            m_toAdd.Insert(pos, weight);
                            m_markedForAddition.Add(ref pos);
                        }
                    }
                }
            }
            ProfilerShort.End();
        }
        private void RemoveBlock(Vector3I min, Vector3I max, bool eraseCubeSet)
        {
            Vector3I pos = min;

            for (var it = new Vector3I.RangeIterator(ref pos, ref max); it.IsValid(); it.GetNext(out pos))
            {
                Debug.Assert(m_cubeSet.Contains(ref pos));

                if (eraseCubeSet)
                {
                    m_cubeSet.Remove(ref pos);
                }

                EraseCubeTriangles(pos);
            }
        }
            /// <summary>
            /// New clipping routine, call on lowest desired lod with position of camera
            /// Should be later enhanced with spread if desired lod would be lower than 0
            /// Finaly it will be used as hint for structure managing cells to be calculated and rendered
            /// </summary>
            /// <param name="localPosition"></param>
            /// <param name="collector"></param>
            internal void DoClipping(Vector3D localPosition, RequestCollector collector, int spread)
            {
                Vector3I min, max;
                {
                    Vector3I center;
                    MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref localPosition, out center);
                    min = center - spread;
                    max = center + spread;
                    Vector3I.Clamp(ref min, ref Vector3I.Zero, ref m_lodSizeMinusOne, out min);
                    Vector3I.Clamp(ref max, ref Vector3I.Zero, ref m_lodSizeMinusOne, out max);
                }
                var it0    = new Vector3I.RangeIterator(ref min, ref max);
                var ignore = BoundingBox.CreateInvalid();

                DoClipping(collector, min, max, ref ignore);
            }
 internal void InvalidateRange(Vector3I lodMin, Vector3I lodMax)
 {
     var cell = new MyCellCoord(m_lodIndex, lodMin);
     for (var it = new Vector3I.RangeIterator(ref lodMin, ref lodMax);
         it.IsValid(); it.GetNext(out cell.CoordInLod))
     {
         CellData data;
         var id = cell.PackId64();
         using (m_storedCellDataLock.AcquireSharedUsing())
         {
             if (m_storedCellData.TryGetValue(id, out data))
             {
                 data.State = CellState.Invalid;
             }
         }
     }
 }
        // Actually, this function marks even cubes around the block to make sure that any changes caused in their triangles
        // will be reflected in the navigation mesh.
        public void MarkBlockChanged(MySlimBlock block)
        {
            Vector3I min = block.Min - Vector3I.One;
            Vector3I max = block.Max + Vector3I.One;

            Vector3I pos = min;
            for (var it = new Vector3I.RangeIterator(ref block.Min, ref block.Max); it.IsValid(); it.GetNext(out pos))
            {
                m_changedCubes.Add(pos);
            }

            Vector3I minCell = CubeToCell(ref min);
            Vector3I maxCell = CubeToCell(ref max);

            pos = minCell;
            for (var it = new Vector3I.RangeIterator(ref minCell, ref maxCell); it.IsValid(); it.GetNext(out pos))
            {
                m_changedCells.Add(pos);
            }
        }
Exemple #34
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 void Submit()
            {
                ProfilerShort.Begin("RequestCollector.Submit");

                MyCellCoord cell = default(MyCellCoord);
                foreach (var cellId in m_cancelRequests)
                {
                    cell.SetUnpack(cellId);
                    MyRenderProxy.CancelClipmapCell(m_clipmapId, cell);
                    bool removed = m_sentRequests.Remove(cellId);
                    Debug.Assert(removed);
                }

                foreach (var highPriorityRequest in m_unsentRequestsHigh)
                {
                    cell.SetUnpack(highPriorityRequest);
                    MyRenderProxy.RequireClipmapCell(m_clipmapId, cell, highPriority: true);
                }
                m_unsentRequestsHigh.Clear();

                int addedCount = 0;
                for (int i = m_unsentRequestsLow.Length - 1; i >= 0; i--)
                {
                    var unsent = m_unsentRequestsLow[i];
                    while (0 < unsent.Count && m_sentRequests.Count < m_maxRequests)
                    {
                        var cellId = unsent.FirstElement();

                        cell.SetUnpack(cellId);
                        // Do Z-order style iteration of siblings that also need to
                        // be requested. This ensures faster processing of cells and
                        // shorter time when both lods are rendered.
                        var baseCoord = (cell.CoordInLod >> 1) << 1;
                        var offset = Vector3I.Zero;
                        for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref Vector3I.One);
                            it.IsValid(); it.GetNext(out offset))
                        {
                            cell.CoordInLod = baseCoord + offset;
                            cellId = cell.PackId64();
                            if (!unsent.Remove(cellId))
                            {
                                continue;
                            }

                            Debug.Assert(!m_cancelRequests.Contains(cellId));
                            MyRenderProxy.RequireClipmapCell(m_clipmapId, cell, highPriority: false);
                            bool added = m_sentRequests.Add(cellId);
                            Debug.Assert(added);
                            addedCount++;
                        }
                    }

                    // When set reaches reasonably small size, stop freeing memory
                    if (unsent.Count > 100)
                        unsent.TrimExcess();
                }

                m_cancelRequests.Clear();

                ProfilerShort.End();
            }
        /// <summary>
        /// Writes multiblocks (compound block and block ID) to outMultiBlocks collection with the same multiblockId.
        /// </summary>
        public static void GetBlocksInMultiBlock(MyCubeGrid grid, Vector3I minPosition, Vector3I maxPosition, MyMultiBlockDefinition multiBlockDefinition, int multiBlockId,
            HashSet<Tuple<MySlimBlock, ushort?>> outMultiBlocks)
        {
            Debug.Assert(multiBlockId != 0);
            if (multiBlockId == 0)
                return;

            Vector3I cube = minPosition;
            for (Vector3I.RangeIterator it = new Vector3I.RangeIterator(ref minPosition, ref maxPosition); it.IsValid(); it.GetNext(out cube))
            {
                MySlimBlock slimBlock = grid.GetCubeBlock(cube);
                if (slimBlock == null)
                    continue;

                MyCompoundCubeBlock compound = slimBlock.FatBlock as MyCompoundCubeBlock;

                if (compound != null)
                {
                    m_tmpSlimBlocks.Clear();

                    foreach (var blockInCompound in compound.GetBlocks(m_tmpSlimBlocks))
                    {
                        if (blockInCompound.MultiBlockDefinition == multiBlockDefinition && blockInCompound.MultiBlockId == multiBlockId)
                        {
                            ushort? blockInCompoundId = compound.GetBlockId(blockInCompound);
                            outMultiBlocks.Add(new Tuple<MySlimBlock, ushort?>(slimBlock, blockInCompoundId));
                        }
                    }

                    m_tmpSlimBlocks.Clear();
                }
                else
                {
                    MyFracturedBlock fracturedBlock = slimBlock.FatBlock as MyFracturedBlock;
                    if (fracturedBlock != null)
                    {
                        if (fracturedBlock.IsMultiBlockPart(multiBlockDefinition.Id, multiBlockId))
                            outMultiBlocks.Add(new Tuple<MySlimBlock, ushort?>(slimBlock, null));
                    }
                    else
                    {
                        if (slimBlock.MultiBlockDefinition == multiBlockDefinition && slimBlock.MultiBlockId == multiBlockId)
                            outMultiBlocks.Add(new Tuple<MySlimBlock, ushort?>(slimBlock, null));
                    }
                }
            }
        }
Exemple #37
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();
                }
            }
        }
        protected override void Init(MyObjectBuilder_DefinitionBase ob)
        {
            base.Init(ob);

            var objectBuilder = ob as MyObjectBuilder_BlockNavigationDefinition;
            Debug.Assert(ob != null);
            if (ob == null) return;

            if (objectBuilder.NoEntry || objectBuilder.Triangles == null)
            {
                NoEntry = true;
            }
            else
            {
                NoEntry = false;
                var newMesh = new MyGridNavigationMesh(null, null, objectBuilder.Triangles.Length);

                Vector3I maxPos = objectBuilder.Size - Vector3I.One - objectBuilder.Center;
                Vector3I minPos = - (Vector3I)(objectBuilder.Center);

                foreach (var triOb in objectBuilder.Triangles)
                {
                    Vector3 pa = (Vector3)triOb.Points[0];
                    Vector3 pb = (Vector3)triOb.Points[1];
                    Vector3 pc = (Vector3)triOb.Points[2];

                    var tri = newMesh.AddTriangle(ref pa, ref pb, ref pc);

                    var center = (pa + pb + pc) / 3.0f;

                    // We want to move the triangle vertices more towards the triangle center to ensure correct calculation of containing cube
                    Vector3 cvA = (center - pa) * 0.0001f;
                    Vector3 cvB = (center - pb) * 0.0001f;
                    Vector3 cvC = (center - pc) * 0.0001f;
                    Vector3I gridPosA = Vector3I.Round(pa + cvA);
                    Vector3I gridPosB = Vector3I.Round(pb + cvB);
                    Vector3I gridPosC = Vector3I.Round(pc + cvC);
                    Vector3I.Clamp(ref gridPosA, ref minPos, ref maxPos, out gridPosA);
                    Vector3I.Clamp(ref gridPosB, ref minPos, ref maxPos, out gridPosB);
                    Vector3I.Clamp(ref gridPosC, ref minPos, ref maxPos, out gridPosC);
                    Vector3I min, max;
                    Vector3I.Min(ref gridPosA, ref gridPosB, out min);
                    Vector3I.Min(ref min, ref gridPosC, out min);
                    Vector3I.Max(ref gridPosA, ref gridPosB, out max);
                    Vector3I.Max(ref max, ref gridPosC, out max);

                    Vector3I pos = min;
                    for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.GetNext(out pos))
                    {
                        newMesh.RegisterTriangle(tri, ref pos);
                    }
                }

                m_mesh = newMesh;
            }
        }
        /// <param name="minVoxelChanged">Inclusive min.</param>
        /// <param name="maxVoxelChanged">Inclusive max.</param>
        internal void InvalidateRange(Vector3I minVoxelChanged, Vector3I maxVoxelChanged)
        {
            MyPrecalcComponent.AssertUpdateThread();
            ProfilerShort.Begin("MyVoxelPhysicsBody.InvalidateRange");

            minVoxelChanged -= MyPrecalcComponent.InvalidatedRangeInflate;
            maxVoxelChanged += MyPrecalcComponent.InvalidatedRangeInflate;
            m_voxelMap.Storage.ClampVoxelCoord(ref minVoxelChanged);
            m_voxelMap.Storage.ClampVoxelCoord(ref maxVoxelChanged);

            Vector3I minCellChanged, maxCellChanged;
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref minVoxelChanged, out minCellChanged);
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxVoxelChanged, out maxCellChanged);

            Vector3I minCellChangedVoxelMap, maxCellChangedVoxelMap;
            minCellChangedVoxelMap = minCellChanged - m_cellsOffset;
            maxCellChangedVoxelMap = maxCellChanged - m_cellsOffset;

            Debug.Assert(RigidBody != null, "RigidBody in voxel physics is null! This must not happen.");
            if (RigidBody != null)
            {
                var shape = (HkUniformGridShape)RigidBody.GetShape();
                var tmpBuffer = m_cellsToGenerateBuffer;
                int invalidCount = shape.InvalidateRange(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap, tmpBuffer);
                if (invalidCount > tmpBuffer.Length)
                {
                    // Not storing this new buffer in static variable since this is just temporary and potentially large.
                    // Static variable could be potentially the same as leak.
                    tmpBuffer = new Vector3I[invalidCount];
                    int invalidCount2 = shape.InvalidateRange(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap, tmpBuffer);
                    Debug.Assert(invalidCount == invalidCount2);
                    invalidCount = invalidCount2;
                }

                Debug.Assert(invalidCount <= tmpBuffer.Length);
                for (int i = 0; i < invalidCount; i++)
                {
                    InvalidCells.Add(tmpBuffer[i]);
                }
                if (RunningBatchTask != null)
                {
                    RunningBatchTask.Cancel();
                    foreach (var oldInvalidCell in RunningBatchTask.CellBatch)
                    {
                        InvalidCells.Add(oldInvalidCell);
                    }
                    RunningBatchTask = null;
                }
                if (InvalidCells.Count != 0)
                    MyPrecalcComponent.PhysicsWithInvalidCells.Add(this);
            }

            var cell = minCellChanged;
            for (var it = new Vector3I.RangeIterator(ref minCellChanged, ref maxCellChanged);
                it.IsValid(); it.GetNext(out cell))
            {
                m_workTracker.Cancel(cell);
            }

            m_needsShapeUpdate = true;

            ProfilerShort.End();
        }
        internal void InvalidateRange(Vector3I minVoxelChanged, Vector3I maxVoxelChanged, int lod)
        {
            MyPrecalcComponent.AssertUpdateThread();
            // No physics there ever was so we don't care.
            if (!m_bodiesInitialized) return;

            if (m_queueInvalidation)
            {
                if (m_queuedRange.Max.X < 0)
                {
                    m_queuedRange = new BoundingBoxI(minVoxelChanged, maxVoxelChanged);
                }
                else
                {
                    var bb = new BoundingBoxI(minVoxelChanged, maxVoxelChanged);
                    m_queuedRange.Include(ref bb);
                }
                return;
            }

            ProfilerShort.Begin("MyVoxelPhysicsBody.InvalidateRange");
            minVoxelChanged -= MyPrecalcComponent.InvalidatedRangeInflate;
            maxVoxelChanged += MyPrecalcComponent.InvalidatedRangeInflate;
            m_voxelMap.Storage.ClampVoxelCoord(ref minVoxelChanged);
            m_voxelMap.Storage.ClampVoxelCoord(ref maxVoxelChanged);

            Vector3I minCellChanged, maxCellChanged;
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref minVoxelChanged, out minCellChanged);
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxVoxelChanged, out maxCellChanged);

            Vector3I minCellChangedVoxelMap, maxCellChangedVoxelMap;
            minCellChangedVoxelMap = (minCellChanged - m_cellsOffset) >> lod;
            maxCellChangedVoxelMap = (maxCellChanged - m_cellsOffset) >> lod;

            var maxCell = m_voxelMap.Size - 1;
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxCell, out maxCell);
            maxCell >>= lod;
            Vector3I.Min(ref maxCellChangedVoxelMap, ref maxCell, out maxCellChangedVoxelMap);

            Debug.Assert(RigidBody != null, "RigidBody in voxel physics is null! This must not happen.");

            var rb = GetRigidBody(lod);
            Debug.Assert(rb != null, "RigidBody in voxel physics is null! This must not happen.");
            
            if (rb != null)
            {
                HkUniformGridShape shape = (HkUniformGridShape) rb.GetShape();
                Debug.Assert(shape.Base.IsValid);

                var tmpBuffer = m_cellsToGenerateBuffer;
                int invalidCount = shape.InvalidateRange(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap, tmpBuffer);
                if (invalidCount > tmpBuffer.Length)
                {
                    // Not storing this new buffer in static variable since this is just temporary and potentially large.
                    // Static variable could be potentially the same as leak.
                    tmpBuffer = new Vector3I[invalidCount];
                    int invalidCount2 = shape.InvalidateRange(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap, tmpBuffer);
                    Debug.Assert(invalidCount == invalidCount2);
                    invalidCount = invalidCount2;
                }
                
                shape.InvalidateRangeImmediate(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap);
                Debug.Assert(invalidCount <= tmpBuffer.Length);
                for (int i = 0; i < invalidCount; i++)
                {
                    InvalidCells.Add(tmpBuffer[i]);
                }
                if (RunningBatchTask == null && InvalidCells.Count != 0)
                {
                    MyPrecalcComponent.PhysicsWithInvalidCells.Add(this);
                }
            }

            if (minCellChangedVoxelMap == Vector3I.Zero && maxCellChangedVoxelMap == maxCell)
            {
                m_workTracker.CancelAll();
            }
            else
            {
                var cell = minCellChanged;
                for (var it = new Vector3I.RangeIterator(ref minCellChanged, ref maxCellChanged);
                    it.IsValid(); it.GetNext(out cell))
                {
                    m_workTracker.Cancel(new MyCellCoord(lod, cell));
                }
            }

            m_needsShapeUpdate = true;

            ProfilerShort.End();

            m_voxelMap.RaisePhysicsChanged();
        }
        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 MyProceduralCell GenerateObjectSeedsCell(ref Vector3I cellId)
        {
            MyProceduralCell cell = new MyProceduralCell(cellId);
            ProfilerShort.Begin("GenerateObjectSeedsCell");
            IMyModule cellDensityFunction = CalculateCellDensityFunction(ref cellId);
            if (cellDensityFunction == null)
            {
                ProfilerShort.End();
                return null;
            }
            int cellSeed = GetCellSeed(ref cellId);
            using (MyRandom.Instance.PushSeed(cellSeed))
            {
                var random = MyRandom.Instance;

                int index = 0;
                Vector3I subCellId = Vector3I.Zero;
                Vector3I max = new Vector3I(SUBCELLS - 1);
                for (var iter = new Vector3I.RangeIterator(ref Vector3I.Zero, ref max); iter.IsValid(); iter.GetNext(out subCellId))
                {
                    Vector3D position = new Vector3D(random.NextDouble(), random.NextDouble(), random.NextDouble());
                    position += (Vector3D)subCellId / SUBCELL_SIZE;
                    position += cellId;
                    position *= CELL_SIZE;

                    if (!MyEntities.IsInsideWorld(position))
                    {
                        continue;
                    }

                    ProfilerShort.Begin("GetValue");
                    var value = cellDensityFunction.GetValue(position.X, position.Y, position.Z);
                    ProfilerShort.End();

                    if (value < m_objectDensity) // -1..+1
                    {
                        var objectSeed = new MyObjectSeed(cell, position, GetObjectSize(random.NextDouble()));
                        objectSeed.Type = GetSeedType(random.NextDouble());
                        objectSeed.Seed = random.Next();
                        objectSeed.Index = index++;

                        GenerateObject(cell, objectSeed, ref index, random, cellDensityFunction);
                    }
                }
            }

            ProfilerShort.End();
            return cell;
        }
        public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient)
        {

            m_resultVerticesCounter = 0;
            m_resultTrianglesCounter = 0;
            m_edgeVertexCalcCounter++;
            m_temporaryVoxelsCounter++;            

            CalcPolygCubeSize(lod, storage.Size);

            m_voxelStart = voxelStart;
            //voxelStart = voxelStart;
            //voxelEnd = voxelEnd;
            var ssize = storage.Size;
            m_cache.Resize(voxelStart, voxelEnd);

            // Load content first, check it if it contains isosurface, early exit if it doesn't.
            storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd);

            if (!m_cache.ContainsIsoSurface())
                return null;

            storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, lod, ref voxelStart, ref voxelEnd);

            ProfilerShort.Begin("Marching cubes");
            {
                //  Size of voxel or cell (in meters) and size of voxel map / voxel cells
                ComputeSizeAndOrigin(lod, storage.Size);


                var start = Vector3I.Zero;
                var end = voxelEnd - voxelStart - 3;
                Vector3I coord0 = start;


                for (var it = new Vector3I.RangeIterator(ref start, ref end); it.IsValid(); it.GetNext(out coord0))
                {
                    int cubeIndex = 0;
                    if (m_cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 1;
                    if (m_cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 2;
                    if (m_cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 4;
                    if (m_cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 8;
                    if (m_cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 16;
                    if (m_cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 32;
                    if (m_cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 64;
                    if (m_cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 128;

                    //  Cube is entirely in/out of the surface
                    if (MyMarchingCubesConstants.EdgeTable[cubeIndex] == 0)
                    {
                        continue;
                    }

                    //  We can get this voxel content right from cache (not using GetVoxelContent method), because after CopyVoxelContents these array must be filled. But only content, not material, normal, etc.
                    Vector3I tempVoxelCoord0 = ComputeTemporaryVoxelData(m_cache, ref coord0, cubeIndex, lod);

                    //  Create the triangles
                    CreateTriangles(ref coord0, cubeIndex, ref tempVoxelCoord0);
                }
            }
            ProfilerShort.End();


            double numCellsHalf = 0.5f * (m_cache.Size3D.X);
            var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod);
            var vertexCellOffset = voxelStart - AffectedRangeOffset;

            IMyIsoMesherOutputBuffer isomesh = new MyIsoMesh();


            for (int i = 0; i < m_resultVerticesCounter; i++)
            {
                var pos = (m_resultVertices[i].Position - (Vector3)storage.Size / 2) / storage.Size;                
                m_resultVertices[i].Position = pos;
                m_resultVertices[i].PositionMorph = pos;
                m_resultVertices[i].NormalMorph = m_resultVertices[i].Normal;
                m_resultVertices[i].MaterialMorph = m_resultVertices[i].Material;
                m_resultVertices[i].AmbientMorph = m_resultVertices[i].Ambient;
            }

            for (int i = 0; i < m_resultVerticesCounter; i++)
            {
                isomesh.WriteVertex(ref m_resultVertices[i].Cell, ref m_resultVertices[i].Position, ref m_resultVertices[i].Normal, (byte)m_resultVertices[i].Material, m_resultVertices[i].Ambient);
            }

            for (int i = 0; i < m_resultTrianglesCounter; i++)
            {
                isomesh.WriteTriangle(m_resultTriangles[i].VertexIndex0, m_resultTriangles[i].VertexIndex1, m_resultTriangles[i].VertexIndex2);
            }

            var mIsoMesh = (MyIsoMesh)isomesh;
            mIsoMesh.PositionOffset = storage.Size / 2;
            mIsoMesh.PositionScale = storage.Size;
            mIsoMesh.CellStart = voxelStart;
            mIsoMesh.CellEnd = voxelEnd;

            var vertexCells = mIsoMesh.Cells.GetInternalArray();
            for (int i = 0; i < mIsoMesh.VerticesCount; i++)
            {
                vertexCells[i] += vertexCellOffset;
            }

            return (MyIsoMesh)isomesh;
        }
Exemple #45
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);
                }
            }
        }
Exemple #46
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();
                }
            }

        }
        private MyShipMergeBlock GetOtherMergeBlock()
        {
            Vector3I minI, maxI;
            CalculateMergeArea(out minI, out maxI);

            Vector3I pos = minI;
            for (Vector3I.RangeIterator it = new Vector3I.RangeIterator(ref minI, ref maxI); it.IsValid(); it.GetNext(out pos))
            {
                var block = this.CubeGrid.GetCubeBlock(pos);
                if (block != null && block.FatBlock != null)
                {
                    var mergeBlock = block.FatBlock as MyShipMergeBlock;
                    if (mergeBlock == null) continue;

                    Vector3I otherMinI, otherMaxI;
                    mergeBlock.CalculateMergeArea(out otherMinI, out otherMaxI);
                    Vector3I faceNormal = Base6Directions.GetIntVector(this.Orientation.TransformDirection(m_forward));

                    // Bounding box test of minI <-> maxI and otherMinI(shifted by faceNormal) <-> otherMaxI(shifted by faceNormal)
                    otherMinI = maxI - (otherMinI + faceNormal);
                    otherMaxI = otherMaxI + faceNormal - minI;
                    if (otherMinI.X < 0) continue;
                    if (otherMinI.Y < 0) continue;
                    if (otherMinI.Z < 0) continue;
                    if (otherMaxI.X < 0) continue;
                    if (otherMaxI.Y < 0) continue;
                    if (otherMaxI.Z < 0) continue;

                    return mergeBlock;
                }
            }

            return null;
        }
        private MySlimBlock GetBlockInMergeArea()
        {
            Vector3I minI, maxI;
            CalculateMergeArea(out minI, out maxI);

            Vector3I pos = minI;
            for (Vector3I.RangeIterator it = new Vector3I.RangeIterator(ref minI, ref maxI); it.IsValid(); it.GetNext(out pos))
            {
                var block = this.CubeGrid.GetCubeBlock(pos);
                if (block != null)
                    return block;
            }

            return null;
        }
Exemple #49
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();
            }
        }
            internal void DoClipping(Vector3D localPosition, float farPlaneDistance, RequestCollector collector)
            {
                MyClipmap.ComputeLodViewBounds(m_parent.m_scaleGroup, m_lodIndex, out m_nearDistance, out m_farDistance);

                m_fitsInFrustum = (farPlaneDistance * 1.25f) > m_nearDistance;

                if (!m_fitsInFrustum)
                    return;

                Vector3I min, max;
                {
                    var minD = localPosition - m_farDistance;
                    var maxD = localPosition + m_farDistance;
                    MyVoxelCoordSystems.LocalPositionToRenderCellCoord(ref minD, out min);
                    MyVoxelCoordSystems.LocalPositionToRenderCellCoord(ref maxD, out max);
                    Vector3I.Max(ref min, ref Vector3I.Zero, out min);
                    Vector3I.Max(ref max, ref Vector3I.Zero, out max);
                    min >>= m_lodIndex;
                    max >>= m_lodIndex;

                    Vector3I.Min(ref min, ref m_lodSizeMinusOne, out min);
                    Vector3I.Min(ref max, ref m_lodSizeMinusOne, out max);
                }

                if (m_lastMin == min && m_lastMax == max && !m_parent.m_updateClipping)
                    return;

                m_lastMin = min;
                m_lastMax = max;

                LodLevel parentLod, childLod;
                GetNearbyLodLevels(out parentLod, out childLod);

                // Moves cells which are still needed from one collection to another.
                // All that is left behind is unloaded as no longer needed.

                // Move everything in range to collection of next stored cells.
                MyUtils.Swap(ref m_storedCellData, ref m_clippedCells);
                m_storedCellData.Clear();
                MyCellCoord cell = new MyCellCoord(m_lodIndex, ref min);
                for (var it = new Vector3I.RangeIterator(ref min, ref max);
                    it.IsValid(); it.GetNext(out cell.CoordInLod))
                {
                    if (!WasAncestorCellLoaded(parentLod, ref cell))
                        continue;

                    var cellId = cell.PackId64();
                    CellData data;
                    if (m_clippedCells.TryGetValue(cellId, out data))
                        m_clippedCells.Remove(cellId);
                    else
                        data = new CellData();

                    if (data.State == CellState.Invalid)
                    {
                        collector.AddRequest(cellId, data.WasLoaded);
                        data.State = CellState.Pending;
                    }
                    m_storedCellData.Add(cellId, data);
                }
            }
        protected override MyProceduralCell GenerateProceduralCell(ref VRageMath.Vector3I cellId)
        {
            MyProceduralCell cell = new MyProceduralCell(cellId, this);
            ProfilerShort.Begin("GenerateObjectSeedsCell");

            IMyModule densityFunctionFilled = GetCellDensityFunctionFilled(cell.BoundingVolume);
            if (densityFunctionFilled == null)
            {
                ProfilerShort.End();
                return null;
            }
            IMyModule densityFunctionRemoved = GetCellDensityFunctionRemoved(cell.BoundingVolume);

            int cellSeed = GetCellSeed(ref cellId);
            var random = MyRandom.Instance;
            using (random.PushSeed(cellSeed))
            {
                int index = 0;
                Vector3I subCellId = Vector3I.Zero;
                Vector3I max = new Vector3I(SUBCELLS - 1);
                for (var iter = new Vector3I.RangeIterator(ref Vector3I.Zero, ref max); iter.IsValid(); iter.GetNext(out subCellId))
                {
                    // there is a bug in the position calculation which can very rarely cause overlaping objects but backwards compatibility so meh
                    Vector3D position = new Vector3D(random.NextDouble(), random.NextDouble(), random.NextDouble());
                    position += (Vector3D)subCellId / SUBCELL_SIZE;
                    position += cellId;
                    position *= CELL_SIZE;

                    if (!MyEntities.IsInsideWorld(position))
                    {
                        continue;
                    }

                    ProfilerShort.Begin("Density functions");
                    double valueRemoved = -1;
                    if (densityFunctionRemoved != null)
                    {
                        valueRemoved = densityFunctionRemoved.GetValue(position.X, position.Y, position.Z);

                        if (valueRemoved <= -1)
                        {
                            ProfilerShort.End();
                            continue;
                        }
                    }

                    var valueFilled = densityFunctionFilled.GetValue(position.X, position.Y, position.Z);

                    if (densityFunctionRemoved != null)
                    {
                        if (valueRemoved < valueFilled)
                        {
                            ProfilerShort.End();
                            continue;
                        }
                    }
                    ProfilerShort.End();

                    if (valueFilled < m_objectDensity) // -1..+1
                    {
                        var objectSeed = new MyObjectSeed(cell, position, GetObjectSize(random.NextDouble()));
                        objectSeed.Type = GetSeedType(random.NextDouble());
                        objectSeed.Seed = random.Next();
                        objectSeed.Index = index++;

                        GenerateObject(cell, objectSeed, ref index, random, densityFunctionFilled, densityFunctionRemoved);
                    }
                }
            }

            ProfilerShort.End();
            return cell;
        }
            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();
        }
        public void InvalidateRange(Vector3I minVoxelChanged, Vector3I maxVoxelChanged)
        {
            minVoxelChanged -= MyPrecalcComponent.InvalidatedRangeInflate;
            maxVoxelChanged += MyPrecalcComponent.InvalidatedRangeInflate;

            m_voxelMap.Storage.ClampVoxelCoord(ref minVoxelChanged);
            m_voxelMap.Storage.ClampVoxelCoord(ref maxVoxelChanged);

            Vector3I minCell, maxCell;
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref minVoxelChanged, out minCell);
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxVoxelChanged, out maxCell);

            Vector3I currentCell = minCell;
            for (var it = new Vector3I.RangeIterator(ref minCell, ref maxCell); it.IsValid(); it.GetNext(out currentCell))
            {
                if (m_processedCells.Contains(ref currentCell))
                {
                    RemoveCell(currentCell);
                }

                MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, currentCell);
                m_higherLevelHelper.TryClearCell(coord.PackId64());
            }
        }
        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 MarkBoxForAddition(BoundingBoxD box)
        {
            ProfilerShort.Begin("VoxelNavMesh.MarkBoxForAddition");
            Vector3I pos, end;
            MyVoxelCoordSystems.WorldPositionToVoxelCoord(m_voxelMap.PositionLeftBottomCorner, ref box.Min, out pos);
            MyVoxelCoordSystems.WorldPositionToVoxelCoord(m_voxelMap.PositionLeftBottomCorner, ref box.Max, out end);

            m_voxelMap.Storage.ClampVoxelCoord(ref pos);
            m_voxelMap.Storage.ClampVoxelCoord(ref end);

            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref pos, out pos);
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref end, out end);

            Vector3 center = pos + end;
            center = center * 0.5f;

            pos /= 1 << NAVMESH_LOD;
            end /= 1 << NAVMESH_LOD;

            for (var it = new Vector3I.RangeIterator(ref pos, ref end); it.IsValid(); it.GetNext(out pos))
            {
                if (!m_processedCells.Contains(ref pos) && !m_markedForAddition.Contains(ref pos))
                {
                    float weight = 1.0f / (0.01f + Vector3.RectangularDistance(pos, center));

                    if (!m_toAdd.Full)
                    {
                        m_toAdd.Insert(pos, weight);
                        m_markedForAddition.Add(ref pos);
                    }
                    else
                    {
                        float min = m_toAdd.MinKey();
                        if (weight > min)
                        {
                            Vector3I posRemoved = m_toAdd.RemoveMin();
                            m_markedForAddition.Remove(ref posRemoved);

                            m_toAdd.Insert(pos, weight);
                            m_markedForAddition.Add(ref pos);
                        }
                    }
                }
            }
            ProfilerShort.End();
        }
        /// <summary>
        /// For debugging/testing only! This can be very slow for large storage.
        /// </summary>
        public void Voxelize(MyStorageDataTypeFlags data)
        {
            var cache = new MyStorageDataCache();

            cache.Resize(new Vector3I(LeafSizeInVoxels));
            var leafCount = (Size / LeafSizeInVoxels);
            Vector3I leaf = Vector3I.Zero;
            var end = leafCount - 1;
            for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref end);
                it.IsValid();
                it.GetNext(out leaf))
            {
                Debug.WriteLine("Processing {0} / {1}", leaf, end);
                var min = leaf * LeafSizeInVoxels;
                var max = min + (LeafSizeInVoxels - 1);
                ReadRangeInternal(cache, ref Vector3I.Zero, data, 0, ref min, ref max);
                WriteRangeInternal(cache, data, ref min, ref max);
            }

            OnRangeChanged(Vector3I.Zero, Size - 1, data);
        }
 void IMyOctreeLeafNode.WriteRange(MyStorageDataCache source, ref Vector3I readOffset, ref Vector3I min, ref Vector3I max)
 {
     m_octree.WriteRange(source, m_dataType, ref readOffset, ref min, ref max);
     if (DEBUG_WRITES)
     {
         var tmp = new MyStorageDataCache();
         tmp.Resize(min, max);
         m_octree.ReadRange(tmp, m_dataType, ref Vector3I.Zero, 0, ref min, ref max);
         Vector3I p = Vector3I.Zero;
         var cacheEnd = max - min;
         int errorCounter = 0;
         for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref cacheEnd);
             it.IsValid(); it.GetNext(out p))
         {
             var read = readOffset + p;
             if (source.Get(m_dataType, ref read) != tmp.Get(m_dataType, ref p))
                 ++errorCounter;
         }
         Debug.Assert(errorCounter == 0, string.Format("{0} errors writing to leaf octree.", errorCounter));
     }
 }
        internal void GenerateAllShapes()
        {
            if (!m_bodiesInitialized) CreateRigidBodies();

            var min = Vector3I.Zero;

            Vector3I storageSize = m_voxelMap.Size;
            Vector3I max = new Vector3I(0, 0, 0);
            max.X = storageSize.X >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS;
            max.Y = storageSize.Y >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS;
            max.Z = storageSize.Z >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS;

            max += min;

            var args = new MyPrecalcJobPhysicsPrefetch.Args
            {
                GeometryCell = new MyCellCoord(1, min),
                Storage = m_voxelMap.Storage,
                TargetPhysics = this,
                Tracker = m_workTracker
            };
            for (var it = new Vector3I.RangeIterator(ref min, ref max);
                it.IsValid();
                it.GetNext(out args.GeometryCell.CoordInLod))
            {
                MyPrecalcJobPhysicsPrefetch.Start(args);
            }
        }
        private static void WriteRange(
            ref WriteRangeArgs args,
            byte defaultData,
            int lodIdx,
            Vector3I lodCoord,
            ref Vector3I min,
            ref Vector3I max)
        {
            MyOctreeNode node = new MyOctreeNode();
            {
                MyCellCoord leaf = new MyCellCoord(lodIdx - LeafLodCount, ref lodCoord);
                var leafKey = leaf.PackId64();
                if (args.Leaves.ContainsKey(leafKey))
                {
                    args.Leaves.Remove(leafKey);
                    var childBase = lodCoord << 1;
                    Vector3I childOffset;
                    MyCellCoord child = new MyCellCoord();
                    child.Lod = leaf.Lod - 1;
                    var leafSize = LeafSizeInVoxels << child.Lod;
                    for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i)
                    {
                        ComputeChildCoord(i, out childOffset);
                        child.CoordInLod = childBase + childOffset;
                        var childCopy = child;
                        childCopy.Lod += LeafLodCount;
                        IMyOctreeLeafNode octreeLeaf = new MyProviderLeaf(args.Provider, args.DataType, ref childCopy);
                        args.Leaves.Add(child.PackId64(), octreeLeaf);
                        node.SetChild(i, true);
                        node.SetData(i, octreeLeaf.GetFilteredValue());
                    }
                }
                else
                {
                    leaf.Lod -= 1; // changes to node coord instead of leaf coord
                    var nodeKey = leaf.PackId64();

                    if (!args.Nodes.TryGetValue(nodeKey, out node))
                    {
                        for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i)
                            node.SetData(i, defaultData);
                    }
                }
            }

            if (lodIdx == (LeafLodCount + 1))
            {
                MyCellCoord child = new MyCellCoord();
                Vector3I childBase = lodCoord << 1;
                Vector3I minInLod = min >> LeafLodCount;
                Vector3I maxInLod = max >> LeafLodCount;
                Vector3I leafSizeMinusOne = new Vector3I(LeafSizeInVoxels - 1);
                Vector3I childOffset;
                for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i)
                {
                    ComputeChildCoord(i, out childOffset);
                    child.CoordInLod = childBase + childOffset;
                    if (!child.CoordInLod.IsInsideInclusive(ref minInLod, ref maxInLod))
                        continue;
                    var childMin = child.CoordInLod << LeafLodCount;
                    var childMax = childMin + LeafSizeInVoxels - 1;
                    Vector3I.Max(ref childMin, ref min, out childMin);
                    Vector3I.Min(ref childMax, ref max, out childMax);
                    var readOffset = childMin - min;
                    IMyOctreeLeafNode leaf;
                    var leafKey = child.PackId64();
                    var startInChild = childMin - (child.CoordInLod << LeafLodCount);
                    var endInChild = childMax - (child.CoordInLod << LeafLodCount);

                    args.Leaves.TryGetValue(leafKey, out leaf);

                    byte uniformValue;
                    bool uniformLeaf;
                    {
                        // ensure leaf exists and is writable
                        // the only writable leaf type is MicroOctree at this point

                        byte childDefaultData = node.GetData(i);

                        if (leaf == null)
                        {
                            var octree = new MyMicroOctreeLeaf(args.DataType, LeafLodCount, child.CoordInLod << (child.Lod + LeafLodCount));
                            octree.BuildFrom(childDefaultData);
                            leaf = octree;
                        }

                        if (leaf.ReadOnly)
                        {
                            var rangeEnd = new Vector3I(LeafSizeInVoxels - 1);
                            m_temporaryCache.Resize(Vector3I.Zero, rangeEnd);
                            leaf.ReadRange(m_temporaryCache, ref Vector3I.Zero, 0, ref Vector3I.Zero, ref rangeEnd);
                            var inCell = startInChild;
                            for (var it2 = new Vector3I.RangeIterator(ref startInChild, ref endInChild);
                                it2.IsValid(); it2.GetNext(out inCell))
                            {
                                var read = readOffset + (inCell - startInChild);
                                m_temporaryCache.Set(args.DataType, ref inCell, args.Source.Get(args.DataType, ref read));
                            }

                            var octree = new MyMicroOctreeLeaf(args.DataType, LeafLodCount, child.CoordInLod << (child.Lod + LeafLodCount));
                            octree.BuildFrom(m_temporaryCache);
                            leaf = octree;
                        }
                        else
                        {
                            leaf.WriteRange(args.Source, ref readOffset, ref startInChild, ref endInChild);
                        }

                        uniformLeaf = ((MyMicroOctreeLeaf)leaf).TryGetUniformValue(out uniformValue);
                    }

                    if (!uniformLeaf)
                    {
                        args.Leaves[leafKey] = leaf;
                        node.SetChild(i, true);
                    }
                    else
                    {
                        args.Leaves.Remove(leafKey);
                        node.SetChild(i, false);
                    }

                    node.SetData(i, leaf.GetFilteredValue());
                }
                args.Nodes[new MyCellCoord(lodIdx - 1 - LeafLodCount, ref lodCoord).PackId64()] = node;
            }
            else
            {
                MyCellCoord child = new MyCellCoord();
                child.Lod = lodIdx - 2 - LeafLodCount;
                var childBase = lodCoord << 1;
                Vector3I childOffset;
                var minInChild = (min >> (lodIdx-1)) - childBase;
                var maxInChild = (max >> (lodIdx-1)) - childBase;
                for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i)
                {
                    ComputeChildCoord(i, out childOffset);
                    if (!childOffset.IsInsideInclusive(ref minInChild, ref maxInChild))
                        continue;

                    child.CoordInLod = childBase + childOffset;
                    WriteRange(ref args, node.GetData(i), lodIdx - 1, child.CoordInLod, ref min, ref max);
                    var childKey = child.PackId64();
                    var childNode = args.Nodes[childKey];
                    if (!childNode.HasChildren && childNode.AllDataSame())
                    {
                        node.SetChild(i, false);
                        node.SetData(i, childNode.GetData(0));
                        args.Nodes.Remove(childKey);
                    }
                    else
                    {
                        node.SetChild(i, true);
                        node.SetData(i, childNode.ComputeFilteredValue(args.DataFilter));
                    }
                }

                args.Nodes[new MyCellCoord(lodIdx - 1 - LeafLodCount, ref lodCoord).PackId64()] = node;
            }
        }