using UnityEngine; using System.Collections.Generic; namespace UnityEngine.ProBuilder.Csg { sealed class Node { public List polygons; public Node front; /// Reference to front node. public Node back; /// Reference to front node. public Plane plane; public Node() { this.front = null; this.back = null; } public Node(List list) { Build(list); // this.front = null; // this.back = null; } public Node(List list, Plane plane, Node front, Node back) { this.polygons = list; this.plane = plane; this.front = front; this.back = back; } public Node Clone() { Node clone = new Node(this.polygons, this.plane, this.front, this.back); return clone; } // Remove all polygons in this BSP tree that are inside the other BSP tree // `bsp`. public void ClipTo(Node other) { this.polygons = other.ClipPolygons(this.polygons); if (this.front != null) { this.front.ClipTo(other); } if (this.back != null) { this.back.ClipTo(other); } } // Convert solid space to empty space and empty space to solid space. public void Invert() { for (int i = 0; i < this.polygons.Count; i++) this.polygons[i].Flip(); this.plane.Flip(); if (this.front != null) { this.front.Invert(); } if (this.back != null) { this.back.Invert(); } Node tmp = this.front; this.front = this.back; this.back = tmp; } // Build a BSP tree out of `polygons`. When called on an existing tree, the // new polygons are filtered down to the bottom of the tree and become new // nodes there. Each set of polygons is partitioned using the first polygon // (no heuristic is used to pick a good split). public void Build(List list) { if (list.Count < 1) return; if (this.plane == null || !this.plane.Valid()) { this.plane = new Plane(); this.plane.normal = list[0].plane.normal; this.plane.w = list[0].plane.w; } if (this.polygons == null) this.polygons = new List(); List list_front = new List(); List list_back = new List(); for (int i = 0; i < list.Count; i++) { this.plane.SplitPolygon(list[i], this.polygons, this.polygons, list_front, list_back); } if (list_front.Count > 0) { if (this.front == null) this.front = new Node(); this.front.Build(list_front); } if (list_back.Count > 0) { if (this.back == null) this.back = new Node(); this.back.Build(list_back); } } // Recursively remove all polygons in `polygons` that are inside this BSP // tree. public List ClipPolygons(List list) { if (!this.plane.Valid()) { return list; } List list_front = new List(); List list_back = new List(); for (int i = 0; i < list.Count; i++) { this.plane.SplitPolygon(list[i], list_front, list_back, list_front, list_back); } if (this.front != null) { list_front = this.front.ClipPolygons(list_front); } if (this.back != null) { list_back = this.back.ClipPolygons(list_back); } else { list_back.Clear(); } // Position [First, Last] // list_front.insert(list_front.end(), list_back.begin(), list_back.end()); list_front.AddRange(list_back); return list_front; } // Return a list of all polygons in this BSP tree. public List AllPolygons() { List list = this.polygons; List list_front = new List(), list_back = new List(); if (this.front != null) { list_front = this.front.AllPolygons(); } if (this.back != null) { list_back = this.back.AllPolygons(); } list.AddRange(list_front); list.AddRange(list_back); return list; } #region STATIC OPERATIONS // Return a new CSG solid representing space in either this solid or in the // solid `csg`. Neither this solid nor the solid `csg` are modified. public static Node Union(Node a1, Node b1) { Node a = a1.Clone(); Node b = b1.Clone(); a.ClipTo(b); b.ClipTo(a); b.Invert(); b.ClipTo(a); b.Invert(); a.Build(b.AllPolygons()); Node ret = new Node(a.AllPolygons()); return ret; } // Return a new CSG solid representing space in this solid but not in the // solid `csg`. Neither this solid nor the solid `csg` are modified. public static Node Subtract(Node a1, Node b1) { Node a = a1.Clone(); Node b = b1.Clone(); a.Invert(); a.ClipTo(b); b.ClipTo(a); b.Invert(); b.ClipTo(a); b.Invert(); a.Build(b.AllPolygons()); a.Invert(); Node ret = new Node(a.AllPolygons()); return ret; } // Return a new CSG solid representing space both this solid and in the // solid `csg`. Neither this solid nor the solid `csg` are modified. public static Node Intersect(Node a1, Node b1) { Node a = a1.Clone(); Node b = b1.Clone(); a.Invert(); b.ClipTo(a); b.Invert(); a.ClipTo(b); b.ClipTo(a); a.Build(b.AllPolygons()); a.Invert(); Node ret = new Node(a.AllPolygons()); return ret; } #endregion } }