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; }