Exemple #1
0
 internal static CSGTreeNode Find(CompactNodeID compactNodeID)
 {
     if (compactNodeID == CompactNodeID.Invalid)
     {
         return(CSGTreeNode.Invalid);
     }
     ref var hierarchy = ref CompactHierarchyManager.GetHierarchy(compactNodeID);
        public NodeID GetNodeID(CompactNodeID compactNodeID)
        {
            int nodeIndex;

            Debug.Assert(IsCreated);
            if (compactNodeID == CompactNodeID.Invalid)
            {
                Debug.LogError($"{nameof(compactNodeID)} is an invalid node");
                return(NodeID.Invalid);
            }

            nodeIndex = HierarchyIndexOfInternal(compactNodeID);
            if (nodeIndex == -1)
            {
                return(NodeID.Invalid);
            }

            if (nodeIndex < 0 || nodeIndex >= compactNodes.Length)
            {
                Debug.LogError($"{nameof(compactNodeID)} nodeIndex is out of range");
                return(NodeID.Invalid);
            }

            return(compactNodes[nodeIndex].nodeID);
        }
        public bool DeleteRecursive(CompactNodeID compactNodeID)
        {
            if (compactNodeID == RootID) // Cannot remove root
            {
                return(false);
            }

            var nodeIndex = HierarchyIndexOfInternal(compactNodeID);

            if (nodeIndex == -1)
            {
                throw new ArgumentException(nameof(compactNodeID), $"{nameof(compactNodeID)} is invalid");
            }

            var parentID    = compactNodes[nodeIndex].parentID;
            var parentIndex = HierarchyIndexOfInternal(parentID);

            if (parentIndex == -1)
            {
                // node doesn't have a parent, so it cannot be removed from its parent
                var childCount = ChildCount(compactNodeID);
                if (childCount > 0)
                {
                    DeleteRangeInternal(nodeIndex, 0, childCount, deleteChildren: true);
                }
                FreeIndexRange(nodeIndex, 1);
                return(true);
            }

            var index  = SiblingIndexOfInternal(parentIndex, nodeIndex);
            var result = DeleteRangeInternal(parentIndex, index, range: 1, deleteChildren: true);

            return(result);
        }
        public bool Detach(CompactNodeID compactNodeID)
        {
            Debug.Assert(IsCreated);

            if (compactNodeID == RootID) // Cannot remove root
            {
                return(false);
            }

            var nodeIndex = HierarchyIndexOfInternal(compactNodeID);

            if (nodeIndex == -1)
            {
                throw new ArgumentException(nameof(compactNodeID), $"{nameof(compactNodeID)} is invalid");
            }

            var parentID    = compactNodes[nodeIndex].parentID;
            var parentIndex = HierarchyIndexOfInternal(parentID);

            if (parentIndex == -1)
            {
                return(false); // node doesn't have a parent, so it cannot be removed from its parent
            }
            var index = SiblingIndexOfInternal(parentIndex, nodeIndex);

            return(DetachRangeInternal(parentIndex, index, range: 1));
        }
        public int SiblingIndexOf(CompactNodeID parent, CompactNodeID child)
        {
            Debug.Assert(IsCreated);
            if (parent == CompactNodeID.Invalid)
            {
                return(-1);
            }

            var nodeIndex = HierarchyIndexOfInternal(child);

            if (nodeIndex == -1)
            {
                return(-1);
            }

            var childParent = compactNodes[nodeIndex].parentID;

            if (childParent == CompactNodeID.Invalid ||
                childParent != parent)
            {
                return(-1);
            }

            var parentIndex = HierarchyIndexOfInternal(childParent);

            Debug.Assert(parentIndex != -1);
            return(SiblingIndexOfInternal(parentIndex, nodeIndex));
        }
        public bool DeleteChildFromParentRecursiveAt(CompactNodeID parentID, int index)
        {
            Debug.Assert(IsCreated);

            var parentIndex = HierarchyIndexOfInternal(parentID);

            if (parentIndex < 0)
            {
                throw new ArgumentException(nameof(parentID), $"{nameof(parentID)} is invalid");
            }
            return(DeleteRangeInternal(parentIndex, index, range: 1, deleteChildren: true));
        }
        public int ChildCount(CompactNodeID compactNodeID)
        {
            Debug.Assert(IsCreated);
            var nodeIndex = HierarchyIndexOfInternal(compactNodeID);

            if (nodeIndex == -1)
            {
                throw new ArgumentException(nameof(compactNodeID), $"{nameof(compactNodeID)} is invalid");
            }

            return(compactNodes[nodeIndex].childCount);
        }
        public bool DetachChildrenFromParentAt(CompactNodeID parentID, int index, int range)
        {
            Debug.Assert(IsCreated);

            var parentIndex = HierarchyIndexOfInternal(parentID);

            if (parentIndex < 0)
            {
                throw new ArgumentException(nameof(parentID), $"{nameof(parentID)} is invalid");
            }
            return(DetachRangeInternal(parentIndex, index, range));
        }
        public bool DestroyAllChildrenFromParent(CompactNodeID parentID)
        {
            Debug.Assert(IsCreated);

            var parentIndex = HierarchyIndexOfInternal(parentID);

            if (parentIndex < 0)
            {
                throw new ArgumentException(nameof(parentID), $"{nameof(parentID)} is invalid");
            }
            return(DeleteAllChildrenInternal(parentIndex));
        }
        public bool IsValidCompactNodeID(CompactNodeID compactNodeID)
        {
            Debug.Assert(IsCreated);

            if (!idManager.IsValidID(compactNodeID.value, compactNodeID.generation, out var index))
            {
                return(false);
            }
            if (compactNodes[index].compactNodeID != compactNodeID)
            {
                return(false);
            }
            return(true);
        }
        public CompactNodeID ParentOf(CompactNodeID compactNodeID)
        {
            Debug.Assert(IsCreated);
            if (compactNodeID == CompactNodeID.Invalid)
            {
                throw new ArgumentException(nameof(compactNodeID), $"{nameof(compactNodeID)} is an invalid node");
            }

            var nodeIndex = HierarchyIndexOfInternal(compactNodeID);

            if (nodeIndex == -1)
            {
                return(CompactNodeID.Invalid);
            }

            return(compactNodes[nodeIndex].parentID);
        }
        public int SiblingIndexOf(CompactNodeID compactNodeID)
        {
            Debug.Assert(IsCreated);
            var nodeIndex = HierarchyIndexOfInternal(compactNodeID);

            if (nodeIndex == -1)
            {
                throw new ArgumentException(nameof(compactNodeID), $"{nameof(compactNodeID)} is an invalid node");
            }

            var parentID = compactNodes[nodeIndex].parentID;

            if (parentID == CompactNodeID.Invalid)
            {
                return(-1);
            }

            var parentIndex = HierarchyIndexOfInternal(parentID);

            Debug.Assert(parentIndex != -1);
            return(SiblingIndexOfInternal(parentIndex, nodeIndex));
        }
Exemple #13
0
        public IntersectionType Get(CompactNodeID nodeID)
        {
            var idValue = nodeID.value;

            idValue -= BitOffset;
            if (idValue < 0 || idValue >= BitCount)
            {
                //Debug.Assert(false);
                return(IntersectionType.InvalidValue);
            }

            idValue <<= 1;
            var int32Index = idValue >> 5;      // divide by 32
            var bitIndex   = idValue & 31;      // remainder
            var twoBit     = ((uint)3) << bitIndex;

            var bitShifted = (uint)intersectionBits[int32Index] & (uint)twoBit;
            var value      = (IntersectionType)((uint)bitShifted >> (int)bitIndex);

            Debug.Assert(value != IntersectionType.InvalidValue);
            return(value);
        }
        public NodeID GetNodeIDNoErrors(CompactNodeID compactNodeID)
        {
            int nodeIndex;

            Debug.Assert(IsCreated);
            if (compactNodeID == CompactNodeID.Invalid)
            {
                return(NodeID.Invalid);
            }

            nodeIndex = HierarchyIndexOfInternalNoErrors(compactNodeID);
            if (nodeIndex == -1)
            {
                return(NodeID.Invalid);
            }

            if (nodeIndex < 0 || nodeIndex >= compactNodes.Length)
            {
                return(NodeID.Invalid);
            }

            return(compactNodes[nodeIndex].nodeID);
        }
 public ref CompactNode GetChildRef(CompactNodeID compactNodeID)
 {
     return(ref UnsafeGetChildRefAtInternal(compactNodeID));
 }
 public void AttachToParent(CompactNodeID parentID, CompactNodeID compactNodeID)
 {
     AttachToParent(ref CompactHierarchyManager.HierarchyIDLookup, CompactHierarchyManager.HierarchyList, ref CompactHierarchyManager.NodeIDLookup, CompactHierarchyManager.Nodes, parentID, compactNodeID, ignoreBrushMeshHashes: true);
 }
 internal ref CompactChildNode GetNodeRef(CompactNodeID compactNodeID)
 {
     return(ref UnsafeGetNodeRefAtInternal(compactNodeID));
 }
 public bool AttachToParentAt(CompactNodeID parentID, int index, CompactNodeID compactNodeID)
 {
     return(AttachToParentAt(ref CompactHierarchyManager.HierarchyIDLookup, CompactHierarchyManager.HierarchyList, ref CompactHierarchyManager.NodeIDLookup, CompactHierarchyManager.Nodes, parentID, index, compactNodeID));
 }
        internal void AttachToParent(ref IDManager hierarchyIDLookup, NativeList <CompactHierarchy> hierarchies, ref IDManager nodeIDLookup, NativeList <CompactNodeID> nodes, CompactNodeID parentID, CompactNodeID compactNodeID, bool ignoreBrushMeshHashes = false)
        {
            Debug.Assert(IsCreated);
            var parentIndex = HierarchyIndexOfInternal(parentID);

            if (parentIndex == -1)
            {
                throw new ArgumentException(nameof(parentID), $"{nameof(parentID)} is invalid");
            }

            if (!IsValidCompactNodeID(compactNodeID))
            {
                return;
            }

            var parentHierarchy  = compactNodes[parentIndex];
            var parentChildCount = parentHierarchy.childCount;

            AttachInternal(ref hierarchyIDLookup, hierarchies, ref nodeIDLookup, nodes, parentID, parentIndex, parentChildCount, compactNodeID, ignoreBrushMeshHashes);
        }
 public CompactNode GetChild(CompactNodeID compactNodeID)
 {
     return(UnsafeGetChildRefAtInternal(compactNodeID));
 }
        internal bool AttachToParentAt(ref IDManager hierarchyIDLookup, NativeList <CompactHierarchy> hierarchies, ref IDManager nodeIDLookup, NativeList <CompactNodeID> nodes, CompactNodeID parentID, int index, CompactNodeID compactNodeID)
        {
            Debug.Assert(IsCreated);

            if (index < 0)
            {
                Debug.LogError("The index must be positive");
                return(false);
            }
            var parentIndex = HierarchyIndexOfInternal(parentID);

            if (parentIndex == -1)
            {
                throw new ArgumentException(nameof(parentID), $"{nameof(parentID)} is invalid");
            }

            if (!IsValidCompactNodeID(compactNodeID))
            {
                return(false);
            }

            return(AttachInternal(ref hierarchyIDLookup, hierarchies, ref nodeIDLookup, nodes, parentID, parentIndex, index, compactNodeID));
        }
 public CompactNode GetChildAt(CompactNodeID compactNodeID, int index)
 {
     return(SafeGetChildRefAtInternal(compactNodeID, index));
 }
        public static ChiselBlobAssetReference <CompactTree> Create(ref CompactHierarchy compactHierarchy,
                                                                    NativeArray <CompactNodeID> nodes,
                                                                    NativeArray <CompactNodeID> brushes,
                                                                    CompactNodeID treeCompactNodeID)
        {
            if (brushes.Length == 0)
            {
                return(ChiselBlobAssetReference <CompactTree> .Null);
            }

            var minNodeIDValue = int.MaxValue;
            var maxNodeIDValue = 0;

            for (int b = 0; b < nodes.Length; b++)
            {
                var nodeID = nodes[b];
                if (nodeID == CompactNodeID.Invalid)
                {
                    continue;
                }

                var nodeIDValue = nodeID.value;
                minNodeIDValue = math.min(nodeIDValue, minNodeIDValue);
                maxNodeIDValue = math.max(nodeIDValue, maxNodeIDValue);
            }

            if (minNodeIDValue == int.MaxValue)
            {
                minNodeIDValue = 0;
            }

            var minBrushIDValue = int.MaxValue;
            var maxBrushIDValue = 0;

            for (int b = 0; b < brushes.Length; b++)
            {
                var brushCompactNodeID = brushes[b];
                if (brushCompactNodeID == CompactNodeID.Invalid)
                {
                    continue;
                }

                var brushCompactNodeIDValue = brushCompactNodeID.value;
                minBrushIDValue = math.min(brushCompactNodeIDValue, minBrushIDValue);
                maxBrushIDValue = math.max(brushCompactNodeIDValue, maxBrushIDValue);
            }

            if (minBrushIDValue == int.MaxValue)
            {
                minBrushIDValue = 0;
            }

            var desiredBrushIDValueToBottomUpLength = (maxBrushIDValue + 1) - minBrushIDValue;

            var brushIDValueToAncestorLegend = new NativeArray <int>(desiredBrushIDValueToBottomUpLength, Allocator.Temp);
            var brushIDValueToOrder          = new NativeArray <int>(desiredBrushIDValueToBottomUpLength, Allocator.Temp);

            using (var brushAncestorLegend = new NativeList <BrushAncestorLegend>(brushes.Length, Allocator.Temp))
                using (var brushAncestorsIDValues = new NativeList <int>(brushes.Length, Allocator.Temp))
                {
                    // Bottom-up -> per brush list of all ancestors to root
                    for (int b = 0; b < brushes.Length; b++)
                    {
                        var brushCompactNodeID = brushes[b];
                        if (!compactHierarchy.IsValidCompactNodeID(brushCompactNodeID))
                        {
                            continue;
                        }

                        var parentStart = brushAncestorsIDValues.Length;

                        var parentCompactNodeID = compactHierarchy.ParentOf(brushCompactNodeID);
                        while (compactHierarchy.IsValidCompactNodeID(parentCompactNodeID) && parentCompactNodeID != treeCompactNodeID)
                        {
                            var parentCompactNodeIDValue = parentCompactNodeID.value;
                            brushAncestorsIDValues.Add(parentCompactNodeIDValue);
                            parentCompactNodeID = compactHierarchy.ParentOf(parentCompactNodeID);
                        }

                        var brushCompactNodeIDValue = brushCompactNodeID.value;
                        brushIDValueToAncestorLegend[brushCompactNodeIDValue - minBrushIDValue] = brushAncestorLegend.Length;
                        brushIDValueToOrder[brushCompactNodeIDValue - minBrushIDValue]          = b;
                        brushAncestorLegend.Add(new BrushAncestorLegend()
                        {
                            ancestorEndIDValue   = brushAncestorsIDValues.Length,
                            ancestorStartIDValue = parentStart
                        });
                    }

                    var nodeQueue      = new NativeList <CompactTopDownBuilderNode>(brushes.Length, Allocator.Temp);
                    var hierarchyNodes = new NativeList <CompactHierarchyNode>(brushes.Length, Allocator.Temp);
                    using (brushIDValueToAncestorLegend)
                        using (brushIDValueToOrder)
                        {
                            if (brushAncestorLegend.Length == 0)
                            {
                                return(ChiselBlobAssetReference <CompactTree> .Null);
                            }

                            // Top-down
                            nodeQueue.Add(new CompactTopDownBuilderNode {
                                compactNodeID = treeCompactNodeID, compactHierarchyindex = 0
                            });
                            hierarchyNodes.Add(new CompactHierarchyNode
                            {
                                Type          = CSGNodeType.Tree,
                                Operation     = CSGOperationType.Additive,
                                CompactNodeID = treeCompactNodeID
                            });

                            while (nodeQueue.Length > 0)
                            {
                                var parentItem          = nodeQueue[0];
                                var parentCompactNodeID = parentItem.compactNodeID;
                                nodeQueue.RemoveAt(0);
                                var nodeCount = compactHierarchy.ChildCount(parentCompactNodeID);
                                if (nodeCount == 0)
                                {
                                    var item = hierarchyNodes[parentItem.compactHierarchyindex];
                                    item.childOffset = -1;
                                    item.childCount  = 0;
                                    hierarchyNodes[parentItem.compactHierarchyindex] = item;
                                    continue;
                                }

                                int firstCompactTreeIndex = 0;
                                // Skip all nodes that are not additive at the start of the branch since they will never produce any geometry
                                while (firstCompactTreeIndex < nodeCount)
                                {
                                    var childCompactNodeID = compactHierarchy.GetChildCompactNodeIDAt(parentItem.compactNodeID, firstCompactTreeIndex);
                                    if (!compactHierarchy.IsValidCompactNodeID(childCompactNodeID))
                                    {
                                        break;
                                    }
                                    var operation = compactHierarchy.GetOperation(childCompactNodeID);
                                    if (operation == CSGOperationType.Additive ||
                                        operation == CSGOperationType.Copy)
                                    {
                                        break;
                                    }
                                    firstCompactTreeIndex++;
                                }

                                var firstChildIndex = hierarchyNodes.Length;
                                for (int i = firstCompactTreeIndex; i < nodeCount; i++)
                                {
                                    var childCompactNodeID = compactHierarchy.GetChildCompactNodeIDAt(parentItem.compactNodeID, i);
                                    // skip invalid nodes (they don't contribute to the mesh)
                                    if (!compactHierarchy.IsValidCompactNodeID(childCompactNodeID))
                                    {
                                        continue;
                                    }

                                    var childType = compactHierarchy.GetTypeOfNode(childCompactNodeID);
                                    if (childType != CSGNodeType.Brush)
                                    {
                                        nodeQueue.Add(new CompactTopDownBuilderNode
                                        {
                                            compactNodeID         = childCompactNodeID,
                                            compactHierarchyindex = hierarchyNodes.Length
                                        });
                                    }
                                    hierarchyNodes.Add(new CompactHierarchyNode
                                    {
                                        Type          = childType,
                                        Operation     = compactHierarchy.GetOperation(childCompactNodeID),
                                        CompactNodeID = childCompactNodeID
                                    });
                                }

                                {
                                    var item = hierarchyNodes[parentItem.compactHierarchyindex];
                                    item.childOffset = firstChildIndex;
                                    item.childCount  = hierarchyNodes.Length - firstChildIndex;
                                    hierarchyNodes[parentItem.compactHierarchyindex] = item;
                                }
                            }

                            using (hierarchyNodes)
                                using (nodeQueue)
                                {
                                    var     builder = new ChiselBlobBuilder(Allocator.Temp);
                                    ref var root    = ref builder.ConstructRoot <CompactTree>();
                                    builder.Construct(ref root.compactHierarchy, hierarchyNodes);
                                    builder.Construct(ref root.brushAncestorLegend, brushAncestorLegend);
                                    builder.Construct(ref root.brushAncestors, brushAncestorsIDValues);
                                    root.minBrushIDValue = minBrushIDValue;
                                    root.minNodeIDValue  = minNodeIDValue;
                                    root.maxNodeIDValue  = maxNodeIDValue;
                                    builder.Construct(ref root.brushIDValueToAncestorLegend, brushIDValueToAncestorLegend, desiredBrushIDValueToBottomUpLength);
                                    var compactTree = builder.CreateBlobAssetReference <CompactTree>(Allocator.Persistent);
                                    builder.Dispose();
                                    return(compactTree);
                                }
                        }
                }
 public CompactNodeID GetChildCompactNodeIDAt(CompactNodeID compactNodeID, int index)
 {
     return(GetChildCompactNodeIDAtInternal(compactNodeID, index));
 }