private unsafe void BuildNode <TDataEnum>(ref StackData <TDataEnum> stack, out MyOctreeNode builtNode) where TDataEnum : struct, IEnumerator <byte> { MyOctreeNode defaultNode = stack.DefaultNode; if (stack.Cell.Lod == 0) { for (int i = 0; i < 8; i++) { stack.Data.MoveNext(); &defaultNode.Data.FixedElementField[i] = stack.Data.Current; } } else { int *numPtr1 = (int *)ref stack.Cell.Lod; numPtr1[0]--; Vector3I coordInLod = stack.Cell.CoordInLod; Vector3I vectori2 = coordInLod << 1; int childIdx = 0; while (true) { Vector3I vectori3; MyOctreeNode node2; if (childIdx >= 8) { int *numPtr2 = (int *)ref stack.Cell.Lod; numPtr2[0]++; stack.Cell.CoordInLod = coordInLod; break; } this.ComputeChildCoord(childIdx, out vectori3); stack.Cell.CoordInLod = (Vector3I)(vectori2 + vectori3); this.BuildNode <TDataEnum>(ref stack, out node2); if (!node2.HasChildren && MyOctreeNode.AllDataSame(&node2.Data.FixedElementField)) { defaultNode.SetChild(childIdx, false); &defaultNode.Data.FixedElementField[childIdx] = node2.Data.FixedElementField; } else { defaultNode.SetChild(childIdx, true); &defaultNode.Data.FixedElementField[childIdx] = this.m_nodeFilter(&node2.Data.FixedElementField, stack.Cell.Lod); this.m_nodes.Add(stack.Cell.PackId32(), node2); } childIdx++; } } builtNode = defaultNode; }
private static void WriteRange( ref WriteRangeArgs args, byte defaultData, int lodIdx, Vector3I lodCoord, ref Vector3I min, ref Vector3I max) { MyOctreeNode node = new MyOctreeNode(); { MyCellCoord leaf = new MyCellCoord(lodIdx - LeafLodCount, ref lodCoord); var leafKey = leaf.PackId64(); if (args.Leaves.ContainsKey(leafKey)) { args.Leaves.Remove(leafKey); var childBase = lodCoord << 1; Vector3I childOffset; MyCellCoord child = new MyCellCoord(); child.Lod = leaf.Lod - 1; var leafSize = LeafSizeInVoxels << child.Lod; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); child.CoordInLod = childBase + childOffset; var childCopy = child; childCopy.Lod += LeafLodCount; IMyOctreeLeafNode octreeLeaf = new MyProviderLeaf(args.Provider, args.DataType, ref childCopy); args.Leaves.Add(child.PackId64(), octreeLeaf); node.SetChild(i, true); node.SetData(i, octreeLeaf.GetFilteredValue()); } } else { leaf.Lod -= 1; // changes to node coord instead of leaf coord var nodeKey = leaf.PackId64(); if (!args.Nodes.TryGetValue(nodeKey, out node)) { for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) node.SetData(i, defaultData); } } } if (lodIdx == (LeafLodCount + 1)) { MyCellCoord child = new MyCellCoord(); Vector3I childBase = lodCoord << 1; Vector3I minInLod = min >> LeafLodCount; Vector3I maxInLod = max >> LeafLodCount; Vector3I leafSizeMinusOne = new Vector3I(LeafSizeInVoxels - 1); Vector3I childOffset; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); child.CoordInLod = childBase + childOffset; if (!child.CoordInLod.IsInsideInclusive(ref minInLod, ref maxInLod)) continue; var childMin = child.CoordInLod << LeafLodCount; var childMax = childMin + LeafSizeInVoxels - 1; Vector3I.Max(ref childMin, ref min, out childMin); Vector3I.Min(ref childMax, ref max, out childMax); var readOffset = childMin - min; IMyOctreeLeafNode leaf; var leafKey = child.PackId64(); var startInChild = childMin - (child.CoordInLod << LeafLodCount); var endInChild = childMax - (child.CoordInLod << LeafLodCount); args.Leaves.TryGetValue(leafKey, out leaf); byte uniformValue; bool uniformLeaf; { // ensure leaf exists and is writable // the only writable leaf type is MicroOctree at this point byte childDefaultData = node.GetData(i); if (leaf == null) { var octree = new MyMicroOctreeLeaf(args.DataType, LeafLodCount, child.CoordInLod << (child.Lod + LeafLodCount)); octree.BuildFrom(childDefaultData); leaf = octree; } if (leaf.ReadOnly) { 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); var inCell = startInChild; for (var it2 = new Vector3I.RangeIterator(ref startInChild, ref endInChild); it2.IsValid(); it2.GetNext(out inCell)) { var read = readOffset + (inCell - startInChild); m_temporaryCache.Set(args.DataType, ref inCell, args.Source.Get(args.DataType, ref read)); } var octree = new MyMicroOctreeLeaf(args.DataType, LeafLodCount, child.CoordInLod << (child.Lod + LeafLodCount)); octree.BuildFrom(m_temporaryCache); leaf = octree; } else { leaf.WriteRange(args.Source, ref readOffset, ref startInChild, ref endInChild); } uniformLeaf = ((MyMicroOctreeLeaf)leaf).TryGetUniformValue(out uniformValue); } if (!uniformLeaf) { args.Leaves[leafKey] = leaf; node.SetChild(i, true); } else { args.Leaves.Remove(leafKey); node.SetChild(i, false); } node.SetData(i, leaf.GetFilteredValue()); } args.Nodes[new MyCellCoord(lodIdx - 1 - LeafLodCount, ref lodCoord).PackId64()] = node; } else { MyCellCoord child = new MyCellCoord(); child.Lod = lodIdx - 2 - LeafLodCount; var childBase = lodCoord << 1; Vector3I childOffset; var minInChild = (min >> (lodIdx-1)) - childBase; var maxInChild = (max >> (lodIdx-1)) - childBase; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); if (!childOffset.IsInsideInclusive(ref minInChild, ref maxInChild)) continue; child.CoordInLod = childBase + childOffset; WriteRange(ref args, node.GetData(i), lodIdx - 1, child.CoordInLod, ref min, ref max); var childKey = child.PackId64(); var childNode = args.Nodes[childKey]; if (!childNode.HasChildren && childNode.AllDataSame()) { node.SetChild(i, false); node.SetData(i, childNode.GetData(0)); args.Nodes.Remove(childKey); } else { node.SetChild(i, true); node.SetData(i, childNode.ComputeFilteredValue(args.DataFilter)); } } args.Nodes[new MyCellCoord(lodIdx - 1 - LeafLodCount, ref lodCoord).PackId64()] = node; } }
private static void WriteRange( ref WriteRangeArgs args, byte defaultData, int lodIdx, Vector3I lodCoord, ref Vector3I min, ref Vector3I max) { MyOctreeNode node = new MyOctreeNode(); { MyCellCoord leaf = new MyCellCoord(lodIdx - LeafLodCount, ref lodCoord); var leafKey = leaf.PackId64(); if (args.Leaves.ContainsKey(leafKey)) { args.Leaves.Remove(leafKey); var childBase = lodCoord << 1; Vector3I childOffset; MyCellCoord child = new MyCellCoord(); child.Lod = leaf.Lod - 1; var leafSize = LeafSizeInVoxels << child.Lod; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); child.CoordInLod = childBase + childOffset; var childCopy = child; childCopy.Lod += LeafLodCount; IMyOctreeLeafNode octreeLeaf = new MyProviderLeaf(args.Provider, args.DataType, ref childCopy); args.Leaves.Add(child.PackId64(), octreeLeaf); node.SetChild(i, true); node.SetData(i, octreeLeaf.GetFilteredValue()); } } else { leaf.Lod -= 1; // changes to node coord instead of leaf coord var nodeKey = leaf.PackId64(); if (!args.Nodes.TryGetValue(nodeKey, out node)) { for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { node.SetData(i, defaultData); } } } } if (lodIdx == (LeafLodCount + 1)) { MyCellCoord child = new MyCellCoord(); Vector3I childBase = lodCoord << 1; Vector3I minInLod = min >> LeafLodCount; Vector3I maxInLod = max >> LeafLodCount; Vector3I leafSizeMinusOne = new Vector3I(LeafSizeInVoxels - 1); Vector3I childOffset; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); child.CoordInLod = childBase + childOffset; if (!child.CoordInLod.IsInsideInclusive(ref minInLod, ref maxInLod)) { continue; } var childMin = child.CoordInLod << LeafLodCount; var childMax = childMin + LeafSizeInVoxels - 1; Vector3I.Max(ref childMin, ref min, out childMin); Vector3I.Min(ref childMax, ref max, out childMax); var readOffset = childMin - min; IMyOctreeLeafNode leaf; var leafKey = child.PackId64(); var startInChild = childMin - (child.CoordInLod << LeafLodCount); var endInChild = childMax - (child.CoordInLod << LeafLodCount); args.Leaves.TryGetValue(leafKey, out leaf); byte uniformValue; bool uniformLeaf; { // ensure leaf exists and is writable // the only writable leaf type is MicroOctree at this point byte childDefaultData = node.GetData(i); if (leaf == null) { var octree = new MyMicroOctreeLeaf(args.DataType, LeafLodCount, child.CoordInLod << (child.Lod + LeafLodCount)); octree.BuildFrom(childDefaultData); leaf = octree; } if (leaf.ReadOnly) { 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); var inCell = startInChild; for (var it2 = new Vector3I.RangeIterator(ref startInChild, ref endInChild); it2.IsValid(); it2.GetNext(out inCell)) { var read = readOffset + (inCell - startInChild); m_temporaryCache.Set(args.DataType, ref inCell, args.Source.Get(args.DataType, ref read)); } var octree = new MyMicroOctreeLeaf(args.DataType, LeafLodCount, child.CoordInLod << (child.Lod + LeafLodCount)); octree.BuildFrom(m_temporaryCache); leaf = octree; } else { leaf.WriteRange(args.Source, ref readOffset, ref startInChild, ref endInChild); } uniformLeaf = ((MyMicroOctreeLeaf)leaf).TryGetUniformValue(out uniformValue); } if (!uniformLeaf) { args.Leaves[leafKey] = leaf; node.SetChild(i, true); } else { args.Leaves.Remove(leafKey); node.SetChild(i, false); } node.SetData(i, leaf.GetFilteredValue()); } args.Nodes[new MyCellCoord(lodIdx - 1 - LeafLodCount, ref lodCoord).PackId64()] = node; } else { MyCellCoord child = new MyCellCoord(); child.Lod = lodIdx - 2 - LeafLodCount; var childBase = lodCoord << 1; Vector3I childOffset; var minInChild = (min >> (lodIdx - 1)) - childBase; var maxInChild = (max >> (lodIdx - 1)) - childBase; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); if (!childOffset.IsInsideInclusive(ref minInChild, ref maxInChild)) { continue; } child.CoordInLod = childBase + childOffset; WriteRange(ref args, node.GetData(i), lodIdx - 1, child.CoordInLod, ref min, ref max); var childKey = child.PackId64(); var childNode = args.Nodes[childKey]; if (!childNode.HasChildren && childNode.AllDataSame()) { node.SetChild(i, false); node.SetData(i, childNode.GetData(0)); args.Nodes.Remove(childKey); } else { node.SetChild(i, true); node.SetData(i, childNode.ComputeFilteredValue(args.DataFilter)); } } args.Nodes[new MyCellCoord(lodIdx - 1 - LeafLodCount, ref lodCoord).PackId64()] = node; } }