void VRage.ModAPI.IMyStorage.ReadRange(MyStorageData target, MyStorageDataTypeFlags dataToRead, int lodIndex, Vector3I lodVoxelRangeMin, Vector3I lodVoxelRangeMax, ref MyVoxelRequestFlags requestFlags) { if ((uint)lodIndex >= (uint)MyCellCoord.MAX_LOD_COUNT) return; ReadRange(target, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); }
public static MyStorageData GetVoxelCacheInSphere(this IMyVoxelBase Voxel, BoundingSphereD Sphere, out Vector3I refCorner, out Vector3I refMaxCorner) { if (Voxel == null) { throw new ArgumentNullException(nameof(Voxel)); } if (Voxel.Storage == null) { throw new ArgumentException("Voxel.Storage is null"); } BoundingBoxD SphereBound = VoxelHelpers.GetWorldBoundariesForSphere(Sphere); Vector3I minCorner, maxCorner; Voxel.MyVoxelGenerator_ComputeShapeBounds(ref SphereBound, out minCorner, out maxCorner); Vector3I minCorner1 = minCorner - 1; Vector3I maxCorner1 = maxCorner + 1; Voxel.Storage_ClampVoxelCoord(ref minCorner1, 1); Voxel.Storage_ClampVoxelCoord(ref maxCorner1, 1); MyStorageData cache = new MyStorageData(MyStorageDataTypeFlags.ContentAndMaterial); cache.Resize(minCorner1, maxCorner1); MyVoxelRequestFlags myVoxelRequestFlags = MyVoxelRequestFlags.AdviseCache | MyVoxelRequestFlags.ConsiderContent; Voxel.Storage.ReadRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, minCorner1, maxCorner1, ref myVoxelRequestFlags); refCorner = minCorner1; refMaxCorner = maxCorner1; return(cache); }
public void ReadRange(MyStorageData target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax, ref MyVoxelRequestFlags requestFlags) { ProfilerShort.Begin(GetType().Name + ".ReadRange"); try { const int SUBRANGE_SIZE_SHIFT = 3; const int SUBRANGE_SIZE = 1 << SUBRANGE_SIZE_SHIFT; var threshold = new Vector3I(SUBRANGE_SIZE); var rangeSize = lodVoxelRangeMax - lodVoxelRangeMin + 1; if ((dataToRead & MyStorageDataTypeFlags.Content) != 0) { target.ClearContent(0); } if ((rangeSize.X <= threshold.X && rangeSize.Y <= threshold.Y && rangeSize.Z <= threshold.Z) || !MyFakes.ENABLE_SPLIT_VOXEL_READ_QUERIES) { using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); } } else { // These optimizations don't work when splitting the range. requestFlags &= ~(MyVoxelRequestFlags.OneMaterial | MyVoxelRequestFlags.ContentChecked); MyVoxelRequestFlags flags = requestFlags; // splitting to smaller ranges to make sure the lock is not held for too long, preventing write on update thread // subranges could be aligned to multiple of their size for possibly better performance var steps = (rangeSize - 1) >> SUBRANGE_SIZE_SHIFT; for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref steps); it.IsValid(); it.MoveNext()) { flags = requestFlags; var offset = it.Current << SUBRANGE_SIZE_SHIFT; var min = lodVoxelRangeMin + offset; var max = min + SUBRANGE_SIZE - 1; Vector3I.Min(ref max, ref lodVoxelRangeMax, out max); Debug.Assert(min.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); Debug.Assert(max.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref offset, dataToRead, lodIndex, ref min, ref max, ref flags); } } // If the storage is consistent this should be fine. requestFlags = flags; } } finally { ProfilerShort.End(); } }
public static void PaintInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx) { using (voxelMap.Pin()) { if (!voxelMap.MarkedForClose) { Vector3I vectori; Vector3I maxCorner; Vector3I minCorner; GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out vectori); if (m_cache == null) { m_cache = new MyStorageData(MyStorageDataTypeFlags.All); } Vector3I_RangeIterator it = new Vector3I_RangeIterator(ref Vector3I.Zero, ref vectori); while (true) { Vector3I vectori2; Vector3I vectori3; if (!it.IsValid()) { MySandboxGame.Static.Invoke(delegate { if (voxelMap.Storage != null) { voxelMap.Storage.NotifyChanged(minCorner, maxCorner, MyStorageDataTypeFlags.All); } }, "PaintInShape notify"); break; } GetCellCorners(ref minCorner, ref maxCorner, ref it, out vectori2, out vectori3); m_cache.Resize(vectori2, vectori3); MyVoxelRequestFlags considerContent = MyVoxelRequestFlags.ConsiderContent; voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.All, 0, vectori2, vectori3, ref considerContent); Vector3I_RangeIterator iterator2 = new Vector3I_RangeIterator(ref vectori2, ref vectori3); while (true) { Vector3D vectord; if (!iterator2.IsValid()) { voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Material, vectori2, vectori3, false, true); it.MoveNext(); break; } Vector3I p = iterator2.Current - vectori2; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref iterator2.Current, out vectord); if ((shape.GetVolume(ref vectord) > 0.5f) && (m_cache.Material(ref p) != 0xff)) { m_cache.Material(ref p, materialIdx); } iterator2.MoveNext(); } } } } }
private void ReadDatForChunk(VoxelChunk chunk, MyStorageDataTypeFlags data) { var rangeStart = chunk.Coords << VoxelChunk.SizeBits; var rangeEnd = ((chunk.Coords + 1) << VoxelChunk.SizeBits) - 1; MyStorageData storage = chunk.MakeData(); MyVoxelRequestFlags flags = 0; ReadRangeInternal(storage, ref Vector3I.Zero, data, 0, ref rangeStart, ref rangeEnd, ref flags); chunk.Cached |= data; }
void IMyOctreeLeafNode.ReadRange(MyStorageData target, MyStorageDataTypeFlags types, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod, ref MyVoxelRequestFlags flags) { var lodShift = m_cell.Lod - lodIndex; var leafMinInLod = m_cell.CoordInLod << lodShift; var min = minInLod + leafMinInLod; var max = maxInLod + leafMinInLod; AssertRangeIsInside(lodIndex, ref min, ref max); ProfilerShort.Begin("MyProviderLeaf.ReadRange"); MyVoxelDataRequest req = new MyVoxelDataRequest() { Target = target, Offset = writeOffset, Lod = lodIndex, minInLod = min, maxInLod = max, RequestFlags = flags, RequestedData = types }; m_provider.ReadRange(ref req); flags = req.Flags; ProfilerShort.End(); }
private unsafe void ProcessCell(MyStorageData cache, IMyStorage storage, Vector3I cell, long detectorId) { Vector3I lodVoxelRangeMin = cell << 3; Vector3I lodVoxelRangeMax = (Vector3I)(lodVoxelRangeMin + 7); storage.ReadRange(cache, MyStorageDataTypeFlags.Content, 2, lodVoxelRangeMin, lodVoxelRangeMax); if (cache.ContainsVoxelsAboveIsoLevel()) { Vector3I vectori3; MyVoxelRequestFlags preciseOrePositions = MyVoxelRequestFlags.PreciseOrePositions; storage.ReadRange(cache, MyStorageDataTypeFlags.Material, 2, lodVoxelRangeMin, lodVoxelRangeMax, ref preciseOrePositions); MaterialPositionData[] materialData = MaterialData; vectori3.Z = 0; while (vectori3.Z < 8) { vectori3.Y = 0; while (true) { if (vectori3.Y >= 8) { int *numPtr4 = (int *)ref vectori3.Z; numPtr4[0]++; break; } vectori3.X = 0; while (true) { if (vectori3.X >= 8) { int *numPtr3 = (int *)ref vectori3.Y; numPtr3[0]++; break; } int linearIdx = cache.ComputeLinear(ref vectori3); if (cache.Content(linearIdx) > 0x7f) { byte index = cache.Material(linearIdx); Vector3D vectord = ((vectori3 + lodVoxelRangeMin) * 4f) + 2f; Vector3 *vectorPtr1 = (Vector3 *)ref materialData[index].Sum; vectorPtr1[0] += vectord; int *numPtr1 = (int *)ref materialData[index].Count; numPtr1[0]++; } int *numPtr2 = (int *)ref vectori3.X; numPtr2[0]++; } } } MyEntityOreDeposit item = null; for (int i = 0; i < materialData.Length; i++) { if (materialData[i].Count != 0) { MyVoxelMaterialDefinition voxelMaterialDefinition = MyDefinitionManager.Static.GetVoxelMaterialDefinition((byte)i); if ((voxelMaterialDefinition != null) && voxelMaterialDefinition.IsRare) { if (item == null) { item = new MyEntityOreDeposit(this.VoxelMap, cell, detectorId); } MyEntityOreDeposit.Data data = new MyEntityOreDeposit.Data { Material = voxelMaterialDefinition, AverageLocalPosition = (Vector3)Vector3D.Transform((materialData[i].Sum / ((float)materialData[i].Count)) - this.VoxelMap.SizeInMetresHalf, Quaternion.CreateFromRotationMatrix(this.VoxelMap.WorldMatrix)) }; item.Materials.Add(data); } } } if (item != null) { this.m_result.Add(item); } else { this.m_emptyCells.Add(cell); } Array.Clear(materialData, 0, materialData.Length); } }
protected override void ReadRangeInternal(MyStorageData target, ref Vector3I targetWriteOffset, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelCoordStart, ref Vector3I lodVoxelCoordEnd, ref MyVoxelRequestFlags flags) { bool hasLod = lodIndex <= (m_treeHeight + LeafLodCount); Debug.Assert(dataToRead != MyStorageDataTypeFlags.None); MyVoxelRequestFlags cflags = 0; MyVoxelRequestFlags mflags = 0; if ((dataToRead & MyStorageDataTypeFlags.Content) != 0) { if (hasLod) { cflags = flags; ReadRange(target, ref targetWriteOffset, MyStorageDataTypeFlags.Content, m_treeHeight, m_contentNodes, m_contentLeaves, lodIndex, ref lodVoxelCoordStart, ref lodVoxelCoordEnd, ref cflags); } } if ((dataToRead.Requests(MyStorageDataTypeEnum.Material) || dataToRead.Requests(MyStorageDataTypeEnum.Occlusion)) && !cflags.HasFlag(MyVoxelRequestFlags.MaterialForContent | MyVoxelRequestFlags.EmptyContent)) { if (hasLod) { mflags = flags; ReadRange(target, ref targetWriteOffset, dataToRead.Without(MyStorageDataTypeEnum.Content), m_treeHeight, m_materialNodes, m_materialLeaves, lodIndex, ref lodVoxelCoordStart, ref lodVoxelCoordEnd, ref mflags); } } // Material and content flags are safe to merge flags = cflags | mflags; }
public static List <Vector3I> GetVoxelPointsInSphere(this IMyVoxelBase Voxel, BoundingSphereD Sphere, out MyStorageData cache) { if (Voxel == null) { throw new ArgumentNullException(nameof(Voxel)); } if (Voxel.Storage == null) { throw new ArgumentException("Voxel.Storage is null"); } List <Vector3I> VoxelPoints = new List <Vector3I>(); MyVoxelBase myVoxel = (Voxel as MyVoxelBase); BoundingBoxD SphereBound = VoxelHelpers.GetWorldBoundariesForSphere(Sphere); Vector3 CoordsSystemOutValue; MyVoxelCoordSystems.WorldPositionToLocalPosition(Sphere.Center, Voxel.PositionComp.WorldMatrix, Voxel.PositionComp.WorldMatrixInvScaled, myVoxel.SizeInMetresHalf, out CoordsSystemOutValue); Vector3I VoxelInSphereCenter = new Vector3I(CoordsSystemOutValue / 1f) + myVoxel.StorageMin; // --- I don't know what exactly this vector magic does, this was salvaged from the game's source --- // The only idea I have is that from the engine's perspective, every asteroid and planet consist of // voxel points (or just "voxels") which are 1 m^3 (2x2x2 small ship blocks) cubes aligned to // the world's XYZ axes, which may have different "filling" levels from 0 (empty) to 255. // The smooth surfaces we see on asteroids are a result of postprocessing of semi-filled voxel cubes // on the outer edges of voxel maps, though this post-processing also affects physics (e.g. collisions). // Voxels, like cube grids, have their local coordinate systems, which are built relative to the voxel map's // left bottom corner. If you want to find or work with a specific voxel point at a given world position, // you have to convert the world coordinates to the voxel map's local coordinates, // which can be done using the whitelisted static class /// <see cref="MyVoxelCoordSystems"/> Vector3I minCorner, maxCorner; Voxel.MyVoxelGenerator_ComputeShapeBounds(ref SphereBound, out minCorner, out maxCorner); Vector3I minCorner1 = minCorner - 1; Vector3I maxCorner1 = maxCorner + 1; Voxel.Storage_ClampVoxelCoord(ref minCorner1, 1); Voxel.Storage_ClampVoxelCoord(ref maxCorner1, 1); cache = new MyStorageData(MyStorageDataTypeFlags.ContentAndMaterial); cache.Resize(minCorner1, maxCorner1); MyVoxelRequestFlags myVoxelRequestFlags = MyVoxelRequestFlags.AdviseCache | MyVoxelRequestFlags.ConsiderContent; Voxel.Storage.ReadRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, minCorner1, maxCorner1, ref myVoxelRequestFlags); // --- Vector3I voxelpoint; voxelpoint.X = minCorner.X; while (voxelpoint.X <= maxCorner.X) { voxelpoint.Y = minCorner.Y; while (voxelpoint.Y <= maxCorner.Y) { voxelpoint.Z = minCorner.Z; while (voxelpoint.Z <= maxCorner.Z) { if (Vector3D.DistanceSquared(VoxelInSphereCenter, voxelpoint) <= Sphere.Radius * Sphere.Radius && cache.Content(ref voxelpoint) > 0) { VoxelPoints.Add(voxelpoint); } voxelpoint.Z++; } voxelpoint.Y++; } voxelpoint.X++; } return(VoxelPoints); }
void VRage.ModAPI.IMyStorage.ReadRange(MyStorageData target, MyStorageDataTypeFlags dataToRead, int lodIndex, Vector3I lodVoxelRangeMin, Vector3I lodVoxelRangeMax, ref MyVoxelRequestFlags requestFlags) { if ((uint)lodIndex >= (uint)MyCellCoord.MAX_LOD_COUNT) { return; } ReadRange(target, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); }
public void ReadRange(MyStorageData target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax) { MyVoxelRequestFlags flags = 0; ReadRange(target, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref flags); }
protected abstract void ReadRangeInternal(MyStorageData target, ref Vector3I targetWriteRange, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax, ref MyVoxelRequestFlags requestFlags);
public static void FillInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx) { using (voxelMap.Pin()) { if (!voxelMap.MarkedForClose) { Vector3I vectori; Vector3I maxCorner; Vector3I minCorner; ulong num = 0UL; GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out vectori); minCorner = Vector3I.Max(Vector3I.One, minCorner); maxCorner = Vector3I.Max(minCorner, maxCorner - Vector3I.One); if (m_cache == null) { m_cache = new MyStorageData(MyStorageDataTypeFlags.All); } Vector3I_RangeIterator it = new Vector3I_RangeIterator(ref Vector3I.Zero, ref vectori); while (true) { Vector3I vectori2; Vector3I vectori3; if (!it.IsValid()) { if (num > 0L) { BoundingBoxD cutOutBox = shape.GetWorldBoundaries(); MySandboxGame.Static.Invoke(delegate { if (voxelMap.Storage != null) { voxelMap.Storage.NotifyChanged(minCorner, maxCorner, MyStorageDataTypeFlags.All); NotifyVoxelChanged(MyVoxelBase.OperationType.Fill, voxelMap, ref cutOutBox); } }, "FillInShape Notify"); } break; } GetCellCorners(ref minCorner, ref maxCorner, ref it, out vectori2, out vectori3); Vector3I originalValue = vectori3; voxelMap.Storage.ClampVoxelCoord(ref vectori2, 0); voxelMap.Storage.ClampVoxelCoord(ref vectori3, 0); ClampingInfo info = CheckForClamping(vectori2, vectori2); ClampingInfo info2 = CheckForClamping(originalValue, vectori3); m_cache.Resize(vectori2, vectori3); MyVoxelRequestFlags considerContent = MyVoxelRequestFlags.ConsiderContent; voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.All, 0, vectori2, vectori3, ref considerContent); ulong num2 = 0UL; Vector3I_RangeIterator iterator2 = new Vector3I_RangeIterator(ref vectori2, ref vectori3); while (true) { if (!iterator2.IsValid()) { if (num2 > 0L) { RemoveSmallVoxelsUsingChachedVoxels(); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.All, vectori2, vectori3, false, true); } num += num2; it.MoveNext(); break; } Vector3I p = iterator2.Current - vectori2; byte num3 = m_cache.Content(ref p); if ((num3 != 0xff) || (m_cache.Material(ref p) != materialIdx)) { if ((((iterator2.Current.X == vectori2.X) && info.X) || (((iterator2.Current.X == vectori3.X) && info2.X) || (((iterator2.Current.Y == vectori2.Y) && info.Y) || (((iterator2.Current.Y == vectori3.Y) && info2.Y) || ((iterator2.Current.Z == vectori2.Z) && info.Z))))) || ((iterator2.Current.Z == vectori3.Z) && info2.Z)) { if (num3 != 0) { m_cache.Material(ref p, materialIdx); } } else { Vector3D vectord; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref iterator2.Current, out vectord); float volume = shape.GetVolume(ref vectord); if (volume > 0f) { long num6 = Math.Max(num3, (int)(volume * 255f)); m_cache.Content(ref p, (byte)num6); if (num6 != 0) { m_cache.Material(ref p, materialIdx); } num2 += ((ulong)num6) - num3; } } } iterator2.MoveNext(); } } } } }
public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient, bool doNotCheck = false) { // change range so normal can be computed at edges (expand by 1 in all directions) voxelStart -= 1; voxelEnd += 1; if (storage == null) { return(null); } using (storage.Pin()) { if (storage.Closed) { return(null); } MyVoxelRequestFlags request = MyVoxelRequestFlags.ContentChecked; // | (doNotCheck ? MyVoxelRequestFlags.DoNotCheck : 0); //if (lod == 0 && generateMaterials) request |= MyVoxelRequestFlags.AdviseCache; bool readAmbient = false; if (generateMaterials && storage.DataProvider != null && storage.DataProvider.ProvidesAmbient) { readAmbient = true; } m_cache.Resize(voxelStart, voxelEnd); if (readAmbient) { m_cache.StoreOcclusion = true; } storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd, ref request); if (request.HasFlag(MyVoxelRequestFlags.EmptyContent) || request.HasFlag(MyVoxelRequestFlags.FullContent) || (!request.HasFlag(MyVoxelRequestFlags.ContentChecked) && !m_cache.ContainsIsoSurface())) { //if(generateMaterials && lod == 0) Debugger.Break(); //storage.DebugDrawChunk(voxelStart, voxelEnd); return(null); } var center = (storage.Size / 2) * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod); var vertexCellOffset = voxelStart - AffectedRangeOffset; double numCellsHalf = 0.5 * (m_cache.Size3D.X - 3); var posOffset = ((Vector3D)vertexCellOffset + numCellsHalf) * (double)voxelSize; if (generateMaterials) { // 255 is the new black m_cache.ClearMaterials(255); } if (readAmbient) { m_cache.Clear(MyStorageDataTypeEnum.Occlusion, 0); } IsoMesher mesher = new IsoMesher(); ProfilerShort.Begin("Dual Contouring"); unsafe { fixed(byte *content = m_cache[MyStorageDataTypeEnum.Content]) fixed(byte *material = m_cache[MyStorageDataTypeEnum.Material]) { var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); mesher.Calculate(size3d.X, content, material, m_buffer, useAmbient, posOffset - center); } } ProfilerShort.End(); if (generateMaterials) { request = 0; request |= MyVoxelRequestFlags.SurfaceMaterial; request |= MyVoxelRequestFlags.ConsiderContent; var req = readAmbient ? MyStorageDataTypeFlags.Material | MyStorageDataTypeFlags.Occlusion : MyStorageDataTypeFlags.Material; storage.ReadRange(m_cache, req, lod, ref voxelStart, ref voxelEnd, ref request); FixCacheMaterial(voxelStart, voxelEnd); unsafe { fixed(byte *content = m_cache[MyStorageDataTypeEnum.Content]) fixed(byte *material = m_cache[MyStorageDataTypeEnum.Material]) { int materialOverride = request.HasFlag(MyVoxelRequestFlags.OneMaterial) ? m_cache.Material(0) : -1; var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); if (readAmbient) fixed(byte *ambient = m_cache[MyStorageDataTypeEnum.Occlusion]) mesher.CalculateMaterials(size3d.X, content, material, ambient, materialOverride); else { mesher.CalculateMaterials(size3d.X, content, material, null, materialOverride); } } } } else { m_cache.ClearMaterials(0); } mesher.Finish(m_buffer); if (m_buffer.VerticesCount == 0 || m_buffer.Triangles.Count == 0) { return(null); } ProfilerShort.Begin("Geometry post-processing"); { var positions = m_buffer.Positions.GetInternalArray(); var vertexCells = m_buffer.Cells.GetInternalArray(); var materials = m_buffer.Materials.GetInternalArray(); for (int i = 0; i < m_buffer.VerticesCount; i++) { Debug.Assert(positions[i].IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); vertexCells[i] += vertexCellOffset; Debug.Assert(vertexCells[i].IsInsideInclusive(voxelStart + 1, voxelEnd - 1)); Debug.Assert(materials[i] != MyVoxelConstants.NULL_MATERIAL); } m_buffer.PositionOffset = posOffset; m_buffer.PositionScale = new Vector3((float)(numCellsHalf * voxelSize)); m_buffer.CellStart = voxelStart + 1; m_buffer.CellEnd = voxelEnd - 1; } ProfilerShort.End(); // Replace filled mesh with new one. // This way prevents allocation of meshes which then end up empty. var buffer = m_buffer; m_buffer = new MyIsoMesh(); return(buffer); } }
public static unsafe void CutOutShapeWithProperties(MyVoxelBase voxelMap, MyShape shape, out float voxelsCountInPercent, out MyVoxelMaterialDefinition voxelMaterial, Dictionary <MyVoxelMaterialDefinition, int> exactCutOutMaterials = null, bool updateSync = false, bool onlyCheck = false, bool applyDamageMaterial = false, bool onlyApplyMaterial = false, bool skipCache = false) { if ((!MySession.Static.EnableVoxelDestruction || ((voxelMap == null) || (voxelMap.Storage == null))) || (shape == null)) { voxelsCountInPercent = 0f; voxelMaterial = null; } else { Vector3I vectori3; Vector3I vectori4; Vector3I maxCorner; Vector3I minCorner; int num = 0; int num2 = 0; MatrixD transformation = shape.Transformation; MatrixD xd2 = transformation * voxelMap.PositionComp.WorldMatrixInvScaled; MatrixD *xdPtr1 = (MatrixD *)ref xd2; xdPtr1.Translation += voxelMap.SizeInMetresHalf; shape.Transformation = xd2; BoundingBoxD worldBoundaries = shape.GetWorldBoundaries(); ComputeShapeBounds(voxelMap, ref worldBoundaries, Vector3.Zero, voxelMap.Storage.Size, out minCorner, out maxCorner); bool flag = (exactCutOutMaterials != null) | applyDamageMaterial; Vector3I voxelCoord = minCorner - 1; Vector3I vectori2 = (Vector3I)(maxCorner + 1); voxelMap.Storage.ClampVoxelCoord(ref voxelCoord, 1); voxelMap.Storage.ClampVoxelCoord(ref vectori2, 1); if (m_cache == null) { m_cache = new MyStorageData(MyStorageDataTypeFlags.All); } m_cache.Resize(voxelCoord, vectori2); MyVoxelRequestFlags requestFlags = (skipCache ? ((MyVoxelRequestFlags)0) : MyVoxelRequestFlags.AdviseCache) | (flag ? MyVoxelRequestFlags.ConsiderContent : ((MyVoxelRequestFlags)0)); voxelMap.Storage.ReadRange(m_cache, flag ? MyStorageDataTypeFlags.All : MyStorageDataTypeFlags.Content, 0, voxelCoord, vectori2, ref requestFlags); if (exactCutOutMaterials != null) { vectori3 = (Vector3I)(m_cache.Size3D / 2); voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref vectori3)); } else { vectori3 = (Vector3I)((voxelCoord + vectori2) / 2); voxelMaterial = voxelMap.Storage.GetMaterialAt(ref vectori3); } MyVoxelMaterialDefinition key = null; vectori4.X = minCorner.X; while (vectori4.X <= maxCorner.X) { vectori4.Y = minCorner.Y; while (true) { if (vectori4.Y > maxCorner.Y) { int *numPtr3 = (int *)ref vectori4.X; numPtr3[0]++; break; } vectori4.Z = minCorner.Z; while (true) { if (vectori4.Z > maxCorner.Z) { int *numPtr2 = (int *)ref vectori4.Y; numPtr2[0]++; break; } Vector3I p = vectori4 - voxelCoord; int linearIdx = m_cache.ComputeLinear(ref p); byte num4 = m_cache.Content(linearIdx); if (num4 != 0) { Vector3D voxelPosition = (Vector3D)((vectori4 - voxelMap.StorageMin) * 1.0); float volume = shape.GetVolume(ref voxelPosition); if (volume != 0f) { int num7 = Math.Max(num4 - ((int)(volume * 255f)), 0); int num8 = num4 - num7; if ((num4 / 10) != (num7 / 10)) { if (!onlyCheck && !onlyApplyMaterial) { m_cache.Content(linearIdx, (byte)num7); } num += num4; num2 += num8; byte materialIndex = m_cache.Material(linearIdx); if (num7 == 0) { m_cache.Material(linearIdx, 0xff); } if (materialIndex != 0xff) { if (flag) { key = MyDefinitionManager.Static.GetVoxelMaterialDefinition(materialIndex); } if (exactCutOutMaterials != null) { int num10; exactCutOutMaterials.TryGetValue(key, out num10); exactCutOutMaterials[key] = num10 + (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? ((int)(num8 * 3.9f)) : num8); } } } } } int *numPtr1 = (int *)ref vectori4.Z; numPtr1[0]++; } } } if ((((num2 > 0) & updateSync) && Sync.IsServer) && !onlyCheck) { shape.SendDrillCutOutRequest(voxelMap, applyDamageMaterial); } if ((num2 > 0) && !onlyCheck) { RemoveSmallVoxelsUsingChachedVoxels(); MyStorageDataTypeFlags all = MyStorageDataTypeFlags.All; if (MyFakes.LOG_NAVMESH_GENERATION && (MyAIComponent.Static.Pathfinding != null)) { MyAIComponent.Static.Pathfinding.GetPathfindingLog().LogStorageWrite(voxelMap, m_cache, all, voxelCoord, vectori2); } voxelMap.Storage.WriteRange(m_cache, all, voxelCoord, vectori2, false, skipCache); } voxelsCountInPercent = (num > 0f) ? (((float)num2) / ((float)num)) : 0f; if (num2 > 0) { BoundingBoxD cutOutBox = shape.GetWorldBoundaries(); MySandboxGame.Static.Invoke(delegate { if (voxelMap.Storage != null) { voxelMap.Storage.NotifyChanged(minCorner, maxCorner, MyStorageDataTypeFlags.All); NotifyVoxelChanged(MyVoxelBase.OperationType.Cut, voxelMap, ref cutOutBox); } }, "CutOutShapeWithProperties notify"); } shape.Transformation = transformation; } }
public static unsafe void ChangeMaterialsInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx, bool[] materialsToChange) { if ((voxelMap != null) && (shape != null)) { using (voxelMap.Pin()) { if (!voxelMap.MarkedForClose) { Vector3I vectori; Vector3I vectori2; Vector3I vectori5; MatrixD xd = shape.Transformation * voxelMap.PositionComp.WorldMatrixInvScaled; MatrixD *xdPtr1 = (MatrixD *)ref xd; xdPtr1.Translation += voxelMap.SizeInMetresHalf; shape.Transformation = xd; BoundingBoxD worldBoundaries = shape.GetWorldBoundaries(); ComputeShapeBounds(voxelMap, ref worldBoundaries, Vector3.Zero, voxelMap.Storage.Size, out vectori, out vectori2); Vector3I voxelCoord = vectori - 1; Vector3I vectori4 = (Vector3I)(vectori2 + 1); voxelMap.Storage.ClampVoxelCoord(ref voxelCoord, 1); voxelMap.Storage.ClampVoxelCoord(ref vectori4, 1); if (m_cache == null) { m_cache = new MyStorageData(MyStorageDataTypeFlags.All); } m_cache.Resize(voxelCoord, vectori4); MyVoxelRequestFlags requestFlags = MyVoxelRequestFlags.AdviseCache | MyVoxelRequestFlags.ConsiderContent; voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, 0, voxelCoord, vectori4, ref requestFlags); vectori5.X = vectori.X; while (vectori5.X <= vectori2.X) { vectori5.Y = vectori.Y; while (true) { if (vectori5.Y > vectori2.Y) { int *numPtr3 = (int *)ref vectori5.X; numPtr3[0]++; break; } vectori5.Z = vectori.Z; while (true) { if (vectori5.Z > vectori2.Z) { int *numPtr2 = (int *)ref vectori5.Y; numPtr2[0]++; break; } Vector3I p = vectori5 - vectori; int linearIdx = m_cache.ComputeLinear(ref p); byte index = m_cache.Material(linearIdx); if (materialsToChange[index]) { Vector3D vectord; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref vectori5, out vectord); if ((shape.GetVolume(ref vectord) > 0.5f) && (m_cache.Material(ref p) != 0xff)) { m_cache.Material(ref p, materialIdx); } } int *numPtr1 = (int *)ref vectori5.Z; numPtr1[0]++; } } } } } } }
public static void CutOutShape(MyVoxelBase voxelMap, MyShape shape, bool voxelHand = false) { if (MySession.Static.EnableVoxelDestruction || MySession.Static.HighSimulationQuality) { using (voxelMap.Pin()) { if (!voxelMap.MarkedForClose) { Vector3I vectori; Vector3I maxCorner; Vector3I minCorner; GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out vectori); ulong num = 0UL; if (m_cache == null) { m_cache = new MyStorageData(MyStorageDataTypeFlags.All); } Vector3I_RangeIterator it = new Vector3I_RangeIterator(ref Vector3I.Zero, ref vectori); while (true) { Vector3I vectori2; Vector3I vectori3; if (!it.IsValid()) { if (num > 0L) { BoundingBoxD cutOutBox = shape.GetWorldBoundaries(); MySandboxGame.Static.Invoke(delegate { if (voxelMap.Storage != null) { voxelMap.Storage.NotifyChanged(minCorner, maxCorner, MyStorageDataTypeFlags.All); NotifyVoxelChanged(MyVoxelBase.OperationType.Cut, voxelMap, ref cutOutBox); } }, "CutOutShape notify"); } break; } GetCellCorners(ref minCorner, ref maxCorner, ref it, out vectori2, out vectori3); Vector3I voxelCoord = vectori2 - 1; Vector3I vectori5 = (Vector3I)(vectori3 + 1); voxelMap.Storage.ClampVoxelCoord(ref voxelCoord, 1); voxelMap.Storage.ClampVoxelCoord(ref vectori5, 1); ulong num2 = 0UL; m_cache.Resize(voxelCoord, vectori5); MyVoxelRequestFlags considerContent = MyVoxelRequestFlags.ConsiderContent; voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.All, 0, voxelCoord, vectori5, ref considerContent); Vector3I_RangeIterator iterator2 = new Vector3I_RangeIterator(ref vectori2, ref vectori3); while (true) { if (!iterator2.IsValid()) { if (num2 > 0L) { RemoveSmallVoxelsUsingChachedVoxels(); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.All, voxelCoord, vectori5, false, true); } num += num2; it.MoveNext(); break; } Vector3I p = iterator2.Current - voxelCoord; byte num3 = m_cache.Content(ref p); if (num3 != 0) { Vector3D vectord; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref iterator2.Current, out vectord); float volume = shape.GetVolume(ref vectord); if (volume != 0f) { int num5 = Math.Min((int)(255f - (volume * 255f)), num3); ulong num6 = (ulong)Math.Abs((int)(num3 - num5)); m_cache.Content(ref p, (byte)num5); if (num5 == 0) { m_cache.Material(ref p, 0xff); } num2 += num6; } } iterator2.MoveNext(); } } } } } }
private unsafe void ReadRange( MyStorageData target, ref Vector3I targetWriteOffset, MyStorageDataTypeFlags types, int treeHeight, Dictionary<UInt64, MyOctreeNode> nodes, Dictionary<UInt64, IMyOctreeLeafNode> leaves, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod, ref MyVoxelRequestFlags flags) { 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(); var octreeType = types.Requests(MyStorageDataTypeEnum.Content) ? MyStorageDataTypeEnum.Content : MyStorageDataTypeEnum.Material; FillOutOfBounds(target, octreeType, ref targetWriteOffset, lodIndex, minInLod, maxInLod); while (stackIdx > 0) { Debug.Assert(stackIdx <= stackSize); data = stack[--stackIdx]; cell.Lod = Math.Max(data.Lod - LeafLodCount, 0); 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); Vector3I minInLeaf = minInLod - nodePosInLod; Vector3I maxInLeaf = maxInLod - nodePosInLod; if (!minInLeaf.IsInsideInclusive(Vector3I.Zero, lodSizeMinusOne) || !maxInLeaf.IsInsideInclusive(Vector3I.Zero, lodSizeMinusOne)) { minInLeaf = Vector3I.Clamp(minInLod - nodePosInLod, Vector3I.Zero, lodSizeMinusOne); maxInLeaf = Vector3I.Clamp(maxInLod - nodePosInLod, Vector3I.Zero, lodSizeMinusOne); // No Optimizations when not reading entirelly from the provider because the octree can't take it. flags &= MyVoxelRequestFlags.SurfaceMaterial; } leaf.ReadRange(target, types, ref writeOffset, lodIndex, ref minInLeaf, ref maxInLeaf, ref flags); // Occlusion is not stored in tree, we just read from provider if (!leaf.ReadOnly && types.Requests(MyStorageDataTypeEnum.Occlusion)) { minInLeaf += nodePosInLod; maxInLeaf += nodePosInLod; ReadFromProvider(target, MyStorageDataTypeFlags.Occlusion, ref writeOffset, lodIndex, ref minInLeaf, ref maxInLeaf, ref flags); } } continue; } cell.Lod -= 1; lodDiff = data.Lod - 1 - lodIndex; MyOctreeNode node; if (nodes.TryGetValue(cell.PackId64(), out node) == false) { Debug.Fail("invalid querry for node"); continue; } 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 { // No Optimizations when not reading entirelly from the provider because the octree can't take it. flags &= MyVoxelRequestFlags.SurfaceMaterial; 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(octreeType, 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(octreeType, ref write, nodeData); } } } } } }
private void ReadFromProvider(MyStorageData target, MyStorageDataTypeFlags types, ref Vector3I writeOffset, int lodIndex, ref Vector3I min, ref Vector3I max, ref MyVoxelRequestFlags flags) { ProfilerShort.Begin("MyProviderLeaf.ReadRange"); MyVoxelDataRequest req = new MyVoxelDataRequest() { Target = target, Offset = writeOffset, Lod = lodIndex, minInLod = min, maxInLod = max, RequestFlags = flags, RequestedData = types }; DataProvider.ReadRange(ref req); flags = req.Flags; ProfilerShort.End(); }
public bool GetVoxelContent(IMyVoxelBase voxel, Vector3D position, out byte content, out byte material, MyStorageData cache = null, Vector3D?endpoint = null, MyVoxelRequestFlags flags = 0) { if (endpoint == null) { endpoint = position; } content = 0; material = 0; if (voxel == null || voxel.Storage == null) { return(false); } if (cache == null) { cache = new MyStorageData(); } var targetMin = position; Vector3D targetMax = endpoint.Value; Vector3I minVoxel, maxVoxel; MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxel.PositionLeftBottomCorner, ref targetMin, out minVoxel); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxel.PositionLeftBottomCorner, ref targetMax, out maxVoxel); MyVoxelBase voxelBase = voxel as MyVoxelBase; minVoxel += voxelBase.StorageMin; maxVoxel += voxelBase.StorageMin; voxel.Storage.ClampVoxel(ref minVoxel); voxel.Storage.ClampVoxel(ref maxVoxel); cache.Resize(minVoxel, maxVoxel); voxel.Storage.ReadRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, minVoxel, maxVoxel, ref flags); // Grab content and material content = cache.Content(0); material = cache.Material(0); return(cache.ContainsVoxelsAboveIsoLevel()); }
public static bool HasFlags(this MyVoxelRequestFlags self, MyVoxelRequestFlags other) { return (self & other) == other; }
public static bool HasFlags(this MyVoxelRequestFlags self, MyVoxelRequestFlags other) { return((self & other) == other); }
public void ReadRange(MyStorageData target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax, ref MyVoxelRequestFlags requestFlags) { ProfilerShort.Begin(GetType().Name + ".ReadRange"); if ((dataToRead & MyStorageDataTypeFlags.Content) != 0) { target.ClearContent(0); } if (requestFlags.HasFlags(MyVoxelRequestFlags.AdviseCache) && lodIndex == 0 && CachedWrites) { ReadRangeAdviseCache(target, dataToRead, ref lodVoxelRangeMin, ref lodVoxelRangeMax); ProfilerShort.End(); return; } if (CachedWrites && lodIndex <= VoxelChunk.SizeBits && m_cachedChunks.Count > 0) { // read occlusion separate if (dataToRead.Requests(MyStorageDataTypeEnum.Occlusion)) { using (m_storageLock.AcquireSharedUsing()) ReadRangeInternal(target, ref Vector3I.Zero, MyStorageDataTypeFlags.Occlusion, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); dataToRead ^= MyStorageDataTypeFlags.Occlusion; } if (m_tmpChunks == null) { m_tmpChunks = new List <VoxelChunk>(); } var lodDiff = VoxelChunk.SizeBits - lodIndex; // We fetch which chunks overlap our current range from the chunk tree, then we read all data from storage and apply those changes var querybb = new BoundingBox(lodVoxelRangeMin << lodIndex, lodVoxelRangeMax << lodIndex); using (m_cacheLock.AcquireSharedUsing()) m_cacheMap.OverlapAllBoundingBox(ref querybb, m_tmpChunks, 0, false); if (m_tmpChunks.Count > 0) { var chunkMin = lodVoxelRangeMin >> lodDiff; var chunkMax = lodVoxelRangeMax >> lodDiff; bool readFromStorage = false; if ((chunkMax - chunkMin + 1).Size > m_tmpChunks.Count) { using (m_storageLock.AcquireSharedUsing()) ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); readFromStorage = true; } for (int i = 0; i < m_tmpChunks.Count; ++i) { var chunk = m_tmpChunks[i]; var pos = chunk.Coords; var celPos = pos << lodDiff; var lodCkStart = pos << lodDiff; lodCkStart = Vector3I.Max(lodCkStart, lodVoxelRangeMin); var targetOffset = lodCkStart - lodVoxelRangeMin; var lodCkEnd = ((pos + 1) << lodDiff) - 1; lodCkEnd = Vector3I.Min(lodCkEnd, lodVoxelRangeMax); lodCkStart -= celPos; lodCkEnd -= celPos; if ((chunk.Cached & dataToRead) != dataToRead && !readFromStorage) { using (m_storageLock.AcquireSharedUsing()) if ((chunk.Cached & dataToRead) != dataToRead) { ReadDatForChunk(chunk, dataToRead); } } using (chunk.Lock.AcquireSharedUsing()) chunk.ReadLod(target, !readFromStorage ? dataToRead : dataToRead & chunk.Cached, ref targetOffset, lodIndex, ref lodCkStart, ref lodCkEnd); } m_tmpChunks.Clear(); ProfilerShort.End(); return; } } // all else using (m_storageLock.AcquireSharedUsing()) ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); ProfilerShort.End(); }
void IMyOctreeLeafNode.ReadRange(MyStorageData target, MyStorageDataTypeFlags types, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod, ref MyVoxelRequestFlags flags) { m_octree.ReadRange(target, m_dataType, ref writeOffset, lodIndex, ref minInLod, ref maxInLod); }
private static unsafe void MakeCraterInternal(MyVoxelBase voxelMap, ref BoundingSphereD sphere, ref Vector3 direction, MyVoxelMaterialDefinition material) { Vector3I vectori; Vector3I vectori2; Vector3I vectori5; Vector3 vector = Vector3.Normalize(sphere.Center - voxelMap.RootVoxel.WorldMatrix.Translation); Vector3D worldPosition = sphere.Center - ((sphere.Radius - 1.0) * 1.2999999523162842); Vector3D vectord2 = sphere.Center + ((sphere.Radius + 1.0) * 1.2999999523162842); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref worldPosition, out vectori); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref vectord2, out vectori2); voxelMap.Storage.ClampVoxelCoord(ref vectori, 1); voxelMap.Storage.ClampVoxelCoord(ref vectori2, 1); Vector3I lodVoxelRangeMin = (Vector3I)(vectori + voxelMap.StorageMin); Vector3I lodVoxelRangeMax = (Vector3I)(vectori2 + voxelMap.StorageMin); bool flag = false; if (m_cache == null) { m_cache = new MyStorageData(MyStorageDataTypeFlags.All); } m_cache.Resize(vectori, vectori2); MyVoxelRequestFlags considerContent = MyVoxelRequestFlags.ConsiderContent; voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.All, 0, lodVoxelRangeMin, lodVoxelRangeMax, ref considerContent); int num = 0; Vector3I p = (Vector3I)((vectori2 - vectori) / 2); byte materialIdx = m_cache.Material(ref p); float num3 = 1f - Vector3.Dot(vector, direction); Vector3 vector2 = ((Vector3)sphere.Center) - ((vector * ((float)sphere.Radius)) * 1.1f); float num4 = (float)(sphere.Radius * 1.5); float num5 = num4 * num4; float num6 = 0.5f * ((2f * num4) + 0.5f); float num7 = 0.5f * ((-2f * num4) + 0.5f); Vector3 vector3 = (vector2 + ((vector * ((float)sphere.Radius)) * (0.7f + num3))) + ((direction * ((float)sphere.Radius)) * 0.65f); float radius = (float)sphere.Radius; float num9 = radius * radius; float num10 = 0.5f * ((2f * radius) + 0.5f); float num11 = 0.5f * ((-2f * radius) + 0.5f); Vector3 vector4 = (vector2 + ((vector * ((float)sphere.Radius)) * num3)) + ((direction * ((float)sphere.Radius)) * 0.3f); float num12 = (float)(sphere.Radius * 0.10000000149011612); float num13 = num12 * num12; float num14 = 0.5f * ((2f * num12) + 0.5f); vectori5.Z = vectori.Z; p.Z = 0; goto TR_003C; TR_0005: int *numPtr1 = (int *)ref vectori5.X; numPtr1[0]++; int *numPtr2 = (int *)ref p.X; numPtr2[0]++; TR_0036: while (true) { Vector3D vectord3; byte num18; if (vectori5.X > vectori2.X) { int *numPtr3 = (int *)ref vectori5.Y; numPtr3[0]++; int *numPtr4 = (int *)ref p.Y; numPtr4[0]++; break; } MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref vectori5, out vectord3); byte num15 = m_cache.Content(ref p); if (num15 != 0xff) { byte num22; float num20 = (float)(vectord3 - vector2).LengthSquared(); float num21 = num20 - num5; if (num21 > num6) { num22 = 0; } else if (num21 < num7) { num22 = 0xff; } else { float num23 = (float)Math.Sqrt((num20 + num5) - ((2f * num4) * Math.Sqrt((double)num20))); if (num21 < 0f) { num23 = -num23; } num22 = (byte)(127f - ((num23 / 0.5f) * 127f)); } if (num22 > num15) { if (material != null) { m_cache.Material(ref p, materialIdx); } flag = true; m_cache.Content(ref p, num22); } } float num16 = (float)(vectord3 - vector3).LengthSquared(); float num17 = num16 - num9; if (num17 > num10) { num18 = 0; } else if (num17 < num11) { num18 = 0xff; } else { float num24 = (float)Math.Sqrt((num16 + num9) - ((2f * radius) * Math.Sqrt((double)num16))); if (num17 < 0f) { num24 = -num24; } num18 = (byte)(127f - ((num24 / 0.5f) * 127f)); } num15 = m_cache.Content(ref p); if ((num15 > 0) && (num18 > 0)) { flag = true; int num25 = num15 - num18; if (num25 < 0) { num25 = 0; } m_cache.Content(ref p, (byte)num25); num += num15 - num25; } float num19 = ((float)(vectord3 - vector4).LengthSquared()) - num13; if (num19 <= 1.5f) { MyVoxelMaterialDefinition voxelMaterialDefinition = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref p)); MyVoxelMaterialDefinition objB = material; if (num19 > 0f) { byte num26 = m_cache.Content(ref p); if (num26 == 0xff) { objB = voxelMaterialDefinition; } if ((num19 >= num14) && (num26 != 0)) { objB = voxelMaterialDefinition; } } if (ReferenceEquals(voxelMaterialDefinition, objB)) { goto TR_0005; } else { m_cache.Material(ref p, objB.Index); flag = true; } } if ((((((float)(vectord3 - vector2).LengthSquared()) - num5) <= 0f) && (m_cache.Content(ref p) > 0)) && m_cache.WrinkleVoxelContent(ref p, 0.5f, 0.45f)) { flag = true; } goto TR_0005; } TR_0039: while (true) { if (vectori5.Y > vectori2.Y) { int *numPtr5 = (int *)ref vectori5.Z; numPtr5[0]++; int *numPtr6 = (int *)ref p.Z; numPtr6[0]++; break; } vectori5.X = vectori.X; p.X = 0; goto TR_0036; } TR_003C: while (true) { if (vectori5.Z <= vectori2.Z) { vectori5.Y = vectori.Y; p.Y = 0; break; } if (flag) { RemoveSmallVoxelsUsingChachedVoxels(); vectori = (Vector3I)(vectori + voxelMap.StorageMin); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.All, vectori, (Vector3I)(vectori2 + voxelMap.StorageMin), true, false); MyShapeSphere sphere1 = new MyShapeSphere(); sphere1.Center = sphere.Center; sphere1.Radius = (float)(sphere.Radius * 1.5); BoundingBoxD worldBoundaries = sphere1.GetWorldBoundaries(); NotifyVoxelChanged(MyVoxelBase.OperationType.Cut, voxelMap, ref worldBoundaries); } return; } goto TR_0039; }
void IMyOctreeLeafNode.ReadRange(MyStorageData target, MyStorageDataTypeFlags types, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod, ref MyVoxelRequestFlags flags) { int num = this.m_cell.Lod - lodIndex; Vector3I vectori = this.m_cell.CoordInLod << num; MyVoxelDataRequest request = new MyVoxelDataRequest { Target = target, Offset = writeOffset, Lod = lodIndex, MinInLod = (Vector3I)(minInLod + vectori), MaxInLod = (Vector3I)(maxInLod + vectori), RequestFlags = flags, RequestedData = types }; this.m_provider.ReadRange(ref request, false); flags = request.Flags; }
public void ReadRange(MyStorageData target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax, ref MyVoxelRequestFlags requestFlags) { ProfilerShort.Begin(GetType().Name + ".ReadRange"); if ((dataToRead & MyStorageDataTypeFlags.Content) != 0) { target.ClearContent(0); } if (requestFlags.HasFlags(MyVoxelRequestFlags.AdviseCache) && lodIndex == 0 && CachedWrites) { ReadRangeAdviseCache(target, dataToRead, ref lodVoxelRangeMin, ref lodVoxelRangeMax); ProfilerShort.End(); return; } if (CachedWrites && lodIndex <= VoxelChunk.SizeBits && m_cachedChunks.Count > 0) { // read occlusion separate if (dataToRead.Requests(MyStorageDataTypeEnum.Occlusion)) { using (m_storageLock.AcquireSharedUsing()) ReadRangeInternal(target, ref Vector3I.Zero, MyStorageDataTypeFlags.Occlusion, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); dataToRead ^= MyStorageDataTypeFlags.Occlusion; } if (m_tmpChunks == null) m_tmpChunks = new List<VoxelChunk>(); var lodDiff = VoxelChunk.SizeBits - lodIndex; // We fetch which chunks overlap our current range from the chunk tree, then we read all data from storage and apply those changes var querybb = new BoundingBox(lodVoxelRangeMin << lodIndex, lodVoxelRangeMax << lodIndex); using (m_cacheLock.AcquireSharedUsing()) m_cacheMap.OverlapAllBoundingBox(ref querybb, m_tmpChunks, 0, false); if (m_tmpChunks.Count > 0) { var chunkMin = lodVoxelRangeMin >> lodDiff; var chunkMax = lodVoxelRangeMax >> lodDiff; bool readFromStorage = false; if ((chunkMax - chunkMin + 1).Size > m_tmpChunks.Count) { using (m_storageLock.AcquireSharedUsing()) ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); readFromStorage = true; } for (int i = 0; i < m_tmpChunks.Count; ++i) { var chunk = m_tmpChunks[i]; var pos = chunk.Coords; var celPos = pos << lodDiff; var lodCkStart = pos << lodDiff; lodCkStart = Vector3I.Max(lodCkStart, lodVoxelRangeMin); var targetOffset = lodCkStart - lodVoxelRangeMin; var lodCkEnd = ((pos + 1) << lodDiff) - 1; lodCkEnd = Vector3I.Min(lodCkEnd, lodVoxelRangeMax); lodCkStart -= celPos; lodCkEnd -= celPos; if ((chunk.Cached & dataToRead) != dataToRead && !readFromStorage) { using (m_storageLock.AcquireSharedUsing()) if ((chunk.Cached & dataToRead) != dataToRead) ReadDatForChunk(chunk, dataToRead); } using (chunk.Lock.AcquireSharedUsing()) chunk.ReadLod(target, !readFromStorage ? dataToRead : dataToRead & chunk.Cached, ref targetOffset, lodIndex, ref lodCkStart, ref lodCkEnd); } m_tmpChunks.Clear(); ProfilerShort.End(); return; } } // all else using (m_storageLock.AcquireSharedUsing()) ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); ProfilerShort.End(); }
public override void Draw() { base.Draw(); if (MySession.Static == null) { return; } if (m_showVoxelProbe) { float halfSize = m_probeSize * .5f; float lodSize = 1 << m_probeLod; if (m_moveProbe) { m_probePosition = MySector.MainCamera.Position + MySector.MainCamera.ForwardVector * m_probeSize * 3; } BoundingBox bb; BoundingBoxD bbp; // Box used for drawing and finding the probe and drawing bb = new BoundingBox(m_probePosition - halfSize, m_probePosition + halfSize); bbp = (BoundingBoxD)bb; m_voxels.Clear(); MyGamePruningStructure.GetAllVoxelMapsInBox(ref bbp, m_voxels); MyVoxelBase map = null; double distance = double.PositiveInfinity; foreach (var vox in m_voxels) { var d = Vector3D.Distance(vox.WorldMatrix.Translation, m_probePosition); if (d < distance) { distance = d; map = vox; } } ContainmentType cont = ContainmentType.Disjoint; if (map != null) { map = map.RootVoxel; Vector3 localPos = Vector3.Transform(m_probePosition, map.PositionComp.WorldMatrixInvScaled); localPos += map.SizeInMetresHalf; // Create similar bounding box in storage space bb = new BoundingBox(localPos - halfSize, localPos + halfSize); m_probedVoxel = map; Section("Probing {1}: {0}", map.StorageName, map.GetType().Name); Text("Probe mode: {0}", m_mode); if (m_mode == ProbeMode.Intersect) { Text("Local Pos: {0}", localPos); Text("Probe Size: {0}", m_probeSize); cont = map.Storage.Intersect(ref bb, false); Text("Result: {0}", cont.ToString()); bbp = (BoundingBoxD)bb; } else { Vector3I min = Vector3I.Floor(bb.Min / lodSize + .5f); Vector3I max = min + ((int)m_probeSize >> m_probeLod) - 1; bbp = new BoundingBoxD(min << m_probeLod, (max + 1) << m_probeLod); bbp.Translate(new Vector3D(-.5)); Text("Probe Size: {0}({1})", (max - min).X + 1, m_probeSize); Text("Probe LOD: {0}", m_probeLod); var requestData = (MyStorageDataTypeEnum)(int)m_mode; MyVoxelRequestFlags flags = MyVoxelRequestFlags.ContentChecked; m_target.Resize(max - min + 1); m_target.Clear(MyStorageDataTypeEnum.Content, 0); m_target.Clear(MyStorageDataTypeEnum.Material, 0); map.Storage.ReadRange(m_target, (MyStorageDataTypeFlags)(1 << (int)requestData), m_probeLod, ref min, ref max, ref flags); if (requestData == MyStorageDataTypeEnum.Content) { if (flags.HasFlag(MyVoxelRequestFlags.EmptyContent)) { cont = ContainmentType.Disjoint; } else if (flags.HasFlag(MyVoxelRequestFlags.FullContent)) { cont = ContainmentType.Contains; } else { int val = m_target.ValueWhenAllEqual(requestData); if (val == -1) { cont = ContainmentType.Intersects; } else if (val >= MyVoxelConstants.VOXEL_ISO_LEVEL) { cont = ContainmentType.Contains; } else { cont = ContainmentType.Disjoint; } } DrawContentsInfo(m_target); } else { cont = ContainmentType.Disjoint; DrawMaterialsInfo(m_target); } Text(Color.Yellow, 1.5f, "Voxel Editing:"); Text("Value to set (Ctrl+Mousewheel): {0}", m_valueToSet); if (m_probeLod != 0) { Text(Color.Red, "Writing to storage is only possible when probe is set to LOD 0"); } else { Text("Use primary mouse button to set."); Text("Position/Extents: {0}/{1}", bbp.Min, bbp.Extents); if (MyInput.Static.IsLeftMousePressed()) { if (requestData == MyStorageDataTypeEnum.Content) { m_target.BlockFillContent(Vector3I.Zero, m_target.Size3D - Vector3I.One, m_valueToSet); } else { m_target.BlockFillMaterial(Vector3I.Zero, m_target.Size3D - Vector3I.One, m_valueToSet); } map.Storage.WriteRange(m_target, (MyStorageDataTypeFlags)(1 << (int)requestData), ref min, ref max); } } } } else { Section("No Voxel Found"); Text("Probe mode: {0}", m_mode); Text("Probe Size: {0}", m_probeSize); } Color c = ColorForContainment(cont); if (map != null) { bbp = bbp.Translate(-map.SizeInMetresHalf); MyOrientedBoundingBoxD oobb = new MyOrientedBoundingBoxD(bbp, map.WorldMatrix); MyRenderProxy.DebugDrawOBB(oobb, c, 0.5f, true, false); } else { MyRenderProxy.DebugDrawAABB(bbp, c, 0.5f, 1.0f, true); } } }
internal void ReadContentRange(ref MyVoxelDataRequest req) { if (Closed) { return; } float lodVoxelSize = (1 << req.Lod) * MyVoxelConstants.VOXEL_SIZE_IN_METRES; Vector3I min = req.minInLod; Vector3I max = req.maxInLod; ProfilerShort.Begin("Distance field computation"); try { Vector3I v = min; Vector3 localPos = v * lodVoxelSize - m_translation; Vector3 localPosStart = localPos; BoundingBox request = new BoundingBox(localPos, localPos + (max - min) * lodVoxelSize); request.Inflate(lodVoxelSize); MyVoxelRequestFlags flags = 0; ContainmentType cont = ContainmentType.Intersects; bool intersects; if (!req.Flags.HasFlags(MyVoxelRequestFlags.DoNotCheck)) { BoundingSphere sphere = new BoundingSphere( Vector3.Zero, OuterRadius + lodVoxelSize); sphere.Intersects(ref request, out intersects); if (!intersects) { cont = ContainmentType.Disjoint; goto end; } sphere.Radius = InnerRadius - lodVoxelSize; ContainmentType ct; sphere.Contains(ref request, out ct); if (ct == ContainmentType.Contains) { cont = ct; goto end; } cont = IntersectBoundingBoxInternal(ref request, lodVoxelSize); if (cont != ContainmentType.Intersects) { goto end; } } bool hit = false; // store request history EnqueueHistory(req); // Setup cache for current map; PrepareCache(); var writeOffsetLoc = req.Offset - min; for (v.Z = min.Z; v.Z <= max.Z; ++v.Z) { for (v.Y = min.Y; v.Y <= max.Y; ++v.Y) { v.X = min.X; var write2 = v + writeOffsetLoc; var write = req.Target.ComputeLinear(ref write2); for (; v.X <= max.X; ++v.X) { float signedDist = SignedDistanceLocal(localPos, lodVoxelSize) / lodVoxelSize; var fillRatio = MathHelper.Clamp(-signedDist, -1f, 1f) * 0.5f + 0.5f; byte content = (byte)(fillRatio * MyVoxelConstants.VOXEL_CONTENT_FULL); if (content != 0) { hit = true; } req.Target.Content(write, content); write += req.Target.StepLinear; localPos.X += lodVoxelSize; } localPos.Y += lodVoxelSize; localPos.X = localPosStart.X; } localPos.Z += lodVoxelSize; localPos.Y = localPosStart.Y; } if (!hit) { PruningStats.Miss(); } else { PruningStats.Hit(); } CullStats.Miss(); return; end :; CullStats.Hit(); if (cont == ContainmentType.Disjoint) { if (req.RequestFlags.HasFlags(MyVoxelRequestFlags.ContentChecked)) { flags |= MyVoxelRequestFlags.EmptyContent | MyVoxelRequestFlags.ContentCheckedDeep | MyVoxelRequestFlags.ContentChecked; } else { req.Target.BlockFillContent(req.Offset, req.Offset + max - min, MyVoxelConstants.VOXEL_CONTENT_EMPTY); } } else if (cont == ContainmentType.Contains) { if (req.RequestFlags.HasFlags(MyVoxelRequestFlags.ContentChecked)) { flags |= MyVoxelRequestFlags.FullContent | MyVoxelRequestFlags.ContentCheckedDeep | MyVoxelRequestFlags.ContentChecked; } else { req.Target.BlockFillContent(req.Offset, req.Offset + max - min, MyVoxelConstants.VOXEL_CONTENT_FULL); } } req.Flags = flags; PruningStats.Hit(); } finally { ProfilerShort.End(); } }
public void ReadMaterialRange(ref MyVoxelDataRequest req) { byte biome; ProfilerShort.Begin("MaterialComputation"); req.Flags = req.RequestFlags & (MyVoxelRequestFlags.SurfaceMaterial | MyVoxelRequestFlags.ConsiderContent); Vector3I minInLod = req.minInLod; Vector3I maxInLod = req.maxInLod; var target = req.Target; float lodVoxelSize = 1 << req.Lod; MyVoxelRequestFlags usedFlags = 0; bool computeOcclusion = req.RequestedData.Requests(MyStorageDataTypeEnum.Occlusion); // We don't bother determining where the surface is if we don't have the normal. bool assignToSurface = req.RequestFlags.HasFlags(MyVoxelRequestFlags.SurfaceMaterial); bool useContent = req.RequestFlags.HasFlags(MyVoxelRequestFlags.ConsiderContent); // Prepare coefficient cache m_planetShape.PrepareCache(); // Here we will compute which rules match the requested range and apply those. if (m_biomes != null) { if (req.SizeLinear > 125) { BoundingBox rbox = new BoundingBox((Vector3)minInLod * lodVoxelSize, (Vector3)maxInLod * lodVoxelSize); PrepareRulesForBoxInternal(ref rbox); } else if (!m_rangeClean || m_providerForRules != this) { CleanRules(); } } Vector3I combinedOffset = -minInLod + req.Offset; Vector3I v = new Vector3I(); for (v.Z = minInLod.Z; v.Z <= maxInLod.Z; ++v.Z) { for (v.Y = minInLod.Y; v.Y <= maxInLod.Y; ++v.Y) { for (v.X = minInLod.X; v.X <= maxInLod.X; ++v.X) { Vector3I coords = v; var write = v + combinedOffset; var writeLinear = target.ComputeLinear(ref write); if ((assignToSurface && target.Material(writeLinear) != 0) || (useContent && target.Content(writeLinear) == 0)) { if (computeOcclusion) { // Prevent empty voxels from affecting occlusion. target.Content(writeLinear, 0); } target.Material(writeLinear, MyVoxelConstants.NULL_MATERIAL); continue; } MyVoxelMaterialDefinition mat = null; byte occlusion = (byte)(computeOcclusion ? 255 : 0); // flag that we want occlusion. Vector3 localPos = coords * lodVoxelSize; mat = GetMaterialForPosition(ref localPos, lodVoxelSize, out biome, ref occlusion); if (mat == null) { mat = MyDefinitionManager.Static.GetVoxelMaterialDefinition(0); } target.Material(writeLinear, mat.Index); if (computeOcclusion) { target[MyStorageDataTypeEnum.Occlusion][writeLinear] = occlusion; } } } } 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, bool applyDamageMaterial = false, bool onlyApplyMaterial = false) { if (MySession.Static.EnableVoxelDestruction == false) { voxelsCountInPercent = 0; voxelMaterial = null; return; } ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()"); int originalSum = 0; int removedSum = 0; bool materials = exactCutOutMaterials != null; // Bring the shape into voxel space. var oldTranmsform = shape.Transformation; var newTransf = oldTranmsform * voxelMap.PositionComp.WorldMatrixInvScaled; newTransf.Translation += voxelMap.SizeInMetresHalf; shape.Transformation = newTransf; // This boundary should now be in our local space var bbox = shape.GetWorldBoundaries(); Vector3I minCorner, maxCorner; ComputeShapeBounds(voxelMap, ref bbox, Vector3.Zero, voxelMap.Storage.Size, out minCorner, out maxCorner); bool readMaterial = exactCutOutMaterials != null || applyDamageMaterial; var cacheMin = minCorner - 1; var cacheMax = maxCorner + 1; //try on making the read/write cell alligned see MyOctreeStorage.WriteRange - Micro octree leaf /*const int SHIFT = 4; * const int REM = (1 << SHIFT) - 1; * const int MASK = ~REM; * cacheMin &= MASK; * cacheMax = (cacheMax + REM) & MASK;*/ voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); m_cache.Resize(cacheMin, cacheMax); m_cache.ClearMaterials(0); // Advise that the read content shall be cached MyVoxelRequestFlags flags = MyVoxelRequestFlags.AdviseCache; voxelMap.Storage.ReadRange(m_cache, readMaterial ? MyStorageDataTypeFlags.ContentAndMaterial : MyStorageDataTypeFlags.Content, 0, ref cacheMin, ref cacheMax, ref flags); Vector3I center; if (materials) { center = m_cache.Size3D / 2; voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref center)); } else { center = (cacheMin + cacheMax) / 2; voxelMaterial = voxelMap.Storage.GetMaterialAt(ref center); } MyVoxelMaterialDefinition voxelMat = null; ProfilerShort.Begin("Main loop"); Vector3I pos; for (pos.X = minCorner.X; pos.X <= maxCorner.X; ++pos.X) { for (pos.Y = minCorner.Y; pos.Y <= maxCorner.Y; ++pos.Y) { for (pos.Z = minCorner.Z; pos.Z <= maxCorner.Z; ++pos.Z) { // get original amount var relPos = pos - cacheMin; var lin = m_cache.ComputeLinear(ref relPos); var original = m_cache.Content(lin); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove { continue; } Vector3D spos = (Vector3D)(pos - voxelMap.StorageMin) * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var volume = shape.GetVolume(ref spos); if (volume == 0f) // if there is no intersection { continue; } var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); var toRemove = maxRemove; // (int)(maxRemove * voxelMat.DamageRatio); var newVal = Math.Max(original - toRemove, 0); //MathHelper.Clamp(original - toRemove, 0, original-maxRemove); var removed = original - newVal; if (!onlyCheck && !onlyApplyMaterial) { m_cache.Content(lin, (byte)newVal); } originalSum += original; removedSum += removed; if (readMaterial) { voxelMat = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(lin)); } 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 (applyDamageMaterial && voxelMat.HasDamageMaterial && !onlyCheck) { m_cache.Material(lin, voxelMat.DamagedMaterialId); } } } } if (removedSum > 0 && updateSync && Sync.IsServer) { shape.SendDrillCutOutRequest(voxelMap, applyDamageMaterial); } 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(); var dataTypeFlags = applyDamageMaterial ? MyStorageDataTypeFlags.ContentAndMaterial : MyStorageDataTypeFlags.Content; if (MyFakes.LOG_NAVMESH_GENERATION) { MyAIComponent.Static.Pathfinding.VoxelPathfinding.DebugLog.LogStorageWrite(voxelMap, m_cache, dataTypeFlags, cacheMin, cacheMax); } voxelMap.Storage.WriteRange(m_cache, dataTypeFlags, ref cacheMin, ref cacheMax); } ProfilerShort.End(); voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f; shape.Transformation = oldTranmsform; if (removedSum > 0) { OnVoxelChanged(MyVoxelBase.OperationType.Cut, voxelMap, shape); } ProfilerShort.End(); }