void BspTreeBuilderT::QuickSortFacesIntoTexNameOrder() { while (ToDoRanges.Size()>=2) { const unsigned long LastIndex =ToDoRanges[ToDoRanges.Size()-1]; ToDoRanges.DeleteBack(); const unsigned long FirstIndex=ToDoRanges[ToDoRanges.Size()-1]; ToDoRanges.DeleteBack(); if (FirstIndex<LastIndex) { const char* x=FaceChildren[LastIndex]->Material->Name.c_str(); unsigned long i=FirstIndex-1; for (unsigned long j=FirstIndex; j<=LastIndex-1; j++) if (_stricmp(FaceChildren[j]->Material->Name.c_str(), x)<0) { i++; std::swap(FaceChildren[i], FaceChildren[j]); std::swap(FaceNrs[i], FaceNrs[j]); } std::swap(FaceChildren[i+1], FaceChildren[LastIndex]); std::swap(FaceNrs[i+1], FaceNrs[LastIndex]); i++; ToDoRanges.PushBack(i+1); ToDoRanges.PushBack(LastIndex); if (i>0) { ToDoRanges.PushBack(FirstIndex); ToDoRanges.PushBack(i-1); } } } }
void BspTreeBuilderT::BuildBSPPortals(unsigned long NodeNr, ArrayT< Plane3T<double> >& NodeList) { const ArrayT<cf::SceneGraph::BspTreeNodeT::NodeT>& Nodes=BspTree->Nodes; NodeList.PushBack(Nodes[NodeNr].Plane.GetMirror()); if (Nodes[NodeNr].FrontIsLeaf) CreateLeafPortals(Nodes[NodeNr].FrontChild, NodeList); else BuildBSPPortals(Nodes[NodeNr].FrontChild, NodeList); NodeList[NodeList.Size()-1]=Nodes[NodeNr].Plane; if (Nodes[NodeNr].BackIsLeaf) CreateLeafPortals(Nodes[NodeNr].BackChild, NodeList); else BuildBSPPortals(Nodes[NodeNr].BackChild, NodeList); NodeList.DeleteBack(); }
void BspTreeBuilderT::Portalize() { ArrayT<cf::SceneGraph::BspTreeNodeT::LeafT>& Leaves=BspTree->Leaves; if (FaceChildren.Size()==0) { // BSP trees with zero faces (and thus no nodes and no leaves) can occur with many entity classes ("point entities"). assert(BspTree->Nodes.Size()==0); assert(BspTree->Leaves.Size()==0); return; } Console->Print(cf::va("\n%-50s %s\n", "*** Portalization ***", GetTimeSinceProgramStart())); unsigned long TotalNrOfPortals=0; // Kommentare des ehem. Portalize berücksichtigen!!! ArrayT< Plane3T<double> > NodeList; BuildBSPPortals(0, NodeList); Console->Print("Portalization : done\n"); for (unsigned long LeafNr=0; LeafNr<Leaves.Size(); LeafNr++) { Console->Print(cf::va("%5.1f%%\r", (double)LeafNr/Leaves.Size()*100.0)); // fflush(stdout); // The stdout console auto-flushes the output. for (unsigned long PortalNr=0; PortalNr<Leaves[LeafNr].Portals.Size(); PortalNr++) for (unsigned long FaceNr=0; FaceNr<Leaves[LeafNr].FaceChildrenSet.Size(); FaceNr++) { const cf::SceneGraph::FaceNodeT* CurrentFace =FaceChildren[Leaves[LeafNr].FaceChildrenSet[FaceNr]]; const Polygon3T<double>& CurrentPortal=Leaves[LeafNr].Portals[PortalNr]; // Wenn das Material der CurrentFace "durchsichtig" ist, d.h. BSP Portale nicht clippt // bzw. nicht solid für sie ist, mache weiter (und lasse das CurrentPortal unberührt). if ((CurrentFace->Material->ClipFlags & MaterialT::Clip_BspPortals)==0) continue; // Wenn die CurrentFace das CurrentPortal nicht überlappt, mache weiter. if (!CurrentFace->Polygon.Overlaps(CurrentPortal, false, MapT::RoundEpsilon)) continue; // Zerschneide das CurrentPortal entlang der Edges der CurrentFace. ArrayT< Polygon3T<double> > NewPortals; CurrentPortal.GetChoppedUpAlong(CurrentFace->Polygon, MapT::RoundEpsilon, NewPortals); // Das letzte der NewPortals überdeckt sich mit der Face, daher löschen wir es. NewPortals.DeleteBack(); // Das alte Portal wird nicht mehr gebraucht. Leaves[LeafNr].Portals[PortalNr]=Leaves[LeafNr].Portals[Leaves[LeafNr].Portals.Size()-1]; Leaves[LeafNr].Portals.DeleteBack(); // Dafür die Splitter anhängen. for (unsigned long PNr=0; PNr<NewPortals.Size(); PNr++) if (NewPortals[PNr].IsValid(MapT::RoundEpsilon, MapT::MinVertexDist)) // Another very serious problem is the fact that we sometimes self-create leaks, // because nearly all operations in this program suffer from rounding errors. // I have *NO* idea how to best combat them (except the introduction of exact arithmetic, which I'm seriously considering). // But for now, lets try something simpler - enforce a "minimum area" for portals. // Portals that are smaller than this minimum are considered degenerate, despite they were classified as valid above. // Note that the same is enforced above, where portals are first created. // UPDATE: As the new Polygon3T<double>::IsValid() method now enforces the MapT::MinVertexDist, // I believe the problem is solved the the polygon area check not longer required. if (NewPortals[PNr].GetArea()>100.0 /* 1 cm^2 */) Leaves[LeafNr].Portals.PushBack(NewPortals[PNr]); PortalNr--; break; } TotalNrOfPortals+=Leaves[LeafNr].Portals.Size(); } Console->Print(cf::va("Portals : %10lu\n", TotalNrOfPortals)); }