public static void DumpTree(BspNode inNode) { Debug.Log("Node..."); Debug.Log("Planar Nodes"); BspNode planar = inNode.planar; while (planar != null) { Debug.Log("Planar Node"); planar = planar.planar; } if (inNode.front != null) { Debug.Log("FrontSide"); DumpTree(inNode.front); } if (inNode.back != null) { Debug.Log("BackSide"); DumpTree(inNode.back); } }
// public static void GetFaces(BspNode inNode, List <Face> outFaces) { while (inNode != null) { // if we are not destroyed if ((inNode.flags & BspNode.BspFlags_IsDestroyed) == 0) { // add to array list outFaces.Add(inNode.face); } if (inNode.front != null) { GetFaces(inNode.front, outFaces); } if (inNode.back != null) { GetFaces(inNode.back, outFaces); } // get to the next planar node inNode = inNode.planar; } }
public override void Initialize(int index, int id, int size, byte[] data, Dictionary <int, WldFragment> fragments, Dictionary <int, string> stringHash, ILogger logger) { base.Initialize(index, id, size, data, fragments, stringHash, logger); var reader = new BinaryReader(new MemoryStream(data)); Name = stringHash[-reader.ReadInt32()]; int nodeCount = reader.ReadInt32(); Nodes = new List <BspNode>(); for (int i = 0; i < nodeCount; ++i) { var node = new BspNode() { NormalX = reader.ReadSingle(), NormalY = reader.ReadSingle(), NormalZ = reader.ReadSingle(), SplitDistance = reader.ReadSingle(), RegionId = reader.ReadInt32(), LeftNode = reader.ReadInt32(), RightNode = reader.ReadInt32() }; Nodes.Add(node); } }
public static BspNode AddNode(BspNode inParent, BspNode.EBspLocation inLocation, Face inFace, int inFlags) { BspNode newNode = new BspNode(); newNode.plane = inFace.GetPlane(); newNode.face = inFace; newNode.front = newNode.back = newNode.planar = null; newNode.flags = inFlags; if (inLocation == BspNode.EBspLocation.BspLocation_Front) { // check that front node is null inParent.front = newNode; } else if (inLocation == BspNode.EBspLocation.BspLocation_Back) { // TODO: check that back node is null inParent.back = newNode; } else if (inLocation == BspNode.EBspLocation.BspLocation_Planar) { // go to the last planar node BspNode lastPlanar = inParent; while (lastPlanar.planar != null) { lastPlanar = lastPlanar.planar; } // add planar node lastPlanar.planar = newNode; } return(newNode); }
private void ExecuteSplitFinalization() { WorkItem currentWorkItem = workItems.Pop(); BspNode parentNode = currentWorkItem.Node; BspNode leftChild = new BspNode(); BspNode rightChild = new BspNode(); parentNode.SetChildren(leftChild, rightChild); parentNode.Splitter = SplitCalculator.States.BestSplitter; List <BspSegment> rightSegs = Partitioner.States.RightSegments; List <BspSegment> leftSegs = Partitioner.States.LeftSegments; rightSegs.AddRange(MinisegCreator.States.Minisegs); leftSegs.AddRange(MinisegCreator.States.Minisegs); string path = currentWorkItem.BranchPath; if (BspConfig.BranchRight) { workItems.Push(new WorkItem(leftChild, leftSegs, path + "L")); workItems.Push(new WorkItem(rightChild, rightSegs, path + "R")); } else { workItems.Push(new WorkItem(rightChild, rightSegs, path + "R")); workItems.Push(new WorkItem(leftChild, leftSegs, path + "L")); } LoadNextWorkItem(); }
public static IEnumerable <int> GetNodeLeafs(ValveBspFile bsp, BspNode node) { if (node.ChildA.IsLeaf) { yield return(node.ChildA.Index); } else { foreach (var leaf in GetNodeLeafs(bsp, bsp.Nodes[node.ChildA.Index])) { yield return(leaf); } } if (node.ChildB.IsLeaf) { yield return(node.ChildB.Index); } else { foreach (var leaf in GetNodeLeafs(bsp, bsp.Nodes[node.ChildB.Index])) { yield return(leaf); } } }
public static void DumpTree( BspNode inNode ) { Debug.Log( "Node..." ); Debug.Log( "Planar Nodes" ); BspNode planar = inNode.planar; while( planar != null ) { Debug.Log( "Planar Node" ); planar = planar.planar; } if( inNode.front != null ) { Debug.Log( "FrontSide" ); DumpTree( inNode.front ); } if( inNode.back != null ) { Debug.Log( "BackSide" ); DumpTree( inNode.back ); } }
/// <summary> /// Combine this mesh with another. /// </summary> /// <param name="anotherMesh">Another mesh.</param> /// <seealso cref="ConstructiveSolidGeometry.Union"/> public virtual void Combine(IMesh anotherMesh) { BspNode <SplittableTriangle> a = this.ToBspTree(); BspNode <SplittableTriangle> b = anotherMesh.ToBspTree(); a.Unite(b); this.SetBsp(a); }
/// <summary> /// Creates a new work item that can be operated on in a BSP pass. /// </summary> /// <param name="node">The node to be operated on.</param> /// <param name="segments">The list of segments for this work item. /// </param> /// <param name="branchPath">The path taken to get here. This should be /// upper case.</param> public WorkItem(BspNode node, List <BspSegment> segments, string branchPath = "") { Debug.Assert(segments.Count > 0, "Should never have zero segments for a work item"); Debug.Assert(branchPath == branchPath.ToUpper(), "Should be using upper case BSP branch paths"); Node = node; Segments = segments; BranchPath = branchPath; }
/// <summary> /// Subtracts another mesh from this one. /// </summary> /// <param name="anotherMesh">Another mesh.</param> /// <seealso cref="ConstructiveSolidGeometry.Subtract"/> public virtual void Subtract(IMesh anotherMesh) { BspNode <SplittableTriangle> a = this.ToBspTree(); BspNode <SplittableTriangle> b = anotherMesh.ToBspTree(); a.Invert(); a.Unite(b); a.Invert(); this.SetBsp(a); }
// private void PerformFaces(BspNode inRoot, List <CSGFace> inFaces) { for (int i = 0; i < inFaces.Count; ++i) { OperationInfo info; InitializeOper(out info); PerformNode(inRoot, inFaces[i] as CSGFace, SIDE_Outside, info); } }
private void PerformTree(BspNode inNode, BspNode inOtherRoot) { while (inNode != null) { // if we are new, stop processing our node... if ((inNode.flags & BspNode.BspFlags_IsNew) != 0) { return; } // if we are not destroyed if ((inNode.flags & BspNode.BspFlags_IsDestroyed) == 0) { OperationInfo info; InitializeOper(out info); // save current node currentNode = inNode; // find last coplanar node BspNode lastPlanar = inNode; while (lastPlanar.planar != null) { lastPlanar = lastPlanar.planar; } // perform nodes face with other tree PerformNode(inOtherRoot, inNode.face, SIDE_Outside, info); // nobody removed us if ((inNode.flags & BspNode.BspFlags_IsDestroyed) == 0) { // remove all planar nodes added (if any) lastPlanar.planar = null; } } // process front node if (inNode.front != null) { PerformTree(inNode.front, inOtherRoot); } // process back node if (inNode.back != null) { PerformTree(inNode.back, inOtherRoot); } // process next planar node inNode = inNode.planar; } }
// void RouteOper(BspNode inNode, CSGFace inFace, EPolySide inSide, OperationInfo info) { if (processState == EProcessState.Process_Master) { csgVisitor.ProcessMaster(this, inFace, inSide, info); } else { csgVisitor.ProcessSlave(this, inFace, inSide, info); } }
public static BspNode ReadBspNode(this BinaryReader br) { var result = new BspNode(); result.plane = br.ReadInt32(); result.frontChild = br.ReadInt16(); result.backChild = br.ReadInt16(); br.BaseStream.Position += 16; return(result); }
private Collision CheckNode(int nodeIdx, Point3D start, Vector movement, float startFraction, float endFraction, float sphere) { // calculate start and end point Point3D s = start + movement * startFraction; Point3D e = start + movement * endFraction; // if this node is a leaf, check for collision within that leaf if (nodeIdx < 0) { return(CheckLeaf(~nodeIdx, start, movement, startFraction, endFraction, sphere)); } // get node BspNode node = Nodes[nodeIdx]; // get splitting plane Plane plane = Planes[node.plane]; // calculate distance of start and end point to plane float ds = plane.Distance(s); float de = plane.Distance(e); if (ds > sphere && de > sphere) { // both points are in front of the plane return(CheckNode(node.frontChild, start, movement, startFraction, endFraction, sphere)); } else if (ds < -sphere && de < -sphere) { // both points are behind the plane return(CheckNode(node.backChild, start, movement, startFraction, endFraction, sphere)); } else { float f1, f2; float ads = System.Math.Abs(ds); float ade = System.Math.Abs(de); float ad = ads + ade; float frac = endFraction - startFraction; f1 = frac * (ads + sphere) / ad + collisionMargin; f2 = frac * (ade + sphere) / ad + collisionMargin; Collision c1 = CheckNode(node.frontChild, start, movement, startFraction, startFraction + f1, sphere); Collision c2 = CheckNode(node.backChild, start, movement, endFraction - f2, endFraction, sphere); return(ClosestCollision(c1, c2)); } }
/// <summary> /// Sets this mesh to value based on given BSP tree. /// </summary> /// <param name="tree">Root node of the BSP tree.</param> public override void SetBsp(BspNode <SplittableTriangle> tree) { // Calculate capacities. // Create vertex pool. List <SplittableTriangle> triangles = tree.AllElements; List <MeshVertex> vertexes = new List <MeshVertex>(triangles.Count * 3); Action <MeshVertex> registerVertex = delegate(MeshVertex vertex) { int index = vertexes.BinarySearch(vertex); if (index < 0) { vertexes.Insert(~index, vertex); } }; for (int i = 0; i < triangles.Count; i++) { registerVertex(triangles[i].First); registerVertex(triangles[i].Second); registerVertex(triangles[i].Third); } // Assign faces. this.faces.Capacity = triangles.Count; for (int i = 0; i < triangles.Count; i++) { this.faces[i] = new IndexedTriangleFace { Indices = new Int32Vector3 ( vertexes.BinarySearch(triangles[i].First), vertexes.BinarySearch(triangles[i].Second), vertexes.BinarySearch(triangles[i].Third) ) }; } // Assign vertex-related data. this.positions.Capacity = vertexes.Count; for (int i = 0; i < vertexes.Count; i++) { MeshVertex vertex = vertexes[i]; this.positions[i] = vertex.Position; this.normals[i] = vertex.Normal; this.texCoords[i] = vertex.UvMapPosition; this.colors0[i] = vertex.PrimaryColor; this.colors1[i] = vertex.SecondaryColor; } }
/// <summary> /// Intersects this mesh with another. /// </summary> /// <param name="anotherMesh">Another mesh.</param> /// <seealso cref="ConstructiveSolidGeometry.Intersection"/> public virtual void Intersect(IMesh anotherMesh) { BspNode <SplittableTriangle> a = this.ToBspTree(); BspNode <SplittableTriangle> b = anotherMesh.ToBspTree(); a.Invert(); // Cut geometry that is not common for the meshes. b.CutTreeOut(a); // b.Invert(); // a.CutTreeOut(b); // // Clean up remains. b.CutTreeOut(a); // Combine geometry. a.AddElements(b.AllElements); // Invert everything. a.Invert(); this.SetBsp(a); }
public void Split(int minimumRoomSize) { int direction = -1; if (Size.Width > Size.Height) { direction = 0; } else if (Size.Height > Size.Width) { direction = 1; } else { direction = Program.Game.Random.Next(2); } if (direction == 0) { var childRoomWidth = (Size.Width / 2) + Program.Game.Random.Next(-3, 4); if (childRoomWidth >= minimumRoomSize && Size.Width - childRoomWidth >= minimumRoomSize) { ChildA = new BspNode(this, new Rectangle(Size.Left, Size.Top, childRoomWidth, Size.Height)); ChildA.Split(minimumRoomSize); ChildB = new BspNode(this, new Rectangle(Size.Left + childRoomWidth, Size.Top, Size.Width - childRoomWidth, Size.Height)); ChildB.Split(minimumRoomSize); } } else { var childRoomHeight = (Size.Height / 2) + Program.Game.Random.Next(-3, 4); if (childRoomHeight >= minimumRoomSize && Size.Height - childRoomHeight >= minimumRoomSize) { ChildA = new BspNode(this, new Rectangle(Size.Left, Size.Top, Size.Width, childRoomHeight)); ChildA.Split(minimumRoomSize); ChildB = new BspNode(this, new Rectangle(Size.Left, Size.Top + childRoomHeight, Size.Width, Size.Height - childRoomHeight)); ChildB.Split(minimumRoomSize); } } }
// public void Perform(ECsgOperation inOper, CSGObject inMaster, CSGObject inSlave) { // we are processing our slave faces processState = EProcessState.Process_Slave; // process faces against master tree PerformFaces(inMaster.rootNode, inSlave.faces); // process face from master tree processState = EProcessState.Process_Master; // perform master faces on slave bsp tree PerformTree(inMaster.rootNode, inSlave.rootNode); // check if how do we need to process generated faces if (inOper == ECsgOperation.CsgOper_Additive || inOper == ECsgOperation.CsgOper_Subtractive) { // add deferred faces to master tree... for (int i = 0; i < deferredFaces.Count; i++) { CSGFace defFace = ((DeferredFace)deferredFaces[i]).face; BspNode startNode = ((DeferredFace)deferredFaces[i]).node; // testing startNode = inMaster.rootNode; // add node to master tree BspGen.AddNodeRecursive(startNode, defFace, BspNode.BspFlags_IsNew); } } else { // clear old faces list inMaster.faces.Clear(); // copy created faces for (int i = 0; i < deferredFaces.Count; i++) { inMaster.faces.Add(deferredFaces[i].face); } } // clear deferred faces deferredFaces.Clear(); }
public static void FacesFromNodes( BspNode inNode, List<Face> outFaces ) { while( inNode != null ) { if( (inNode.flags & BspNode.BspFlags_IsDestroyed) == 0 ) { outFaces.Add( inNode.face ); } if( inNode.front != null ) FacesFromNodes( inNode.front, outFaces ); if( inNode.back != null ) FacesFromNodes( inNode.back, outFaces ); // inNode = inNode.planar; } }
public override Map Generate(int width, int height) { var map = new Map(width, height); rooms = new List <Rectangle>(); var entireMap = new Rectangle(0, 0, map.Width, map.Height); var root = new BspNode(null, entireMap); root.Split(MinimumRoomSize); CreateRooms(root, map); var spawnRoom = root.GetRoom(); Program.Game.Player.X = spawnRoom.Center.X; Program.Game.Player.Y = spawnRoom.Center.Y; var stairsRoom = rooms.Last(); var stairs = ItemFactory.CreateStairs(stairsRoom.Center.X, stairsRoom.Center.Y, Program.Game.DungeonLevel); Program.Game.Entities.Add(stairs); foreach (var room in rooms) { // Don't spawn monsters in the player's room. if (room != spawnRoom) { SpawnMonsters(room); } SpawnItems(map, room); } return(map); }
// public BspNode GenerateBspTree( List<Face> inFaces ) { if( inFaces == null ) { Debug.Log("Not able to create Tree with no Faces"); return null; } Debug.Log( "Building Bsp Tree for " + inFaces.Count + " Faces" ); // create root node BspNode root = new BspNode(); // partition all faces Partition( root, inFaces ); // copy bsp faces back to array list (resulting faces...) GetFaces( root, inFaces ); Debug.Log( "Resulting in " + inFaces.Count + " Faces" ); // result return root; }
public static void FacesFromNodes(BspNode inNode, List <CSGFace> outFaces) { while (inNode != null) { if ((inNode.flags & BspNode.BspFlags_IsDestroyed) == 0) { outFaces.Add(inNode.face); } if (inNode.front != null) { FacesFromNodes(inNode.front, outFaces); } if (inNode.back != null) { FacesFromNodes(inNode.back, outFaces); } // inNode = inNode.planar; } }
// public BspNode GenerateBspTree(List <Face> inFaces) { if (inFaces == null) { Debug.Log("Not able to create Tree with no Faces"); return(null); } Debug.Log("Building Bsp Tree for " + inFaces.Count + " Faces"); // create root node BspNode root = new BspNode(); // partition all faces Partition(root, inFaces); // copy bsp faces back to array list (resulting faces...) GetFaces(root, inFaces); Debug.Log("Resulting in " + inFaces.Count + " Faces"); // result return(root); }
public static void Serialize(SerializingContainer2 sc, ref BspNode node) { if (sc.IsLoading) { node = new BspNode(); } sc.Serialize(ref node.Plane); sc.Serialize(ref node.iVertPool); sc.Serialize(ref node.iSurf); sc.Serialize(ref node.iVertexIndex); sc.Serialize(ref node.ComponentIndex); sc.Serialize(ref node.ComponentNodeIndex); sc.Serialize(ref node.ComponentElementIndex); sc.Serialize(ref node.iBack); sc.Serialize(ref node.iFront); sc.Serialize(ref node.iPlane); sc.Serialize(ref node.iCollisionBound); sc.Serialize(ref node.iZone0); sc.Serialize(ref node.iZone1); sc.Serialize(ref node.NumVertices); sc.Serialize(ref node.NodeFlags); sc.Serialize(ref node.iLeaf0); sc.Serialize(ref node.iLeaf1); }
public static void MergeCoplanars( BspNode inNode ) { // proceed front nodes if( inNode.front != null ) MergeCoplanars( inNode.front ); // proceed back nodes if( inNode.back != null ) MergeCoplanars( inNode.back ); // first try to merge other co planar nodes if( inNode.planar != null ) MergeCoplanars( inNode.planar ); // bool tryToMerge = (inNode.flags & BspNode.BspFlags_IsDestroyed) == 0; while( tryToMerge ) { // get planar node BspNode planarNode = inNode.planar; // assume we are done tryToMerge = false; // get through all planar nodes while( planarNode != null ) { // if we are destroyed, proceed to next if( (planarNode.flags & BspNode.BspFlags_IsDestroyed) != 0 ) { // proceed to next planarNode = planarNode.planar; continue; } Face thisFace = inNode.face; Face otherFace = planarNode.face; // are we facing the same direction if( Vector3.Dot( thisFace.GetPlane().normal, otherFace.GetPlane().normal ) > 0.995f ) { // result Face merged; // if( thisFace.Merge( otherFace, out merged ) ) { // replace this face with merged thisFace = merged; // set other node as destroyed planarNode.flags |= BspNode.BspFlags_IsDestroyed; // retry to merge tryToMerge = true; } } // proceed to next planarNode = planarNode.planar; } } }
public BspNode(BspNode parent, Rectangle size) { Parent = parent; Size = size; }
// public static void GetFaces( BspNode inNode, List<Face> outFaces ) { while( inNode != null ) { // if we are not destroyed if( (inNode.flags & BspNode.BspFlags_IsDestroyed) == 0 ) { // add to array list outFaces.Add( inNode.face ); } if( inNode.front != null ) { GetFaces( inNode.front, outFaces ); } if( inNode.back != null ) { GetFaces( inNode.back, outFaces ); } // get to the next planar node inNode = inNode.planar; } }
/// <summary> /// When implemented, changes this mesh to be perfect representation of the given BSP tree. /// </summary> /// <param name="tree">BSP tree to convert to this mesh.</param> public abstract void SetBsp(BspNode <SplittableTriangle> tree);
private void PerformNode(BspNode inNode, CSGFace inFace, int nodeSide, OperationInfo info) { while (inNode != null) { CSGFace.EPlaneSide side = inFace.Side(inNode.plane); switch (side) { case CSGFace.EPlaneSide.Side_Front: // nodeSide = nodeSide | (inNode.IsCsg() ? 1 : 0); // leaf node if (inNode.front == null) { // set operation infos info.leafNode = inNode; info.leafLocation = BspNode.EBspLocation.BspLocation_Front; // we are done, process face ProcessFace(inFace, SIDE_Outside, info); } // get to next front node (if any) inNode = inNode.front; break; case CSGFace.EPlaneSide.Side_Back: int backSide = inNode.IsCsg() ? 0 : 1; // nodeSide = nodeSide & backSide; // leaf node if (inNode.back == null) { // set leaf infos info.leafNode = inNode; info.leafLocation = BspNode.EBspLocation.BspLocation_Back; // we are done, process face ProcessFace(inFace, SIDE_Inside, info); } // get to next front node (if any) inNode = inNode.back; break; case CSGFace.EPlaneSide.Side_Split: // split face and process front and back CSGFace frontFace, backFace; // inFace.Split(inNode.plane, out frontFace, out backFace); // TODO: set polygon cutted flags frontFace.flags |= CSGFace.FaceFlags_WasCutted; backFace.flags |= CSGFace.FaceFlags_WasCutted; // front node is a leaf node if (inNode.front == null) { // info.leafNode = inNode; info.leafLocation = BspNode.EBspLocation.BspLocation_Front; ProcessFace(frontFace, SIDE_Outside, info); } else { PerformNode(inNode.front, frontFace, nodeSide, info); } // Prcess back node with back face if (inNode.back == null) { // info.leafNode = inNode; info.leafLocation = BspNode.EBspLocation.BspLocation_Back; ProcessFace(backFace, SIDE_Inside, info); } else { // process back node with new face PerformNode(inNode.back, backFace, nodeSide, info); } // stop loop inNode = null; break; case CSGFace.EPlaneSide.Side_Planar: BspNode front, back; if (info.wasPlanar == true) { Debug.Log("Reentering Planar Nodes!"); } // set operation infos info.wasPlanar = true; info.backNode = null; info.processingBack = false; if (Vector3.Dot(inFace.GetPlane().normal, inNode.plane.normal) >= 0.0f) { // same order as we face in the same order front = inNode.front; back = inNode.back; // we are for now outside (as we are looking outside) info.planarSide = SIDE_Outside; } else { // reverse order as we are facing in the opposite direction front = inNode.back; back = inNode.front; // we are now inside as we are looking to the inside info.planarSide = SIDE_Inside; } // we are leaf node (coplanar face) if (front == null && back == null) { // set leaf stuff info.leafNode = inNode; info.leafLocation = BspNode.EBspLocation.BspLocation_Planar; // process node info.processingBack = true; // process face ProcessFace(inFace, InverseSide(info.planarSide), info); // stop loop inNode = null; } else if (front == null && back != null) { // only back nodes info.processingBack = true; // process back inNode = back; } else { // tread like we were on front side (maybe we do have a back node) info.processingBack = false; // remember back node info.backNode = back; // process front inNode = front; } break; } } }
/// <summary> /// Combines two BSP trees using a specified CSG operation /// </summary> private static BspNode Combine( Operation op, BspNode set0, BspNode set1 ) { IList< Edge > set0Edges = Flatten( set0 ); IList< Edge > set1Edges = Flatten( set1 ); List< Edge > sourceEdges = new List<Edge>( ); switch ( op ) { case Operation.Union : Clip( true, false, set0, set1Edges, sourceEdges ); Clip( true, false, set1, set0Edges, sourceEdges ); break; case Operation.EdgeUnion : Clip( false, true, set0, set1Edges, sourceEdges ); foreach ( Edge edge in sourceEdges ) { edge.DoubleSided = true; } sourceEdges.AddRange( set0Edges ); break; case Operation.Intersection : Clip( false, true, set0, set1Edges, sourceEdges ); Clip( false, true, set1, set0Edges, sourceEdges ); break; case Operation.Complement : Clip( false, true, set0, set1Edges, sourceEdges ); Clip( false, true, set1, set0Edges, sourceEdges ); break; } sourceEdges = MergeEdges( sourceEdges ); BspNode rootNode = BuildNode( null, sourceEdges ); return rootNode; }
/// <summary> /// Builds a BSP node from a list of edges /// </summary> private static BspNode BuildNode( BspNode parentNode, IList< Edge > edges ) { if ( edges.Count == 0 ) { return null; } Edge splitter = edges[ 0 ]; // TODO: AP: Choose better splitter BspNode splitNode = new BspNode( parentNode, splitter ); if ( edges.Count == 1 ) { return splitNode; } // Classify edges as left or right edges List< Edge > outsideEdges = new List< Edge >( ); List< Edge > insideEdges = new List< Edge >( ); for ( int edgeIndex = 1; edgeIndex < edges.Count; ++edgeIndex ) { ClassifyEdge( splitter, edges[ edgeIndex ], outsideEdges, insideEdges ); } // Build BSP subtrees from left and right edges if ( outsideEdges.Count > 0 ) { splitNode.Behind = BuildNode( splitNode, outsideEdges ); } if ( insideEdges.Count > 0 ) { splitNode.InFront = BuildNode( splitNode, insideEdges ); } return splitNode; }
/// <summary> /// Flattens a BSP tree into a list of edges /// </summary> private static void Flatten( BspNode root, IList< Edge > edges ) { if ( !root.Edge.Temporary ) { edges.Add( root.Edge ); } if ( root.Behind != null ) { Flatten( root.Behind, edges ); } if ( root.InFront != null ) { Flatten( root.InFront, edges ); } }
/// <summary> /// Sets this mesh to value based on given BSP tree. /// </summary> /// <param name="tree">Root node of the BSP tree.</param> public override void SetBsp(BspNode<SplittableTriangle> tree) { // Calculate capacities. // Create vertex pool. List<SplittableTriangle> triangles = tree.AllElements; List<MeshVertex> vertexes = new List<MeshVertex>(triangles.Count * 3); Action<MeshVertex> registerVertex = delegate(MeshVertex vertex) { int index = vertexes.BinarySearch(vertex); if (index < 0) { vertexes.Insert(~index, vertex); } }; for (int i = 0; i < triangles.Count; i++) { registerVertex(triangles[i].First); registerVertex(triangles[i].Second); registerVertex(triangles[i].Third); } // Assign faces. this.faces.Capacity = triangles.Count; for (int i = 0; i < triangles.Count; i++) { this.faces[i] = new IndexedTriangleFace { Indices = new Int32Vector3 ( vertexes.BinarySearch(triangles[i].First), vertexes.BinarySearch(triangles[i].Second), vertexes.BinarySearch(triangles[i].Third) ) }; } // Assign vertex-related data. this.positions.Capacity = vertexes.Count; for (int i = 0; i < vertexes.Count; i++) { MeshVertex vertex = vertexes[i]; this.positions[i] = vertex.Position; this.normals[i] = vertex.Normal; this.texCoords[i] = vertex.UvMapPosition; this.colors0[i] = vertex.PrimaryColor; this.colors1[i] = vertex.SecondaryColor; } }
// void Partition( BspNode inNode, List<Face> inFaces ) { List<Face> frontFaces = new List<Face>(); List<Face> backFaces = new List<Face>(); Face nodeFace; // find best splitter plane for this bool ret = FindSplitter( inFaces, out nodeFace ); // return has to be true!!! if( ret == false ) { Debug.DebugBreak(); Debug.Log("Error processing Mesh!"); return; } // setup node inNode.front = null; inNode.back = null; inNode.planar = null; inNode.face = nodeFace; inNode.plane = nodeFace.GetPlane(); // split remaining faces into lists for( int i = 0; i < inFaces.Count; ++i ) { // get face Face face = inFaces[i] as Face; // do not process our self if( face == nodeFace ) continue; Face.EPlaneSide side = face.Side( inNode.plane ); switch( side ) { case Face.EPlaneSide.Side_Front: frontFaces.Add( face ); break; case Face.EPlaneSide.Side_Back: backFaces.Add( face ); break; case Face.EPlaneSide.Side_Planar: // get last planar node BspNode lastPlanar = inNode; while( lastPlanar.planar != null ) lastPlanar = lastPlanar.planar; // create new planar node BspNode planar = lastPlanar.planar = new BspNode(); // setup planar node planar.front = null; planar.back = null; planar.planar = null; planar.face = face; planar.plane = face.GetPlane(); break; case Face.EPlaneSide.Side_Split: // TODO... Face front, back; // split face into two parts... ret = face.Split( inNode.plane, out front, out back ); if( ret == false ) Debug.DebugBreak(); // add to front and back frontFaces.Add( front ); backFaces.Add( back ); break; } } // optimizing a bit, clear in array list as we do not need it any more inFaces.Clear(); // process front faces if( frontFaces.Count > 0 ) { inNode.front = new BspNode(); // partition front faces Partition( inNode.front, frontFaces ); } // process back faces if( backFaces.Count > 0 ) { inNode.back = new BspNode(); // partition back faces Partition( inNode.back, backFaces ); } }
/// <summary> /// Performs CSG Operation on this Object (Master) with given Slaves. /// </summary> /// <param name='inOper'> /// In oper. /// </param> /// <param name='inSlaves'> /// In slaves. /// </param> public void PerformCSG( CsgOperation.ECsgOperation inOper, GameObject[] inSlaves ) { // CreateFromMesh(); // create bsp generator BspGen gen = new BspGen( GlobalSettings.BspOptimization ); rootNode = gen.GenerateBspTree( faces ); List<Face> savedFaces = new List<Face>(); // foreach ( GameObject g in inSlaves ) { CSGObject slave = g.GetComponent<CSGObject>(); // if we have a csg object and we are not our self // and intersecting if( slave && g != gameObject && intersect(slave) ) { Debug.Log(g.name); // slave.CreateFromMesh(); // .... BspGen genSlave = new BspGen( GlobalSettings.BspOptimization ); slave.rootNode = genSlave.GenerateBspTree( slave.faces ); CsgVisitor visitor = null; switch( inOper ) { case CsgOperation.ECsgOperation.CsgOper_Additive: visitor = new UnionVisitor(); break; case CsgOperation.ECsgOperation.CsgOper_Subtractive: visitor = new SubtractiveVisitor(); break; case CsgOperation.ECsgOperation.CsgOper_Intersect: visitor = new IntersectVisitor(); break; case CsgOperation.ECsgOperation.CsgOper_DeIntersect: visitor = new DeIntersectVisitor(); break; default: visitor = null; break; } CsgOperation oper = new CsgOperation( visitor ); oper.Perform( inOper, this, slave ); // save faces savedFaces.AddRange( faces ); } } // If we want to merge Coplanars after every Operation if( GlobalSettings.MergeCoplanars ) { MergeFaces(); } // for additive or subtracte operation, built faces list from bsp tree // for others, use faces directly if( inOper == CsgOperation.ECsgOperation.CsgOper_Additive || inOper == CsgOperation.ECsgOperation.CsgOper_Subtractive ) { // create new face list List<Face> newFaces = new List<Face>(); // create faces from bsp nodes BspHelper.FacesFromNodes( rootNode, newFaces ); // copy to face list faces = newFaces; } else { // copy saved faces faces = savedFaces; } // Face.MergeCoplanars( faces ); // copy to unity structure TransferFacesToMesh(); // dumb tree // BspHelper.DumpTree( rootNode ); }
// private void PerformFaces( BspNode inRoot, List<Face> inFaces ) { for( int i = 0; i < inFaces.Count; ++i ) { OperationInfo info; InitializeOper( out info ); PerformNode( inRoot, inFaces[i] as Face, SIDE_Outside, info ); } }
private void PerformTree( BspNode inNode, BspNode inOtherRoot ) { while( inNode != null ) { // if we are new, stop processing our node... if( (inNode.flags & BspNode.BspFlags_IsNew) != 0 ) return; // if we are not destroyed if( (inNode.flags & BspNode.BspFlags_IsDestroyed) == 0 ) { OperationInfo info; InitializeOper( out info ); // save current node currentNode = inNode; // find last coplanar node BspNode lastPlanar = inNode; while( lastPlanar.planar != null ) lastPlanar = lastPlanar.planar; // perform nodes face with other tree PerformNode( inOtherRoot, inNode.face, SIDE_Outside, info ); // nobody removed us if( (inNode.flags & BspNode.BspFlags_IsDestroyed) == 0 ) { // remove all planar nodes added (if any) lastPlanar.planar = null; } } // process front node if( inNode.front != null ) { PerformTree( inNode.front, inOtherRoot ); } // process back node if( inNode.back != null ) { PerformTree( inNode.back, inOtherRoot ); } // process next planar node inNode = inNode.planar; } }
/// <summary> /// Combines a brush with the current geometry set /// </summary> /// <param name="op">CSG operation</param> /// <param name="brush">Brush to add to the level geometry</param> /// <exception cref="InvalidOperationException">Thrown by convex region builder if BSP tree is internally invalid</exception> public void Combine( Operation op, UiPolygon brush ) { BspNode brushBsp = Build( brush, op == Operation.Complement ); BspNode newRoot = null; if ( m_Root == null ) { if ( op == Operation.Union || op == Operation.EdgeUnion ) { newRoot = brushBsp; } } else { newRoot = Combine( op, m_Root, brushBsp ); } if ( newRoot != null ) { FixUpDoubleSidedNodes( newRoot ); BuildConvexRegions( newRoot ); m_Root = newRoot; } if ( GeometryChanged != null ) { GeometryChanged( this, null ); } }
/// <summary> /// Builds the convex regions for a root node and all its children /// </summary> private void BuildConvexRegions( BspNode node ) { // Find the bounding box for the tree float[] bounds = new float[ 4 ] { float.MaxValue, float.MaxValue, float.MinValue, float.MinValue }; GetNodeBoundingRectangle( node, bounds ); // Expand bounds a bit float boundary = 1.0f; bounds[ 0 ] -= boundary; bounds[ 1 ] -= boundary; bounds[ 2 ] += boundary; bounds[ 3 ] += boundary; float width = bounds[ 2 ] - bounds[ 0 ]; float height = bounds[ 3 ] - bounds[ 1 ]; Tesselator tess = new Tesselator( ); Tesselator.Polygon boundingPoly = tess.CreateBoundingPolygon( bounds[ 0 ], bounds[ 1 ], width, height ); BuildConvexRegions( node, tess, boundingPoly ); m_Points = tess.Points.ToArray( ); }
/// <summary> /// Builds the convex region for a node and its children /// </summary> private static void BuildConvexRegions( BspNode node, Tesselator tess, Tesselator.Polygon poly ) { Tesselator.Polygon behindPoly; Tesselator.Polygon inFrontPoly; tess.Split( node.Plane, poly, out behindPoly, out inFrontPoly ); if ( node.Behind != null ) { BuildConvexRegions( node.Behind, tess, behindPoly ); } if ( node.InFront != null ) { BuildConvexRegions( node.InFront, tess, inFrontPoly ); } else { node.ConvexRegion = inFrontPoly.Indices; } }
/// <summary> /// Sets up the node /// </summary> /// <param name="parent">Node parent</param> /// <param name="edge">Node edge</param> public BspNode( BspNode parent, Edge edge ) { m_Parent = parent; m_Edge = edge; m_Quad[ 0 ] = new Point3( edge.P0.X, 0, edge.P0.Y ); m_Quad[ 1 ] = new Point3( edge.P1.X, 0, edge.P1.Y ); m_Quad[ 2 ] = new Point3( edge.P1.X, 5, edge.P1.Y ); m_Quad[ 3 ] = new Point3( edge.P0.X, 5, edge.P0.Y ); }
/// <summary> /// Clips a set of edges against a BSP tree /// </summary> private static void Clip( bool keepOutsideEdges, bool keepInsideEdges, BspNode node, IEnumerable< Edge > edges, IList< Edge > outputEdges ) { IList< Edge > outsideEdges = ( node.Behind != null ) ? new List< Edge >( ) : ( keepOutsideEdges ? outputEdges : null ); IList< Edge > insideEdges = ( node.InFront != null ) ? new List< Edge >( ) : ( keepInsideEdges ? outputEdges : null ); foreach ( Edge edge in edges ) { ClassifyEdge( node.Edge, edge, outsideEdges, insideEdges ); } if ( node.Behind != null ) { Clip( keepOutsideEdges, keepInsideEdges, node.Behind, outsideEdges, outputEdges ); } if ( node.InFront != null ) { Clip( keepOutsideEdges, keepInsideEdges, node.InFront, insideEdges, outputEdges ); } }
// void RouteOper( BspNode inNode, Face inFace, EPolySide inSide, OperationInfo info ) { if( processState == EProcessState.Process_Master ) { csgVisitor.ProcessMaster( this, inFace, inSide, info ); } else { csgVisitor.ProcessSlave( this, inFace, inSide, info ); } }
/// <summary> /// Flattens a BSP tree into a list of edges /// </summary> private static IList<Edge> Flatten( BspNode root ) { List< Edge > edges = new List< Edge >( ); Flatten( root, edges ); return edges; }
private void PerformNode( BspNode inNode, Face inFace, int nodeSide, OperationInfo info ) { while( inNode != null ) { Face.EPlaneSide side = inFace.Side( inNode.plane ); switch( side ) { case Face.EPlaneSide.Side_Front: // nodeSide = nodeSide | (inNode.IsCsg() ? 1 : 0); // leaf node if( inNode.front == null ) { // set operation infos info.leafNode = inNode; info.leafLocation = BspNode.EBspLocation.BspLocation_Front; // we are done, process face ProcessFace( inFace, SIDE_Outside, info ); } // get to next front node (if any) inNode = inNode.front; break; case Face.EPlaneSide.Side_Back: int backSide = inNode.IsCsg() ? 0 : 1; // nodeSide = nodeSide & backSide; // leaf node if( inNode.back == null ) { // set leaf infos info.leafNode = inNode; info.leafLocation = BspNode.EBspLocation.BspLocation_Back; // we are done, process face ProcessFace( inFace, SIDE_Inside, info ); } // get to next front node (if any) inNode = inNode.back; break; case Face.EPlaneSide.Side_Split: // split face and process front and back Face frontFace, backFace; // inFace.Split( inNode.plane, out frontFace, out backFace ); // TODO: set polygon cutted flags frontFace.flags |= Face.FaceFlags_WasCutted; backFace.flags |= Face.FaceFlags_WasCutted; // front node is a leaf node if( inNode.front == null ) { // info.leafNode = inNode; info.leafLocation = BspNode.EBspLocation.BspLocation_Front; ProcessFace( frontFace, SIDE_Outside, info ); } else { PerformNode( inNode.front, frontFace, nodeSide, info ); } // Prcess back node with back face if( inNode.back == null ) { // info.leafNode = inNode; info.leafLocation = BspNode.EBspLocation.BspLocation_Back; ProcessFace( backFace, SIDE_Inside, info ); } else { // process back node with new face PerformNode( inNode.back, backFace, nodeSide, info ); } // stop loop inNode = null; break; case Face.EPlaneSide.Side_Planar: BspNode front, back; if( info.wasPlanar == true ) { Debug.Log( "Reentering Planar Nodes!" ); } // set operation infos info.wasPlanar = true; info.backNode = null; info.processingBack = false; if( Vector3.Dot( inFace.GetPlane().normal, inNode.plane.normal ) >= 0.0f ) { // same order as we face in the same order front = inNode.front; back = inNode.back; // we are for now outside (as we are looking outside) info.planarSide = SIDE_Outside; } else { // reverse order as we are facing in the opposite direction front = inNode.back; back = inNode.front; // we are now inside as we are looking to the inside info.planarSide = SIDE_Inside; } // we are leaf node (coplanar face) if( front == null && back == null ) { // set leaf stuff info.leafNode = inNode; info.leafLocation = BspNode.EBspLocation.BspLocation_Planar; // process node info.processingBack = true; // process face ProcessFace( inFace, InverseSide(info.planarSide), info ); // stop loop inNode = null; } else if( front == null && back != null ) { // only back nodes info.processingBack = true; // process back inNode = back; } else { // tread like we were on front side (maybe we do have a back node) info.processingBack = false; // remember back node info.backNode = back; // process front inNode = front; } break; } } }
/// <summary> /// Gets a bounding rectangle that encompasses a BSP node and its children /// </summary> private static void GetNodeBoundingRectangle( BspNode node, float[] rect ) { if ( node == null ) { return; } rect[ 0 ] = Utils.Min( rect[ 0 ], node.Edge.P0.X, node.Edge.P1.X ); rect[ 1 ] = Utils.Min( rect[ 1 ], node.Edge.P0.Y, node.Edge.P1.Y ); rect[ 2 ] = Utils.Max( rect[ 2 ], node.Edge.P0.X, node.Edge.P1.X ); rect[ 3 ] = Utils.Max( rect[ 3 ], node.Edge.P0.Y, node.Edge.P1.Y ); GetNodeBoundingRectangle( node.Behind, rect ); GetNodeBoundingRectangle( node.InFront, rect ); }
public static BspNode AddNode( BspNode inParent, BspNode.EBspLocation inLocation, Face inFace, int inFlags ) { BspNode newNode = new BspNode(); newNode.plane = inFace.GetPlane(); newNode.face = inFace; newNode.front = newNode.back = newNode.planar = null; newNode.flags = inFlags; if( inLocation == BspNode.EBspLocation.BspLocation_Front ) { // check that front node is null inParent.front = newNode; } else if( inLocation == BspNode.EBspLocation.BspLocation_Back ) { // TODO: check that back node is null inParent.back = newNode; } else if( inLocation == BspNode.EBspLocation.BspLocation_Planar ) { // go to the last planar node BspNode lastPlanar = inParent; while( lastPlanar.planar != null ) lastPlanar = lastPlanar.planar; // add planar node lastPlanar.planar = newNode; } return newNode; }
private void FixUpDoubleSidedNodes( BspNode node ) { if ( node == null ) { return; } FixUpDoubleSidedNodes( node.Behind ); FixUpDoubleSidedNodes( node.InFront ); if ( ( node.Edge.DoubleSided ) && ( node.Behind == null ) ) { node.Behind = new BspNode( node, node.Edge.MakeTemporaryFlippedEdge( ) ); } }
public static BspNode AddNodeRecursive(BspNode inNode, Face inFace, int inFlags) { while (inNode != null) { Face.EPlaneSide planeSide = inFace.Side(inNode.plane); switch (planeSide) { case Face.EPlaneSide.Side_Front: if (inNode.front == null) { return(AddNode(inNode, BspNode.EBspLocation.BspLocation_Front, inFace, inFlags)); } inNode = inNode.front; break; case Face.EPlaneSide.Side_Back: if (inNode.back == null) { return(AddNode(inNode, BspNode.EBspLocation.BspLocation_Back, inFace, inFlags)); } inNode = inNode.back; break; case Face.EPlaneSide.Side_Planar: return(AddNode(inNode, BspNode.EBspLocation.BspLocation_Planar, inFace, inFlags)); case Face.EPlaneSide.Side_Split: Face frontFace, backFace; inFace.Split(inNode.plane, out frontFace, out backFace); if (inNode.front == null) { AddNode(inNode, BspNode.EBspLocation.BspLocation_Front, frontFace, inFlags); } else { AddNodeRecursive(inNode.front, frontFace, inFlags); } if (inNode.back == null) { AddNode(inNode, BspNode.EBspLocation.BspLocation_Back, inFace, inFlags); } else { AddNodeRecursive(inNode.back, backFace, inFlags); } inNode = null; break; } } // happens when face get splitted... return(null); }
public static BspNode AddNodeRecursive( BspNode inNode, Face inFace, int inFlags ) { while( inNode != null ) { Face.EPlaneSide planeSide = inFace.Side( inNode.plane ); switch( planeSide ) { case Face.EPlaneSide.Side_Front: if( inNode.front == null ) return AddNode( inNode, BspNode.EBspLocation.BspLocation_Front, inFace, inFlags ); inNode = inNode.front; break; case Face.EPlaneSide.Side_Back: if( inNode.back == null ) return AddNode( inNode, BspNode.EBspLocation.BspLocation_Back, inFace, inFlags ); inNode = inNode.back; break; case Face.EPlaneSide.Side_Planar: return AddNode( inNode, BspNode.EBspLocation.BspLocation_Planar, inFace, inFlags ); case Face.EPlaneSide.Side_Split: Face frontFace, backFace; inFace.Split( inNode.plane, out frontFace, out backFace ); if( inNode.front == null ) { AddNode( inNode, BspNode.EBspLocation.BspLocation_Front, frontFace, inFlags ); } else { AddNodeRecursive( inNode.front, frontFace, inFlags ); } if( inNode.back == null ) { AddNode( inNode, BspNode.EBspLocation.BspLocation_Back, inFace, inFlags ); } else { AddNodeRecursive( inNode.back, backFace, inFlags ); } inNode = null; break; } } // happens when face get splitted... return null; }
// void Partition(BspNode inNode, List <Face> inFaces) { List <Face> frontFaces = new List <Face>(); List <Face> backFaces = new List <Face>(); Face nodeFace; // find best splitter plane for this bool ret = FindSplitter(inFaces, out nodeFace); // return has to be true!!! if (ret == false) { Debug.DebugBreak(); Debug.Log("Error processing Mesh!"); return; } // setup node inNode.front = null; inNode.back = null; inNode.planar = null; inNode.face = nodeFace; inNode.plane = nodeFace.GetPlane(); // split remaining faces into lists for (int i = 0; i < inFaces.Count; ++i) { // get face Face face = inFaces[i] as Face; // do not process our self if (face == nodeFace) { continue; } Face.EPlaneSide side = face.Side(inNode.plane); switch (side) { case Face.EPlaneSide.Side_Front: frontFaces.Add(face); break; case Face.EPlaneSide.Side_Back: backFaces.Add(face); break; case Face.EPlaneSide.Side_Planar: // get last planar node BspNode lastPlanar = inNode; while (lastPlanar.planar != null) { lastPlanar = lastPlanar.planar; } // create new planar node BspNode planar = lastPlanar.planar = new BspNode(); // setup planar node planar.front = null; planar.back = null; planar.planar = null; planar.face = face; planar.plane = face.GetPlane(); break; case Face.EPlaneSide.Side_Split: // TODO... Face front, back; // split face into two parts... ret = face.Split(inNode.plane, out front, out back); if (ret == false) { Debug.DebugBreak(); } // add to front and back frontFaces.Add(front); backFaces.Add(back); break; } } // optimizing a bit, clear in array list as we do not need it any more inFaces.Clear(); // process front faces if (frontFaces.Count > 0) { inNode.front = new BspNode(); // partition front faces Partition(inNode.front, frontFaces); } // process back faces if (backFaces.Count > 0) { inNode.back = new BspNode(); // partition back faces Partition(inNode.back, backFaces); } }
public static void MergeCoplanars(BspNode inNode) { // proceed front nodes if (inNode.front != null) { MergeCoplanars(inNode.front); } // proceed back nodes if (inNode.back != null) { MergeCoplanars(inNode.back); } // first try to merge other co planar nodes if (inNode.planar != null) { MergeCoplanars(inNode.planar); } // bool tryToMerge = (inNode.flags & BspNode.BspFlags_IsDestroyed) == 0; while (tryToMerge) { // get planar node BspNode planarNode = inNode.planar; // assume we are done tryToMerge = false; // get through all planar nodes while (planarNode != null) { // if we are destroyed, proceed to next if ((planarNode.flags & BspNode.BspFlags_IsDestroyed) != 0) { // proceed to next planarNode = planarNode.planar; continue; } CSGFace thisFace = inNode.face; CSGFace otherFace = planarNode.face; // are we facing the same direction if (Vector3.Dot(thisFace.GetPlane().normal, otherFace.GetPlane().normal) > 0.995f) { // result CSGFace merged; // if (thisFace.Merge(otherFace, out merged)) { // replace this face with merged thisFace = merged; // set other node as destroyed planarNode.flags |= BspNode.BspFlags_IsDestroyed; // retry to merge tryToMerge = true; } } // proceed to next planarNode = planarNode.planar; } } }
private void CreateRooms(BspNode node, Map map) { if (node.ChildA != null || node.ChildB != null) { CreateRooms(node.ChildA, map); CreateRooms(node.ChildB, map); if (node.ChildA != null && node.ChildB != null) { var roomA = node.ChildA.GetRoom(); var roomB = node.ChildB.GetRoom(); if (roomA.Left == roomB.Left || roomA.Right == roomB.Right) { if (roomA.Width >= roomB.Width) { map.CreateVerticalTunnel(roomA.Center.Y, roomB.Center.Y, roomB.Center.X, Tile.Floor); } else { map.CreateVerticalTunnel(roomA.Center.Y, roomB.Center.Y, roomA.Center.X, Tile.Floor); } } else if (roomA.Top == roomB.Top || roomA.Bottom == roomB.Bottom) { if (roomA.Height >= roomB.Height) { map.CreateHorizontalTunnel(roomA.Center.X, roomB.Center.X, roomB.Center.Y, Tile.Floor); } else { map.CreateHorizontalTunnel(roomA.Center.X, roomB.Center.X, roomA.Center.Y, Tile.Floor); } } else { if (roomA.Width >= roomB.Width) { map.CreateVerticalTunnel(roomA.Center.Y, roomB.Center.Y, roomB.Center.X, Tile.Floor); } else { map.CreateVerticalTunnel(roomA.Center.Y, roomB.Center.Y, roomA.Center.X, Tile.Floor); } if (roomA.Height >= roomB.Height) { map.CreateHorizontalTunnel(roomA.Center.X, roomB.Center.X, roomB.Center.Y, Tile.Floor); } else { map.CreateHorizontalTunnel(roomA.Center.X, roomB.Center.X, roomA.Center.Y, Tile.Floor); } } } } else { var room = new Rectangle(); int maxShrinkX = node.Size.Width - MinimumRoomSize; int maxShrinkY = node.Size.Height - MinimumRoomSize; room.Width = node.Size.Width - Program.Game.Random.Next(maxShrinkX); room.Height = node.Size.Height - Program.Game.Random.Next(maxShrinkY); room.X = Program.Game.Random.Next(node.Size.Left, node.Size.Right - room.Width); room.Y = Program.Game.Random.Next(node.Size.Top, node.Size.Bottom - room.Height); node.Room = room; rooms.Add(room); map.CreateRoom(room, Tile.Floor); } }
/// <summary> /// Performs CSG Operation on this Object (Master) with given Slaves. /// </summary> /// <param name='inOper'> /// In oper. /// </param> /// <param name='inSlaves'> /// In slaves. /// </param> public void PerformCSG(CsgOperation.ECsgOperation inOper, GameObject[] inSlaves) { // CreateFromMesh(); // create bsp generator BspGen gen = new BspGen(GlobalSettings.BspOptimization); rootNode = gen.GenerateBspTree(faces); List <CSGFace> savedFaces = new List <CSGFace>(); // foreach (GameObject g in inSlaves) { CSGObject slave = g.GetComponent <CSGObject>(); // if we have a csg object and we are not our self // and intersecting if (slave && g != gameObject && intersect(slave)) { Debug.Log(g.name); // slave.CreateFromMesh(); // .... BspGen genSlave = new BspGen(GlobalSettings.BspOptimization); slave.rootNode = genSlave.GenerateBspTree(slave.faces); CsgVisitor visitor = null; switch (inOper) { case CsgOperation.ECsgOperation.CsgOper_Additive: visitor = new UnionVisitor(); break; case CsgOperation.ECsgOperation.CsgOper_Subtractive: visitor = new SubtractiveVisitor(); break; case CsgOperation.ECsgOperation.CsgOper_Intersect: visitor = new IntersectVisitor(); break; case CsgOperation.ECsgOperation.CsgOper_DeIntersect: visitor = new DeIntersectVisitor(); break; default: visitor = null; break; } CsgOperation oper = new CsgOperation(visitor); oper.Perform(inOper, this, slave); // save faces savedFaces.AddRange(faces); } } // If we want to merge Coplanars after every Operation if (GlobalSettings.MergeCoplanars) { MergeFaces(); } // for additive or subtracte operation, built faces list from bsp tree // for others, use faces directly if (inOper == CsgOperation.ECsgOperation.CsgOper_Additive || inOper == CsgOperation.ECsgOperation.CsgOper_Subtractive) { // create new face list List <CSGFace> newFaces = new List <CSGFace>(); // create faces from bsp nodes BspHelper.FacesFromNodes(rootNode, newFaces); // copy to face list faces = newFaces; } else { // copy saved faces faces = savedFaces; } // Face.MergeCoplanars( faces ); // copy to unity structure TransferFacesToMesh(); // dumb tree // BspHelper.DumpTree( rootNode ); }
/// <summary> /// When implemented, changes this mesh to be perfect representation of the given BSP tree. /// </summary> /// <param name="tree">BSP tree to convert to this mesh.</param> public abstract void SetBsp(BspNode<SplittableTriangle> tree);