private unsafe void WriteRange <TOperator>(MyCellCoord cell, byte defaultData, ref TOperator source, MyStorageDataTypeEnum type, ref Vector3I readOffset, ref Vector3I min, ref Vector3I max) where TOperator : struct, IVoxelOperator { MyOctreeNode node; uint key = cell.PackId32(); if (!this.m_nodes.TryGetValue(key, out node)) { for (int i = 0; i < 8; i++) { &node.Data.FixedElementField[i] = defaultData; } } if (cell.Lod == 0) { Vector3I vectori = cell.CoordInLod << 1; for (int i = 0; i < 8; i++) { Vector3I vectori2; this.ComputeChildCoord(i, out vectori2); Vector3I position = (Vector3I)(vectori + vectori2); if (position.IsInsideInclusiveEnd(ref min, ref max)) { position = (Vector3I)((position - min) + readOffset); source.Op(ref position, type, ref (byte)ref (&node.Data.FixedElementField + i)); } } this.m_nodes[key] = node; } else { Vector3I vectori4 = cell.CoordInLod << 1; Vector3I vectori6 = (min >> cell.Lod) - vectori4; Vector3I vectori7 = (max >> cell.Lod) - vectori4; for (int i = 0; i < 8; i++) { Vector3I vectori5; this.ComputeChildCoord(i, out vectori5); if (vectori5.IsInsideInclusiveEnd(ref vectori6, ref vectori7)) { MyCellCoord coord = new MyCellCoord(cell.Lod - 1, (Vector3I)(vectori4 + vectori5)); this.WriteRange <TOperator>(coord, &node.Data.FixedElementField[i], ref source, type, ref readOffset, ref min, ref max); uint num5 = coord.PackId32(); MyOctreeNode node2 = this.m_nodes[num5]; if (node2.HasChildren || !MyOctreeNode.AllDataSame(&node2.Data.FixedElementField)) { node.SetChild(i, true); &node.Data.FixedElementField[i] = this.m_nodeFilter(&node2.Data.FixedElementField, cell.Lod); } else { node.SetChild(i, false); &node.Data.FixedElementField[i] = node2.Data.FixedElementField; this.m_nodes.Remove(num5); } } } this.m_nodes[key] = node; } }
private void CheckData <T>(ref T data, MyCellCoord cell) where T : struct, IEnumerator <byte> { uint num = cell.PackId32(); MyOctreeNode node = this.m_nodes[num]; for (int i = 0; i < 8; i++) { if (node.HasChild(i)) { Vector3I vectori; this.ComputeChildCoord(i, out vectori); } else { int num3 = 1 << ((3 * cell.Lod) & 0x1f); for (int j = 0; j < num3; j++) { } } } }
private unsafe void CheckData <T>(ref T data, MyCellCoord cell) where T : struct, IEnumerator <TLeafData> { var key = cell.PackId32(); var node = m_nodes[key]; for (int i = 0; i < 8; ++i) { if (node.HasChild(i)) { Vector3I childOffset; ComputeChildCoord(i, out childOffset); CheckData(ref data, new MyCellCoord(cell.Lod - 1, (cell.CoordInLod << 1) + childOffset)); } else { int numNodes = 1 << (3 * cell.Lod); for (int j = 0; j < numNodes; ++j) { Debug.Assert(data.MoveNext()); Debug.Assert(node.Data[i] == data.Current); } } } }
internal unsafe ContainmentType Intersect(ref BoundingBoxI box, bool lazy) { 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; Vector3I minInLod = box.Min; Vector3I maxInLod = box.Max; MyOctreeNode node; Vector3I childPosRelative, min, max, nodePositionInChild; int lodDiff; // TODO(DI): Add support for checking for containment somehow, this needs neighbourhood information which kinda sucks. ContainmentType cont = ContainmentType.Disjoint; while (stackIdx > 0) { Debug.Assert(stackIdx <= stackSize); data = stack[--stackIdx]; node = m_nodes[data.PackId32()]; lodDiff = data.Lod; 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 (data.Lod > 0 && node.HasChild(i)) { Debug.Assert(stackIdx < stackSize); stack[stackIdx++] = new MyCellCoord(data.Lod - 1, nodePositionInChild + childPosRelative); } else { var nodeData = node.Data[i]; if (lodDiff == 0) { if (nodeData != 0) { return(ContainmentType.Intersects); } } else { BoundingBoxI nodeBox; nodeBox.Min = nodePositionInChild + childPosRelative; nodeBox.Min <<= lodDiff; nodeBox.Max = nodeBox.Min + (1 << lodDiff) - 1; Vector3I.Max(ref nodeBox.Min, ref minInLod, out nodeBox.Min); Vector3I.Min(ref nodeBox.Max, ref maxInLod, out nodeBox.Max); bool res; nodeBox.Intersects(ref nodeBox, out res); if (res) { return(ContainmentType.Intersects); } } } } } return(cont); }
private unsafe void WriteRange( MyCellCoord cell, TLeafData defaultData, MyStorageData 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, cell.Lod); } } m_nodes[nodeKey] = node; } }
internal unsafe void ReadRange(MyStorageData 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(); } }
internal unsafe void ReadRange <TOperator>(ref TOperator target, MyStorageDataTypeEnum type, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) where TOperator : struct, IVoxelOperator { try { MyCellCoord *coordPtr = (MyCellCoord *)stackalloc byte[(((IntPtr)EstimateStackSize(this.m_treeHeight)) * sizeof(MyCellCoord))]; MyCellCoord coord = new MyCellCoord(this.m_treeHeight - 1, ref Vector3I.Zero); int index = 0 + 1; coordPtr[index] = coord; while (index > 0) { coord = coordPtr[--index]; MyOctreeNode node = this.m_nodes[coord.PackId32()]; int num3 = coord.Lod - lodIndex; Vector3I vectori4 = coord.CoordInLod << 1; Vector3I min = (minInLod >> num3) - vectori4; Vector3I max = (maxInLod >> num3) - vectori4; for (int i = 0; i < 8; i++) { Vector3I vectori; this.ComputeChildCoord(i, out vectori); if (vectori.IsInsideInclusiveEnd(ref min, ref max)) { if ((lodIndex < coord.Lod) && node.HasChild(i)) { index++; coordPtr[index] = new MyCellCoord(coord.Lod - 1, (Vector3I)(vectori4 + vectori)); } else { byte inOutContent = &node.Data.FixedElementField[i]; Vector3I result = (Vector3I)(vectori4 + vectori); if (num3 == 0) { Vector3I position = (Vector3I)((writeOffset + result) - minInLod); target.Op(ref position, type, ref inOutContent); } else { result = result << num3; Vector3I vectori7 = (Vector3I)((result + (1 << (num3 & 0x1f))) - 1); Vector3I *vectoriPtr1 = (Vector3I *)ref result; Vector3I.Max(ref (Vector3I) ref vectoriPtr1, ref minInLod, out result); Vector3I *vectoriPtr2 = (Vector3I *)ref vectori7; Vector3I.Min(ref (Vector3I) ref vectoriPtr2, ref maxInLod, out vectori7); int z = result.Z; while (z <= vectori7.Z) { int y = result.Y; while (true) { if (y > vectori7.Y) { z++; break; } int x = result.X; while (true) { if (x > vectori7.X) { y++; break; } Vector3I position = writeOffset; int * numPtr1 = (int *)ref position.X; numPtr1[0] += x - minInLod.X; int *numPtr2 = (int *)ref position.Y; numPtr2[0] += y - minInLod.Y; int *numPtr3 = (int *)ref position.Z; numPtr3[0] += z - minInLod.Z; target.Op(ref position, type, ref inOutContent); x++; } } } } } } } } } finally { } }
internal unsafe ContainmentType Intersect(ref BoundingBoxI box, int lod, bool exhaustiveContainmentCheck = true) { MyCellCoord *coordPtr = (MyCellCoord *)stackalloc byte[(((IntPtr)EstimateStackSize(this.m_treeHeight)) * sizeof(MyCellCoord))]; MyCellCoord coord = new MyCellCoord(this.m_treeHeight - 1, ref Vector3I.Zero); int index = 0 + 1; coordPtr[index] = coord; Vector3I min = box.Min; Vector3I max = box.Max; ContainmentType disjoint = ContainmentType.Disjoint; while (index > 0) { coord = coordPtr[--index]; MyOctreeNode node = this.m_nodes[coord.PackId32()]; int num3 = coord.Lod; Vector3I vectori6 = coord.CoordInLod << 1; Vector3I vectori4 = (min >> num3) - vectori6; Vector3I vectori5 = (max >> num3) - vectori6; for (int i = 0; i < 8; i++) { Vector3I vectori3; this.ComputeChildCoord(i, out vectori3); if (vectori3.IsInsideInclusiveEnd(ref vectori4, ref vectori5)) { if ((coord.Lod > 0) && node.HasChild(i)) { index++; coordPtr[index] = new MyCellCoord(coord.Lod - 1, (Vector3I)(vectori6 + vectori3)); } else { byte num5 = &node.Data.FixedElementField[i]; if (num3 == 0) { if (num5 != 0) { return(ContainmentType.Intersects); } } else { BoundingBoxI xi; bool flag; xi.Min = (Vector3I)(vectori6 + vectori3); Vector3I *vectoriPtr1 = (Vector3I *)ref xi.Min; vectoriPtr1[0] = vectoriPtr1[0] << num3; BoundingBoxI *xiPtr1 = (BoundingBoxI *)ref xi; xiPtr1->Max = (Vector3I)((xi.Min + (1 << (num3 & 0x1f))) - 1); Vector3I.Max(ref xi.Min, ref min, out xi.Min); Vector3I.Min(ref xi.Max, ref max, out xi.Max); ((BoundingBoxI *)ref xi).Intersects(ref xi, out flag); if (flag) { return(ContainmentType.Intersects); } } } } } } return(disjoint); }
private static bool ResetOutsideBorders( IMyStorageDataProvider provider, MyStorageDataTypeEnum dataType, int lodIdx, Dictionary <UInt64, MyOctreeNode> nodes, Dictionary <UInt64, IMyOctreeLeafNode> leaves, Vector3I lodCoord, Vector3I minVoxel, Vector3I maxVoxel, out bool canCollapse, Dictionary <UInt64, IMyOctreeLeafNode> outResetLeaves = null) { canCollapse = false; bool changed = false; var currentCell = new MyCellCoord(lodIdx, lodCoord); var key = currentCell.PackId64(); var leafCell = currentCell; var leafKey = leafCell.PackId32(); IMyOctreeLeafNode leaf; if (leaves.TryGetValue(leafKey, out leaf)) { canCollapse = leaf.ReadOnly; if (leafCell.Lod != 0) { Debug.Assert(leaf.ReadOnly); return(false); } else if (!leaf.ReadOnly) { var minCell = minVoxel >> (LeafLodCount + leafCell.Lod); var maxCell = maxVoxel >> (LeafLodCount + leafCell.Lod); if (!leafCell.CoordInLod.IsInsideInclusive(ref minCell, ref maxCell)) { canCollapse = true; leaves.Remove(leafKey); var leafSize = LeafSizeInVoxels << leafCell.Lod; var minLeafVoxel = leafCell.CoordInLod * leafSize; var maxLeafVoxel = minLeafVoxel + (leafSize - 1); var leafNew = new MyProviderLeaf(provider, dataType, ref minLeafVoxel, ref maxLeafVoxel); leaves.Add(leafKey, leafNew); changed = true; if (outResetLeaves != null) { outResetLeaves.Add(leafKey, leafNew); } } } } else { currentCell.Lod -= 1; key = currentCell.PackId64(); var nodeCell = currentCell; var nodeKey = currentCell.PackId32(); var node = nodes[nodeKey]; var childBase = lodCoord << 1; Vector3I childOffset; var minInChild = (minVoxel >> (LeafLodCount + currentCell.Lod)) - childBase; var maxInChild = (maxVoxel >> (LeafLodCount + currentCell.Lod)) - childBase; var leafSize = LeafSizeInVoxels << currentCell.Lod; Vector3I childMin, childMax; unsafe { canCollapse = true; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; i++) { ComputeChildCoord(i, out childOffset); if (childOffset.IsInsideExclusive(ref minInChild, ref maxInChild)) { canCollapse = false; continue; } currentCell.CoordInLod = childBase + childOffset; if (node.HasChild(i)) { bool localCanCollapse; bool resetChanged = ResetOutsideBorders(provider, dataType, currentCell.Lod, nodes, leaves, currentCell.CoordInLod, minVoxel, maxVoxel, out localCanCollapse, outResetLeaves: outResetLeaves); changed = changed || resetChanged; canCollapse = localCanCollapse && canCollapse; } else { childMin = currentCell.CoordInLod * leafSize; childMax = childMin + (leafSize - 1); IMyOctreeLeafNode octreeLeaf = new MyProviderLeaf(provider, dataType, ref childMin, ref childMax); leaves.Add(currentCell.PackId32(), octreeLeaf); node.SetChild(i, true); node.SetData(i, octreeLeaf.GetFilteredValue()); changed = true; } } nodes[nodeKey] = node; if (canCollapse) { // Remove leaves for (int i = 0; i < MyOctreeNode.CHILD_COUNT; i++) { if (node.HasChild(i)) { ComputeChildCoord(i, out childOffset); currentCell.CoordInLod = childBase + childOffset; var childKey = currentCell.PackId64(); leaves.Remove(childKey); node.SetChild(i, false); } } // Remove node nodes.Remove(nodeKey); // Add leaf var newLeafSize = LeafSizeInVoxels << leafCell.Lod; var minLeafVoxel = leafCell.CoordInLod * newLeafSize; var maxLeafVoxel = minLeafVoxel + (newLeafSize - 1); var leafNew = new MyProviderLeaf(provider, dataType, ref minLeafVoxel, ref maxLeafVoxel); leaves.Add(leafKey, leafNew); } } } return(changed); }
private static ulong CountChangedVoxelsAmount( MyOctreeStorage baseStorage, int lodIdx, Dictionary <UInt64, MyOctreeNode> nodes, Dictionary <UInt64, IMyOctreeLeafNode> leaves, Vector3I lodCoord) { var currentCell = new MyCellCoord(lodIdx, lodCoord); var leafKey = currentCell.PackId32(); IMyOctreeLeafNode leaf; if (leaves.TryGetValue(leafKey, out leaf)) { if (!leaf.ReadOnly && currentCell.Lod == 0) { // Read data from leaf var rangeEnd = new Vector3I(LeafSizeInVoxels - 1); m_temporaryCache.Resize(Vector3I.Zero, rangeEnd); leaf.ReadRange(m_temporaryCache, ref Vector3I.Zero, 0, ref Vector3I.Zero, ref rangeEnd); // Read data from base storage var minLeafVoxel = currentCell.CoordInLod * LeafSizeInVoxels; var maxLeafVoxel = minLeafVoxel + (LeafSizeInVoxels - 1); m_temporaryCache2.Resize(minLeafVoxel, maxLeafVoxel); baseStorage.ReadRange(m_temporaryCache2, MyStorageDataTypeFlags.Content, currentCell.Lod, ref minLeafVoxel, ref maxLeafVoxel); byte[] origData = m_temporaryCache2.Data; byte[] currData = m_temporaryCache.Data; Debug.Assert(currData.Length == origData.Length); if (currData.Length != origData.Length) { return(0); } ulong countChangedVoxels = 0; for (int i = (int)MyStorageDataTypeEnum.Content; i < m_temporaryCache.SizeLinear; i += m_temporaryCache.StepLinear) { countChangedVoxels += (ulong)Math.Abs(currData[i] - origData[i]); } return(countChangedVoxels); } } else { currentCell.Lod -= 1; var nodeKey = currentCell.PackId32(); var node = nodes[nodeKey]; var childBase = lodCoord << 1; Vector3I childOffset; if (node.HasChildren) { ulong count = 0; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; i++) { if (node.HasChild(i)) { ComputeChildCoord(i, out childOffset); currentCell.CoordInLod = childBase + childOffset; count += CountChangedVoxelsAmount(baseStorage, currentCell.Lod, nodes, leaves, currentCell.CoordInLod); } } return(count); } else { return((ulong)((MyOctreeNode.CHILD_COUNT << (currentCell.Lod * 3)) * LeafSizeInVoxels * LeafSizeInVoxels * LeafSizeInVoxels * MyVoxelConstants.VOXEL_CONTENT_FULL)); } } return(0); }