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(); }
public static void FillInShape( MyVoxelMap voxelMap, MyShape shape, out float voxelsCountInPercent, byte materialIdx, float fillRatio = 1, bool updateSync = false, bool onlyCheck = false) { Profiler.Begin("MyVoxelGenerator::FillInShape()"); if (voxelMap == null) { voxelsCountInPercent = 0f; return; } if (updateSync && Sync.IsServer) { shape.SendFillRequest(voxelMap.SyncObject, materialIdx, fillRatio); } int originalSum = 0; int filledSum = 0; Vector3I minCorner = voxelMap.GetVoxelCoordinateFromMeters(shape.GetMin() - MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * 1.01f); Vector3I maxCorner = voxelMap.GetVoxelCoordinateFromMeters(shape.GetMax() + MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * 1.01f); voxelMap.FixVoxelCoord(ref minCorner); voxelMap.FixVoxelCoord(ref maxCorner); m_cache.Resize(ref minCorner, ref maxCorner); voxelMap.Storage.ReadRange(m_cache, true, true, MyVoxelGeometry.GetLodIndex(MyLodTypeEnum.LOD0), ref minCorner, ref maxCorner); 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 - minCorner; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_FULL) // if there is nothing to add { continue; } var vpos = voxelMap.GetVoxelPositionAbsolute(ref tempVoxelCoord); var volume = shape.GetVolume(ref vpos); if (volume <= 0f) // there is nothing to fill { continue; } m_cache.Material(ref relPos, materialIdx); // set material var maxFill = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); var toFill = (int)(maxFill * fillRatio); if (original > maxFill) { maxFill = original; } var newVal = MathHelper.Clamp(original + toFill, 0, maxFill); if (!onlyCheck) { m_cache.Content(ref relPos, (byte)newVal); } originalSum += original; filledSum += original + newVal; } } } if (filledSum > 0 && !onlyCheck) { voxelMap.Storage.WriteRange(m_cache, true, true, ref minCorner, ref maxCorner); voxelMap.InvalidateCache(minCorner - 1, maxCorner + 1); } voxelsCountInPercent = (originalSum > 0f) ? (float)filledSum / (float)originalSum : 0f; Profiler.End(); }