- removed MS SourceSafe junk
[genesis3d.git] / GBSPLib / PORTALS.CPP
1 /****************************************************************************************/\r
2 /*  Portals.cpp                                                                         */\r
3 /*                                                                                      */\r
4 /*  Author: John Pollard                                                                */\r
5 /*  Description: Creates and manages portals (passages from leaf-to-leaf)               */\r
6 /*                                                                                      */\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
11 /*                                                                                      */\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
16 /*                                                                                      */\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
20 /*                                                                                      */\r
21 /****************************************************************************************/\r
22 #include <Windows.h>\r
23 #include <Stdio.h>\r
24 #include <Assert.h>\r
25 \r
26 #include "Portals.h"\r
27 #include "Poly.h"\r
28 #include "Bsp.h"\r
29 #include "GBSPFile.h"\r
30 #include "Leaf.h"\r
31 #include "Utils.h"\r
32 #include "Map.h"\r
33 \r
34 #include "Ram.h"\r
35 \r
36 GBSP_Node       *OutsideNode;\r
37 geVec3d         NodeMins, NodeMaxs;\r
38 geBoolean       VisPortals;\r
39 \r
40 geBoolean CreateAllOutsidePortals(GBSP_Node *Node);\r
41 void GetNodeMinsMaxs(GBSP_Node *Node);\r
42 geBoolean AddPortalToNodes(GBSP_Portal *Portal, GBSP_Node *Front, GBSP_Node *Back);\r
43 geBoolean RemovePortalFromNode(GBSP_Portal *Portal, GBSP_Node *Node);\r
44 GBSP_Portal *AllocPortal(void);\r
45 \r
46 //=====================================================================================\r
47 //      CreatePolyOnNode\r
48 //=====================================================================================\r
49 geBoolean CreatePolyOnNode (GBSP_Node *Node, GBSP_Poly **Out)\r
50 {\r
51         GBSP_Poly       *Poly;\r
52         GBSP_Plane      *Plane;\r
53         GBSP_Node       *Parent;\r
54 \r
55         Poly = CreatePolyFromPlane(&Planes[Node->PlaneNum]);\r
56 \r
57         if (!Poly)\r
58         {\r
59                 GHook.Error("CreatePolyOnNode:  Could not create poly.\n");\r
60                 return GE_FALSE;\r
61         }\r
62 \r
63         // Clip this portal by all the parents of this node\r
64         for (Parent = Node->Parent ; Parent && Poly ; )\r
65         {\r
66                 geBoolean       Side;\r
67 \r
68                 Plane = &Planes[Parent->PlaneNum];\r
69 \r
70                 Side = (Parent->Children[0] == Node) ? GE_FALSE : GE_TRUE;\r
71                         \r
72                 if (!ClipPolyEpsilon(Poly, 0.001f, Plane, Side, &Poly))\r
73                         return GE_FALSE;\r
74 \r
75                 Node = Parent;\r
76                 Parent = Parent->Parent;\r
77         }\r
78 \r
79         *Out = Poly;\r
80 \r
81         return GE_TRUE;\r
82 }\r
83 \r
84 //=====================================================================================\r
85 //      CreatePortals\r
86 //=====================================================================================\r
87 geBoolean CreatePortals(GBSP_Node *RootNode, GBSP_Model *Model, geBoolean Vis)\r
88 {\r
89         if (Verbose)\r
90                 GHook.Printf(" --- Create Portals --- \n");\r
91 \r
92         VisPortals = Vis;\r
93 \r
94         OutsideNode = &Model->OutsideNode;\r
95 \r
96         NodeMins = Model->Mins;\r
97         NodeMaxs = Model->Maxs;\r
98 \r
99         if (!CreateAllOutsidePortals(RootNode))\r
100         {\r
101                 GHook.Error("CreatePortals:  Could not create bbox portals.\n");\r
102                 return GE_FALSE;\r
103         }\r
104 \r
105         if (!PartitionPortals_r(RootNode))\r
106         {\r
107                 GHook.Error("CreatePortals:  Could not partition portals.\n");\r
108                 return GE_FALSE;\r
109         }\r
110 \r
111         return GE_TRUE;\r
112 }\r
113 \r
114 //=====================================================================================\r
115 //      CreateOutsidePortal\r
116 //=====================================================================================\r
117 GBSP_Portal *CreateOutsidePortal(GBSP_Plane *Plane, GBSP_Node *Node)\r
118 {\r
119         GBSP_Portal     *NewPortal;\r
120         int32           Side;\r
121 \r
122         NewPortal = AllocPortal();\r
123         if (!NewPortal)\r
124                 return NULL;\r
125 \r
126         NewPortal->Poly = CreatePolyFromPlane(Plane);\r
127         if (!NewPortal->Poly)\r
128         {\r
129                 return NULL;\r
130         }\r
131         NewPortal->PlaneNum = FindPlane(Plane, &Side);\r
132 \r
133         if (NewPortal->PlaneNum == -1)\r
134         {\r
135                 GHook.Error("CreateOutsidePortal:  Could not create plane.\n");\r
136                 return NULL;\r
137         }\r
138 \r
139         if (!Side)\r
140         {\r
141                 if (!AddPortalToNodes(NewPortal, Node, OutsideNode))\r
142                         return NULL;\r
143         }\r
144         else\r
145         {\r
146                 if (!AddPortalToNodes(NewPortal, OutsideNode, Node))\r
147                         return NULL;\r
148         }\r
149 \r
150         return NewPortal;\r
151 }\r
152 \r
153 //=====================================================================================\r
154 //      CreateAllOutsidePortals\r
155 //=====================================================================================\r
156 geBoolean CreateAllOutsidePortals(GBSP_Node *Node)\r
157 {\r
158         int32           k, i, Index;\r
159         GBSP_Plane      PPlanes[6];\r
160         GBSP_Portal     *Portals[6];\r
161 \r
162         memset(OutsideNode, 0, sizeof(GBSP_Node));\r
163 \r
164         memset(PPlanes, 0, 6*sizeof(GBSP_Plane));\r
165 \r
166         OutsideNode->PlaneNum = PLANENUM_LEAF;\r
167         OutsideNode->Contents = BSP_CONTENTS_SOLID2;\r
168         OutsideNode->Portals = NULL;\r
169         OutsideNode->BrushList = NULL;\r
170 \r
171         // So there won't be NULL volume leafs when we create the outside portals\r
172         for (k=0; k< 3; k++)\r
173         {\r
174                 if (VectorToSUB(NodeMins, k)-128 <= -MIN_MAX_BOUNDS || VectorToSUB(NodeMaxs, k)+128 >= MIN_MAX_BOUNDS)\r
175                 {\r
176                         GHook.Error("CreateAllOutsidePortals:  World BOX out of range...\n");\r
177                         return GE_FALSE;\r
178                 }\r
179 \r
180                 VectorToSUB(NodeMins, k) -= (geFloat)128;\r
181                 VectorToSUB(NodeMaxs, k) += (geFloat)128;\r
182         }\r
183 \r
184         // Create 6 portals, and point to the outside and the RootNode\r
185         for (i=0; i<3; i++)\r
186         {\r
187                 for (k=0; k<2; k++)\r
188                 {\r
189                         Index = k*3 + i;\r
190                         geVec3d_Clear(&PPlanes[Index].Normal);\r
191 \r
192                         if (k == 0)\r
193                         {\r
194                                 VectorToSUB(PPlanes[Index].Normal, i) = (geFloat)1;\r
195                                 PPlanes[Index].Dist = VectorToSUB(NodeMins, i);\r
196                         }\r
197                         else\r
198                         {\r
199                                 VectorToSUB(PPlanes[Index].Normal, i) = (geFloat)-1;\r
200                                 PPlanes[Index].Dist = -VectorToSUB(NodeMaxs, i);\r
201                         }\r
202                         \r
203                         Portals[Index] = CreateOutsidePortal(&PPlanes[Index], Node);\r
204                         if (!Portals[Index])\r
205                                 return GE_FALSE;\r
206                 }\r
207         }\r
208                                                           \r
209         for (i=0; i< 6; i++)\r
210         {\r
211                 for (k=0; k< 6; k++)\r
212                 {\r
213                         if (k == i)\r
214                                 continue;\r
215 \r
216                         if (!ClipPoly(Portals[i]->Poly, &PPlanes[k], GE_FALSE, &Portals[i]->Poly))\r
217                         {\r
218                                 GHook.Error("CreateAllOutsidePortals:  There was an error clipping the portal.\n");\r
219                                 return GE_FALSE;\r
220                         }\r
221 \r
222                         if (!Portals[i]->Poly)\r
223                         {\r
224                                 GHook.Error("CreateAllOutsidePortals:  Portal was clipped away.\n");\r
225                                 return GE_FALSE;\r
226                         }\r
227                 }\r
228         }\r
229 \r
230         return GE_TRUE;\r
231 }\r
232 \r
233 //=====================================================================================\r
234 //      CheckPortal\r
235 //=====================================================================================\r
236 geBoolean CheckPortal(GBSP_Portal *Portal)\r
237 {\r
238         GBSP_Poly       *Poly;\r
239         geVec3d         *Verts;\r
240         int32           i, k;\r
241         geFloat         Val;\r
242 \r
243         Poly = Portal->Poly;\r
244         Verts = Poly->Verts;\r
245 \r
246         if (Poly->NumVerts < 3)\r
247         {\r
248                 GHook.Error("CheckPortal:  NumVerts < 3.\n");\r
249                 return GE_FALSE;\r
250         }\r
251 \r
252         for (i=0; i< Poly->NumVerts; i++)\r
253         {\r
254                 for (k=0; k<3; k++)\r
255                 {\r
256                         Val = VectorToSUB(Verts[i], k);\r
257 \r
258                         if (Val == MIN_MAX_BOUNDS)\r
259                         {\r
260                                 GHook.Error("CheckPortal:  Portal was not clipped on all sides!!!\n");\r
261                                 return GE_FALSE;\r
262                         }\r
263                 \r
264                         if (Val == -MIN_MAX_BOUNDS)\r
265                         {\r
266                                 GHook.Error("CheckPortal:  Portal was not clipped on all sides!!!\n");\r
267                                 return GE_FALSE;\r
268                         }\r
269                 }\r
270         }\r
271 \r
272         return GE_TRUE;\r
273 }\r
274 \r
275 //=======================================================================================\r
276 //      CalcNodeBoundsFromPortals\r
277 //      Calcs bounds for nodes, and leafs\r
278 //=======================================================================================\r
279 void CalcNodeBoundsFromPortals(GBSP_Node *Node)\r
280 {\r
281         GBSP_Portal             *p;\r
282         int32                   s, i;\r
283 \r
284         ClearBounds(&Node->Mins, &Node->Maxs);\r
285 \r
286         for (p=Node->Portals; p; p = p->Next[s])\r
287         {\r
288                 s = (p->Nodes[1] == Node);\r
289 \r
290                 for (i=0; i<p->Poly->NumVerts; i++)\r
291                         AddPointToBounds(&p->Poly->Verts[i], &Node->Mins, &Node->Maxs);\r
292         }\r
293 }\r
294 \r
295 //=====================================================================================\r
296 //      PartitionPortals_r\r
297 //=====================================================================================\r
298 geBoolean PartitionPortals_r(GBSP_Node *Node)\r
299 {\r
300         GBSP_Poly               *NewPoly, *FPoly, *BPoly;\r
301         GBSP_Plane              *pPlane, *pPlane2;\r
302         GBSP_Portal             *Portal, *NewPortal, *Next;\r
303         GBSP_Node               *Front, *Back, *OtherNode;\r
304         int32                   Side;\r
305 \r
306         CalcNodeBoundsFromPortals(Node);\r
307 \r
308         if (Node->PlaneNum == PLANENUM_LEAF)\r
309                 return GE_TRUE;\r
310 \r
311         if (VisPortals && Node->Detail)                 // We can stop at detail seperators for the vis tree\r
312                 return GE_TRUE;\r
313 \r
314         //if (!InitializeNodePortal(Node))\r
315         //      return GE_FALSE;\r
316         //if (!DistributeNodePortalsToChildren(Node))\r
317         //      return GE_FALSE;\r
318 \r
319         Front = Node->Children[0];\r
320         Back = Node->Children[1];\r
321 \r
322         pPlane = &Planes[Node->PlaneNum];\r
323 \r
324         // Create a new portal\r
325         if (!CreatePolyOnNode (Node, &NewPoly))\r
326         {\r
327                 GHook.Error("PartitionPortals_r:  CreatePolyOnNode failed.\n");\r
328                 return GE_FALSE;\r
329         }\r
330 \r
331         // Clip it against all other portals attached to this node\r
332         for (Portal = Node->Portals; Portal && NewPoly; Portal = Portal->Next[Side])\r
333         {\r
334                 if (Portal->Nodes[0] == Node)\r
335                         Side = 0;\r
336                 else if (Portal->Nodes[1] == Node)\r
337                         Side = 1;\r
338                 else\r
339                 {\r
340                         GHook.Error("PartitionPortals_r:  Portal does not look at either node.\n");\r
341                         return GE_FALSE;\r
342                 }\r
343 \r
344                 pPlane2 = &Planes[Portal->PlaneNum];\r
345 \r
346                 if (!ClipPolyEpsilon(NewPoly, 0.001f, pPlane2, Side, &NewPoly))\r
347                 {\r
348                         GHook.Error("PartitionPortals_r:  There was an error clipping the poly.\n");\r
349                         return GE_FALSE;\r
350                 }\r
351 \r
352                 if (!NewPoly)\r
353                 {\r
354                         GHook.Printf("PartitionPortals_r:  Portal was cut away.\n");\r
355                         break;\r
356                 }\r
357         }\r
358         \r
359         if (NewPoly && PolyIsTiny (NewPoly))\r
360         {\r
361                 FreePoly(NewPoly);\r
362                 NewPoly = NULL;\r
363         }\r
364 \r
365         if (NewPoly)\r
366         {\r
367                 NewPortal = AllocPortal();\r
368                 if (!NewPortal)\r
369                 {\r
370                         GHook.Error("PartitionPortals_r:  Out of memory for portal.\n");\r
371                         return GE_FALSE;\r
372                 }\r
373                 NewPortal->Poly = NewPoly;\r
374                 NewPortal->PlaneNum = Node->PlaneNum;\r
375                 NewPortal->OnNode = Node;\r
376 \r
377                 if (!CheckPortal(NewPortal))\r
378                 {\r
379                         GHook.Error("PartiionPortals_r:  Check Portal failed.\n");\r
380                         return GE_FALSE;\r
381                 }\r
382                 else\r
383                         AddPortalToNodes(NewPortal, Front, Back);\r
384 \r
385         }\r
386         \r
387         // Partition all portals by this node\r
388         for (Portal = Node->Portals; Portal; Portal = Next)\r
389         {\r
390                 if (Portal->Nodes[0] == Node)\r
391                         Side = 0;\r
392                 else if (Portal->Nodes[1] == Node)\r
393                         Side = 1;\r
394                 else\r
395                 {\r
396                         GHook.Error("PartitionPortals_r:  Portal does not look at either node.\n");\r
397                         return GE_FALSE;\r
398                 }\r
399 \r
400                 Next = Portal->Next[Side];\r
401                 \r
402                 // Remember the node on the back side\r
403                 OtherNode = Portal->Nodes[!Side];\r
404                 RemovePortalFromNode(Portal, Portal->Nodes[0]);\r
405                 RemovePortalFromNode(Portal, Portal->Nodes[1]);\r
406 \r
407                 if (!SplitPolyEpsilon(Portal->Poly, 0.001f, pPlane, &FPoly, &BPoly, GE_FALSE))\r
408                 {\r
409                         GHook.Error("PartitionPortals_r:  Could not split portal.\n");\r
410                         return GE_FALSE;\r
411                 }\r
412                 \r
413                 if (FPoly && PolyIsTiny(FPoly))\r
414                 {\r
415                         FreePoly(FPoly);\r
416                         FPoly = NULL;\r
417                 }\r
418 \r
419                 if (BPoly && PolyIsTiny(BPoly))\r
420                 {\r
421                         FreePoly(BPoly);\r
422                         BPoly = NULL;\r
423                 }\r
424                 \r
425                 if (!FPoly && !BPoly)\r
426                         continue;\r
427                 \r
428                 if (!FPoly)\r
429                 {\r
430                         Portal->Poly = BPoly;\r
431                         if (Side)\r
432                                 AddPortalToNodes(Portal, OtherNode, Back);\r
433                         else\r
434                                 AddPortalToNodes(Portal, Back, OtherNode);\r
435                         continue;\r
436                 }\r
437 \r
438                 if (!BPoly)\r
439                 {\r
440                         Portal->Poly = FPoly;\r
441                         if (Side)\r
442                                 AddPortalToNodes(Portal, OtherNode, Front);\r
443                         else\r
444                                 AddPortalToNodes(Portal, Front, OtherNode);\r
445                         continue;\r
446                 }\r
447 \r
448                 // Portal was split\r
449                 NewPortal = AllocPortal();\r
450                 if (!NewPortal)\r
451                 {\r
452                         GHook.Error("PartitionPortals_r:  Out of memory for portal.\n");\r
453                         return GE_FALSE;\r
454                 }\r
455                 Portal->Poly = FPoly;\r
456                 *NewPortal = *Portal;\r
457                 NewPortal->Poly = BPoly;\r
458                 \r
459                 if (Side)\r
460                 {\r
461                         AddPortalToNodes(Portal, OtherNode, Front);\r
462                         AddPortalToNodes(NewPortal, OtherNode, Back);\r
463                 }\r
464                 else\r
465                 {\r
466                         AddPortalToNodes(Portal, Front, OtherNode);\r
467                         AddPortalToNodes(NewPortal, Back, OtherNode);\r
468                 }\r
469         }\r
470 \r
471         if (Node->Portals != NULL)\r
472         {\r
473                 GHook.Printf("*WARNING* PartitionPortals_r:  Portals still on node after distribution...\n");\r
474         }\r
475         \r
476         if (!PartitionPortals_r(Front))\r
477                 return GE_FALSE;\r
478 \r
479         if (!PartitionPortals_r(Back))\r
480                 return GE_FALSE;\r
481 \r
482         return GE_TRUE;\r
483 }\r
484 \r
485 //=====================================================================================\r
486 //      AddPortalToNodes\r
487 //=====================================================================================\r
488 geBoolean AddPortalToNodes(GBSP_Portal *Portal, GBSP_Node *Front, GBSP_Node *Back)\r
489 {\r
490         if (Portal->Nodes[0] || Portal->Nodes[1])\r
491         {\r
492                 GHook.Error("LinkPortal:  Portal allready looks at one of the nodes.\n");\r
493                 return GE_FALSE;\r
494         }\r
495 \r
496         Portal->Nodes[0] = Front;\r
497         Portal->Next[0] = Front->Portals;\r
498         Front->Portals = Portal;\r
499 \r
500         Portal->Nodes[1] = Back;\r
501         Portal->Next[1] = Back->Portals;\r
502         Back->Portals = Portal;\r
503 \r
504         return GE_TRUE;\r
505 }\r
506 \r
507 //=====================================================================================\r
508 //      RemovePortalFromNode\r
509 //=====================================================================================\r
510 geBoolean RemovePortalFromNode(GBSP_Portal *Portal, GBSP_Node *Node)\r
511 {\r
512         GBSP_Portal     *p, **p2;\r
513         int32           Side;\r
514 \r
515         assert(Node->Portals);          // Better have some portals on this node\r
516         assert(!(Portal->Nodes[0] == Node && Portal->Nodes[1] == Node));\r
517         assert(Portal->Nodes[0] == Node || Portal->Nodes[1] == Node);   \r
518 \r
519         // Find the portal on this node\r
520         for (p2 = &Node->Portals, p = *p2; p; p2 = &p->Next[Side], p = *p2)\r
521         {\r
522                 assert(!(p->Nodes[0] == Node && p->Nodes[1] == Node));\r
523                 assert(p->Nodes[0] == Node || p->Nodes[1] == Node);\r
524 \r
525                 Side = (p->Nodes[1] == Node);   // Get the side of the portal that this node is on\r
526 \r
527                 if (p == Portal)\r
528                         break;                  // Got it\r
529         }\r
530          \r
531         assert(p && p2 && *p2);\r
532 \r
533         Side = (Portal->Nodes[1] == Node);      // Get the side of the portal that the node was on\r
534         \r
535         *p2 = Portal->Next[Side];\r
536         Portal->Nodes[Side] = NULL;\r
537 \r
538         return GE_TRUE;\r
539 }\r
540 \r
541 //=====================================================================================\r
542 //      AllocPortal\r
543 //=====================================================================================\r
544 GBSP_Portal *AllocPortal(void)\r
545 {\r
546         GBSP_Portal     *NewPortal;\r
547 \r
548         NewPortal = GE_RAM_ALLOCATE_STRUCT(GBSP_Portal);\r
549 \r
550         if (!NewPortal)\r
551         {\r
552                 GHook.Error("AllocPortal:  Out of memory!\n");\r
553                 return NULL;\r
554         }\r
555 \r
556         memset(NewPortal, 0, sizeof(GBSP_Portal));\r
557 \r
558         return NewPortal;\r
559 }\r
560 \r
561 //=====================================================================================\r
562 //      FreePortal\r
563 //=====================================================================================\r
564 geBoolean FreePortal(GBSP_Portal *Portal)\r
565 {\r
566         if (!Portal->Poly)\r
567         {\r
568                 GHook.Error("FreePortal:  Portal with NULL Poly.\n");\r
569                 return GE_FALSE;\r
570         }\r
571 \r
572         FreePoly(Portal->Poly);\r
573 \r
574         geRam_Free(Portal);\r
575 \r
576         return GE_TRUE;\r
577 }\r
578 \r
579 //=====================================================================================\r
580 //      FreePOrtals_r\r
581 //=====================================================================================\r
582 geBoolean FreePortals_r(GBSP_Node *Node)\r
583 {\r
584         GBSP_Portal *Portal, *Next;\r
585         int32           Side;\r
586 \r
587         if (!Node)\r
588                 return GE_TRUE;\r
589         \r
590         for (Portal = Node->Portals; Portal; Portal = Next)\r
591         {\r
592                 if (Portal->Nodes[0] == Node)\r
593                         Side = 0;\r
594                 else if (Portal->Nodes[1] == Node)\r
595                         Side = 1;\r
596                 else\r
597                 {\r
598                         GHook.Error("FreePortals_r:  Portal does not look at either node.\n");\r
599                         return GE_FALSE;\r
600                 }\r
601 \r
602                 Next = Portal->Next[Side];\r
603 \r
604                 if (!RemovePortalFromNode(Portal, Portal->Nodes[0]))\r
605                         return GE_FALSE;\r
606 \r
607                 if (!RemovePortalFromNode(Portal, Portal->Nodes[1]))\r
608                         return GE_FALSE;\r
609 \r
610                 if (!FreePortal(Portal))\r
611                         return GE_FALSE;\r
612         }\r
613 \r
614         Node->Portals = NULL;\r
615 \r
616         if (Node->PlaneNum == PLANENUM_LEAF)\r
617                 return GE_TRUE;\r
618 \r
619         if (!FreePortals_r(Node->Children[0]))\r
620                 return GE_FALSE;\r
621 \r
622         if (!FreePortals_r(Node->Children[1]))\r
623                 return GE_FALSE;\r
624 \r
625         return GE_TRUE;\r
626 }\r
627 \r
628 //=====================================================================================\r
629 //      FreePortals\r
630 //=====================================================================================\r
631 geBoolean FreePortals(GBSP_Node *RootNode)\r
632 {\r
633         return(FreePortals_r(RootNode));\r
634 }\r
635 \r
636 void AddPointToBounds(geVec3d *v, geVec3d *Mins, geVec3d *Maxs);\r
637 \r
638 //=====================================================================================\r
639 //      GetNodeMinsMaxs\r
640 //=====================================================================================\r
641 void GetNodeMinsMaxs(GBSP_Node *Node)\r
642 {\r
643         ClearBounds(&NodeMins, &NodeMaxs);\r
644 \r
645         NodeMins = Node->Mins;\r
646         NodeMaxs = Node->Maxs;\r
647 }\r
648 \r
649 //====================================================================================\r
650 //      GetLeafBBoxFromPortals\r
651 //====================================================================================\r
652 geBoolean GetLeafBBoxFromPortals(GBSP_Node *Node, geVec3d *Mins, geVec3d *Maxs)\r
653 {\r
654         GBSP_Poly       *Poly;\r
655         geVec3d         *Verts;\r
656         GBSP_Portal     *Portal;\r
657         int32           i, k, Side;\r
658 \r
659         if (Node->PlaneNum != PLANENUM_LEAF)\r
660         {\r
661                 GHook.Error("GetLeafBBoxFromPortals:  Not a leaf.\n");\r
662                 return GE_FALSE;\r
663         }\r
664 \r
665         ClearBounds(Mins, Maxs);\r
666 \r
667         for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side])\r
668         {\r
669                 Side = (Portal->Nodes[1] == Node);\r
670 \r
671                 Poly = Portal->Poly;\r
672 \r
673                 Verts = Poly->Verts;\r
674                 for (i=0; i< Poly->NumVerts; i++)\r
675                 {\r
676                         for (k=0; k<3; k++)\r
677                         {\r
678                                 if (VectorToSUB(Verts[i], k) < VectorToSUB(*Mins, k))\r
679                                         VectorToSUB(*Mins, k) = VectorToSUB(Verts[i], k);\r
680                                 if (VectorToSUB(Verts[i], k) > VectorToSUB(*Maxs, k))\r
681                                         VectorToSUB(*Maxs, k) = VectorToSUB(Verts[i], k);\r
682                         }\r
683                 }\r
684         }\r
685 \r
686         return GE_TRUE;\r
687 }\r