private static bool ResetVoxelInArea(Vector3D Center, float Radius) { try { BoundingSphereD Sphere = new BoundingSphereD(Center, Radius); List <MyVoxelBase> Maps = MyEntities.GetEntitiesInSphere(ref Sphere).OfType <MyVoxelBase>().ToList(); if (Maps.Count == 0) { return(true); } foreach (var voxelMap in Maps) { using (voxelMap.Pin()) { if (voxelMap.MarkedForClose) { continue; } MyShapeSphere shape = new MyShapeSphere(); shape.Center = Center; shape.Radius = Radius; Vector3I minCorner; Vector3I maxCorner; Vector3I numCells; BoundingBoxD shapeAabb = shape.GetWorldBoundaries(); Vector3I StorageSize = voxelMap.Storage.Size; MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref shapeAabb.Min, out minCorner); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref shapeAabb.Max, out maxCorner); minCorner += voxelMap.StorageMin; maxCorner += voxelMap.StorageMin; maxCorner += 1; StorageSize -= 1; Vector3I.Clamp(ref minCorner, ref Vector3I.Zero, ref StorageSize, out minCorner); Vector3I.Clamp(ref maxCorner, ref Vector3I.Zero, ref StorageSize, out maxCorner); numCells = new Vector3I((maxCorner.X - minCorner.X) / 16, (maxCorner.Y - minCorner.Y) / 16, (maxCorner.Z - minCorner.Z) / 16); minCorner = Vector3I.Max(Vector3I.One, minCorner); maxCorner = Vector3I.Max(minCorner, maxCorner - Vector3I.One); voxelMap.Storage.DeleteRange(MyStorageDataTypeFlags.ContentAndMaterial, minCorner, maxCorner, false); BoundingBoxD cutOutBox = shape.GetWorldBoundaries(); MySandboxGame.Static.Invoke(delegate { if (voxelMap.Storage != null) { voxelMap.Storage.NotifyChanged(minCorner, maxCorner, MyStorageDataTypeFlags.ContentAndMaterial); MyVoxelGenerator.NotifyVoxelChanged(MyVoxelBase.OperationType.Revert, voxelMap, ref cutOutBox); } }, "RevertShape notify"); } } return(true); } catch (Exception ex) { _log.Error(ex, "Voxel reset failed!"); return(false); } }
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; } }
public static void ClampVoxelCoord(this VRage.ModAPI.IMyStorage self, ref Vector3I voxelCoord, int distance = 1) { if (self != null) { Vector3I max = self.Size - distance; Vector3I.Clamp(ref voxelCoord, ref Vector3I.Zero, ref max, out voxelCoord); } }
private static void RemoveSmallVoxelsUsingChachedVoxels() { ProfilerShort.Begin("MyVoxelGenerator::RemoveSmallVoxelsUsingChachedVoxels()"); Vector3I voxel; var cacheSize = m_cache.Size3D; var sizeMinusOne = cacheSize - 1; for (voxel.X = 0; voxel.X < cacheSize.X; voxel.X++) { for (voxel.Y = 0; voxel.Y < cacheSize.Y; voxel.Y++) { for (voxel.Z = 0; voxel.Z < cacheSize.Z; voxel.Z++) { // IMPORTANT: When doing transformations on 'content' value, cast it to int always!!! // It's because you can easily forget that result will be negative and if you put negative into byte, it will // be overflown and you will be surprised by results!! int content = m_cache.Content(ref voxel); // Check if this is small/invisible voxel (less than 127), but still not empty (more than 0) if ((content > 0) && (content < MyVoxelConstants.VOXEL_ISO_LEVEL)) { Vector3I neighborVoxel; Vector3I neighborVoxelMin = voxel - 1; Vector3I neighborVoxelMax = voxel + 1; Vector3I.Clamp(ref neighborVoxelMin, ref Vector3I.Zero, ref sizeMinusOne, out neighborVoxelMin); Vector3I.Clamp(ref neighborVoxelMax, ref Vector3I.Zero, ref sizeMinusOne, out neighborVoxelMax); bool foundNonEmptyVoxel = false; for (neighborVoxel.X = neighborVoxelMin.X; neighborVoxel.X <= neighborVoxelMax.X; neighborVoxel.X++) { for (neighborVoxel.Y = neighborVoxelMin.Y; neighborVoxel.Y <= neighborVoxelMax.Y; neighborVoxel.Y++) { for (neighborVoxel.Z = neighborVoxelMin.Z; neighborVoxel.Z <= neighborVoxelMax.Z; neighborVoxel.Z++) { int neighborContent = m_cache.Content(ref neighborVoxel); // Check if this is small/invisible voxel if (neighborContent >= MyVoxelConstants.VOXEL_ISO_LEVEL) { foundNonEmptyVoxel = true; goto END_NEIGHBOR_LOOP; } } } } END_NEIGHBOR_LOOP: if (foundNonEmptyVoxel == false) { m_cache.Content(ref voxel, MyVoxelConstants.VOXEL_CONTENT_EMPTY); } } } } } ProfilerShort.End(); }
public static void ClampVoxelCoord(this Sandbox.ModAPI.Interfaces.IMyStorage self, ref Vector3I voxelCoord, int distance = 1) { if (self == null) { return; } var sizeMinusOne = self.Size - distance; Vector3I.Clamp(ref voxelCoord, ref Vector3I.Zero, ref sizeMinusOne, out voxelCoord); }
public static void ClampVoxelCoord(this IMyStorage self, ref Vector3I voxelCoord, int distance = 1) { if (self == null) { return; } Vector3I max = self.Size - distance; Vector3I.Clamp(ref voxelCoord, ref Vector3I.Zero, ref max, out voxelCoord); }
private static void ComputeShapeBounds( ref BoundingBoxD shapeAabb, Vector3D voxelMapMinCorner, Vector3I storageSize, out Vector3I voxelMin, out Vector3I voxelMax) { MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMapMinCorner, ref shapeAabb.Min, out voxelMin); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMapMinCorner, ref shapeAabb.Max, out voxelMax); voxelMax += 1; storageSize -= 1; Vector3I.Clamp(ref voxelMin, ref Vector3I.Zero, ref storageSize, out voxelMin); Vector3I.Clamp(ref voxelMax, ref Vector3I.Zero, ref storageSize, out voxelMax); }
public static void Storage_ClampVoxelCoord(this IMyVoxelBase Voxel, ref Vector3I voxelCoord, int distance = 1) { if (Voxel == null) { throw new ArgumentNullException(nameof(Voxel)); } if (Voxel.Storage == null) { throw new ArgumentException("Voxel.Storage is null"); } Vector3I vector3I = Voxel.Storage.Size - distance; Vector3I.Clamp(ref voxelCoord, ref Vector3I.Zero, ref vector3I, out voxelCoord); }
private static void ComputeShapeBounds(MyVoxelBase voxelMap, ref BoundingBoxD shapeAabb, Vector3D voxelMapMinCorner, Vector3I storageSize, out Vector3I voxelMin, out Vector3I voxelMax) { MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMapMinCorner, ref shapeAabb.Min, out voxelMin); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMapMinCorner, ref shapeAabb.Max, out voxelMax); voxelMin += voxelMap.StorageMin; voxelMax += voxelMap.StorageMin; voxelMax += 1; //what? why? Another hack of MK? storageSize -= 1; Vector3I.Clamp(ref voxelMin, ref Vector3I.Zero, ref storageSize, out voxelMin); Vector3I.Clamp(ref voxelMax, ref Vector3I.Zero, ref storageSize, out voxelMax); }
/// <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); }
public static void ComputeShapeBounds(MyVoxelBase voxelMap, ref BoundingBoxD shapeAabb, out Vector3I voxelMin, out Vector3I voxelMax) { var storageSize = voxelMap.Storage.Size; MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref shapeAabb.Min, out voxelMin); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref shapeAabb.Max, out voxelMax); voxelMin += voxelMap.StorageMin; voxelMax += voxelMap.StorageMin; voxelMax += 1; storageSize -= 1; Vector3I.Clamp(ref voxelMin, ref Vector3I.Zero, ref storageSize, out voxelMin); Vector3I.Clamp(ref voxelMax, ref Vector3I.Zero, ref storageSize, out voxelMax); }
/// <summary> /// Invalidates voxel cache /// </summary> /// <param name="minChanged">Inclusive min</param> /// <param name="maxChanged">Inclusive max</param> public void InvalidateCache(Vector3I minChanged, Vector3I maxChanged) { minChanged = Vector3I.Clamp(minChanged, Vector3I.Zero, SizeMinusOne); maxChanged = Vector3I.Clamp(maxChanged, Vector3I.Zero, SizeMinusOne); VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("MyVoxelMap::InvalidateCache()"); Geometry.InvalidateRange(minChanged, maxChanged); MyVoxelCacheRender.RemoveCellForVoxels(this, minChanged, maxChanged); if (Physics != null) { Physics.InvalidateRange(minChanged, maxChanged); } InvalidateRenderObjects(true); VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); }
public Vector3ILineIterator(Vector3I start, Vector3I end) { if (start == end) { throw new ArgumentException("Start and end cannot be equal"); } _start = start; _end = end; Current = start; _direction = Vector3I.Clamp(end - start, -Vector3I.One, Vector3I.One); if (_direction.RectangularLength() > 1) { throw new ArgumentException("Start and end are not in a straight line"); } }
public void OnStorageChanged(Vector3I minChanged, Vector3I maxChanged, MyStorageDataTypeFlags dataChanged) { ProfilerShort.Begin("MyVoxelMap::storage_RangeChanged"); minChanged = Vector3I.Clamp(minChanged, m_storageMin, m_storageMax); maxChanged = Vector3I.Clamp(maxChanged, m_storageMin, m_storageMax); Debug.Assert(minChanged.IsInsideInclusive(ref m_storageMin, ref m_storageMax) && maxChanged.IsInsideInclusive(ref m_storageMin, ref m_storageMax)); // Physics doesn't care about materials, just shape of things. if ((dataChanged & MyStorageDataTypeFlags.Content) != 0 && Physics != null) { Physics.InvalidateRange(minChanged, maxChanged); } ProfilerShort.End(); }
public static void MyVoxelGenerator_ComputeShapeBounds(this IMyVoxelBase VoxelMap, ref BoundingBoxD shapeAabb, out Vector3I voxelMin, out Vector3I voxelMax) { if (VoxelMap == null) { throw new ArgumentNullException(nameof(VoxelMap)); } if (VoxelMap.Storage == null) { throw new ArgumentException("Voxel.Storage is null"); } MyVoxelBase voxelMap = VoxelMap as MyVoxelBase; Vector3I storageSize = voxelMap.Storage.Size; MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref shapeAabb.Min, out voxelMin); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref shapeAabb.Max, out voxelMax); voxelMin += voxelMap.StorageMin; voxelMax += voxelMap.StorageMin; voxelMax += 1; storageSize -= 1; Vector3I.Clamp(ref voxelMin, ref Vector3I.Zero, ref storageSize, out voxelMin); Vector3I.Clamp(ref voxelMax, ref Vector3I.Zero, ref storageSize, out voxelMax); }
public static void CutOutShape( MyVoxelMap voxelMap, MyShape shape, out float voxelsCountInPercent, out MyVoxelMaterialDefinition voxelMaterial, float removeRatio = 1, Dictionary <MyVoxelMaterialDefinition, int> exactCutOutMaterials = null, bool updateSync = true, bool onlyCheck = false) { Profiler.Begin("MyVoxelGenerator::CutOutShape()"); if (updateSync && Sync.IsServer) { shape.SendCutOutRequest(voxelMap.SyncObject, removeRatio); } int originalSum = 0; int removedSum = 0; Vector3I minCorner = voxelMap.GetVoxelCoordinateFromMeters(shape.GetMin()); Vector3I maxCorner = voxelMap.GetVoxelCoordinateFromMeters(shape.GetMax()); voxelMap.FixVoxelCoord(ref minCorner); voxelMap.FixVoxelCoord(ref maxCorner); var cacheMin = minCorner - 1; var cacheMax = maxCorner + 1; voxelMap.FixVoxelCoord(ref cacheMin); voxelMap.FixVoxelCoord(ref cacheMax); m_cache.Resize(ref cacheMin, ref cacheMax); voxelMap.Storage.ReadRange(m_cache, true, true, MyVoxelGeometry.GetLodIndex(MyLodTypeEnum.LOD0), ref cacheMin, ref cacheMax); { Vector3I exactCenter = voxelMap.GetVoxelCoordinateFromMeters(shape.GetCenter()); exactCenter -= cacheMin; exactCenter = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1); voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter)); } Vector3I tempVoxelCoord; for (tempVoxelCoord.X = minCorner.X; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++) { for (tempVoxelCoord.Y = minCorner.Y; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++) { for (tempVoxelCoord.Z = minCorner.Z; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++) { var relPos = tempVoxelCoord - cacheMin; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove { continue; } var vpos = voxelMap.GetVoxelPositionAbsolute(ref tempVoxelCoord); 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 * removeRatio * voxelMat.DamageRatio); if (voxelMap.Storage is MyCellStorage) { if (toRemove < MyCellStorage.Quantizer.GetMinimumQuantizableValue()) { toRemove = MyCellStorage.Quantizer.GetMinimumQuantizableValue(); } } 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, true, false, ref cacheMin, ref cacheMax); voxelMap.InvalidateCache(cacheMin, cacheMax); } voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f; Profiler.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(m_lodIndex, ref minD, out min); MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref maxD, out max); Vector3I.Clamp(ref min, ref Vector3I.Zero, ref m_lodSizeMinusOne, out min); Vector3I.Clamp(ref max, ref Vector3I.Zero, 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); } }
public static void CutOutShapeWithProperties( MyVoxelBase voxelMap, MyShape shape, out float voxelsCountInPercent, out MyVoxelMaterialDefinition voxelMaterial, Dictionary <MyVoxelMaterialDefinition, int> exactCutOutMaterials = null, bool updateSync = false, bool onlyCheck = false) { if (MySession.Static.EnableVoxelDestruction == false) { voxelsCountInPercent = 0; voxelMaterial = null; return; } ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()"); int originalSum = 0; int removedSum = 0; // Some shapes just ignore transforms so we round the bbox conservativelly by converting it to sphere var bbox = shape.GetWorldBoundaries(); var center = bbox.Center; var radius = (center - bbox.Min).Length(); MatrixD mat = voxelMap.PositionComp.WorldMatrix; MatrixD inverse; //Vector3D translation = mat.Translation; //mat.Translation = Vector3D.Zero; // invert is used to bring voxel coordinates back to world. inverse = voxelMap.PositionComp.WorldMatrixInvScaled;//MatrixD.Invert(ref mat, out inverse); Vector3 offset = voxelMap.StorageMin + voxelMap.SizeInMetresHalf; Vector3D.Transform(ref center, ref inverse, out center); // The transform is centered, but the code expects voxel local coordinates. center += voxelMap.SizeInMetresHalf; bbox = new BoundingBoxD(center - radius, center + radius); Vector3I minCorner, maxCorner; ComputeShapeBounds(voxelMap, ref bbox, Vector3.Zero, voxelMap.Storage.Size, out minCorner, out maxCorner); var cacheMin = minCorner - 1; var cacheMax = maxCorner + 1; voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); m_cache.Resize(cacheMin, cacheMax); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cacheMin, ref cacheMax); { var shapeCenter = bbox.Center; Vector3I exactCenter; MyVoxelCoordSystems.WorldPositionToVoxelCoord(Vector3.Zero, ref shapeCenter, out exactCenter); exactCenter -= cacheMin; exactCenter = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1); voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter)); } ProfilerShort.Begin("Main loop"); for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cacheMin; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove { continue; } Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToLocalPosition(ref it.Current, out vpos); // center vpos -= offset; // transform back to world space. Vector3D.Transform(ref vpos, ref mat, out vpos); var volume = shape.GetVolume(ref vpos); if (volume == 0f) // if there is no intersection { continue; } var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); var voxelMat = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref relPos)); var toRemove = (int)(maxRemove * voxelMat.DamageRatio); var newVal = MathHelper.Clamp(original - toRemove, 0, original - maxRemove); var removed = Math.Abs(original - newVal); if (!onlyCheck) { m_cache.Content(ref relPos, (byte)newVal); } originalSum += original; removedSum += removed; if (exactCutOutMaterials != null) { int value = 0; exactCutOutMaterials.TryGetValue(voxelMat, out value); value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed); exactCutOutMaterials[voxelMat] = value; } } if (removedSum > 0 && updateSync && Sync.IsServer) { shape.SendDrillCutOutRequest(voxelMap); } ProfilerShort.BeginNextBlock("Write"); if (removedSum > 0 && !onlyCheck) { // Clear all small voxel that may have been created during explosion. They can be created even outside the range of // explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the // explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we // will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove // B voxels too. //!! TODO AR & MK : check if this is needed !! RemoveSmallVoxelsUsingChachedVoxels(); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax); } ProfilerShort.End(); voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f; if (removedSum > 0) { CheckNeighbourStaticGridsAfterVoxelChanged(MyVoxelBase.OperationType.Cut, voxelMap, shape); } ProfilerShort.End(); }
public static void CutOutShapeWithProperties( MyVoxelBase voxelMap, MyShape shape, out float voxelsCountInPercent, out MyVoxelMaterialDefinition voxelMaterial, Dictionary <MyVoxelMaterialDefinition, int> exactCutOutMaterials = null, bool updateSync = false, bool onlyCheck = false) { ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()"); int originalSum = 0; int removedSum = 0; var bbox = shape.GetWorldBoundaries(); Vector3I minCorner, maxCorner; ComputeShapeBounds(ref bbox, voxelMap.PositionLeftBottomCorner, voxelMap.Storage.Size, out minCorner, out maxCorner); var cacheMin = minCorner - 1; var cacheMax = maxCorner + 1; voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); m_cache.Resize(cacheMin, cacheMax); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cacheMin, ref cacheMax); { var shapeCenter = bbox.Center; Vector3I exactCenter; MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref shapeCenter, out exactCenter); exactCenter -= cacheMin; exactCenter = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1); voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter)); } for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cacheMin; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove { continue; } Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); var volume = shape.GetVolume(ref vpos); if (volume == 0f) // if there is no intersection { continue; } var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); var voxelMat = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref relPos)); var toRemove = (int)(maxRemove * voxelMat.DamageRatio); var newVal = MathHelper.Clamp(original - toRemove, 0, maxRemove); var removed = Math.Abs(original - newVal); if (!onlyCheck) { m_cache.Content(ref relPos, (byte)newVal); } originalSum += original; removedSum += removed; if (exactCutOutMaterials != null) { int value = 0; exactCutOutMaterials.TryGetValue(voxelMat, out value); value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed); exactCutOutMaterials[voxelMat] = value; } } if (removedSum > 0 && !onlyCheck) { // Clear all small voxel that may have been created during explosion. They can be created even outside the range of // explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the // explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we // will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove // B voxels too. //!! TODO AR & MK : check if this is needed !! RemoveSmallVoxelsUsingChachedVoxels(); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax); } if (removedSum > 0 && updateSync && Sync.IsServer) { shape.SendDrillCutOutRequest(voxelMap.SyncObject); } voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f; ProfilerShort.End(); }
private void ClampCellCoord(ref Vector3I cellCoord) { var dataCellsCountMinusOne = m_cellsCount - 1; Vector3I.Clamp(ref cellCoord, ref Vector3I.Zero, ref dataCellsCountMinusOne, out cellCoord); }
// If voxel coord0 (in voxel units, not meters) is outside of the voxelmap, we fix its coordinate so it lie in the voxelmap. public void FixVoxelCoord(ref Vector3I voxelCoord) { var sizeMinusOne = Storage.Size - 1; Vector3I.Clamp(ref voxelCoord, ref Vector3I.Zero, ref sizeMinusOne, out voxelCoord); }
private static unsafe void ReadRange( MyStorageDataCache target, ref Vector3I targetWriteOffset, MyStorageDataTypeEnum type, int treeHeight, Dictionary <UInt64, MyOctreeNode> nodes, Dictionary <UInt64, IMyOctreeLeafNode> leaves, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { int stackIdx = 0; int stackSize = MySparseOctree.EstimateStackSize(treeHeight); MyCellCoord *stack = stackalloc MyCellCoord[stackSize]; MyCellCoord data = new MyCellCoord(treeHeight + LeafLodCount, ref Vector3I.Zero); stack[stackIdx++] = data; MyCellCoord cell = new MyCellCoord(); while (stackIdx > 0) { Debug.Assert(stackIdx <= stackSize); data = stack[--stackIdx]; cell.Lod = data.Lod - LeafLodCount; cell.CoordInLod = data.CoordInLod; int lodDiff; IMyOctreeLeafNode leaf; if (leaves.TryGetValue(cell.PackId64(), out leaf)) { lodDiff = data.Lod - lodIndex; var rangeMinInDataLod = minInLod >> lodDiff; var rangeMaxInDataLod = maxInLod >> lodDiff; if (data.CoordInLod.IsInsideInclusive(ref rangeMinInDataLod, ref rangeMaxInDataLod)) { var nodePosInLod = data.CoordInLod << lodDiff; var writeOffset = nodePosInLod - minInLod; Vector3I.Max(ref writeOffset, ref Vector3I.Zero, out writeOffset); writeOffset += targetWriteOffset; var lodSizeMinusOne = new Vector3I((1 << lodDiff) - 1); var minInLeaf = Vector3I.Clamp(minInLod - nodePosInLod, Vector3I.Zero, lodSizeMinusOne); var maxInLeaf = Vector3I.Clamp(maxInLod - nodePosInLod, Vector3I.Zero, lodSizeMinusOne); leaf.ReadRange(target, ref writeOffset, lodIndex, ref minInLeaf, ref maxInLeaf); } continue; } cell.Lod -= 1; lodDiff = data.Lod - 1 - lodIndex; var node = nodes[cell.PackId64()]; var min = minInLod >> lodDiff; var max = maxInLod >> lodDiff; var nodePositionInChild = data.CoordInLod << 1; min -= nodePositionInChild; max -= nodePositionInChild; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { Vector3I childPosRelative; ComputeChildCoord(i, out childPosRelative); if (!childPosRelative.IsInsideInclusive(ref min, ref max)) { continue; } if (lodIndex < data.Lod && node.HasChild(i)) { Debug.Assert(stackIdx < stackSize); stack[stackIdx++] = new MyCellCoord(data.Lod - 1, nodePositionInChild + childPosRelative); } else { var childMin = nodePositionInChild + childPosRelative; childMin <<= lodDiff; var writeOffset = childMin - minInLod; Vector3I.Max(ref writeOffset, ref Vector3I.Zero, out writeOffset); writeOffset += targetWriteOffset; var nodeData = node.GetData(i); if (lodDiff == 0) { target.Set(type, ref writeOffset, nodeData); } else { var childMax = childMin + ((1 << lodDiff) - 1); Vector3I.Max(ref childMin, ref minInLod, out childMin); Vector3I.Min(ref childMax, ref maxInLod, out childMax); for (int z = childMin.Z; z <= childMax.Z; ++z) { for (int y = childMin.Y; y <= childMax.Y; ++y) { for (int x = childMin.X; x <= childMax.X; ++x) { Vector3I write = writeOffset; write.X += x - childMin.X; write.Y += y - childMin.Y; write.Z += z - childMin.Z; target.Set(type, ref write, nodeData); } } } } } } } }
public static bool DoGrading( IReadOnlyList <IRailGradeComponent> components, Vector3D target, float radius, uint availableForDeposit, uint availableForExcavate, uint[] excavatedByMaterial, byte materialToDeposit, out uint totalDeposited, out uint totalExcavated, bool testDynamic, out bool triedToChange, out bool intersectedDynamic) { try { var voxelRadius = (int)Math.Ceiling(radius); { _dynamicEntities.Clear(); _workingVoxels.Clear(); var sphere = new BoundingSphereD(target, voxelRadius + 2); var tmp = MyEntities.GetEntitiesInSphere(ref sphere); using (tmp.GetClearToken()) foreach (var e in tmp) { if (e is MyVoxelBase vox) { _workingVoxels.Add(vox); } if (e.Physics != null && !e.Physics.IsStatic) { _dynamicEntities.Add(e); } } } totalDeposited = 0; totalExcavated = 0; triedToChange = false; intersectedDynamic = false; var fill = new IGradeShape[components.Count]; var excavate = new IGradeShape[components.Count]; for (var i = 0; i < components.Count; i++) { components[i].Unblit(out fill[i], out excavate[i]); } var voxel = MyGamePruningStructureSandbox.GetClosestPlanet(target)?.RootVoxel; if (voxel == null) { return(false); } Vector3I center; MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxel.PositionLeftBottomCorner, ref target, out center); var voxMin = center - voxelRadius - 1; var voxMax = center + voxelRadius + 1; _storage.Resize(voxMin, voxMax); voxel.Storage.ReadRange(_storage, MyStorageDataTypeFlags.ContentAndMaterial, 0, voxMin, voxMax); var changed = false; #region Mutate for (var i = 0; i <= voxelRadius && (!triedToChange || availableForExcavate > 0 || availableForDeposit > 0); i++) { for (var e = new ShellEnumerator(center - i, center + i); e.MoveNext() && (!triedToChange || availableForExcavate > 0 || availableForDeposit > 0);) { var vCoord = e.Current; var dataCoord = e.Current - voxMin; Vector3D worldCoord; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxel.PositionLeftBottomCorner, ref vCoord, out worldCoord); var cval = _storage.Get(MyStorageDataTypeEnum.Content, ref dataCoord); byte?excavationDensity = null; if (cval > 0 && (!triedToChange || availableForExcavate > 0)) { float density = 0; foreach (var c in excavate.Where(x => x != null)) { density = Math.Max(density, c.GetDensity(ref worldCoord)); } if (density > 0) { excavationDensity = (byte)((1 - density) * byte.MaxValue); } } byte?fillDensity = null; if (cval < byte.MaxValue && (!triedToChange || availableForDeposit > 0)) { float density = 0; foreach (var c in fill.Where(x => x != null)) { density = Math.Max(density, c.GetDensity(ref worldCoord)); } if (density > 0) { fillDensity = (byte)(density * byte.MaxValue); } } if ((!fillDensity.HasValue || cval >= fillDensity.Value) && (!excavationDensity.HasValue || cval <= excavationDensity.Value)) { continue; } if (excavationDensity.HasValue && excavationDensity.Value < cval) { triedToChange = true; var toExtract = (uint)Math.Min(availableForExcavate, cval - excavationDensity.Value); if (toExtract > 0) { var mid = _storage.Get(MyStorageDataTypeEnum.Material, ref dataCoord); if (excavatedByMaterial != null && mid < excavatedByMaterial.Length) { excavatedByMaterial[mid] += toExtract; } DisableFarming(worldCoord); _storage.Set(MyStorageDataTypeEnum.Content, ref dataCoord, (byte)(cval - toExtract)); totalExcavated += toExtract; availableForExcavate -= toExtract; changed = true; } continue; } if (!fillDensity.HasValue || fillDensity.Value <= cval) { continue; } triedToChange = true; var toFill = Math.Min(availableForDeposit, fillDensity.Value - cval); if (toFill <= 0) { continue; } // would this deposit in midair? { var test = worldCoord; test += 2 * Vector3D.Normalize( MyGravityProviderSystem.CalculateNaturalGravityInPoint(worldCoord)); Vector3I vtest; MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxel.PositionLeftBottomCorner, ref test, out vtest); vtest = Vector3I.Clamp(vtest, voxMin, voxMax) - voxMin; if (vtest != vCoord && _storage.Get(MyStorageDataTypeEnum.Content, ref vtest) == 0) { continue; } } // would it touch something dynamic? if (testDynamic) { var box = new BoundingBoxD(worldCoord - 0.25, worldCoord + 0.25); var bad = false; foreach (var k in _dynamicEntities) { if (k.PositionComp.WorldAABB.Contains(box) == ContainmentType.Disjoint) { continue; } var obb = new OrientedBoundingBoxD(k.PositionComp.LocalAABB, k.WorldMatrix); if (!obb.Intersects(ref box)) { continue; } bad = true; break; } if (bad) { intersectedDynamic = true; continue; } } changed = true; DisableFarming(worldCoord); availableForDeposit = (uint)(availableForDeposit - toFill); totalDeposited += (uint)toFill; _storage.Set(MyStorageDataTypeEnum.Content, ref dataCoord, (byte)(cval + toFill)); if (fillDensity.Value <= cval * 1.25f) { continue; } var t = -Vector3I.One; for (var itrContent = new Vector3I_RangeIterator(ref t, ref Vector3I.One); itrContent.IsValid(); itrContent.MoveNext()) { var tpos = dataCoord + itrContent.Current; // var state = _storage.Get(MyStorageDataTypeEnum.Content, ref tpos); // if (itrContent.Current == Vector3I.Zero || state == 0) _storage.Set(MyStorageDataTypeEnum.Material, ref tpos, materialToDeposit); } } } #endregion Mutate if (changed) { voxel.Storage.WriteRange(_storage, MyStorageDataTypeFlags.ContentAndMaterial, voxMin, voxMax); } return(changed); } finally { _dynamicEntities.Clear(); _workingVoxels.Clear(); } }
private void ClampCellCoord(ref Vector3I cellCoord) { Vector3I max = this.m_cellsCount - 1; Vector3I.Clamp(ref cellCoord, ref Vector3I.Zero, ref max, out cellCoord); }
/// <summary> /// Start the reads if it is not already running. /// </summary> /// <param name="onFinished">Invoked when reads finish, not invoked if already running.</param> /// <returns>True if started, false if already running.</returns> public void Read() { Profiler.StartProfileBlock(); m_throwOutVoxelData = Globals.ElapsedTime + Static.LifeSpan_VoxelData; NeedsUpdate = false; Vector3D m_oreDetectorPosition = m_oreDetector.GetPosition(); Vector3D worldMin = m_oreDetectorPosition - m_maxRange; Vector3D worldMax = m_oreDetectorPosition + m_maxRange; float rangeSquared = m_maxRange * m_maxRange; Vector3I odPosVoxelStorage, m_localMin, m_localMax; MyVoxelCoordSystems.WorldPositionToVoxelCoord(m_voxel.PositionLeftBottomCorner, ref m_oreDetectorPosition, out odPosVoxelStorage); MyVoxelCoordSystems.WorldPositionToVoxelCoord(m_voxel.PositionLeftBottomCorner, ref worldMin, out m_localMin); MyVoxelCoordSystems.WorldPositionToVoxelCoord(m_voxel.PositionLeftBottomCorner, ref worldMax, out m_localMax); MyVoxelBase vox = m_voxel as MyVoxelBase; if (m_voxel == null || m_voxel.Storage == null) { Profiler.EndProfileBlock(); return; } m_localMin = Vector3I.Clamp(m_localMin, vox.StorageMin, vox.StorageMax); m_localMax = Vector3I.Clamp(m_localMax, vox.StorageMin, vox.StorageMax); m_localMin >>= QUERY_LOD; m_localMax >>= QUERY_LOD; odPosVoxelStorage >>= QUERY_LOD; Log.DebugLog("minLocal: " + m_localMin + ", maxLocal: " + m_localMax + ", odPosVoxelStorage: " + odPosVoxelStorage); Vector3I size = m_localMax - m_localMin; Log.DebugLog("number of coords in box: " + (size.X + 1) * (size.Y + 1) * (size.Z + 1)); //ulong processed = 0; foreach (List <Vector3I> locations in m_materialLocations2.Values) { locations.Clear(); } Vector3I vector = new Vector3I(); for (vector.X = m_localMin.X; vector.X < m_localMax.X; vector.X += QUERY_STEP) { for (vector.Y = m_localMin.Y; vector.Y < m_localMax.Y; vector.Y += QUERY_STEP) { for (vector.Z = m_localMin.Z; vector.Z < m_localMax.Z; vector.Z += QUERY_STEP) { if (vector.DistanceSquared(odPosVoxelStorage) <= rangeSquared) { m_voxel.Storage.ReadRange(m_storage, MyStorageDataTypeFlags.ContentAndMaterial, QUERY_LOD, vector, vector + QUERY_MAX); Vector3I index = Vector3I.Zero; Vector3I size3D = m_storage.Size3D; for (index.X = 0; index.X < size3D.X; index.X++) { for (index.Y = 0; index.Y < size3D.Y; index.Y++) { for (index.Z = 0; index.Z < size3D.Z; index.Z++) { int linear = m_storage.ComputeLinear(ref index); if (m_storage.Content(linear) > MyVoxelConstants.VOXEL_ISO_LEVEL) { byte mat = m_storage.Material(linear); if (Static.RareMaterials[mat]) { //Log.DebugLog("mat: " + mat + ", content: " + m_storage.Content(linear) + ", vector: " + vector + ", position: " + vector + index // + ", name: " + MyDefinitionManager.Static.GetVoxelMaterialDefinition(mat).MinedOre, "Read()"); //m_materialLocations[vector + index] = mat; List <Vector3I> locations; if (!m_materialLocations2.TryGetValue(mat, out locations)) { locations = new List <Vector3I>(1000); m_materialLocations2.Add(mat, locations); } locations.Add(vector + index); //processed++; goto Finished_Deposit; } } } } } Finished_Deposit :; //processed++; } } } } //Log.DebugLog("read " + processed + ", chunks" + ", number of mats: " + m_materialLocations.Count, Logger.severity.DEBUG); Profiler.EndProfileBlock(); }
/// <summary> /// Recursive clipping function requests cells in provided range and /// cells needed from parent to wrap the lod safely /// </summary> /// <param name="collector"></param> /// <param name="it0">requested range</param> /// <param name="ignore">inner range filled by children</param> private void DoClipping(RequestCollector collector, Vector3I min, Vector3I max, ref BoundingBox ignore) { LodLevel parentLod, clevel; GetNearbyLodLevels(out parentLod, out clevel); MyCellCoord cell = new MyCellCoord(m_lodIndex, Vector3I.Zero); //if (collector.SentRequestsEmpty) { MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); } var it0 = new Vector3I.RangeIterator(ref min, ref max); cell.CoordInLod = it0.Current; var shiftToParent = MyVoxelCoordSystems.RenderCellSizeShiftToLessDetailed(cell.Lod); var parentCell = parentLod != null ? new MyCellCoord(parentLod.m_lodIndex, cell.CoordInLod >> shiftToParent) : cell; var parentIgnore = new BoundingBox(parentCell.CoordInLod, parentCell.CoordInLod); BoundingBox bb = new BoundingBox(cell.CoordInLod, cell.CoordInLod); for (; it0.IsValid(); it0.GetNext(out cell.CoordInLod)) //cells to be loaded { if (ignore.Contains((Vector3)cell.CoordInLod) == ContainmentType.Contains) { continue; //lower lod requested } if (parentLod != null) //get also their lodcell mates { parentCell = new MyCellCoord(parentLod.m_lodIndex, cell.CoordInLod >> shiftToParent); var it = GetChildrenCoords(this, ref parentCell); bb.Include(it); parentIgnore.Max = parentCell.CoordInLod; } } if (parentLod != null) { Vector3I parentMinI = Vector3I.Round(parentIgnore.Min - Vector3.One); Vector3I parentMaxI = Vector3I.Round(parentIgnore.Max + Vector3.One); //Vector3I.Clamp(ref parentMinI, ref Vector3I.Zero, ref m_lodSizeMinusOne, out parentMinI); //Vector3I.Clamp(ref parentMaxI, ref Vector3I.Zero, ref m_lodSizeMinusOne, out parentMaxI); var parentIterator = new Vector3I.RangeIterator(ref parentMinI, ref parentMaxI); parentLod.DoClipping(collector, parentMinI, parentMaxI, ref parentIgnore); } Vector3I start, end; start = Vector3I.Round(bb.Min); end = Vector3I.Round(bb.Max); Vector3I.Clamp(ref start, ref Vector3I.Zero, ref m_lodSizeMinusOne, out start); Vector3I.Clamp(ref end, ref Vector3I.Zero, ref m_lodSizeMinusOne, out end); it0 = new Vector3I.RangeIterator(ref start, ref end); cell.CoordInLod = it0.Current; for (; it0.IsValid(); it0.GetNext(out cell.CoordInLod)) //cells to be loaded { if (ignore.Contains((Vector3)cell.CoordInLod) == ContainmentType.Contains) { continue; //lower lod requested } var cellId = cell.PackId64(); CellData data; if (m_clippedCells.TryGetValue(cellId, out data)) { m_clippedCells.Remove(cellId); } else { var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId); data = CellsCache.Read(clipmapCellId); if (data == null) //cache miss { data = new CellData(); ClippingCacheMisses++; } else { //cache hit ClippingCacheHits++; data.InScene = false; if (data.Cell != null) { m_nonEmptyCells[cellId] = data; } } } if (data.State == CellState.Invalid) { if (!TryAddCellRequest(collector, parentLod, cell, cellId, data)) { continue; } } if (!m_storedCellData.ContainsKey(cellId)) { m_storedCellData.Add(cellId, data); } } }