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.
7 /**************************/
8 /*** CaPVS World (Code) ***/
9 /**************************/
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!!!
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
);
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;
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
);
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
;
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
;
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
);
261 void CaPVSWorldT::SaveToDisk(const char* FileName
) const
263 m_World
.SaveToDisk(FileName
);