1 /****************************************************************************************/
\r
4 /* Author: John Pollard */
\r
5 /* Description: Does the flood filling of the leafs, and removes untouchable leafs */
\r
7 /* The contents of this file are subject to the Genesis3D Public License */
\r
8 /* Version 1.01 (the "License"); you may not use this file except in */
\r
9 /* compliance with the License. You may obtain a copy of the License at */
\r
10 /* http://www.genesis3d.com */
\r
12 /* Software distributed under the License is distributed on an "AS IS" */
\r
13 /* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */
\r
14 /* the License for the specific language governing rights and limitations */
\r
15 /* under the License. */
\r
17 /* The Original Code is Genesis3D, released March 25, 1999. */
\r
18 /*Genesis3D Version 1.1 released November 15, 1999 */
\r
19 /* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */
\r
21 /****************************************************************************************/
\r
22 #include <Windows.h>
\r
27 #include "Portals.h"
\r
30 #include "GBSPFile.h"
\r
34 geBoolean HitEntity = GE_FALSE;
\r
35 int32 EntityHit = 0;
\r
38 int32 NumRemovedLeafs;
\r
40 //=====================================================================================
\r
42 //=====================================================================================
\r
43 geBoolean PlaceEntities(GBSP_Node *RootNode)
\r
51 for (i=1; i< NumEntities; i++)
\r
53 if (!(Entities[i].Flags & ENTITY_HAS_ORIGIN)) // No "Origin" in entity
\r
56 Node = FindLeaf(RootNode, &Entities[i].Origin);
\r
60 if (!(Node->Contents & BSP_CONTENTS_SOLID2))
\r
69 GHook.Error("PlaceEntities: No valid entities for operation %i.\n", NumEntities);
\r
76 //=====================================================================================
\r
77 // FillUnTouchedLeafs_r
\r
78 //=====================================================================================
\r
79 void FillUnTouchedLeafs_r(GBSP_Node *Node)
\r
81 if (Node->PlaneNum != PLANENUM_LEAF)
\r
83 FillUnTouchedLeafs_r(Node->Children[0]);
\r
84 FillUnTouchedLeafs_r(Node->Children[1]);
\r
88 if ((Node->Contents & BSP_CONTENTS_SOLID2))
\r
89 return; //allready solid or removed...
\r
91 if (Node->CurrentFill != CurrentFill)
\r
93 // Fill er in with solid so it does not show up...(Preserve user contents)
\r
94 Node->Contents &= (0xffff0000);
\r
95 Node->Contents |= BSP_CONTENTS_SOLID2;
\r
100 //=====================================================================================
\r
102 //=====================================================================================
\r
103 geBoolean FillLeafs2_r(GBSP_Node *Node)
\r
105 GBSP_Portal *Portal;
\r
108 if (Node->Contents & BSP_CONTENTS_SOLID2)
\r
111 if (Node->CurrentFill == CurrentFill)
\r
114 Node->CurrentFill = CurrentFill;
\r
116 for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side])
\r
118 if (Portal->Nodes[0] == Node)
\r
120 else if (Portal->Nodes[1] == Node)
\r
124 GHook.Error("RemoveOutside2_r: Portal does not look at either node.\n");
\r
128 // Go though the portal to the node on the other side (!side)
\r
129 if (!FillLeafs2_r(Portal->Nodes[!Side]))
\r
136 //=====================================================================================
\r
138 // See if a portal can be passed through or not
\r
139 //=====================================================================================
\r
140 geBoolean CanPassPortal(GBSP_Portal *Portal)
\r
142 if (Portal->Nodes[0]->PlaneNum != PLANENUM_LEAF)
\r
143 GHook.Printf("*WARNING* CanPassPortal: Portal does not seperate leafs.\n");
\r
145 if (Portal->Nodes[1]->PlaneNum != PLANENUM_LEAF)
\r
146 GHook.Printf("*WARNING* CanPassPortal: Portal does not seperate leafs.\n");
\r
148 if (Portal->Nodes[0]->Contents & BSP_CONTENTS_SOLID2)
\r
151 if (Portal->Nodes[1]->Contents & BSP_CONTENTS_SOLID2)
\r
157 //=====================================================================================
\r
159 //=====================================================================================
\r
160 geBoolean FillLeafs_r(GBSP_Node *Node, geBoolean Fill, int32 Dist)
\r
162 GBSP_Portal *Portal;
\r
168 if (Node->Contents & BSP_CONTENTS_SOLID2)
\r
171 if (Node->CurrentFill == CurrentFill)
\r
174 Node->CurrentFill = CurrentFill;
\r
176 Node->Occupied = Dist;
\r
180 // Preserve user contents
\r
181 Node->Contents &= 0xffff0000;
\r
182 Node->Contents |= BSP_CONTENTS_SOLID2;
\r
188 HitEntity = GE_TRUE;
\r
189 EntityHit = Node->Entity;
\r
195 for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side])
\r
197 if (Portal->Nodes[0] == Node)
\r
199 else if (Portal->Nodes[1] == Node)
\r
203 GHook.Error("FillLeafs_r: Portal does not look at either node.\n");
\r
207 //if (!CanPassPortal(Portal))
\r
210 if (!FillLeafs_r(Portal->Nodes[!Side], Fill, Dist+1))
\r
217 //=====================================================================================
\r
218 // FillFromEntities
\r
219 //=====================================================================================
\r
220 geBoolean FillFromEntities(GBSP_Node *RootNode)
\r
228 for (i=1; i< NumEntities; i++) // Don't use the world as an entity (skip 0)!!
\r
230 if (!(Entities[i].Flags & ENTITY_HAS_ORIGIN)) // No "Origin" in entity
\r
233 Node = FindLeaf(RootNode, &Entities[i].Origin);
\r
235 if (Node->Contents & BSP_CONTENTS_SOLID2)
\r
238 // There is at least one entity in empty space...
\r
241 if (!FillLeafs2_r(Node))
\r
247 GHook.Error("FillFromEntities: No valid entities for operation.\n");
\r
254 //=====================================================================================
\r
256 //=====================================================================================
\r
257 void LeafCenter(GBSP_Node *Node, geVec3d *PortalMid)
\r
259 int32 NumPortals, Side;
\r
261 GBSP_Portal *Portal;
\r
264 geVec3d_Clear(PortalMid);
\r
266 for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side])
\r
268 Side = Portal->Nodes[1] == Node;
\r
270 PolyCenter(Portal->Poly, &Mid);
\r
271 geVec3d_Add(PortalMid, &Mid, PortalMid);
\r
275 geVec3d_Scale(PortalMid, 1.0f/(geFloat)NumPortals, PortalMid);
\r
278 //=====================================================================================
\r
280 //=====================================================================================
\r
281 geBoolean WriteLeakFile (char *FileName, GBSP_Node *Start, GBSP_Node *Outside)
\r
285 char FileName2[1024];
\r
292 GHook.Printf("--- WriteLeakFile ---\n");
\r
295 // Write the points to the file
\r
297 sprintf (FileName2, "%s.Pnt", FileName);
\r
298 PntFile = fopen (FileName2, "wb");
\r
301 GHook.Error ("WriteLeakFile: Couldn't open %s\n", FileName);
\r
305 strcpy(TAG, "LEAK");
\r
306 fwrite(TAG, sizeof(char), 4, PntFile);
\r
308 Pos1 = ftell(PntFile);
\r
310 fwrite(&Count, sizeof(int32), 1, PntFile);
\r
314 fwrite(&Entities[EntityHit].Origin, sizeof(geVec3d), 1, PntFile);
\r
319 while (Node && Node->Occupied > 1)
\r
322 GBSP_Portal *p, *NextPortal;
\r
323 GBSP_Node *NextNode;
\r
326 // find the best portal exit
\r
327 Next = Node->Occupied;
\r
331 GHook.Printf("Occupied : %5i\n", Node->Occupied);
\r
333 for (p=Node->Portals ; p ; p = p->Next[!s])
\r
335 s = (p->Nodes[0] == Node);
\r
337 if (p->Nodes[s] == Outside)
\r
343 if (p->Nodes[s]->Occupied && p->Nodes[s]->Occupied < Next)
\r
346 NextNode = p->Nodes[s];
\r
347 Next = NextNode->Occupied;
\r
356 if (NextPortal && Node && Node != Outside)
\r
358 // Write out the center of the portal
\r
359 PolyCenter(NextPortal->Poly, &Mid);
\r
360 fwrite(&Mid, sizeof(geVec3d), 1, PntFile);
\r
362 // Then writer out the center of the leaf it goes too
\r
363 LeafCenter(Node, &Mid);
\r
364 fwrite(&Mid, sizeof(geVec3d), 1, PntFile);
\r
369 GHook.Printf("Num Points : %5i\n", Count);
\r
372 Pos2 = ftell(PntFile);
\r
374 GHook.Printf("Pos1 = %5i\n", Pos1);
\r
375 GHook.Printf("Pos2 = %5i\n", Pos2);
\r
377 fseek(PntFile, Pos1, SEEK_SET);
\r
379 fwrite(&Count, sizeof(int32), 1, PntFile);
\r
381 fseek(PntFile, Pos2, SEEK_SET);
\r
388 //=====================================================================================
\r
389 // RemoveHiddenLeafs
\r
390 //=====================================================================================
\r
391 int32 RemoveHiddenLeafs(GBSP_Node *RootNode, GBSP_Node *ONode)
\r
395 GHook.Printf(" --- Remove Hidden Leafs --- \n");
\r
397 OutsideNode = ONode;
\r
399 Side = OutsideNode->Portals->Nodes[0] == OutsideNode;
\r
401 NumRemovedLeafs = 0;
\r
403 if (!PlaceEntities(RootNode))
\r
406 HitEntity = GE_FALSE;
\r
410 if (!FillLeafs_r(OutsideNode->Portals->Nodes[Side], GE_FALSE, 1))
\r
415 GHook.Printf("*****************************************\n");
\r
416 GHook.Printf("* *** LEAK *** *\n");
\r
417 GHook.Printf("* Level is NOT sealed. *\n");
\r
418 GHook.Printf("* Optimal removal will not be performed.*\n");
\r
419 GHook.Printf("*****************************************\n");
\r
421 WriteLeakFile("Test", HitNode, ONode);
\r
427 if (!FillFromEntities(RootNode))
\r
430 FillUnTouchedLeafs_r(RootNode);
\r
433 GHook.Printf("Removed Leafs : %5i\n", NumRemovedLeafs);
\r
435 return NumRemovedLeafs;
\r