Ejemplo n.º 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;
            }
        }
Ejemplo n.º 2
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;
            }
        }
Ejemplo n.º 3
0
        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.PackId64();

            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 leafCellCopy = leafCell;
                        leafCellCopy.Lod += LeafLodCount;
                        var leafNew = new MyProviderLeaf(provider, dataType, ref leafCellCopy);
                        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.PackId64();
                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;

                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
                        {
                            var currentCellCopy = currentCell;
                            currentCellCopy.Lod += LeafLodCount;
                            IMyOctreeLeafNode octreeLeaf = new MyProviderLeaf(provider, dataType, ref currentCellCopy);
                            leaves.Add(currentCell.PackId64(), 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 leafCellCopy = leafCell;
                        leafCellCopy.Lod += LeafLodCount;
                        var leafNew = new MyProviderLeaf(provider, dataType, ref leafCellCopy);
                        leaves.Add(leafKey, leafNew);
                }
            }
            }

            return changed;
        }
Ejemplo n.º 4
0
        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.PackId64();

            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 leafCellCopy = leafCell;
                        leafCellCopy.Lod += LeafLodCount;
                        var leafNew = new MyProviderLeaf(provider, dataType, ref leafCellCopy);
                        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.PackId64();
                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;

                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
                        {
                            var currentCellCopy = currentCell;
                            currentCellCopy.Lod += LeafLodCount;
                            IMyOctreeLeafNode octreeLeaf = new MyProviderLeaf(provider, dataType, ref currentCellCopy);
                            leaves.Add(currentCell.PackId64(), 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 leafCellCopy = leafCell;
                        leafCellCopy.Lod += LeafLodCount;
                        var leafNew = new MyProviderLeaf(provider, dataType, ref leafCellCopy);
                        leaves.Add(leafKey, leafNew);
                    }
                }
            }

            return(changed);
        }