protected override void WriteRangeInternal(MyStorageDataCache source, MyStorageDataTypeFlags dataToWrite, ref Vector3I voxelRangeMin, ref Vector3I voxelRangeMax) { ProfilerShort.Begin("MyOctreeStorage.WriteRange"); Debug.Assert(dataToWrite != MyStorageDataTypeFlags.None); if ((dataToWrite & MyStorageDataTypeFlags.Content) != 0) { var args = new WriteRangeArgs() { DataFilter = MyOctreeNode.ContentFilter, DataType = MyStorageDataTypeEnum.Content, Leaves = m_contentLeaves, Nodes = m_contentNodes, Provider = m_dataProvider, Source = source, }; WriteRange(ref args, 0, m_treeHeight + LeafLodCount, Vector3I.Zero, ref voxelRangeMin, ref voxelRangeMax); } if ((dataToWrite & MyStorageDataTypeFlags.Material) != 0) { var args = new WriteRangeArgs() { DataFilter = MyOctreeNode.MaterialFilter, DataType = MyStorageDataTypeEnum.Material, Leaves = m_materialLeaves, Nodes = m_materialNodes, Provider = m_dataProvider, Source = source, }; WriteRange(ref args, 0, m_treeHeight + LeafLodCount, Vector3I.Zero, ref voxelRangeMin, ref voxelRangeMax); } ProfilerShort.End(); }
internal void BuildFrom(MyStorageDataCache source) { Debug.Assert(source.Size3D == new Vector3I(m_octree.TreeWidth)); var enumer = new MyStorageDataCache.MortonEnumerator(source, m_dataType); m_octree.Build(enumer); }
public override void ReadMaterialRange(MyStorageDataCache target, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod, float lodVoxelSizeHalf) { float lodVoxelSize = 2f * lodVoxelSizeHalf; byte defaultMaterial = m_material.Index; 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) { var write = v - minInLod + writeOffset; byte slope = target.Material(ref write); if (slope == 0) { continue; } Vector3 localPos = v * lodVoxelSize; var mat = GetMaterialForPosition(ref localPos, lodVoxelSize); target.Material(ref write, mat.Index); } } } }
/// <summary> /// Create a new Asteroid, ready for some manipulation. /// </summary> /// <param name="name"></param> /// <param name="size">Currently the size must be multiple of 64, eg. 128x64x256</param> /// <param name="position"></param> public static IMyVoxelMap CreateNewAsteroid(string storageName, Vector3I size, Vector3D position) { var cache = new MyStorageDataCache(); // new storage is created completely full // no geometry will be created because that requires full-empty transition var storage = MyAPIGateway.Session.VoxelMaps.CreateStorage(size); // midspace's Note: The following steps appear redundant, as the storage space is created empty. /* // always ensure cache is large enough for whatever you plan to load into it cache.Resize(size); // range is specified using inclusive min and max coordinates // Choose a reasonable size of range you plan to work with, to avoid high memory usage // memory size in bytes required by cache is computed as Size.X * Size.Y * Size.Z * 2, where Size is size of the range. // min and max coordinates are inclusive, so if you want to read 8^3 voxels starting at coordinate [8,8,8], you // should pass in min = [8,8,8], max = [15,15,15] // For LOD, you should only use LOD0 or LOD1 // When you write data inside cache back to storage, you always write to LOD0 (the most detailed LOD), LOD1 can only be read from. storage.ReadRange(cache, MyStorageDataTypeFlags.All, 0, Vector3I.Zero, size - 1); // resets all loaded content to empty cache.ClearContent(0); // write new data back to the storage storage.WriteRange(cache, MyStorageDataTypeFlags.Content, Vector3I.Zero, size - 1); */ return MyAPIGateway.Session.VoxelMaps.CreateVoxelMap(storageName, storage, position, 0); }
public override void ReadMaterialRange(MyStorageDataCache target, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod, float lodVoxelSizeHalf) { float lodVoxelSize = 2f * lodVoxelSizeHalf; byte defaultMaterial = m_material.Index; 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) { var write = v - minInLod + writeOffset; byte slope = target.Material(ref write); if (slope == 0) continue; Vector3 localPos = v * lodVoxelSize; var mat = GetMaterialForPosition(ref localPos, lodVoxelSize); target.Material(ref write, mat.Index); } } } }
void ModAPI.Interfaces.IMyStorage.ReadRange(MyStorageDataCache target, MyStorageDataTypeFlags dataToRead, int lodIndex, Vector3I lodVoxelRangeMin, Vector3I lodVoxelRangeMax) { if ((uint)lodIndex >= (uint)MyCellCoord.MAX_LOD_COUNT) return; ReadRange(target, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax); }
void ModAPI.Interfaces.IMyStorage.ReadRange(MyStorageDataCache target, MyStorageDataTypeFlags dataToRead, int lodIndex, Vector3I lodVoxelRangeMin, Vector3I lodVoxelRangeMax) { if ((uint)lodIndex >= (uint)MyCellCoord.MAX_LOD_COUNT) { return; } ReadRange(target, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax); }
void IMyOctreeLeafNode.ReadRange(MyStorageDataCache target, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { var leafMinInLod = m_leafMin >> lodIndex; var min = minInLod + leafMinInLod; var max = maxInLod + leafMinInLod; AssertRangeIsInside(lodIndex, ref min, ref max); ProfilerShort.Begin("MyProviderLeaf.ReadRange"); m_provider.ReadRange(target, m_dataType, ref writeOffset, lodIndex, ref min, ref max); ProfilerShort.End(); }
// Linearly interpolates position, normal and material on poly-cube edge. Interpolated point is where an isosurface cuts an edge between two vertices, each with their own scalar value. void GetVertexInterpolation(MyStorageDataCache cache, MyTemporaryVoxel inputVoxelA, MyTemporaryVoxel inputVoxelB, int edgeIndex) { MyEdge edge = m_edges[edgeIndex]; byte contentA = cache.Content(inputVoxelA.IdxInCache); byte contentB = cache.Content(inputVoxelB.IdxInCache); byte materialA = cache.Material(inputVoxelA.IdxInCache); byte materialB = cache.Material(inputVoxelB.IdxInCache); if (Math.Abs(MyVoxelConstants.VOXEL_ISO_LEVEL - contentA) < 0.00001f) { edge.Position = inputVoxelA.Position; edge.Normal = inputVoxelA.Normal; edge.Material = materialA; edge.Ambient = inputVoxelA.Ambient; return; } if (Math.Abs(MyVoxelConstants.VOXEL_ISO_LEVEL - contentB) < 0.00001f) { edge.Position = inputVoxelB.Position; edge.Normal = inputVoxelB.Normal; edge.Material = materialB; edge.Ambient = inputVoxelB.Ambient; return; } float mu = (float)(MyVoxelConstants.VOXEL_ISO_LEVEL - contentA) / (float)(contentB - contentA); Debug.Assert(mu > 0.0f && mu < 1.0f); edge.Position.X = inputVoxelA.Position.X + mu * (inputVoxelB.Position.X - inputVoxelA.Position.X); edge.Position.Y = inputVoxelA.Position.Y + mu * (inputVoxelB.Position.Y - inputVoxelA.Position.Y); edge.Position.Z = inputVoxelA.Position.Z + mu * (inputVoxelB.Position.Z - inputVoxelA.Position.Z); edge.Normal.X = inputVoxelA.Normal.X + mu * (inputVoxelB.Normal.X - inputVoxelA.Normal.X); edge.Normal.Y = inputVoxelA.Normal.Y + mu * (inputVoxelB.Normal.Y - inputVoxelA.Normal.Y); edge.Normal.Z = inputVoxelA.Normal.Z + mu * (inputVoxelB.Normal.Z - inputVoxelA.Normal.Z); if (MyVRageUtils.IsZero(edge.Normal)) { edge.Normal = inputVoxelA.Normal; } else { edge.Normal = MyVRageUtils.Normalize(edge.Normal); } float mu2 = ((float)contentB) / (((float)contentA) + ((float)contentB)); edge.Material = (mu2 <= 0.5f) ? materialA : materialB; edge.Ambient = inputVoxelA.Ambient + mu2 * (inputVoxelB.Ambient - inputVoxelA.Ambient); return; }
void IMyStorageDataProvider.ReadRange(MyStorageDataCache target, MyStorageDataTypeEnum dataType, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { if (dataType == MyStorageDataTypeEnum.Content) { ReadContentRange(target, ref writeOffset, lodIndex, ref minInLod, ref maxInLod); } else { ReadMaterialRange(target, ref writeOffset, lodIndex, ref minInLod, ref maxInLod); } }
public void ReadRange(MyStorageDataCache target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax) { ProfilerShort.Begin(GetType().Name + ".ReadRange"); try { const int SUBRANGE_SIZE_SHIFT = 3; const int SUBRANGE_SIZE = 1 << SUBRANGE_SIZE_SHIFT; var threshold = new Vector3I(SUBRANGE_SIZE); var rangeSize = lodVoxelRangeMax - lodVoxelRangeMin + 1; if ((dataToRead & MyStorageDataTypeFlags.Content) != 0) { target.ClearContent(0); } if ((dataToRead & MyStorageDataTypeFlags.Material) != 0) { target.ClearMaterials(m_defaultMaterial); } if (rangeSize.X <= threshold.X && rangeSize.Y <= threshold.Y && rangeSize.Z <= threshold.Z) { using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax); } } else { // splitting to smaller ranges to make sure the lock is not held for too long, preventing write on update thread // subranges could be aligned to multiple of their size for possibly better performance var steps = (rangeSize - 1) >> SUBRANGE_SIZE_SHIFT; for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref steps); it.IsValid(); it.MoveNext()) { var offset = it.Current << SUBRANGE_SIZE_SHIFT; var min = lodVoxelRangeMin + offset; var max = min + SUBRANGE_SIZE - 1; Vector3I.Min(ref max, ref lodVoxelRangeMax, out max); Debug.Assert(min.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); Debug.Assert(max.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref offset, dataToRead, lodIndex, ref min, ref max); } } } } finally { ProfilerShort.End(); } }
private void RemoveAllAsteroids(MyGuiControlButton sender) { MyCsgShapePlanetShapeAttributes shapeAttributes = new MyCsgShapePlanetShapeAttributes(); shapeAttributes.Seed = 12345; shapeAttributes.Diameter = 60; shapeAttributes.Radius = 60 / 2.0f; shapeAttributes.DeviationScale = 0.003f; float maxHillSize = 10; float planetHalfDeviation = (shapeAttributes.Diameter * shapeAttributes.DeviationScale) / 2.0f; float hillHalfDeviation = planetHalfDeviation * maxHillSize; float canyonHalfDeviation = 1; float averagePlanetRadius = shapeAttributes.Radius - hillHalfDeviation; float outerRadius = averagePlanetRadius + hillHalfDeviation; float innerRadius = averagePlanetRadius - canyonHalfDeviation; float atmosphereRadius = MathHelper.Max(outerRadius, averagePlanetRadius * 1.08f); float minPlanetRadius = MathHelper.Min(innerRadius, averagePlanetRadius - planetHalfDeviation * 2 * 2.5f); MyCsgShapePlanetMaterialAttributes materialAttributes = new MyCsgShapePlanetMaterialAttributes(); materialAttributes.OreStartDepth = innerRadius; materialAttributes.OreEndDepth = innerRadius; materialAttributes.OreEndDepth = MathHelper.Max(materialAttributes.OreEndDepth, 0); materialAttributes.OreStartDepth = MathHelper.Max(materialAttributes.OreStartDepth, 0); materialAttributes.OreProbabilities = new MyOreProbability[10]; for (int i = 0; i < 10; ++i) { materialAttributes.OreProbabilities[i] = new MyOreProbability(); materialAttributes.OreProbabilities[i].OreName = "Ice_01"; materialAttributes.OreProbabilities[i].CummulativeProbability = 0.0f; } shapeAttributes.AveragePlanetRadius = averagePlanetRadius; IMyStorageDataProvider dataProvider = MyCompositeShapeProvider.CreatePlanetShape(0, ref shapeAttributes, maxHillSize, ref materialAttributes); IMyStorage storage = new MyOctreeStorage(dataProvider, MyVoxelCoordSystems.FindBestOctreeSize(shapeAttributes.Diameter)); MyStorageDataCache cache = new MyStorageDataCache(); cache.Resize(storage.Size); Vector3I start = Vector3I.Zero; Vector3I end = storage.Size; storage.ReadRange(cache, MyStorageDataTypeFlags.Content, 1, ref start, ref end); dataProvider.ReleaseHeightMaps(); }
private static void VoxelReading() { var camera = MySector.MainCamera; if (camera == null) { return; } var offset = 0; // MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF; var targetPosition = camera.Position + (Vector3D)camera.ForwardVector * 4.5f - offset; MyVoxelBase targetVoxelMap = null; foreach (var voxelMap in MySession.Static.VoxelMaps.Instances) { if (voxelMap.PositionComp.WorldAABB.Contains(targetPosition) == ContainmentType.Contains) { targetVoxelMap = voxelMap; break; } } if (targetVoxelMap == null) { return; } var targetMin = targetPosition - Vector3.One * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var targetMax = targetPosition + Vector3.One * MyVoxelConstants.VOXEL_SIZE_IN_METRES; Vector3I minVoxel, maxVoxel; MyVoxelCoordSystems.WorldPositionToVoxelCoord(targetVoxelMap.PositionLeftBottomCorner, ref targetMin, out minVoxel); MyVoxelCoordSystems.WorldPositionToVoxelCoord(targetVoxelMap.PositionLeftBottomCorner, ref targetMax, out maxVoxel); MyVoxelCoordSystems.VoxelCoordToWorldPosition(targetVoxelMap.PositionLeftBottomCorner, ref minVoxel, out targetMin); MyVoxelCoordSystems.VoxelCoordToWorldPosition(targetVoxelMap.PositionLeftBottomCorner, ref maxVoxel, out targetMax); { BoundingBoxD bbox = BoundingBoxD.CreateInvalid(); bbox.Include(targetMin); bbox.Include(targetMax); VRageRender.MyRenderProxy.DebugDrawAABB(bbox, Vector3.One, 1f, 1f, true); } if (MyInput.Static.IsNewLeftMousePressed()) { var cache = new MyStorageDataCache(); cache.Resize(minVoxel, maxVoxel); targetVoxelMap.Storage.ReadRange(cache, MyStorageDataTypeFlags.Content, 0, ref minVoxel, ref maxVoxel); targetVoxelMap.Storage.WriteRange(cache, MyStorageDataTypeFlags.Content, ref minVoxel, ref maxVoxel); Debug.Assert(true); } }
/// <summary> /// called multiple times for ships, to be kept up to date. /// </summary> public override void UpdateAfterSimulation10() { if (CommandAsteroidEditClear.ActiveVoxelDeleter) { var worldMatrix = MyAPIGateway.Session.Player.Controller.ControlledEntity.Entity.WorldMatrix; var position = worldMatrix.Translation + worldMatrix.Forward * 1.6f + worldMatrix.Up * 1.35f + worldMatrix.Right * 0.1f; var currentAsteroidList = new List<IMyVoxelBase>(); var bb = new BoundingBoxD(position - 0.2f, position + 0.2f); MyAPIGateway.Session.VoxelMaps.GetInstances(currentAsteroidList, v => v.IsBoxIntersectingBoundingBoxOfThisVoxelMap(ref bb)); if (currentAsteroidList.Count > 0) { _isInRange = true; var storage = currentAsteroidList[0].Storage; var point = new Vector3I(position - currentAsteroidList[0].PositionLeftBottomCorner); var cache = new MyStorageDataCache(); var min = (point / 64) * 64; var max = min + 63; var size = max - min; cache.Resize(size); storage.ReadRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, (int)VRageRender.MyLodTypeEnum.LOD0, min, max); Vector3I p = point - min; var content = cache.Content(ref p); if (content > 0) { content = 0x00; cache.Content(ref p, content); storage.WriteRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, min, max); } //storage = null; } else { _isInRange = false; } } if (CommandAsteroidEditSet.ActiveVoxelSetter) { var worldMatrix = MyAPIGateway.Session.Player.Controller.ControlledEntity.Entity.WorldMatrix; CommandAsteroidEditSet.ActiveVoxelSetterPosition = worldMatrix.Translation + worldMatrix.Forward * 1.6f + worldMatrix.Up * 1.35f + worldMatrix.Right * 0.1f; } else { CommandAsteroidEditSet.ActiveVoxelSetterPosition = null; } }
public static MyVoxelMaterialDefinition GetMaterialAt(this IMyStorage self, ref Vector3I voxelCoords) { MyVoxelMaterialDefinition def; MyStorageDataCache cache = new MyStorageDataCache(); cache.Resize(Vector3I.One); cache.ClearMaterials(0); self.ReadRange(cache, MyStorageDataTypeFlags.Material, 0, ref voxelCoords, ref voxelCoords); def = MyDefinitionManager.Static.GetVoxelMaterialDefinition(cache.Material(0)); return def; }
public static MyVoxelMaterialDefinition GetMaterialAt(this IMyStorage self, ref Vector3I voxelCoords) { MyVoxelMaterialDefinition def; MyStorageDataCache cache = new MyStorageDataCache(); cache.Resize(Vector3I.One); cache.ClearMaterials(0); self.ReadRange(cache, MyStorageDataTypeFlags.Material, 0, ref voxelCoords, ref voxelCoords); def = MyDefinitionManager.Static.GetVoxelMaterialDefinition(cache.Material(0)); return(def); }
protected void RefreshCache( ) { IMyVoxelMap voxelMap = (IMyVoxelMap)BackingObject; m_cache = new MyStorageDataCache( ); Vector3I size = voxelMap.Storage.Size; m_cache.Resize(size); // SandboxGameAssemblyWrapper.Instance.GameAction(() => // { voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, 0, Vector3I.Zero, size - 1); //voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, Vector3I.Zero, size - 1); // }); foreach (byte materialIndex in m_cache.Data) { try { MyVoxelMaterialDefinition material = MyDefinitionManager.Static.GetVoxelMaterialDefinition(materialIndex); if (material == null) { continue; } if (!m_materialTotals.ContainsKey(material)) { m_materialTotals.Add(material, 1); } else { m_materialTotals[material]++; } } catch (Exception ex) { ApplicationLog.BaseLog.Error(ex); } } }
/// <summary> /// For debugging/testing only! This can be very slow for large storage. /// </summary> public void Voxelize(MyStorageDataTypeFlags data) { var cache = new MyStorageDataCache(); cache.Resize(new Vector3I(LeafSizeInVoxels)); var leafCount = (Size / LeafSizeInVoxels); Vector3I leaf = Vector3I.Zero; var end = leafCount - 1; for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref end); it.IsValid(); it.GetNext(out leaf)) { Debug.WriteLine("Processing {0} / {1}", leaf, end); var min = leaf * LeafSizeInVoxels; var max = min + (LeafSizeInVoxels - 1); ReadRangeInternal(cache, ref Vector3I.Zero, data, 0, ref min, ref max); WriteRangeInternal(cache, data, ref min, ref max); } OnRangeChanged(Vector3I.Zero, Size - 1, data); }
public void WriteRange(MyStorageDataCache source, MyStorageDataTypeFlags dataToWrite, ref Vector3I voxelRangeMin, ref Vector3I voxelRangeMax) { MyPrecalcComponent.AssertUpdateThread(); ProfilerShort.Begin(GetType().Name + ".WriteRange"); try { using (m_lock.AcquireExclusiveUsing()) { m_compressedData = null; WriteRangeInternal(source, dataToWrite, ref voxelRangeMin, ref voxelRangeMax); } ProfilerShort.BeginNextBlock(GetType().Name + ".OnRangeChanged"); OnRangeChanged(voxelRangeMin, voxelRangeMax, dataToWrite); } finally { ProfilerShort.End(); } }
protected override void ReadRangeInternal(MyStorageDataCache target, ref Vector3I targetWriteOffset, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelCoordStart, ref Vector3I lodVoxelCoordEnd) { bool hasLod = lodIndex <= (m_treeHeight + LeafLodCount); Debug.Assert(dataToRead != MyStorageDataTypeFlags.None); if ((dataToRead & MyStorageDataTypeFlags.Content) != 0) { if (hasLod) { ReadRange(target, ref targetWriteOffset, MyStorageDataTypeEnum.Content, m_treeHeight, m_contentNodes, m_contentLeaves, lodIndex, ref lodVoxelCoordStart, ref lodVoxelCoordEnd); } } if ((dataToRead & MyStorageDataTypeFlags.Material) != 0) { if (hasLod) { ReadRange(target, ref targetWriteOffset, MyStorageDataTypeEnum.Material, m_treeHeight, m_materialNodes, m_materialLeaves, lodIndex, ref lodVoxelCoordStart, ref lodVoxelCoordEnd); } } }
void IMyOctreeLeafNode.WriteRange(MyStorageDataCache source, ref Vector3I readOffset, ref Vector3I min, ref Vector3I max) { m_octree.WriteRange(source, m_dataType, ref readOffset, ref min, ref max); if (DEBUG_WRITES) { var tmp = new MyStorageDataCache(); tmp.Resize(min, max); m_octree.ReadRange(tmp, m_dataType, ref Vector3I.Zero, 0, ref min, ref max); Vector3I p = Vector3I.Zero; var cacheEnd = max - min; int errorCounter = 0; for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref cacheEnd); it.IsValid(); it.GetNext(out p)) { var read = readOffset + p; if (source.Get(m_dataType, ref read) != tmp.Get(m_dataType, ref p)) { ++errorCounter; } } Debug.Assert(errorCounter == 0, string.Format("{0} errors writing to leaf octree.", errorCounter)); } }
internal void ReadContentRange(MyStorageDataCache target, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { float lodVoxelSizeHalf; BoundingBox queryBox; BoundingSphere querySphere; SetupReading(lodIndex, ref minInLod, ref maxInLod, out lodVoxelSizeHalf, out queryBox, out querySphere); float lodVoxelSize = 2f * lodVoxelSizeHalf; ProfilerShort.Begin("Testing removed shapes"); var overlappedRemovedShapes = OverlappedRemovedShapes; overlappedRemovedShapes.Clear(); ContainmentType testRemove = ContainmentType.Disjoint; for (int i = 0; i < m_data.RemovedShapes.Length; ++i) { var test = m_data.RemovedShapes[i].Contains(ref queryBox, ref querySphere, lodVoxelSize); if (test == ContainmentType.Contains) { testRemove = ContainmentType.Contains; break; // completely empty so we can leave } else if (test == ContainmentType.Intersects) { testRemove = ContainmentType.Intersects; overlappedRemovedShapes.Add(m_data.RemovedShapes[i]); } } ProfilerShort.End(); if (testRemove == ContainmentType.Contains) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_EMPTY); ProfilerShort.End(); return; } ProfilerShort.Begin("Testing filled shapes"); var overlappedFilledShapes = OverlappedFilledShapes; overlappedFilledShapes.Clear(); ContainmentType testFill = ContainmentType.Disjoint; for (int i = 0; i < m_data.FilledShapes.Length; ++i) { var test = m_data.FilledShapes[i].Contains(ref queryBox, ref querySphere, lodVoxelSize); if (test == ContainmentType.Contains) { overlappedFilledShapes.Clear(); testFill = ContainmentType.Contains; break; } else if (test == ContainmentType.Intersects) { overlappedFilledShapes.Add(m_data.FilledShapes[i]); testFill = ContainmentType.Intersects; } } ProfilerShort.End(); if (testFill == ContainmentType.Disjoint) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_EMPTY); ProfilerShort.End(); return; } else if (testRemove == ContainmentType.Disjoint && testFill == ContainmentType.Contains) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_FULL); ProfilerShort.End(); return; } ProfilerShort.Begin("Distance field computation"); Vector3I v; 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) { Vector3 localPos = v * lodVoxelSize; float distFill; if (testFill == ContainmentType.Contains) { distFill = -1f; } else { distFill = 1f; foreach (var shape in overlappedFilledShapes) { distFill = Math.Min(distFill, shape.SignedDistance(ref localPos, lodVoxelSize, m_data.MacroModule, m_data.DetailModule)); if (distFill <= -1) break; } } float distRemoved = 1f; if (testRemove != ContainmentType.Disjoint) { foreach (var shape in overlappedRemovedShapes) { distRemoved = Math.Min(distRemoved, shape.SignedDistance(ref localPos, lodVoxelSize, m_data.MacroModule, m_data.DetailModule)); if (distRemoved <= -1) break; } } float signedDist = MathHelper.Max(distFill, -distRemoved); var fillRatio = MathHelper.Clamp(-signedDist, -1f, 1f) * 0.5f + 0.5f; var write = v - minInLod + writeOffset; target.Content(ref write, (byte)(fillRatio * MyVoxelConstants.VOXEL_CONTENT_FULL)); } } } ProfilerShort.End(); }
private bool FindMaterial(IMyStorage storage, byte[] findMaterial) { if (findMaterial.Length == 0) return false; var oldCache = new MyStorageDataCache(); oldCache.Resize(storage.Size); storage.ReadRange(oldCache, MyStorageDataTypeFlags.ContentAndMaterial, 2, Vector3I.Zero, storage.Size - 1); //MyAPIGateway.Utilities.ShowMessage("check", string.Format("SizeLinear {0} {1}.", oldCache.SizeLinear, oldCache.StepLinear)); Vector3I p; for (p.Z = 0; p.Z < storage.Size.Z; ++p.Z) for (p.Y = 0; p.Y < storage.Size.Y; ++p.Y) for (p.X = 0; p.X < storage.Size.X; ++p.X) { var content = oldCache.Content(ref p); var material = oldCache.Material(ref p); if (content > 0 && findMaterial.Contains(material)) { return true; } } return false; }
protected void RefreshCache( ) { IMyVoxelMap voxelMap = (IMyVoxelMap)BackingObject; m_cache = new MyStorageDataCache( ); Vector3I size = voxelMap.Storage.Size; m_cache.Resize( size ); // SandboxGameAssemblyWrapper.Instance.GameAction(() => // { voxelMap.Storage.ReadRange( m_cache, MyStorageDataTypeFlags.Material, 0, Vector3I.Zero, size - 1 ); //voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, Vector3I.Zero, size - 1); // }); foreach ( byte materialIndex in m_cache.Data ) { try { MyVoxelMaterialDefinition material = MyDefinitionManager.Static.GetVoxelMaterialDefinition( materialIndex ); if ( material == null ) continue; if ( !m_materialTotals.ContainsKey( material ) ) m_materialTotals.Add( material, 1 ); else m_materialTotals[ material ]++; } catch ( Exception ex ) { ApplicationLog.BaseLog.Error( ex ); } } }
void ModAPI.Interfaces.IMyStorage.WriteRange(MyStorageDataCache source, MyStorageDataTypeFlags dataToWrite, Vector3I voxelRangeMin, Vector3I voxelRangeMax) { WriteRange(source, dataToWrite, ref voxelRangeMin, ref voxelRangeMax); }
void IMyOctreeLeafNode.WriteRange(MyStorageDataCache source, ref Vector3I readOffset, ref Vector3I min, ref Vector3I max) { throw new NotSupportedException(); }
private unsafe void WriteRange( MyCellCoord cell, TLeafData defaultData, MyStorageDataCache source, MyStorageDataTypeEnum type, ref Vector3I readOffset, ref Vector3I min, ref Vector3I max) { var nodeKey = cell.PackId32(); MyOctreeNode node; if (!m_nodes.TryGetValue(nodeKey, out node)) { for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { node.Data[i] = defaultData; } } if (cell.Lod == 0) { var childBase = cell.CoordInLod << 1; Vector3I childOffset; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); var child = childBase + childOffset; if (!child.IsInsideInclusive(ref min, ref max)) { continue; } child -= min; child += readOffset; node.Data[i] = source.Get(type, ref child); } m_nodes[nodeKey] = node; } else { var childBase = cell.CoordInLod << 1; Vector3I childOffset; var minInChild = (min >> cell.Lod) - childBase; var maxInChild = (max >> cell.Lod) - childBase; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); if (!childOffset.IsInsideInclusive(ref minInChild, ref maxInChild)) { continue; } var childCell = new MyCellCoord(cell.Lod - 1, childBase + childOffset); WriteRange(childCell, node.Data[i], source, type, ref readOffset, ref min, ref max); var childKey = childCell.PackId32(); var childNode = m_nodes[childKey]; if (!childNode.HasChildren && MyOctreeNode.AllDataSame(childNode.Data)) { node.SetChild(i, false); node.Data[i] = childNode.Data[0]; m_nodes.Remove(childKey); } else { node.SetChild(i, true); node.Data[i] = m_nodeFilter(childNode.Data); } } m_nodes[nodeKey] = node; } }
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); } } } } } } } }
protected abstract void ReadRangeInternal(MyStorageDataCache target, ref Vector3I targetWriteRange, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax);
private static MyStorageBase Compatibility_LoadCellStorage(int fileVersion, Stream stream) { // Size of this voxel map (in voxels) Vector3I tmpSize; tmpSize.X = stream.ReadInt32(); tmpSize.Y = stream.ReadInt32(); tmpSize.Z = stream.ReadInt32(); var storage = new MyOctreeStorage(null, tmpSize); // Size of data cell in voxels. Has to be the same as current size specified by our constants. Vector3I cellSize; cellSize.X = stream.ReadInt32(); cellSize.Y = stream.ReadInt32(); cellSize.Z = stream.ReadInt32(); Trace.Assert(cellSize.X == MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS && cellSize.Y == MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS && cellSize.Z == MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS); Vector3I cellsCount = tmpSize / cellSize; Dictionary<byte, MyVoxelMaterialDefinition> mappingTable = null; if (fileVersion == STORAGE_TYPE_VERSION_CELL) { // loading material names->index mappings mappingTable = Compatibility_LoadMaterialIndexMapping(stream); } else if (fileVersion == 1) { // material name->index mappings were not saved in this version } var startCoord = Vector3I.Zero; var endCoord = new Vector3I(MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS - 1); var cache = new MyStorageDataCache(); cache.Resize(Vector3I.Zero, endCoord); Vector3I cellCoord; for (cellCoord.X = 0; cellCoord.X < cellsCount.X; cellCoord.X++) { for (cellCoord.Y = 0; cellCoord.Y < cellsCount.Y; cellCoord.Y++) { for (cellCoord.Z = 0; cellCoord.Z < cellsCount.Z; cellCoord.Z++) { MyVoxelRangeType cellType = (MyVoxelRangeType)stream.ReadByteNoAlloc(); // Cell's are FULL by default, therefore we don't need to change them switch (cellType) { case MyVoxelRangeType.EMPTY: cache.ClearContent(MyVoxelConstants.VOXEL_CONTENT_EMPTY); break; case MyVoxelRangeType.FULL: cache.ClearContent(MyVoxelConstants.VOXEL_CONTENT_FULL); break; case MyVoxelRangeType.MIXED: Vector3I v; for (v.X = 0; v.X < MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; v.X++) { for (v.Y = 0; v.Y < MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; v.Y++) { for (v.Z = 0; v.Z < MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; v.Z++) { cache.Content(ref v, stream.ReadByteNoAlloc()); } } } break; } startCoord = cellCoord * MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; endCoord = startCoord + (MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS - 1); storage.WriteRange(cache, MyStorageDataTypeFlags.Content, ref startCoord, ref endCoord); } } } try { // In case materials are not saved, catch any exceptions caused by this. // Read materials and indestructible for (cellCoord.X = 0; cellCoord.X < cellsCount.X; cellCoord.X++) { for (cellCoord.Y = 0; cellCoord.Y < cellsCount.Y; cellCoord.Y++) { for (cellCoord.Z = 0; cellCoord.Z < cellsCount.Z; cellCoord.Z++) { bool isSingleMaterial = stream.ReadByteNoAlloc() == 1; MyVoxelMaterialDefinition material = null; if (isSingleMaterial) { material = Compatibility_LoadCellVoxelMaterial(stream, mappingTable); cache.ClearMaterials(material.Index); } else { byte indestructibleContent; Vector3I voxelCoordInCell; for (voxelCoordInCell.X = 0; voxelCoordInCell.X < MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; voxelCoordInCell.X++) { for (voxelCoordInCell.Y = 0; voxelCoordInCell.Y < MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; voxelCoordInCell.Y++) { for (voxelCoordInCell.Z = 0; voxelCoordInCell.Z < MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; voxelCoordInCell.Z++) { material = Compatibility_LoadCellVoxelMaterial(stream, mappingTable); indestructibleContent = stream.ReadByteNoAlloc(); cache.Material(ref voxelCoordInCell, material.Index); } } } } startCoord = cellCoord * MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; endCoord = startCoord + (MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS - 1); storage.WriteRange(cache, MyStorageDataTypeFlags.Material, ref startCoord, ref endCoord); } } } } catch (EndOfStreamException ex) { MySandboxGame.Log.WriteLine(ex); } return storage; }
void IMyOctreeLeafNode.WriteRange(MyStorageDataCache source, ref Vector3I readOffset, ref Vector3I min, ref Vector3I max) { m_octree.WriteRange(source, m_dataType, ref readOffset, ref min, ref max); if (DEBUG_WRITES) { var tmp = new MyStorageDataCache(); tmp.Resize(min, max); m_octree.ReadRange(tmp, m_dataType, ref Vector3I.Zero, 0, ref min, ref max); Vector3I p = Vector3I.Zero; var cacheEnd = max - min; int errorCounter = 0; for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref cacheEnd); it.IsValid(); it.GetNext(out p)) { var read = readOffset + p; if (source.Get(m_dataType, ref read) != tmp.Get(m_dataType, ref p)) ++errorCounter; } Debug.Assert(errorCounter == 0, string.Format("{0} errors writing to leaf octree.", errorCounter)); } }
void IMyOctreeLeafNode.ReadRange(MyStorageDataCache target, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { m_octree.ReadRange(target, m_dataType, ref writeOffset, lodIndex, ref minInLod, ref maxInLod); }
/// <summary> /// /// </summary> /// <param name="voxelMap"></param> /// <param name="resolution">0 to 8. 0 for fine/slow detail.</param> /// <param name="distance"></param> /// <returns></returns> private int FindMaterial(IMyVoxelBase voxelMap, Vector3D center, int resolution, double distance) { int hits = 0; var materials = MyDefinitionManager.Static.GetVoxelMaterialDefinitions().Where(v => v.IsRare).ToArray(); var findMaterial = materials.Select(f => f.Index).ToArray(); var storage = voxelMap.Storage; var scale = (int)Math.Pow(2, resolution); //MyAPIGateway.Utilities.ShowMessage("center", center.ToString()); var point = new Vector3I(center - voxelMap.PositionLeftBottomCorner); //MyAPIGateway.Utilities.ShowMessage("point", point.ToString()); var min = ((point - (int)distance) / 64) * 64; min = Vector3I.Max(min, Vector3I.Zero); //MyAPIGateway.Utilities.ShowMessage("min", min.ToString()); var max = ((point + (int)distance) / 64) * 64; max = Vector3I.Max(max, min + 64); //MyAPIGateway.Utilities.ShowMessage("max", max.ToString()); //MyAPIGateway.Utilities.ShowMessage("size", voxelMap.StorageName + " " + storage.Size.ToString()); if (min.X >= storage.Size.X || min.Y >= storage.Size.Y || min.Z >= storage.Size.Z) { //MyAPIGateway.Utilities.ShowMessage("size", "out of range"); return 0; } var oldCache = new MyStorageDataCache(); //var smin = new Vector3I(0, 0, 0); //var smax = new Vector3I(31, 31, 31); ////var size = storage.Size; //var size = smax - smin + 1; //size = new Vector3I(16, 16, 16); //oldCache.Resize(size); //storage.ReadRange(oldCache, MyStorageDataTypeFlags.ContentAndMaterial, resolution, Vector3I.Zero, size - 1); var smax = (max / scale) - 1; var smin = (min / scale); var size = smax - smin + 1; oldCache.Resize(size); storage.ReadRange(oldCache, MyStorageDataTypeFlags.ContentAndMaterial, resolution, smin, smax); //MyAPIGateway.Utilities.ShowMessage("smax", smax.ToString()); //MyAPIGateway.Utilities.ShowMessage("size", size .ToString()); //MyAPIGateway.Utilities.ShowMessage("size - 1", (size - 1).ToString()); Vector3I p; for (p.Z = 0; p.Z < size.Z; ++p.Z) for (p.Y = 0; p.Y < size.Y; ++p.Y) for (p.X = 0; p.X < size.X; ++p.X) { // place GPS in the center of the Voxel var position = voxelMap.PositionLeftBottomCorner + (p * scale) + (scale / 2) + min; if (Math.Sqrt((position - center).LengthSquared()) < distance) { var content = oldCache.Content(ref p); var material = oldCache.Material(ref p); if (content > 0 && findMaterial.Contains(material)) { var index = Array.IndexOf(findMaterial, material); var name = materials[index].MinedOre; var gps = MyAPIGateway.Session.GPS.Create("Ore " + name, "scanore", position, true, false); MyAPIGateway.Session.GPS.AddLocalGps(gps); hits++; } } } return hits; }
private void UpdateLoad() { ConstructAreas(); if (m_checkQueue.Count == 0) { bool finishedLoading = true; m_ground = MySession.Static.VoxelMaps.TryGetVoxelMapByName("Ground"); if (m_ground != null) { m_worldArea = m_ground.SizeInMetres.X * m_ground.SizeInMetres.Z; m_voxelCache = new MyStorageDataCache(); m_voxelCache.Resize(Vector3I.One * 3); InvalidateAreaValues(); if (m_highLevelBoxes.Count == 0) { // MW: we need to find some candidates for forest starting points finishedLoading = false; m_findValidForestPhase = true; } } if (finishedLoading) { m_loadPhase = false; if (LoadFinished != null) LoadFinished(); } } }
void IMyStorageDataProvider.ReadRange(MyStorageDataCache target, MyStorageDataTypeEnum dataType, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { if (dataType == MyStorageDataTypeEnum.Content) ReadContentRange(target, ref writeOffset, lodIndex, ref minInLod, ref maxInLod); else ReadMaterialRange(target, ref writeOffset, lodIndex, ref minInLod, ref maxInLod); }
void IMyStorage.ReadRange(MyStorageDataCache target, bool readContent, bool readMaterials, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax) { m_trueStorage.ReadRange(target, readContent, readMaterials, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax); }
public virtual void ReadMaterialRange(MyStorageDataCache target, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod, float lodVoxelSizeHalf) { target.BlockFillMaterial(writeOffset, writeOffset + (maxInLod - minInLod), m_material.Index); }
internal void ReadContentRange(MyStorageDataCache target, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { float lodVoxelSizeHalf; BoundingBox queryBox; BoundingSphere querySphere; SetupReading(lodIndex, ref minInLod, ref maxInLod, out lodVoxelSizeHalf, out queryBox, out querySphere); float lodVoxelSize = 2f * lodVoxelSizeHalf; ProfilerShort.Begin("Testing removed shapes"); var overlappedRemovedShapes = OverlappedRemovedShapes; overlappedRemovedShapes.Clear(); ContainmentType testRemove = ContainmentType.Disjoint; for (int i = 0; i < m_data.RemovedShapes.Length; ++i) { var test = m_data.RemovedShapes[i].Contains(ref queryBox, ref querySphere, lodVoxelSize); if (test == ContainmentType.Contains) { testRemove = ContainmentType.Contains; break; // completely empty so we can leave } else if (test == ContainmentType.Intersects) { testRemove = ContainmentType.Intersects; overlappedRemovedShapes.Add(m_data.RemovedShapes[i]); } } ProfilerShort.End(); if (testRemove == ContainmentType.Contains) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_EMPTY); ProfilerShort.End(); return; } ProfilerShort.Begin("Testing filled shapes"); var overlappedFilledShapes = OverlappedFilledShapes; overlappedFilledShapes.Clear(); ContainmentType testFill = ContainmentType.Disjoint; for (int i = 0; i < m_data.FilledShapes.Length; ++i) { var test = m_data.FilledShapes[i].Contains(ref queryBox, ref querySphere, lodVoxelSize); if (test == ContainmentType.Contains) { overlappedFilledShapes.Clear(); testFill = ContainmentType.Contains; break; } else if (test == ContainmentType.Intersects) { overlappedFilledShapes.Add(m_data.FilledShapes[i]); testFill = ContainmentType.Intersects; } } ProfilerShort.End(); if (testFill == ContainmentType.Disjoint) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_EMPTY); ProfilerShort.End(); return; } else if (testRemove == ContainmentType.Disjoint && testFill == ContainmentType.Contains) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_FULL); ProfilerShort.End(); return; } ProfilerShort.Begin("Distance field computation"); Vector3I v; 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) { Vector3 localPos = v * lodVoxelSize; float distFill; if (testFill == ContainmentType.Contains) { distFill = -1f; } else { distFill = 1f; foreach (var shape in overlappedFilledShapes) { ProfilerShort.Begin("shape distance"); distFill = Math.Min(distFill, shape.SignedDistance(ref localPos, lodVoxelSize, m_data.MacroModule, m_data.DetailModule)); ProfilerShort.End(); if (distFill <= -1) { break; } } } float distRemoved = 1f; if (testRemove != ContainmentType.Disjoint) { foreach (var shape in overlappedRemovedShapes) { distRemoved = Math.Min(distRemoved, shape.SignedDistance(ref localPos, lodVoxelSize, m_data.MacroModule, m_data.DetailModule)); if (distRemoved <= -1) { break; } } } ProfilerShort.Begin("content"); float signedDist = MathHelper.Max(distFill, -distRemoved); var fillRatio = MathHelper.Clamp(-signedDist, -1f, 1f) * 0.5f + 0.5f; var write = v - minInLod + writeOffset; target.Content(ref write, (byte)(fillRatio * MyVoxelConstants.VOXEL_CONTENT_FULL)); ProfilerShort.End(); } } } ProfilerShort.End(); }
internal void WriteRange(MyStorageDataCache source, MyStorageDataTypeEnum type, ref Vector3I readOffset, ref Vector3I min, ref Vector3I max) { ProfilerShort.Begin("MySparseOctree2.WriteRange"); WriteRange(new MyCellCoord(m_treeHeight - 1, Vector3I.Zero), m_defaultContent, source, type, ref readOffset, ref min, ref max); ProfilerShort.End(); }
internal void ReadMaterialRange(MyStorageDataCache target, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { float lodVoxelSizeHalf; BoundingBox queryBox; BoundingSphere querySphere; SetupReading(lodIndex, ref minInLod, ref maxInLod, out lodVoxelSizeHalf, out queryBox, out querySphere); float lodVoxelSize = 2f * lodVoxelSizeHalf; var overlappedDeposits = OverlappedDeposits; { ProfilerShort.Begin("Testing deposit shapes"); overlappedDeposits.Clear(); ContainmentType testDeposits = ContainmentType.Disjoint; for (int i = 0; i < m_data.Deposits.Length; ++i) { var test = m_data.Deposits[i].Shape.Contains(ref queryBox, ref querySphere, lodVoxelSize); if (test != ContainmentType.Disjoint) { overlappedDeposits.Add(m_data.Deposits[i]); testDeposits = ContainmentType.Intersects; } } ProfilerShort.End(); if (testDeposits == ContainmentType.Disjoint) { ProfilerShort.Begin("target.BlockFillMaterial"); target.BlockFillMaterial(writeOffset, writeOffset + (maxInLod - minInLod), m_data.DefaultMaterial.Index); ProfilerShort.End(); return; } } ProfilerShort.Begin("Material computation"); Vector3I v; 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) { Vector3 localPos = v * lodVoxelSize; float closestDistance = 1f; byte closestMaterialIdx = m_data.DefaultMaterial.Index; foreach (var deposit in overlappedDeposits) { float distance = deposit.Shape.SignedDistance(ref localPos, MyVoxelConstants.VOXEL_SIZE_IN_METRES, m_data.MacroModule, m_data.DetailModule); if (distance < 0f && distance <= closestDistance) { closestDistance = distance; // DA: Pass default material to the layered deposit so only that does these if-s. var materialDef = deposit.GetMaterialForPosition(ref localPos, lodVoxelSize); closestMaterialIdx = materialDef == null ? m_data.DefaultMaterial.Index : materialDef.Index; } } var write = v - minInLod + writeOffset; target.Material(ref write, closestMaterialIdx); } } } ProfilerShort.End(); }
internal unsafe void ReadRange(MyStorageDataCache target, MyStorageDataTypeEnum type, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { ProfilerShort.Begin("MySparseOctree2.ReadRangeToContent"); try { int stackIdx = 0; int stackSize = MySparseOctree.EstimateStackSize(m_treeHeight); MyCellCoord *stack = stackalloc MyCellCoord[stackSize]; MyCellCoord data = new MyCellCoord(m_treeHeight - 1, ref Vector3I.Zero); stack[stackIdx++] = data; MyOctreeNode node; Vector3I childPosRelative, min, max, nodePositionInChild; int lodDiff; while (stackIdx > 0) { Debug.Assert(stackIdx <= stackSize); data = stack[--stackIdx]; node = m_nodes[data.PackId32()]; lodDiff = data.Lod - lodIndex; min = minInLod >> lodDiff; max = maxInLod >> lodDiff; nodePositionInChild = data.CoordInLod << 1; min -= nodePositionInChild; max -= nodePositionInChild; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { 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 nodeData = node.Data[i]; var childMin = nodePositionInChild + childPosRelative; if (lodDiff == 0) { var write = writeOffset + childMin - minInLod; target.Set(type, ref write, nodeData); } else { childMin <<= lodDiff; 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) { var write = writeOffset; write.X += x - minInLod.X; write.Y += y - minInLod.Y; write.Z += z - minInLod.Z; target.Set(type, ref write, nodeData); } } } } } } } } finally { ProfilerShort.End(); } }
protected abstract void WriteRangeInternal(MyStorageDataCache source, MyStorageDataTypeFlags dataToWrite, ref Vector3I voxelRangeMin, ref Vector3I voxelRangeMax);
public override bool Invoke(string messageText) { // voxelset [0/off] [1/on] [A] [B] [C/Clear] if (messageText.StartsWith("/voxelset ", StringComparison.InvariantCultureIgnoreCase)) { var strings = messageText.Split(' '); if (strings.Length > 1) { if (strings[1].Equals("off", StringComparison.InvariantCultureIgnoreCase) || strings[1].Equals("0", StringComparison.InvariantCultureIgnoreCase)) { ActiveVoxelSetterPosition = null; _activeVoxelSetterPositionA = null; _activeVoxelSetterPositionB = null; _activeVoxelSetterNameA = null; _activeVoxelSetterNameB = null; ActiveVoxelSetter = false; MyAPIGateway.Utilities.ShowNotification("Voxel setter off", 1000, MyFontEnum.Green); return true; } if (strings[1].Equals("on", StringComparison.InvariantCultureIgnoreCase) || strings[1].Equals("1", StringComparison.InvariantCultureIgnoreCase)) { ActiveVoxelSetterPosition = null; _activeVoxelSetterPositionA = null; _activeVoxelSetterPositionB = null; _activeVoxelSetterNameA = null; _activeVoxelSetterNameB = null; ActiveVoxelSetter = true; MyAPIGateway.Utilities.ShowNotification("Voxel setter activated", 1000, MyFontEnum.Green); return true; } if (!ActiveVoxelSetter) { MyAPIGateway.Utilities.ShowNotification("Voxel setter hasn't been actived.", 2000, MyFontEnum.Red); return true; } if (strings[1].Equals("A", StringComparison.InvariantCultureIgnoreCase)) { var tmp = ActiveVoxelSetterPosition; if (tmp.HasValue) { var currentAsteroidList = new List<IMyVoxelBase>(); var bb = new BoundingBoxD(tmp.Value - 0.2f, tmp.Value + 0.2f); MyAPIGateway.Session.VoxelMaps.GetInstances(currentAsteroidList, v => v.IsBoxIntersectingBoundingBoxOfThisVoxelMap(ref bb)); if (currentAsteroidList.Count > 0) { _activeVoxelSetterNameA = currentAsteroidList[0].StorageName; _activeVoxelSetterPositionA = tmp; } } if (_activeVoxelSetterPositionA.HasValue) MyAPIGateway.Utilities.ShowMessage(_activeVoxelSetterNameA, "Voxel setter point A: active"); //MyAPIGateway.Utilities.ShowNotification("Voxel setter A: active.", 1000, MyFontEnum.Green); else MyAPIGateway.Utilities.ShowNotification("Voxel setter A: invalid.", 1000, MyFontEnum.Red); return true; } if (strings[1].Equals("B", StringComparison.InvariantCultureIgnoreCase)) { var tmp = ActiveVoxelSetterPosition; if (tmp.HasValue) { var currentAsteroidList = new List<IMyVoxelBase>(); var bb = new BoundingBoxD(tmp.Value - 0.2f, tmp.Value + 0.2f); MyAPIGateway.Session.VoxelMaps.GetInstances(currentAsteroidList, v => v.IsBoxIntersectingBoundingBoxOfThisVoxelMap(ref bb)); if (currentAsteroidList.Count > 0) { _activeVoxelSetterNameB = currentAsteroidList[0].StorageName; _activeVoxelSetterPositionB = tmp; } } if (_activeVoxelSetterPositionB.HasValue) MyAPIGateway.Utilities.ShowMessage(_activeVoxelSetterNameB, "Voxel setter point B: active"); //MyAPIGateway.Utilities.ShowNotification("Voxel setter B: active.", 1000, MyFontEnum.Green); else MyAPIGateway.Utilities.ShowNotification("Voxel setter B: invalid.", 1000, MyFontEnum.Red); return true; } if (strings[1].Equals("C", StringComparison.InvariantCultureIgnoreCase) || strings[1].Equals("Clear", StringComparison.InvariantCultureIgnoreCase)) { if (_activeVoxelSetterPositionA.HasValue && _activeVoxelSetterPositionB.HasValue && _activeVoxelSetterNameA == _activeVoxelSetterNameB) { var currentAsteroidList = new List<IMyVoxelBase>(); MyAPIGateway.Session.VoxelMaps.GetInstances(currentAsteroidList, v => v.StorageName.Equals(_activeVoxelSetterNameA, StringComparison.InvariantCultureIgnoreCase)); if (currentAsteroidList.Count > 0) { var storage = currentAsteroidList[0].Storage; var point1 = new Vector3I(_activeVoxelSetterPositionA.Value - currentAsteroidList[0].PositionLeftBottomCorner); var point2 = new Vector3I(_activeVoxelSetterPositionB.Value - currentAsteroidList[0].PositionLeftBottomCorner); var cache = new MyStorageDataCache(); var size = storage.Size; cache.Resize(size); storage.ReadRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, (int)VRageRender.MyLodTypeEnum.LOD0, Vector3I.Zero, size - 1); var min = Vector3I.Min(point1, point2); var max = Vector3I.Max(point1, point2); MyAPIGateway.Utilities.ShowMessage("Cutting", min.ToString() + " " + max.ToString()); //MyAPIGateway.Utilities.ShowNotification("cutting:" + min.ToString() + " " + max.ToString(), 5000, MyFontEnum.Blue); Vector3I p; for (p.Z = min.Z; p.Z <= max.Z; ++p.Z) for (p.Y = min.Y; p.Y <= max.Y; ++p.Y) for (p.X = min.X; p.X <= max.X; ++p.X) cache.Content(ref p, 0); storage.WriteRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, Vector3I.Zero, size - 1); } } else if (_activeVoxelSetterNameA != _activeVoxelSetterNameB) { MyAPIGateway.Utilities.ShowNotification("Voxel setter Cut: different asteroids.", 2000, MyFontEnum.Red); } else { MyAPIGateway.Utilities.ShowNotification("Voxel setter Cut: invalid points.", 2000, MyFontEnum.Red); } return true; } if (strings[1].Equals("F", StringComparison.InvariantCultureIgnoreCase) || strings[1].Equals("Fill", StringComparison.InvariantCultureIgnoreCase)) { if (_activeVoxelSetterPositionA.HasValue && _activeVoxelSetterPositionB.HasValue && _activeVoxelSetterNameA == _activeVoxelSetterNameB) { var currentAsteroidList = new List<IMyVoxelBase>(); MyAPIGateway.Session.VoxelMaps.GetInstances(currentAsteroidList, v => v.StorageName.Equals(_activeVoxelSetterNameA, StringComparison.InvariantCultureIgnoreCase)); if (currentAsteroidList.Count > 0) { var storage = currentAsteroidList[0].Storage; var point1 = new Vector3I(_activeVoxelSetterPositionA.Value - currentAsteroidList[0].PositionLeftBottomCorner); var point2 = new Vector3I(_activeVoxelSetterPositionB.Value - currentAsteroidList[0].PositionLeftBottomCorner); var cache = new MyStorageDataCache(); var size = storage.Size; cache.Resize(size); storage.ReadRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, (int)VRageRender.MyLodTypeEnum.LOD0, Vector3I.Zero, size - 1); var min = Vector3I.Min(point1, point2); var max = Vector3I.Max(point1, point2); MyAPIGateway.Utilities.ShowMessage("Filling", min.ToString() + " " + max.ToString()); //MyAPIGateway.Utilities.ShowNotification("filling:" + min.ToString() + " " + max.ToString(), 5000, MyFontEnum.Blue); Vector3I p; for (p.Z = min.Z; p.Z <= max.Z; ++p.Z) for (p.Y = min.Y; p.Y <= max.Y; ++p.Y) for (p.X = min.X; p.X <= max.X; ++p.X) cache.Content(ref p, 0xff); storage.WriteRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, Vector3I.Zero, size - 1); } } else if (_activeVoxelSetterNameA != _activeVoxelSetterNameB) { MyAPIGateway.Utilities.ShowNotification("Voxel setter Cut: different asteroids.", 2000, MyFontEnum.Red); } else { MyAPIGateway.Utilities.ShowNotification("Voxel setter Cut: invalid points.", 2000, MyFontEnum.Red); } return true; } } } return false; }
private Vector3I ComputeTemporaryVoxelData(MyStorageDataCache cache, ref Vector3I coord0, int cubeIndex, int lod) { int coord0LinIdx = coord0.X * m_sX + coord0.Y * m_sY + coord0.Z * m_sZ; MyTemporaryVoxel tempVoxel0 = m_temporaryVoxels[coord0LinIdx]; MyTemporaryVoxel tempVoxel1 = m_temporaryVoxels[coord0LinIdx + m_sX]; MyTemporaryVoxel tempVoxel2 = m_temporaryVoxels[coord0LinIdx + m_sX + m_sZ]; MyTemporaryVoxel tempVoxel3 = m_temporaryVoxels[coord0LinIdx + m_sZ]; MyTemporaryVoxel tempVoxel4 = m_temporaryVoxels[coord0LinIdx + m_sY]; MyTemporaryVoxel tempVoxel5 = m_temporaryVoxels[coord0LinIdx + m_sX + m_sY]; MyTemporaryVoxel tempVoxel6 = m_temporaryVoxels[coord0LinIdx + m_sX + m_sY + m_sZ]; MyTemporaryVoxel tempVoxel7 = m_temporaryVoxels[coord0LinIdx + m_sY + m_sZ]; Vector3I coord1 = new Vector3I(coord0.X + 1, coord0.Y + 0, coord0.Z + 0); Vector3I coord2 = new Vector3I(coord0.X + 1, coord0.Y + 0, coord0.Z + 1); Vector3I coord3 = new Vector3I(coord0.X + 0, coord0.Y + 0, coord0.Z + 1); Vector3I coord4 = new Vector3I(coord0.X + 0, coord0.Y + 1, coord0.Z + 0); Vector3I coord5 = new Vector3I(coord0.X + 1, coord0.Y + 1, coord0.Z + 0); Vector3I coord6 = new Vector3I(coord0.X + 1, coord0.Y + 1, coord0.Z + 1); Vector3I coord7 = new Vector3I(coord0.X + 0, coord0.Y + 1, coord0.Z + 1); Vector3I tempVoxelCoord0 = coord0; Vector3I tempVoxelCoord1 = coord1; Vector3I tempVoxelCoord2 = coord2; Vector3I tempVoxelCoord3 = coord3; Vector3I tempVoxelCoord4 = coord4; Vector3I tempVoxelCoord5 = coord5; Vector3I tempVoxelCoord6 = coord6; Vector3I tempVoxelCoord7 = coord7; tempVoxel0.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord0); tempVoxel1.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord1); tempVoxel2.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord2); tempVoxel3.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord3); tempVoxel4.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord4); tempVoxel5.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord5); tempVoxel6.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord6); tempVoxel7.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord7); //tempVoxel0.Position.X = m_originPosition.X + (coord0.X) * m_voxelSizeInMeters; //tempVoxel0.Position.Y = m_originPosition.Y + (coord0.Y) * m_voxelSizeInMeters; //tempVoxel0.Position.Z = m_originPosition.Z + (coord0.Z) * m_voxelSizeInMeters; tempVoxel0.Position.X = (m_voxelStart.X + coord0.X) * m_voxelSizeInMeters; tempVoxel0.Position.Y = (m_voxelStart.Y + coord0.Y) * m_voxelSizeInMeters; tempVoxel0.Position.Z = (m_voxelStart.Z + coord0.Z) * m_voxelSizeInMeters; tempVoxel1.Position.X = tempVoxel0.Position.X + m_voxelSizeInMeters; tempVoxel1.Position.Y = tempVoxel0.Position.Y; tempVoxel1.Position.Z = tempVoxel0.Position.Z; tempVoxel2.Position.X = tempVoxel0.Position.X + m_voxelSizeInMeters; tempVoxel2.Position.Y = tempVoxel0.Position.Y; tempVoxel2.Position.Z = tempVoxel0.Position.Z + m_voxelSizeInMeters; tempVoxel3.Position.X = tempVoxel0.Position.X; tempVoxel3.Position.Y = tempVoxel0.Position.Y; tempVoxel3.Position.Z = tempVoxel0.Position.Z + m_voxelSizeInMeters; tempVoxel4.Position.X = tempVoxel0.Position.X; tempVoxel4.Position.Y = tempVoxel0.Position.Y + m_voxelSizeInMeters; tempVoxel4.Position.Z = tempVoxel0.Position.Z; tempVoxel5.Position.X = tempVoxel0.Position.X + m_voxelSizeInMeters; tempVoxel5.Position.Y = tempVoxel0.Position.Y + m_voxelSizeInMeters; tempVoxel5.Position.Z = tempVoxel0.Position.Z; tempVoxel6.Position.X = tempVoxel0.Position.X + m_voxelSizeInMeters; tempVoxel6.Position.Y = tempVoxel0.Position.Y + m_voxelSizeInMeters; tempVoxel6.Position.Z = tempVoxel0.Position.Z + m_voxelSizeInMeters; tempVoxel7.Position.X = tempVoxel0.Position.X; tempVoxel7.Position.Y = tempVoxel0.Position.Y + m_voxelSizeInMeters; tempVoxel7.Position.Z = tempVoxel0.Position.Z + m_voxelSizeInMeters; // Normals at grid corners (calculated from gradient) GetVoxelNormal(tempVoxel0, ref coord0, ref tempVoxelCoord0, tempVoxel0); GetVoxelNormal(tempVoxel1, ref coord1, ref tempVoxelCoord1, tempVoxel0); GetVoxelNormal(tempVoxel2, ref coord2, ref tempVoxelCoord2, tempVoxel0); GetVoxelNormal(tempVoxel3, ref coord3, ref tempVoxelCoord3, tempVoxel0); GetVoxelNormal(tempVoxel4, ref coord4, ref tempVoxelCoord4, tempVoxel0); GetVoxelNormal(tempVoxel5, ref coord5, ref tempVoxelCoord5, tempVoxel0); GetVoxelNormal(tempVoxel6, ref coord6, ref tempVoxelCoord6, tempVoxel0); GetVoxelNormal(tempVoxel7, ref coord7, ref tempVoxelCoord7, tempVoxel0); // Ambient occlusion colors at grid corners // IMPORTANT: At this point normals must be calculated because GetVoxelAmbientAndSun() will be retrieving them from temp table and not checking if there is actual value GetVoxelAmbient(tempVoxel0, ref coord0, ref tempVoxelCoord0); GetVoxelAmbient(tempVoxel1, ref coord1, ref tempVoxelCoord1); GetVoxelAmbient(tempVoxel2, ref coord2, ref tempVoxelCoord2); GetVoxelAmbient(tempVoxel3, ref coord3, ref tempVoxelCoord3); GetVoxelAmbient(tempVoxel4, ref coord4, ref tempVoxelCoord4); GetVoxelAmbient(tempVoxel5, ref coord5, ref tempVoxelCoord5); GetVoxelAmbient(tempVoxel6, ref coord6, ref tempVoxelCoord6); GetVoxelAmbient(tempVoxel7, ref coord7, ref tempVoxelCoord7); // Find the vertices where the surface intersects the cube int edgeVal = MyMarchingCubesConstants.EdgeTable[cubeIndex]; if ((edgeVal & 1) == 1) { GetVertexInterpolation(cache, tempVoxel0, tempVoxel1, 0); } if ((edgeVal & 2) == 2) { GetVertexInterpolation(cache, tempVoxel1, tempVoxel2, 1); } if ((edgeVal & 4) == 4) { GetVertexInterpolation(cache, tempVoxel2, tempVoxel3, 2); } if ((edgeVal & 8) == 8) { GetVertexInterpolation(cache, tempVoxel3, tempVoxel0, 3); } if ((edgeVal & 16) == 16) { GetVertexInterpolation(cache, tempVoxel4, tempVoxel5, 4); } if ((edgeVal & 32) == 32) { GetVertexInterpolation(cache, tempVoxel5, tempVoxel6, 5); } if ((edgeVal & 64) == 64) { GetVertexInterpolation(cache, tempVoxel6, tempVoxel7, 6); } if ((edgeVal & 128) == 128) { GetVertexInterpolation(cache, tempVoxel7, tempVoxel4, 7); } if ((edgeVal & 256) == 256) { GetVertexInterpolation(cache, tempVoxel0, tempVoxel4, 8); } if ((edgeVal & 512) == 512) { GetVertexInterpolation(cache, tempVoxel1, tempVoxel5, 9); } if ((edgeVal & 1024) == 1024) { GetVertexInterpolation(cache, tempVoxel2, tempVoxel6, 10); } if ((edgeVal & 2048) == 2048) { GetVertexInterpolation(cache, tempVoxel3, tempVoxel7, 11); } return(tempVoxelCoord0); }
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); } } } } } }
private bool ReplaceAsteroidMaterial(IMyVoxelBase originalAsteroid, string searchMaterialName1, string searchMaterialName2) { MyVoxelMaterialDefinition material1; string suggestedMaterials = ""; if (!Support.FindMaterial(searchMaterialName1, out material1, ref suggestedMaterials)) { MyAPIGateway.Utilities.ShowMessage("Invalid Material1 specified.", "Cannot find the material '{0}'.\r\nTry the following: {1}", searchMaterialName1, suggestedMaterials); return true; } MyVoxelMaterialDefinition material2; if (!Support.FindMaterial(searchMaterialName2, out material2, ref suggestedMaterials)) { MyAPIGateway.Utilities.ShowMessage("Invalid Material2 specified.", "Cannot find the material '{0}'.\r\nTry the following: {1}", searchMaterialName2, suggestedMaterials); return true; } var oldStorage = originalAsteroid.Storage; var oldCache = new MyStorageDataCache(); oldCache.Resize(oldStorage.Size); oldStorage.ReadRange(oldCache, MyStorageDataTypeFlags.ContentAndMaterial, 0, Vector3I.Zero, oldStorage.Size - 1); Vector3I p; for (p.Z = 0; p.Z < oldStorage.Size.Z; ++p.Z) for (p.Y = 0; p.Y < oldStorage.Size.Y; ++p.Y) for (p.X = 0; p.X < oldStorage.Size.X; ++p.X) { var material = oldCache.Material(ref p); if (material == material1.Index) oldCache.Material(ref p, material2.Index); } oldStorage.WriteRange(oldCache, MyStorageDataTypeFlags.ContentAndMaterial, Vector3I.Zero, oldStorage.Size - 1); MyAPIGateway.Utilities.ShowMessage("Asteroid", "'{0}' material '{1}' replaced with '{2}'.", originalAsteroid.StorageName, material1.Id.SubtypeName, material2.Id.SubtypeName); return true; }
// Linearly interpolates position, normal and material on poly-cube edge. Interpolated point is where an isosurface cuts an edge between two vertices, each with their own scalar value. void GetVertexInterpolation(MyStorageDataCache cache, MyTemporaryVoxel inputVoxelA, MyTemporaryVoxel inputVoxelB, int edgeIndex) { MyEdge edge = m_edges[edgeIndex]; byte contentA = cache.Content(inputVoxelA.IdxInCache); byte contentB = cache.Content(inputVoxelB.IdxInCache); byte materialA = cache.Material(inputVoxelA.IdxInCache); byte materialB = cache.Material(inputVoxelB.IdxInCache); if (Math.Abs(MyVoxelConstants.VOXEL_ISO_LEVEL - contentA) < 0.00001f) { edge.Position = inputVoxelA.Position; edge.Normal = inputVoxelA.Normal; edge.Material = materialA; edge.Ambient = inputVoxelA.Ambient; return; } if (Math.Abs(MyVoxelConstants.VOXEL_ISO_LEVEL - contentB) < 0.00001f) { edge.Position = inputVoxelB.Position; edge.Normal = inputVoxelB.Normal; edge.Material = materialB; edge.Ambient = inputVoxelB.Ambient; return; } float mu = (float)(MyVoxelConstants.VOXEL_ISO_LEVEL - contentA) / (float)(contentB - contentA); Debug.Assert(mu > 0.0f && mu < 1.0f); edge.Position.X = inputVoxelA.Position.X + mu * (inputVoxelB.Position.X - inputVoxelA.Position.X); edge.Position.Y = inputVoxelA.Position.Y + mu * (inputVoxelB.Position.Y - inputVoxelA.Position.Y); edge.Position.Z = inputVoxelA.Position.Z + mu * (inputVoxelB.Position.Z - inputVoxelA.Position.Z); //edge.Normal = ComputeVertexNormal(ref edge.Position); edge.Normal.X = inputVoxelA.Normal.X + mu * (inputVoxelB.Normal.X - inputVoxelA.Normal.X); edge.Normal.Y = inputVoxelA.Normal.Y + mu * (inputVoxelB.Normal.Y - inputVoxelA.Normal.Y); edge.Normal.Z = inputVoxelA.Normal.Z + mu * (inputVoxelB.Normal.Z - inputVoxelA.Normal.Z); if (MyUtils.IsZero(edge.Normal)) edge.Normal = inputVoxelA.Normal; else edge.Normal = MyUtils.Normalize(edge.Normal); if (MyUtils.IsZero(edge.Normal)) edge.Normal = inputVoxelA.Normal; float mu2 = ((float)contentB) / (((float)contentA) + ((float)contentB)); edge.Material = (mu2 <= 0.5f) ? materialA : materialB; edge.Ambient = inputVoxelA.Ambient + mu2 * (inputVoxelB.Ambient - inputVoxelA.Ambient); return; }
void IMyStorage.WriteRange(MyStorageDataCache source, bool writeContent, bool writeMaterials, ref Vector3I voxelRangeMin, ref Vector3I voxelRangeMax) { EnsureMutable(); m_trueStorage.WriteRange(source, writeContent, writeMaterials, ref voxelRangeMin, ref voxelRangeMax); }
private Vector3I ComputeTemporaryVoxelData(MyStorageDataCache cache, ref Vector3I coord0, int cubeIndex, int lod) { int coord0LinIdx = coord0.X * m_sX + coord0.Y * m_sY + coord0.Z * m_sZ; MyTemporaryVoxel tempVoxel0 = m_temporaryVoxels[coord0LinIdx]; MyTemporaryVoxel tempVoxel1 = m_temporaryVoxels[coord0LinIdx + m_sX]; MyTemporaryVoxel tempVoxel2 = m_temporaryVoxels[coord0LinIdx + m_sX + m_sZ]; MyTemporaryVoxel tempVoxel3 = m_temporaryVoxels[coord0LinIdx + m_sZ]; MyTemporaryVoxel tempVoxel4 = m_temporaryVoxels[coord0LinIdx + m_sY]; MyTemporaryVoxel tempVoxel5 = m_temporaryVoxels[coord0LinIdx + m_sX + m_sY]; MyTemporaryVoxel tempVoxel6 = m_temporaryVoxels[coord0LinIdx + m_sX + m_sY + m_sZ]; MyTemporaryVoxel tempVoxel7 = m_temporaryVoxels[coord0LinIdx + m_sY + m_sZ]; Vector3I coord1 = new Vector3I(coord0.X + 1, coord0.Y + 0, coord0.Z + 0); Vector3I coord2 = new Vector3I(coord0.X + 1, coord0.Y + 0, coord0.Z + 1); Vector3I coord3 = new Vector3I(coord0.X + 0, coord0.Y + 0, coord0.Z + 1); Vector3I coord4 = new Vector3I(coord0.X + 0, coord0.Y + 1, coord0.Z + 0); Vector3I coord5 = new Vector3I(coord0.X + 1, coord0.Y + 1, coord0.Z + 0); Vector3I coord6 = new Vector3I(coord0.X + 1, coord0.Y + 1, coord0.Z + 1); Vector3I coord7 = new Vector3I(coord0.X + 0, coord0.Y + 1, coord0.Z + 1); Vector3I tempVoxelCoord0 = coord0; Vector3I tempVoxelCoord1 = coord1; Vector3I tempVoxelCoord2 = coord2; Vector3I tempVoxelCoord3 = coord3; Vector3I tempVoxelCoord4 = coord4; Vector3I tempVoxelCoord5 = coord5; Vector3I tempVoxelCoord6 = coord6; Vector3I tempVoxelCoord7 = coord7; tempVoxel0.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord0); tempVoxel1.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord1); tempVoxel2.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord2); tempVoxel3.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord3); tempVoxel4.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord4); tempVoxel5.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord5); tempVoxel6.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord6); tempVoxel7.IdxInCache = cache.ComputeLinear(ref tempVoxelCoord7); //tempVoxel0.Position.X = m_originPosition.X + (coord0.X) * m_voxelSizeInMeters; //tempVoxel0.Position.Y = m_originPosition.Y + (coord0.Y) * m_voxelSizeInMeters; //tempVoxel0.Position.Z = m_originPosition.Z + (coord0.Z) * m_voxelSizeInMeters; tempVoxel0.Position.X = (m_voxelStart.X + coord0.X) * m_voxelSizeInMeters; tempVoxel0.Position.Y = (m_voxelStart.Y + coord0.Y) * m_voxelSizeInMeters; tempVoxel0.Position.Z = (m_voxelStart.Z + coord0.Z) * m_voxelSizeInMeters; tempVoxel1.Position.X = tempVoxel0.Position.X + m_voxelSizeInMeters; tempVoxel1.Position.Y = tempVoxel0.Position.Y; tempVoxel1.Position.Z = tempVoxel0.Position.Z; tempVoxel2.Position.X = tempVoxel0.Position.X + m_voxelSizeInMeters; tempVoxel2.Position.Y = tempVoxel0.Position.Y; tempVoxel2.Position.Z = tempVoxel0.Position.Z + m_voxelSizeInMeters; tempVoxel3.Position.X = tempVoxel0.Position.X; tempVoxel3.Position.Y = tempVoxel0.Position.Y; tempVoxel3.Position.Z = tempVoxel0.Position.Z + m_voxelSizeInMeters; tempVoxel4.Position.X = tempVoxel0.Position.X; tempVoxel4.Position.Y = tempVoxel0.Position.Y + m_voxelSizeInMeters; tempVoxel4.Position.Z = tempVoxel0.Position.Z; tempVoxel5.Position.X = tempVoxel0.Position.X + m_voxelSizeInMeters; tempVoxel5.Position.Y = tempVoxel0.Position.Y + m_voxelSizeInMeters; tempVoxel5.Position.Z = tempVoxel0.Position.Z; tempVoxel6.Position.X = tempVoxel0.Position.X + m_voxelSizeInMeters; tempVoxel6.Position.Y = tempVoxel0.Position.Y + m_voxelSizeInMeters; tempVoxel6.Position.Z = tempVoxel0.Position.Z + m_voxelSizeInMeters; tempVoxel7.Position.X = tempVoxel0.Position.X; tempVoxel7.Position.Y = tempVoxel0.Position.Y + m_voxelSizeInMeters; tempVoxel7.Position.Z = tempVoxel0.Position.Z + m_voxelSizeInMeters; // Normals at grid corners (calculated from gradient) GetVoxelNormal(tempVoxel0, ref coord0, ref tempVoxelCoord0, tempVoxel0); GetVoxelNormal(tempVoxel1, ref coord1, ref tempVoxelCoord1, tempVoxel0); GetVoxelNormal(tempVoxel2, ref coord2, ref tempVoxelCoord2, tempVoxel0); GetVoxelNormal(tempVoxel3, ref coord3, ref tempVoxelCoord3, tempVoxel0); GetVoxelNormal(tempVoxel4, ref coord4, ref tempVoxelCoord4, tempVoxel0); GetVoxelNormal(tempVoxel5, ref coord5, ref tempVoxelCoord5, tempVoxel0); GetVoxelNormal(tempVoxel6, ref coord6, ref tempVoxelCoord6, tempVoxel0); GetVoxelNormal(tempVoxel7, ref coord7, ref tempVoxelCoord7, tempVoxel0); // Ambient occlusion colors at grid corners // IMPORTANT: At this point normals must be calculated because GetVoxelAmbientAndSun() will be retrieving them from temp table and not checking if there is actual value GetVoxelAmbient(tempVoxel0, ref coord0, ref tempVoxelCoord0); GetVoxelAmbient(tempVoxel1, ref coord1, ref tempVoxelCoord1); GetVoxelAmbient(tempVoxel2, ref coord2, ref tempVoxelCoord2); GetVoxelAmbient(tempVoxel3, ref coord3, ref tempVoxelCoord3); GetVoxelAmbient(tempVoxel4, ref coord4, ref tempVoxelCoord4); GetVoxelAmbient(tempVoxel5, ref coord5, ref tempVoxelCoord5); GetVoxelAmbient(tempVoxel6, ref coord6, ref tempVoxelCoord6); GetVoxelAmbient(tempVoxel7, ref coord7, ref tempVoxelCoord7); // Find the vertices where the surface intersects the cube int edgeVal = MyMarchingCubesConstants.EdgeTable[cubeIndex]; if ((edgeVal & 1) == 1) { GetVertexInterpolation(cache, tempVoxel0, tempVoxel1, 0); } if ((edgeVal & 2) == 2) { GetVertexInterpolation(cache, tempVoxel1, tempVoxel2, 1); } if ((edgeVal & 4) == 4) { GetVertexInterpolation(cache, tempVoxel2, tempVoxel3, 2); } if ((edgeVal & 8) == 8) { GetVertexInterpolation(cache, tempVoxel3, tempVoxel0, 3); } if ((edgeVal & 16) == 16) { GetVertexInterpolation(cache, tempVoxel4, tempVoxel5, 4); } if ((edgeVal & 32) == 32) { GetVertexInterpolation(cache, tempVoxel5, tempVoxel6, 5); } if ((edgeVal & 64) == 64) { GetVertexInterpolation(cache, tempVoxel6, tempVoxel7, 6); } if ((edgeVal & 128) == 128) { GetVertexInterpolation(cache, tempVoxel7, tempVoxel4, 7); } if ((edgeVal & 256) == 256) { GetVertexInterpolation(cache, tempVoxel0, tempVoxel4, 8); } if ((edgeVal & 512) == 512) { GetVertexInterpolation(cache, tempVoxel1, tempVoxel5, 9); } if ((edgeVal & 1024) == 1024) { GetVertexInterpolation(cache, tempVoxel2, tempVoxel6, 10); } if ((edgeVal & 2048) == 2048) { GetVertexInterpolation(cache, tempVoxel3, tempVoxel7, 11); } return tempVoxelCoord0; }
private static MyStorageBase Compatibility_LoadCellStorage(int fileVersion, Stream stream) { // Size of this voxel map (in voxels) Vector3I tmpSize; tmpSize.X = stream.ReadInt32(); tmpSize.Y = stream.ReadInt32(); tmpSize.Z = stream.ReadInt32(); var storage = new MyOctreeStorage(null, tmpSize); // Size of data cell in voxels. Has to be the same as current size specified by our constants. Vector3I cellSize; cellSize.X = stream.ReadInt32(); cellSize.Y = stream.ReadInt32(); cellSize.Z = stream.ReadInt32(); Trace.Assert(cellSize.X == MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS && cellSize.Y == MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS && cellSize.Z == MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS); Vector3I cellsCount = tmpSize / cellSize; Dictionary <byte, MyVoxelMaterialDefinition> mappingTable = null; if (fileVersion == STORAGE_TYPE_VERSION_CELL) { // loading material names->index mappings mappingTable = Compatibility_LoadMaterialIndexMapping(stream); } else if (fileVersion == 1) { // material name->index mappings were not saved in this version } var startCoord = Vector3I.Zero; var endCoord = new Vector3I(MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS - 1); var cache = new MyStorageDataCache(); cache.Resize(Vector3I.Zero, endCoord); Vector3I cellCoord; for (cellCoord.X = 0; cellCoord.X < cellsCount.X; cellCoord.X++) { for (cellCoord.Y = 0; cellCoord.Y < cellsCount.Y; cellCoord.Y++) { for (cellCoord.Z = 0; cellCoord.Z < cellsCount.Z; cellCoord.Z++) { MyVoxelRangeType cellType = (MyVoxelRangeType)stream.ReadByteNoAlloc(); // Cell's are FULL by default, therefore we don't need to change them switch (cellType) { case MyVoxelRangeType.EMPTY: cache.ClearContent(MyVoxelConstants.VOXEL_CONTENT_EMPTY); break; case MyVoxelRangeType.FULL: cache.ClearContent(MyVoxelConstants.VOXEL_CONTENT_FULL); break; case MyVoxelRangeType.MIXED: Vector3I v; for (v.X = 0; v.X < MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; v.X++) { for (v.Y = 0; v.Y < MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; v.Y++) { for (v.Z = 0; v.Z < MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; v.Z++) { cache.Content(ref v, stream.ReadByteNoAlloc()); } } } break; } startCoord = cellCoord * MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; endCoord = startCoord + (MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS - 1); storage.WriteRange(cache, MyStorageDataTypeFlags.Content, ref startCoord, ref endCoord); } } } try { // In case materials are not saved, catch any exceptions caused by this. // Read materials and indestructible for (cellCoord.X = 0; cellCoord.X < cellsCount.X; cellCoord.X++) { for (cellCoord.Y = 0; cellCoord.Y < cellsCount.Y; cellCoord.Y++) { for (cellCoord.Z = 0; cellCoord.Z < cellsCount.Z; cellCoord.Z++) { bool isSingleMaterial = stream.ReadByteNoAlloc() == 1; MyVoxelMaterialDefinition material = null; if (isSingleMaterial) { material = Compatibility_LoadCellVoxelMaterial(stream, mappingTable); cache.ClearMaterials(material.Index); } else { byte indestructibleContent; Vector3I voxelCoordInCell; for (voxelCoordInCell.X = 0; voxelCoordInCell.X < MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; voxelCoordInCell.X++) { for (voxelCoordInCell.Y = 0; voxelCoordInCell.Y < MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; voxelCoordInCell.Y++) { for (voxelCoordInCell.Z = 0; voxelCoordInCell.Z < MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; voxelCoordInCell.Z++) { material = Compatibility_LoadCellVoxelMaterial(stream, mappingTable); indestructibleContent = stream.ReadByteNoAlloc(); cache.Material(ref voxelCoordInCell, material.Index); } } } } startCoord = cellCoord * MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; endCoord = startCoord + (MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS - 1); storage.WriteRange(cache, MyStorageDataTypeFlags.Material, ref startCoord, ref endCoord); } } } } catch (EndOfStreamException ex) { MySandboxGame.Log.WriteLine(ex); } return(storage); }