// 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); } }
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; } }
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); }
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); }
/// <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); }
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); } }
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); } }
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); }
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; } } } }
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(); }
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); }
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); }
public void ReadRange(MyStorageData target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax, ref MyVoxelRequestFlags requestFlags) { ProfilerShort.Begin(GetType().Name + ".ReadRange"); try { const int SUBRANGE_SIZE_SHIFT = 3; const int SUBRANGE_SIZE = 1 << SUBRANGE_SIZE_SHIFT; var threshold = new Vector3I(SUBRANGE_SIZE); var rangeSize = lodVoxelRangeMax - lodVoxelRangeMin + 1; if ((dataToRead & MyStorageDataTypeFlags.Content) != 0) { target.ClearContent(0); } if ((rangeSize.X <= threshold.X && rangeSize.Y <= threshold.Y && rangeSize.Z <= threshold.Z) || !MyFakes.ENABLE_SPLIT_VOXEL_READ_QUERIES) { using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); } } else { // These optimizations don't work when splitting the range. requestFlags &= ~(MyVoxelRequestFlags.OneMaterial | MyVoxelRequestFlags.ContentChecked); MyVoxelRequestFlags flags = requestFlags; // splitting to smaller ranges to make sure the lock is not held for too long, preventing write on update thread // subranges could be aligned to multiple of their size for possibly better performance var steps = (rangeSize - 1) >> SUBRANGE_SIZE_SHIFT; for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref steps); it.IsValid(); it.MoveNext()) { flags = requestFlags; var offset = it.Current << SUBRANGE_SIZE_SHIFT; var min = lodVoxelRangeMin + offset; var max = min + SUBRANGE_SIZE - 1; Vector3I.Min(ref max, ref lodVoxelRangeMax, out max); Debug.Assert(min.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); Debug.Assert(max.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref offset, dataToRead, lodIndex, ref min, ref max, ref flags); } } // If the storage is consistent this should be fine. requestFlags = flags; } } finally { ProfilerShort.End(); } }
public 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"); } } } }
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); }
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; } } }
/// <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); }
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; }
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; }
/// <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); } }
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)); } } } }
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; }
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); } } }
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; }
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 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); } }
/// <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; } }