// // Pick a splitter poly then split a pool of polygons into front and back polygons and // recurse. // // iParent = Parent Bsp node, or INDEX_NONE if this is the root node. // IsFront = 1 if this is the front node of iParent, 0 of back (undefined if iParent==INDEX_NONE) // void FBSPOps::SplitPolyList ( UModel *Model, int32 iParent, ENodePlace NodePlace, int32 NumPolys, FPoly **PolyList, EBspOptimization Opt, int32 Balance, int32 PortalBias, int32 RebuildSimplePolys ) { FMemMark Mark(FMemStack::Get()); // Keeping track of allocated FPoly structures to delete later on. TArray<FPoly*> AllocatedFPolys; // To account for big EdPolys split up. int32 NumPolysToAlloc = NumPolys + 8 + NumPolys/4; int32 NumFront=0; FPoly **FrontList = new(FMemStack::Get(),NumPolysToAlloc)FPoly*; int32 NumBack =0; FPoly **BackList = new(FMemStack::Get(),NumPolysToAlloc)FPoly*; FPoly *SplitPoly = FindBestSplit( NumPolys, PolyList, Opt, Balance, PortalBias ); // Add the splitter poly to the Bsp with either a new BspSurf or an existing one. if( RebuildSimplePolys ) { SplitPoly->iLink = Model->Surfs.Num(); } int32 iOurNode = bspAddNode(Model,iParent,NodePlace,0,SplitPoly); int32 iPlaneNode = iOurNode; // Now divide all polygons in the pool into (A) polygons that are // in front of Poly, and (B) polygons that are in back of Poly. // Coplanar polys are inserted immediately, before recursing. // If any polygons are split by Poly, we ignrore the original poly, // split it into two polys, and add two new polys to the pool. FPoly *FrontEdPoly = new FPoly; FPoly *BackEdPoly = new FPoly; // Keep track of allocations. AllocatedFPolys.Add( FrontEdPoly ); AllocatedFPolys.Add( BackEdPoly ); for( int32 i=0; i<NumPolys; i++ ) { FPoly *EdPoly = PolyList[i]; if( EdPoly == SplitPoly ) { continue; } switch( EdPoly->SplitWithPlane( SplitPoly->Vertices[0], SplitPoly->Normal, FrontEdPoly, BackEdPoly, 0 ) ) { case SP_Coplanar: if( RebuildSimplePolys ) { EdPoly->iLink = Model->Surfs.Num()-1; } iPlaneNode = bspAddNode( Model, iPlaneNode, NODE_Plane, 0, EdPoly ); break; case SP_Front: FrontList[NumFront++] = PolyList[i]; break; case SP_Back: BackList[NumBack++] = PolyList[i]; break; case SP_Split: // Create front & back nodes. FrontList[NumFront++] = FrontEdPoly; BackList [NumBack ++] = BackEdPoly; FrontEdPoly = new FPoly; BackEdPoly = new FPoly; // Keep track of allocations. AllocatedFPolys.Add( FrontEdPoly ); AllocatedFPolys.Add( BackEdPoly ); break; } } // Recursively split the front and back pools. if( NumFront > 0 ) SplitPolyList( Model, iOurNode, NODE_Front, NumFront, FrontList, Opt, Balance, PortalBias, RebuildSimplePolys ); if( NumBack > 0 ) SplitPolyList( Model, iOurNode, NODE_Back, NumBack, BackList, Opt, Balance, PortalBias, RebuildSimplePolys ); // Delete FPolys allocated above. We cannot use FMemStack::Get() for FPoly as the array data FPoly contains will be allocated in regular memory. for( int32 i=0; i<AllocatedFPolys.Num(); i++ ) { FPoly* AllocatedFPoly = AllocatedFPolys[i]; delete AllocatedFPoly; } Mark.Pop(); }
/** * Builds Bsp from the editor polygon set (EdPolys) of a model. * * Opt = Bsp optimization, BSP_Lame (fast), BSP_Good (medium), BSP_Optimal (slow) * Balance = 0-100, 0=only worry about minimizing splits, 100=only balance tree. */ void FBSPOps::bspBuild( UModel* Model, enum EBspOptimization Opt, int32 Balance, int32 PortalBias, int32 RebuildSimplePolys, int32 iNode ) { int32 OriginalPolys = Model->Polys->Element.Num(); // Empty the model's tables. if( RebuildSimplePolys==1 ) { // Empty everything but polys. Model->EmptyModel( 1, 0 ); } else if( RebuildSimplePolys==0 ) { // Empty node vertices. for( int32 i=0; i<Model->Nodes.Num(); i++ ) Model->Nodes[i].NumVertices = 0; // Refresh the Bsp. bspRefresh(Model,1); // Empty nodes. Model->EmptyModel( 0, 0 ); } if( Model->Polys->Element.Num() ) { // Allocate polygon pool. FMemMark Mark(FMemStack::Get()); FPoly** PolyList = new( FMemStack::Get(), Model->Polys->Element.Num() )FPoly*; // Add all FPolys to active list. for( int32 i=0; i<Model->Polys->Element.Num(); i++ ) if( Model->Polys->Element[i].Vertices.Num() ) PolyList[i] = &Model->Polys->Element[i]; // Now split the entire Bsp by splitting the list of all polygons. SplitPolyList ( Model, INDEX_NONE, NODE_Root, Model->Polys->Element.Num(), PolyList, Opt, Balance, PortalBias, RebuildSimplePolys ); // Now build the bounding boxes for all nodes. if( RebuildSimplePolys==0 ) { // Remove unreferenced things. bspRefresh( Model, 1 ); // Rebuild all bounding boxes. bspBuildBounds( Model ); } Mark.Pop(); } // UE_LOG(LogBSPOps, Log, TEXT("bspBuild built %i convex polys into %i nodes"), OriginalPolys, Model->Nodes.Num() ); }