Exemple #1
0
        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;
            }
        }