Fix issue in Rocket.lua script.
[Cafu-Engine.git] / CaPVS / CaPVSWorld.cpp
blob5e8e5a39f89cb4baeb917765ffabb00f9aae04f9
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
7 /**************************/
8 /*** CaPVS World (Code) ***/
9 /**************************/
11 #include <stdio.h>
12 #include "CaPVSWorld.hpp"
13 #include "SceneGraph/Node.hpp"
14 #include "SceneGraph/BspTreeNode.hpp"
15 #include "SceneGraph/FaceNode.hpp"
18 CaPVSWorldT::CaPVSWorldT(const char* FileName, ModelManagerT& ModelMan, cf::GuiSys::GuiResourcesT& GuiRes, unsigned long SLC_MaxRecursionDepth_, double SLC_MinSubTreeFacesArea_)
19 : m_World(FileName, ModelMan, GuiRes),
20 m_BspTree(m_World.m_StaticEntityData[0]->m_BspTree),
21 SLC_MaxRecursionDepth(SLC_MaxRecursionDepth_),
22 SLC_MinSubTreeFacesArea(SLC_MinSubTreeFacesArea_)
27 double CaPVSWorldT::SubTreeFacesArea(unsigned long NodeNr) const
29 const ArrayT<cf::SceneGraph::BspTreeNodeT::NodeT>& Nodes = m_BspTree->Nodes;
30 const ArrayT<cf::SceneGraph::BspTreeNodeT::LeafT>& Leaves = m_BspTree->Leaves;
32 // TODO: This method counts faces that are in multiple leaves multiply!
33 // This is a BUG that should be fixed!!!
34 double Area=0.0;
36 if (Nodes[NodeNr].FrontIsLeaf)
38 const cf::SceneGraph::BspTreeNodeT::LeafT& L=Leaves[Nodes[NodeNr].FrontChild];
40 for (unsigned long SetNr=0; SetNr<L.FaceChildrenSet.Size(); SetNr++)
41 Area += m_BspTree->FaceChildren[L.FaceChildrenSet[SetNr]]->Polygon.GetArea();
43 else Area+=SubTreeFacesArea(Nodes[NodeNr].FrontChild);
45 if (Nodes[NodeNr].BackIsLeaf)
47 const cf::SceneGraph::BspTreeNodeT::LeafT& L=Leaves[Nodes[NodeNr].BackChild];
49 for (unsigned long SetNr=0; SetNr<L.FaceChildrenSet.Size(); SetNr++)
50 Area += m_BspTree->FaceChildren[L.FaceChildrenSet[SetNr]]->Polygon.GetArea();
52 else Area+=SubTreeFacesArea(Nodes[NodeNr].BackChild);
54 return Area;
58 // Considers the sub-tree beginning at node 'NodeNr', and determines whether a SuperLeaf should be constructed from it or not.
59 // Returns 'true' when a SuperLeaf should be constructed, 'false' otherwise.
60 bool CaPVSWorldT::SuperLeafConditionIsMet(unsigned long NodeNr, unsigned long RecursionDepth) const
62 if (RecursionDepth>SLC_MaxRecursionDepth) return true;
63 if (SubTreeFacesArea(NodeNr)<SLC_MinSubTreeFacesArea) return true;
65 return false;
69 void CaPVSWorldT::CreateSuperLeafFromSubTreeRecursive(unsigned long NodeNr, SuperLeafT& SuperLeaf) const
71 const ArrayT<cf::SceneGraph::BspTreeNodeT::NodeT>& Nodes = m_BspTree->Nodes;
72 const ArrayT<cf::SceneGraph::BspTreeNodeT::LeafT>& Leaves = m_BspTree->Leaves;
74 if (Nodes[NodeNr].FrontIsLeaf)
76 const unsigned long LeafNr=Nodes[NodeNr].FrontChild;
78 SuperLeaf.LeafSet.PushBack(LeafNr);
80 for (unsigned long PortalNr=0; PortalNr<Leaves[LeafNr].Portals.Size(); PortalNr++)
81 SuperLeaf.Portals.PushBack(Leaves[LeafNr].Portals[PortalNr]);
83 if (SuperLeaf.LeafSet.Size()>1)
85 SuperLeaf.BB.Insert(Leaves[LeafNr].BB.Min);
86 SuperLeaf.BB.Insert(Leaves[LeafNr].BB.Max);
88 else SuperLeaf.BB=Leaves[LeafNr].BB;
90 else CreateSuperLeafFromSubTreeRecursive(Nodes[NodeNr].FrontChild, SuperLeaf);
92 if (Nodes[NodeNr].BackIsLeaf)
94 const unsigned long LeafNr=Nodes[NodeNr].BackChild;
96 SuperLeaf.LeafSet.PushBack(LeafNr);
98 for (unsigned long PortalNr=0; PortalNr<Leaves[LeafNr].Portals.Size(); PortalNr++)
99 SuperLeaf.Portals.PushBack(Leaves[LeafNr].Portals[PortalNr]);
101 if (SuperLeaf.LeafSet.Size()>1)
103 SuperLeaf.BB.Insert(Leaves[LeafNr].BB.Min);
104 SuperLeaf.BB.Insert(Leaves[LeafNr].BB.Max);
106 else SuperLeaf.BB=Leaves[LeafNr].BB;
108 else CreateSuperLeafFromSubTreeRecursive(Nodes[NodeNr].BackChild, SuperLeaf);
112 // Traverses the sub-tree beginning at node 'NodeNr' and constructs a SuperLeaf from it.
113 // The resulting SuperLeaf is returned.
114 SuperLeafT CaPVSWorldT::CreateSuperLeafFromSubTree(unsigned long NodeNr) const
116 SuperLeafT SuperLeaf;
118 CreateSuperLeafFromSubTreeRecursive(NodeNr, SuperLeaf);
120 return SuperLeaf;
124 void CaPVSWorldT::CreateSuperLeavesRecursive(unsigned long NodeNr, ArrayT<SuperLeafT>& SuperLeaves, unsigned long RecursionDepth) const
126 const ArrayT<cf::SceneGraph::BspTreeNodeT::NodeT>& Nodes = m_BspTree->Nodes;
127 const ArrayT<cf::SceneGraph::BspTreeNodeT::LeafT>& Leaves = m_BspTree->Leaves;
129 if (Nodes[NodeNr].FrontIsLeaf)
131 // Create SuperLeaf from single leaf child.
132 const unsigned long LeafNr=Nodes[NodeNr].FrontChild;
134 SuperLeaves.PushBackEmpty();
135 SuperLeaves[SuperLeaves.Size()-1].LeafSet.PushBack(LeafNr);
136 SuperLeaves[SuperLeaves.Size()-1].Portals=Leaves[LeafNr].Portals;
137 SuperLeaves[SuperLeaves.Size()-1].BB =Leaves[LeafNr].BB;
139 else
141 if (SuperLeafConditionIsMet(Nodes[NodeNr].FrontChild, RecursionDepth+1))
143 // Create SuperLeaf from the remaining front sub-tree.
144 SuperLeaves.PushBack(CreateSuperLeafFromSubTree(Nodes[NodeNr].FrontChild));
146 else CreateSuperLeavesRecursive(Nodes[NodeNr].FrontChild, SuperLeaves, RecursionDepth+1);
149 if (Nodes[NodeNr].BackIsLeaf)
151 // Create SuperLeaf from single leaf child.
152 const unsigned long LeafNr=Nodes[NodeNr].BackChild;
154 SuperLeaves.PushBackEmpty();
155 SuperLeaves[SuperLeaves.Size()-1].LeafSet.PushBack(LeafNr);
156 SuperLeaves[SuperLeaves.Size()-1].Portals=Leaves[LeafNr].Portals;
157 SuperLeaves[SuperLeaves.Size()-1].BB =Leaves[LeafNr].BB;
159 else
161 if (SuperLeafConditionIsMet(Nodes[NodeNr].BackChild, RecursionDepth+1))
163 // Create SuperLeaf from the remaining back sub-tree.
164 SuperLeaves.PushBack(CreateSuperLeafFromSubTree(Nodes[NodeNr].BackChild));
166 else CreateSuperLeavesRecursive(Nodes[NodeNr].BackChild, SuperLeaves, RecursionDepth+1);
171 void CaPVSWorldT::CreateSuperLeaves(ArrayT<SuperLeafT>& SuperLeaves) const
173 const ArrayT<cf::SceneGraph::BspTreeNodeT::LeafT>& Leaves = m_BspTree->Leaves;
175 printf("\n*** Create SuperLeaves ***\n");
177 CreateSuperLeavesRecursive(0, SuperLeaves, 0);
179 printf("%5lu SuperLeaves created from\n", SuperLeaves.Size());
180 printf("%5lu world leaves in CW file.\n", Leaves.Size());
184 unsigned long CaPVSWorldT::WhatLeaf(const VectorT& Position) const
186 return m_BspTree->WhatLeaf(Position);
190 double CaPVSWorldT::ClipLine(const VectorT& P, const VectorT& U) const
192 return m_BspTree->ClipLine(P, U, 0.0, 1.0);
196 void CaPVSWorldT::StorePVS(const ArrayT<SuperLeafT>& SuperLeaves, const ArrayT<unsigned long>& SuperLeavesPVS)
198 const ArrayT<cf::SceneGraph::BspTreeNodeT::LeafT>& Leaves = m_BspTree->Leaves;
199 ArrayT<uint32_t>& PVS = m_BspTree->PVS;
201 // 'PVS' zurücksetzen (völlige Blindheit).
202 for (unsigned long Vis=0; Vis<PVS.Size(); Vis++) PVS[Vis]=0;
204 // 'SuperLeavesPVS' ins 'PVS' übertragen.
205 for (unsigned long SL1Nr=0; SL1Nr<SuperLeaves.Size(); SL1Nr++)
206 for (unsigned long SL2Nr=0; SL2Nr<SuperLeaves.Size(); SL2Nr++)
208 const unsigned long PVSTotalBitNr1=SL1Nr*SuperLeaves.Size()+SL2Nr;
209 const unsigned long PVSTotalBitNr2=SL2Nr*SuperLeaves.Size()+SL1Nr;
210 const bool CanSeeFrom1To2=bool((SuperLeavesPVS[PVSTotalBitNr1 >> 5] >> (PVSTotalBitNr1 & 31)) & 1);
211 const bool CanSeeFrom2To1=bool((SuperLeavesPVS[PVSTotalBitNr2 >> 5] >> (PVSTotalBitNr2 & 31)) & 1);
213 // 'CanSeeFrom2To1' ist nicht wirklich notwendig, nur wegen der PVS-Matrix-Symmetrie
214 // (um "Can see from A to B, but not vice versa!" zu vermeiden)!
215 if (CanSeeFrom1To2 && CanSeeFrom2To1)
217 // Kann von allen Leaves in 'SuperLeaves[SL1Nr]' alle Leaves in 'SuperLeaves[SL2Nr]' sehen.
218 for (unsigned long LeafSet1Nr=0; LeafSet1Nr<SuperLeaves[SL1Nr].LeafSet.Size(); LeafSet1Nr++)
219 for (unsigned long LeafSet2Nr=0; LeafSet2Nr<SuperLeaves[SL2Nr].LeafSet.Size(); LeafSet2Nr++)
221 const unsigned long Leaf1Nr=SuperLeaves[SL1Nr].LeafSet[LeafSet1Nr];
222 const unsigned long Leaf2Nr=SuperLeaves[SL2Nr].LeafSet[LeafSet2Nr];
224 if (!Leaves[Leaf1Nr].IsInnerLeaf) continue;
225 if (!Leaves[Leaf2Nr].IsInnerLeaf) continue;
227 // Kann von 'Leaf1Nr' nach 'Leaf2Nr' sehen, markiere also 'Leaf2Nr' als von 'Leaf1Nr' aus sichtbar.
228 const unsigned long PVSTotalBitNr=Leaf1Nr*Leaves.Size()+Leaf2Nr;
229 const unsigned long PVS_W32_Nr =PVSTotalBitNr >> 5;
230 const unsigned long PVSBitMask =1 << (PVSTotalBitNr & 31);
231 PVS[PVS_W32_Nr]|=PVSBitMask;
238 unsigned long CaPVSWorldT::GetChecksumAndPrintStats() const
240 const ArrayT<uint32_t>& PVS = m_BspTree->PVS;
242 printf("\n*** Statistics ***\n");
244 unsigned long CheckSum=0;
246 for (unsigned long Count=0; Count<PVS.Size(); Count++)
248 CheckSum+=(PVS[Count] >> 24) & 0xFF;
249 CheckSum+=(PVS[Count] >> 16) & 0xFF;
250 CheckSum+=(PVS[Count] >> 8) & 0xFF;
251 CheckSum+=(PVS[Count] ) & 0xFF;
254 printf("Size (bytes) : %10lu\n", PVS.Size()*4);
255 printf("CheckSum : %10lu\n", CheckSum );
257 return CheckSum;
261 void CaPVSWorldT::SaveToDisk(const char* FileName) const
263 m_World.SaveToDisk(FileName);