- propper names for global includes
[genesis3d.git] / GBSPLib / VIS.CPP
1 /****************************************************************************************/\r
2 /*  Vis.cpp                                                                             */\r
3 /*                                                                                      */\r
4 /*  Author: John Pollard                                                                */\r
5 /*  Description: Vises a BSP                                                            */\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 \r
25 #include "Utils.h"\r
26 #include "Vis.h"\r
27 #include "GBSPFile.h"\r
28 #include "Poly.h"\r
29 #include "Bsp.h"\r
30 \r
31 #include "Ram.h"\r
32 \r
33 int32           NumVisPortals;                                  // Total portals\r
34 int32           NumVisPortalBytes;                              // Total portals / 8\r
35 int32           NumVisPortalLongs;                              // Total portalbytes / sizeof(uint32)\r
36 VIS_Portal      *VisPortals;                                    // NumVisPortals\r
37 pVIS_Portal     *VisSortedPortals;                              // Pointers to portals sorted by MightSee\r
38 uint8           *PortalSeen;                                    // Temp vis array\r
39 uint8           *PortalBits;\r
40 \r
41 int32           NumVisLeafs;                                    // Total VisLeafs\r
42 int32           NumVisLeafBytes;                                // NumVisLeaf / 8\r
43 int32           NumVisLeafLongs;                                // NumVisBytes / sizeof(uint32)\r
44 uint8           *LeafVisBits;                                   // Should be NumVisLeafs * (NumVisLeafs / 8)\r
45 VIS_Leaf        *VisLeafs;                                              // NumVisLeafs\r
46 \r
47 int32           TotalVisibleLeafs;\r
48 \r
49 geBoolean       VisVerbose = GE_FALSE;\r
50 geBoolean       NoSort = GE_FALSE;\r
51 geBoolean       FullVis = GE_TRUE;\r
52 \r
53 void FreeFileVisData(void);\r
54 geBoolean StartWritingVis(geVFile *f);\r
55 geBoolean FinishWritingVis(geVFile *f);\r
56 void FreeAllVisData(void);\r
57 void SortPortals(void);\r
58 geBoolean CalcPortalInfo(VIS_Portal *Portal);\r
59 \r
60 //=======================================================================================\r
61 //      VisGBSPFile\r
62 //=======================================================================================\r
63 geBoolean VisGBSPFile(char *FileName, VisParms *Parms)\r
64 {\r
65         char    PFile[200];\r
66         geVFile *f;\r
67 \r
68         f = NULL;\r
69 \r
70         GHook.Printf(" --- Vis GBSP File --- \n");\r
71 \r
72         NoSort = !Parms->SortPortals;\r
73         VisVerbose = Parms->Verbose;\r
74         FullVis = Parms->FullVis;\r
75         \r
76         // Fill in the global bsp data\r
77         if (!LoadGBSPFile(FileName))\r
78         {\r
79                 GHook.Error("PvsGBSPFile:  Could not load GBSP file: %s\n", FileName);\r
80                 goto ExitWithError;\r
81         }\r
82 \r
83         // Clean out any old vis data\r
84         FreeFileVisData();              \r
85 \r
86         // Open the bsp file for writing\r
87         f = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_DOS, FileName, NULL, GE_VFILE_OPEN_CREATE);\r
88         \r
89         if (!f)         // Oops\r
90         {\r
91                 GHook.Error("VisGBSPFile:  Could not open GBSP file for writing: %s.\n", FileName);\r
92                 goto ExitWithError;\r
93         }\r
94 \r
95         // Prepare the portal file name\r
96         strcpy(PFile, FileName);\r
97         StripExtension(PFile);\r
98         DefaultExtension(PFile, ".GPF");\r
99         \r
100         // Load the portal file\r
101         if (!LoadPortalFile(PFile))\r
102                 goto ExitWithError;\r
103 \r
104         GHook.Printf("NumPortals           : %5i\n", NumVisPortals);\r
105 \r
106         // Write out everything but vis info\r
107         if (!StartWritingVis(f))\r
108                 goto ExitWithError;\r
109 \r
110         // Vis'em\r
111         if (!VisAllLeafs())\r
112                 goto ExitWithError;\r
113 \r
114         // Record the vis data\r
115         NumGFXVisData = NumVisLeafs*NumVisLeafBytes;\r
116         GFXVisData = LeafVisBits;\r
117 \r
118         // Save the leafs, clusters, vis data, etc\r
119         if (!FinishWritingVis(f))\r
120                 goto ExitWithError;\r
121 \r
122         // Free all the vis stuff\r
123         FreeAllVisData();\r
124 \r
125         // Free any remaining leftover bsp data\r
126         FreeGBSPFile();         \r
127 \r
128         geVFile_Close(f);\r
129 \r
130         return GE_TRUE;\r
131 \r
132         // ==== ERROR ====\r
133         ExitWithError:\r
134         {\r
135                 GHook.Error("PvsGBSPFile:  Could not vis the file: %s\n", FileName);\r
136 \r
137                 if (f)\r
138                         geVFile_Close(f);\r
139 \r
140                 FreeAllVisData();\r
141                 FreeGBSPFile();\r
142 \r
143                 return GE_FALSE;\r
144         }\r
145 }\r
146 \r
147 //=======================================================================================\r
148 //      FreeFileVisData\r
149 //=======================================================================================\r
150 void FreeFileVisData(void)\r
151 {\r
152         if (GFXVisData)\r
153                 geRam_Free(GFXVisData);\r
154         GFXVisData = NULL;\r
155         NumGFXVisData = 0;\r
156 }\r
157 \r
158 int32 LeafSee;\r
159 //=======================================================================================\r
160 //      VisAllLeafs\r
161 //=======================================================================================\r
162 geBoolean VisAllLeafs(void)\r
163 {\r
164         int32   i;\r
165 \r
166         // Create PortalSeen array.  This is used by Vis flooding routines\r
167         // This is deleted below...\r
168         PortalSeen = GE_RAM_ALLOCATE_ARRAY(uint8,NumVisPortals);\r
169 \r
170         if (!PortalSeen)\r
171                 goto ExitWithError;\r
172 \r
173         // Flood all the leafs with the fast method first...\r
174         for (i=0; i< NumVisLeafs; i++)\r
175                 FloodLeafPortalsFast(i);\r
176 \r
177         // Check for cancel request\r
178         if (CancelRequest)\r
179         {\r
180                 GHook.Printf("Cancel requested...\n");\r
181                 goto ExitWithError;\r
182         }\r
183 \r
184         // Sort the portals with MightSee\r
185         SortPortals();\r
186 \r
187         if (FullVis)\r
188                 if (!FloodPortalsSlow())\r
189                         return GE_FALSE;\r
190 \r
191         // Don't need this anymore...\r
192         geRam_Free(PortalSeen);\r
193         PortalSeen = NULL;\r
194 \r
195         LeafVisBits = GE_RAM_ALLOCATE_ARRAY(uint8,NumVisLeafs*NumVisLeafBytes);\r
196 \r
197         if (!LeafVisBits)\r
198         {\r
199                 GHook.Error("VisAllLeafs:  Out of memory for LeafVisBits.\n");\r
200                 goto ExitWithError;\r
201         }\r
202 \r
203         memset(LeafVisBits, 0, NumVisLeafs*NumVisLeafBytes);\r
204         TotalVisibleLeafs = 0;\r
205 \r
206         PortalBits = GE_RAM_ALLOCATE_ARRAY(uint8,NumVisPortalBytes);\r
207 \r
208         if (!PortalBits)\r
209                 goto ExitWithError;\r
210 \r
211         for (i=0; i< NumVisLeafs; i++)\r
212         {\r
213                 LeafSee = 0;\r
214                 \r
215                 if (!CollectLeafVisBits(i))\r
216                         goto ExitWithError;\r
217 \r
218                 TotalVisibleLeafs += LeafSee;\r
219         }\r
220         geRam_Free(PortalBits);\r
221 \r
222         GHook.Printf("Total visible areas           : %5i\n", TotalVisibleLeafs);\r
223         GHook.Printf("Average visible from each area: %5i\n", TotalVisibleLeafs / NumVisLeafs);\r
224 \r
225         return GE_TRUE;\r
226 \r
227         // ==== ERROR ====\r
228         ExitWithError:\r
229         {\r
230                 // Free all the global vis data\r
231                 FreeAllVisData();\r
232 \r
233                 return GE_FALSE;\r
234         }\r
235 }\r
236 \r
237 //=======================================================================================\r
238 //      CollectLeafVisBits\r
239 //=======================================================================================\r
240 geBoolean CollectLeafVisBits(int32 LeafNum)\r
241 {\r
242         VIS_Portal      *Portal, *SPortal;\r
243         VIS_Leaf        *Leaf;\r
244         uint8           *LeafBits, *VisBits;\r
245         int32           k, Bit, SLeaf;\r
246         \r
247         Leaf = &VisLeafs[LeafNum];\r
248 \r
249         LeafBits = &LeafVisBits[LeafNum * NumVisLeafBytes];\r
250 \r
251         memset(PortalBits, 0, NumVisPortalBytes);\r
252 \r
253         // 'OR' all portals that this portal can see into one list\r
254         for (Portal = Leaf->Portals; Portal; Portal = Portal->Next)\r
255         {\r
256                 if (Portal->FinalVisBits)                               // Try to use final vis info first\r
257                         VisBits = Portal->FinalVisBits;\r
258                 else if (Portal->VisBits)\r
259                         VisBits = Portal->VisBits;\r
260                 else\r
261                 {\r
262                         GHook.Error("No VisInfo for portal.\n");\r
263                         return GE_FALSE;\r
264                 }\r
265 \r
266                 for (k=0; k< NumVisPortalBytes; k++)\r
267                         PortalBits[k] |= VisBits[k];\r
268 \r
269                 if (Portal->VisBits)\r
270                         geRam_Free(Portal->VisBits);\r
271                 if (Portal->FinalVisBits)\r
272                         geRam_Free(Portal->FinalVisBits);                               // Don't need this anymore\r
273 \r
274                 Portal->VisBits = NULL;\r
275                 Portal->FinalVisBits = NULL;\r
276         }\r
277 \r
278         // Take this list, and or all leafs that each visible portal looks in to\r
279         for (k=0; k< NumVisPortals; k++)\r
280         {\r
281                 if (PortalBits[k>>3] & (1<<(k&7)) )\r
282                 {\r
283                         SPortal = VisPortals+k;\r
284                         SLeaf = SPortal->Leaf;\r
285                         LeafBits[SLeaf>>3] |= 1<<(SLeaf&7);\r
286                 }\r
287         }\r
288                         \r
289         Bit = 1<<(LeafNum&7);\r
290 \r
291         // He should not have seen himself (yet...)\r
292         if ((LeafBits[LeafNum>>3] & Bit))\r
293                 GHook.Printf("*WARNING* CollectLeafVisBits:  Leaf:%i can see himself!\n", LeafNum);\r
294 \r
295         LeafBits[LeafNum>>3] |= Bit;                    // Make sure he can see himself!!!\r
296 \r
297         for (k=0; k< NumVisLeafs; k++)\r
298         {\r
299                 Bit = 1<<(k&7);\r
300                 if ((LeafBits[k>>3] & Bit) )\r
301                         LeafSee++;\r
302         }\r
303 \r
304         if (LeafSee == 0)\r
305         {\r
306                 GHook.Error("CollectLeafVisBits:  Leaf can't see nothing.\n");\r
307                 return GE_FALSE;\r
308         }\r
309 \r
310         GFXClusters[LeafNum].VisOfs = (int32)(LeafBits - LeafVisBits);\r
311 \r
312         return GE_TRUE;\r
313 }\r
314 \r
315 //=======================================================================================\r
316 //      LoadPortalFile\r
317 //=======================================================================================\r
318 geBoolean LoadPortalFile(char *FileName)\r
319 {\r
320         int32           LeafFrom, LeafTo;\r
321         VIS_Portal      *pPortal;\r
322         VIS_Leaf        *pLeaf;\r
323         GBSP_Poly       *pPoly;\r
324         int32           i, NumVerts;\r
325         char            TAG[13];\r
326         geVFile         *f;\r
327 \r
328         pPoly = NULL;\r
329 \r
330         // open the file\r
331         f = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_DOS, FileName, NULL, GE_VFILE_OPEN_READONLY);\r
332 \r
333         if (!f)         // opps\r
334         {\r
335                 GHook.Error("LoadPortalFile:  Could not open %s for reading.\n", FileName);\r
336                 goto ExitWithError;\r
337         }\r
338         \r
339         // \r
340         //      Check the TAG\r
341         //\r
342         if (geVFile_Read(f, TAG, sizeof(char) * 12) != GE_TRUE)\r
343         {\r
344                 GHook.Error("LoadPortalFile:  Error reading portal file TAG.\n");\r
345                 goto ExitWithError;\r
346         }\r
347 \r
348         if (strncmp(TAG, "GBSP_PRTFILE", 12))\r
349         {\r
350                 GHook.Error("LoadPortalFile:  %s is not a GBSP Portal file.\n", FileName);\r
351                 goto ExitWithError;\r
352         }\r
353 \r
354         //\r
355         //      Get the number of portals\r
356         //\r
357         if (geVFile_Read(f, &NumVisPortals, sizeof(int32)) != GE_TRUE)\r
358         {\r
359                 GHook.Error("LoadPortalFile:  Error reading NumVisPortals.\n");\r
360                 goto ExitWithError;\r
361         }\r
362 \r
363         if (NumVisPortals >= MAX_TEMP_PORTALS)\r
364         {\r
365                 GHook.Error("LoadPortalFile:  Max portals for temp buffers.\n");\r
366                 goto ExitWithError;\r
367         }\r
368         \r
369         VisPortals = GE_RAM_ALLOCATE_ARRAY(VIS_Portal,NumVisPortals);\r
370         \r
371         if (!VisPortals)\r
372         {\r
373                 GHook.Error("LoadPortalFile:  Out of memory for VisPortals.\n");\r
374                 goto ExitWithError;\r
375         }\r
376         \r
377         memset(VisPortals, 0, sizeof(VIS_Portal)*NumVisPortals);\r
378 \r
379         VisSortedPortals = GE_RAM_ALLOCATE_ARRAY(pVIS_Portal,NumVisPortals);\r
380         \r
381         if (!VisSortedPortals)\r
382         {\r
383                 GHook.Error("LoadPortalFile:  Out of memory for VisSortedPortals.\n");\r
384                 goto ExitWithError;\r
385         }\r
386 \r
387         //\r
388         //      Get the number of leafs\r
389         //\r
390         if (geVFile_Read(f, &NumVisLeafs, sizeof(int32)) != GE_TRUE)\r
391         {\r
392                 GHook.Error("LoadPortalFile:  Error reading NumVisLeafs.\n");\r
393                 goto ExitWithError;\r
394         }\r
395 \r
396         if (NumVisLeafs > NumGFXLeafs)\r
397                 goto ExitWithError;\r
398         \r
399         VisLeafs = GE_RAM_ALLOCATE_ARRAY(VIS_Leaf,NumVisLeafs);\r
400         if (!VisLeafs)\r
401         {\r
402                 GHook.Error("LoadPortalFile:  Out of memory for VisLeafs.\n");\r
403                 goto ExitWithError;\r
404         }\r
405 \r
406         memset(VisLeafs, 0, sizeof(VIS_Leaf)*NumVisLeafs);\r
407         \r
408         //\r
409         //      Load in the portals\r
410         //\r
411         for (i=0; i< NumVisPortals; i++)\r
412         {\r
413                 if (geVFile_Read(f, &NumVerts, sizeof(int32)) != GE_TRUE)\r
414                 {\r
415                         GHook.Error("LoadPortalFile:  Error reading NumVerts.\n");\r
416                         goto ExitWithError;\r
417                 }\r
418 \r
419                 pPoly = AllocPoly(NumVerts);\r
420 \r
421                 if (!pPoly)\r
422                         goto ExitWithError;\r
423 \r
424                 if (geVFile_Read(f, pPoly->Verts, sizeof(geVec3d) * NumVerts) != GE_TRUE)\r
425                 {\r
426                         GHook.Error("LoadPortalFile:  Error reading portal vertices.\n");\r
427                         goto ExitWithError;\r
428                 }\r
429                 \r
430                 if (geVFile_Read(f, &LeafFrom, sizeof(int32)) != GE_TRUE)\r
431                 {\r
432                         GHook.Error("LoadPortalFile:  Error reading portal LeafFrom.\n");\r
433                         goto ExitWithError;\r
434                 }\r
435                 \r
436                 if (geVFile_Read(f, &LeafTo, sizeof(int32)) != GE_TRUE)\r
437                 {\r
438                         GHook.Error("LoadPortalFile:  Error reading portal LeafTo.\n");\r
439                         goto ExitWithError;\r
440                 }\r
441 \r
442                 if (LeafFrom >= NumVisLeafs || LeafFrom < 0)\r
443                 {\r
444                         GHook.Error("LoadPortalFile:  Invalid LeafFrom: %i.\n", LeafFrom);\r
445                         goto ExitWithError;\r
446                 }\r
447 \r
448                 if (LeafTo >= NumVisLeafs || LeafTo < 0)\r
449                 {\r
450                         GHook.Error("LoadPortalFile:  Invalid LeafTo: %i.\n", LeafTo);\r
451                         goto ExitWithError;\r
452                 }\r
453 \r
454                 pLeaf = &VisLeafs[LeafFrom];\r
455                 pPortal = &VisPortals[i];\r
456 \r
457                 pPortal->Poly = pPoly;\r
458                 pPortal->Leaf = LeafTo;\r
459                 PlaneFromVerts(pPoly->Verts, &pPortal->Plane);\r
460                 \r
461                 pPortal->Next = pLeaf->Portals;\r
462                 pLeaf->Portals = pPortal;\r
463 \r
464                 CalcPortalInfo(pPortal);\r
465         }\r
466         \r
467         NumVisLeafBytes = ((NumVisLeafs+63)&~63) >> 3;\r
468         NumVisPortalBytes = ((NumVisPortals+63)&~63) >> 3;\r
469 \r
470         NumVisPortalLongs = NumVisPortalBytes/sizeof(uint32);\r
471         NumVisLeafLongs = NumVisLeafBytes/sizeof(uint32);\r
472 \r
473         geVFile_Close(f);\r
474 \r
475         return GE_TRUE;\r
476 \r
477         // ==== ERROR ===\r
478         ExitWithError:\r
479         {\r
480                 if (f)\r
481                         geVFile_Close(f);\r
482 \r
483                 if (VisPortals)\r
484                         geRam_Free(VisPortals);\r
485                 if (VisSortedPortals)\r
486                         geRam_Free(VisSortedPortals);\r
487                 if (VisLeafs)\r
488                         geRam_Free(VisLeafs);\r
489 \r
490                 if (pPoly)\r
491                         FreePoly(pPoly);\r
492 \r
493                 VisPortals = NULL;\r
494                 VisSortedPortals = NULL;\r
495                 VisLeafs = NULL;\r
496                 pPoly = NULL;\r
497 \r
498                 return GE_FALSE;\r
499         }\r
500 }\r
501 \r
502 //================================================================================\r
503 //      StartWritingVis\r
504 //================================================================================\r
505 geBoolean StartWritingVis(geVFile *f)\r
506 {\r
507         // Write out everything but the vis data\r
508 \r
509         GBSP_ChunkData  CurrentChunkData[] = {\r
510                 { GBSP_CHUNK_HEADER                     , sizeof(GBSP_Header)   ,1             , &GBSPHeader},\r
511                 { GBSP_CHUNK_MODELS                     , sizeof(GFX_Model)             ,NumGFXModels  , GFXModels },\r
512                 { GBSP_CHUNK_NODES                      , sizeof(GFX_Node)              ,NumGFXNodes   , GFXNodes  },\r
513                 { GBSP_CHUNK_PORTALS            , sizeof(GFX_Portal)    ,NumGFXPortals , GFXPortals},\r
514                 { GBSP_CHUNK_BNODES                     , sizeof(GFX_BNode)             ,NumGFXBNodes  , GFXBNodes },\r
515                 { GBSP_CHUNK_PLANES                     , sizeof(GFX_Plane)             ,NumGFXPlanes  , GFXPlanes },\r
516                 { GBSP_CHUNK_FACES                      , sizeof(GFX_Face)              ,NumGFXFaces   , GFXFaces  },\r
517                 { GBSP_CHUNK_AREAS                      , sizeof(GFX_Area)              ,NumGFXAreas   , GFXAreas  },\r
518                 { GBSP_CHUNK_AREA_PORTALS       , sizeof(GFX_AreaPortal),NumGFXAreaPortals      , GFXAreaPortals  },\r
519                 { GBSP_CHUNK_LEAF_FACES         , sizeof(int32)          ,NumGFXLeafFaces, GFXLeafFaces  },\r
520                 { GBSP_CHUNK_LEAF_SIDES         , sizeof(GFX_LeafSide)  ,NumGFXLeafSides, GFXLeafSides  },\r
521                 { GBSP_CHUNK_VERTS                      , sizeof(geVec3d)               ,NumGFXVerts   , GFXVerts  },\r
522                 { GBSP_CHUNK_VERT_INDEX         , sizeof(int32)                 ,NumGFXVertIndexList , GFXVertIndexList},\r
523                 { GBSP_CHUNK_RGB_VERTS          , sizeof(geVec3d)               ,NumGFXRGBVerts, GFXRGBVerts  },\r
524                 { GBSP_CHUNK_ENTDATA            , sizeof(uint8)                 ,NumGFXEntData , GFXEntData},\r
525                 { GBSP_CHUNK_TEXTURES           , sizeof(GFX_Texture)   ,NumGFXTextures, GFXTextures},\r
526                 { GBSP_CHUNK_TEXINFO            , sizeof(GFX_TexInfo)   ,NumGFXTexInfo , GFXTexInfo},\r
527                 { GBSP_CHUNK_TEXDATA            , sizeof(uint8)                 ,NumGFXTexData , GFXTexData},\r
528                 { GBSP_CHUNK_LIGHTDATA          , sizeof(uint8)                 ,NumGFXLightData , GFXLightData},\r
529                 { GBSP_CHUNK_SKYDATA            , sizeof(GFX_SkyData)   ,1                              , &GFXSkyData},\r
530                 { GBSP_CHUNK_PALETTES           , sizeof(DRV_Palette)   ,NumGFXPalettes, GFXPalettes},\r
531                 { GBSP_CHUNK_MOTIONS            , sizeof(uint8)                 ,NumGFXMotionBytes, GFXMotionData},\r
532         };\r
533 \r
534         if (!WriteChunks(CurrentChunkData, sizeof(CurrentChunkData) / sizeof(CurrentChunkData[0]), f))\r
535         {\r
536                 GHook.Error("leaf StartWritingVis:  Could not write ChunkData.\n");\r
537                 return GE_FALSE;\r
538         }\r
539 \r
540         return GE_TRUE;\r
541 }\r
542 \r
543 //================================================================================\r
544 //      FinishWritingVis\r
545 //================================================================================\r
546 geBoolean FinishWritingVis(geVFile *f)\r
547 {\r
548         GBSP_ChunkData  ChunkDataEnd[] = {\r
549                 { GBSP_CHUNK_LEAFS      , sizeof(GFX_Leaf)              ,NumGFXLeafs   , GFXLeafs  },\r
550                 { GBSP_CHUNK_CLUSTERS   , sizeof(GFX_Cluster)   ,NumGFXClusters, GFXClusters},\r
551                 { GBSP_CHUNK_VISDATA    , sizeof(uint8)                 , NumGFXVisData, GFXVisData},\r
552                 { GBSP_CHUNK_END                , 0                                             ,0             , NULL },\r
553         };\r
554 \r
555         if (!WriteChunks(ChunkDataEnd, 4, f))\r
556         {\r
557                 GHook.Error("FinishWritingVis:  Could not write ChunkData.\n");\r
558                 return GE_FALSE;\r
559         }\r
560 \r
561         return GE_TRUE;\r
562 }\r
563 \r
564 //================================================================================\r
565 //      FreeAllVisData\r
566 //================================================================================\r
567 void FreeAllVisData(void)\r
568 {\r
569 \r
570         int32           i;\r
571 \r
572         if (LeafVisBits)\r
573                 geRam_Free(LeafVisBits);\r
574         LeafVisBits = NULL;\r
575 \r
576         GFXVisData = NULL;\r
577         NumGFXVisData = 0;\r
578 \r
579         if (VisPortals)\r
580         {\r
581                 for (i=0; i< NumVisPortals; i++)\r
582                 {\r
583                         FreePoly(VisPortals[i].Poly);\r
584 \r
585                         if (VisPortals[i].FinalVisBits)\r
586                                 geRam_Free(VisPortals[i].FinalVisBits);\r
587 \r
588                         if (VisPortals[i].VisBits)\r
589                                 geRam_Free(VisPortals[i].VisBits);\r
590                 }\r
591 \r
592                 geRam_Free(VisPortals);\r
593         }\r
594 \r
595         if (VisSortedPortals)\r
596                 geRam_Free(VisSortedPortals);\r
597         if (PortalSeen)\r
598                 geRam_Free(PortalSeen);\r
599         if (VisLeafs)\r
600                 geRam_Free(VisLeafs);\r
601 \r
602         VisPortals = NULL;\r
603         VisSortedPortals = NULL;\r
604         PortalSeen = NULL;\r
605         VisLeafs = NULL;\r
606 \r
607         FreeGBSPFile();         // Free rest of GBSP GFX data\r
608 }\r
609 \r
610 //================================================================================\r
611 //      CleanupVis\r
612 //================================================================================\r
613 void CleanupVis(void)\r
614 {\r
615         FreeAllVisData();\r
616 }\r
617 \r
618 //================================================================================\r
619 //      PComp\r
620 //================================================================================\r
621 int PComp(const void *a, const void *b)\r
622 {\r
623         if ( (*(VIS_Portal**)a)->MightSee == (*(VIS_Portal **)b)->MightSee)\r
624                 return 0;\r
625         if ( (*(VIS_Portal**)a)->MightSee < (*(VIS_Portal**)b)->MightSee)\r
626                 return -1;\r
627         return 1;\r
628 }\r
629 \r
630 //================================================================================\r
631 //      SortPortals\r
632 //================================================================================\r
633 void SortPortals(void)\r
634 {\r
635         int             i;\r
636         \r
637         for (i=0 ; i<NumVisPortals ; i++)\r
638                 VisSortedPortals[i] = &VisPortals[i];\r
639 \r
640         if (NoSort)\r
641                 return;\r
642 \r
643         qsort(VisSortedPortals, NumVisPortals, sizeof(VisSortedPortals[0]), PComp);\r
644 }\r
645 \r
646 //================================================================================\r
647 //      CalcPortalInfo\r
648 //================================================================================\r
649 geBoolean CalcPortalInfo(VIS_Portal *Portal)\r
650 {\r
651         geFloat         BestDist, Dist;\r
652         GBSP_Poly       *Poly;\r
653         geVec3d         Vect;\r
654         int32                   i;\r
655 \r
656         Poly = Portal->Poly;\r
657 \r
658         PolyCenter(Poly, &Portal->Center);      \r
659 \r
660         BestDist = 0.0f;\r
661 \r
662         for (i=0; i< Poly->NumVerts; i++)\r
663         {\r
664                 geVec3d_Subtract(&Poly->Verts[i], &Portal->Center, &Vect);\r
665 \r
666                 Dist = geVec3d_Length(&Vect);\r
667 \r
668                 if (Dist > BestDist)\r
669                         BestDist = Dist;\r
670         }\r
671 \r
672         Portal->Radius = BestDist;\r
673 \r
674         return GE_TRUE;\r
675 }