1 /****************************************************************************************/
\r
4 /* Author: John Pollard */
\r
5 /* Description: Vises a BSP */
\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 "GBSPFile.h"
\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
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
47 int32 TotalVisibleLeafs;
\r
49 geBoolean VisVerbose = GE_FALSE;
\r
50 geBoolean NoSort = GE_FALSE;
\r
51 geBoolean FullVis = GE_TRUE;
\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
60 //=======================================================================================
\r
62 //=======================================================================================
\r
63 geBoolean VisGBSPFile(char *FileName, VisParms *Parms)
\r
70 GHook.Printf(" --- Vis GBSP File --- \n");
\r
72 NoSort = !Parms->SortPortals;
\r
73 VisVerbose = Parms->Verbose;
\r
74 FullVis = Parms->FullVis;
\r
76 // Fill in the global bsp data
\r
77 if (!LoadGBSPFile(FileName))
\r
79 GHook.Error("PvsGBSPFile: Could not load GBSP file: %s\n", FileName);
\r
83 // Clean out any old vis data
\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
91 GHook.Error("VisGBSPFile: Could not open GBSP file for writing: %s.\n", FileName);
\r
95 // Prepare the portal file name
\r
96 strcpy(PFile, FileName);
\r
97 StripExtension(PFile);
\r
98 DefaultExtension(PFile, ".GPF");
\r
100 // Load the portal file
\r
101 if (!LoadPortalFile(PFile))
\r
102 goto ExitWithError;
\r
104 GHook.Printf("NumPortals : %5i\n", NumVisPortals);
\r
106 // Write out everything but vis info
\r
107 if (!StartWritingVis(f))
\r
108 goto ExitWithError;
\r
111 if (!VisAllLeafs())
\r
112 goto ExitWithError;
\r
114 // Record the vis data
\r
115 NumGFXVisData = NumVisLeafs*NumVisLeafBytes;
\r
116 GFXVisData = LeafVisBits;
\r
118 // Save the leafs, clusters, vis data, etc
\r
119 if (!FinishWritingVis(f))
\r
120 goto ExitWithError;
\r
122 // Free all the vis stuff
\r
125 // Free any remaining leftover bsp data
\r
135 GHook.Error("PvsGBSPFile: Could not vis the file: %s\n", FileName);
\r
147 //=======================================================================================
\r
149 //=======================================================================================
\r
150 void FreeFileVisData(void)
\r
153 geRam_Free(GFXVisData);
\r
159 //=======================================================================================
\r
161 //=======================================================================================
\r
162 geBoolean VisAllLeafs(void)
\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
171 goto ExitWithError;
\r
173 // Flood all the leafs with the fast method first...
\r
174 for (i=0; i< NumVisLeafs; i++)
\r
175 FloodLeafPortalsFast(i);
\r
177 // Check for cancel request
\r
180 GHook.Printf("Cancel requested...\n");
\r
181 goto ExitWithError;
\r
184 // Sort the portals with MightSee
\r
188 if (!FloodPortalsSlow())
\r
191 // Don't need this anymore...
\r
192 geRam_Free(PortalSeen);
\r
195 LeafVisBits = GE_RAM_ALLOCATE_ARRAY(uint8,NumVisLeafs*NumVisLeafBytes);
\r
199 GHook.Error("VisAllLeafs: Out of memory for LeafVisBits.\n");
\r
200 goto ExitWithError;
\r
203 memset(LeafVisBits, 0, NumVisLeafs*NumVisLeafBytes);
\r
204 TotalVisibleLeafs = 0;
\r
206 PortalBits = GE_RAM_ALLOCATE_ARRAY(uint8,NumVisPortalBytes);
\r
209 goto ExitWithError;
\r
211 for (i=0; i< NumVisLeafs; i++)
\r
215 if (!CollectLeafVisBits(i))
\r
216 goto ExitWithError;
\r
218 TotalVisibleLeafs += LeafSee;
\r
220 geRam_Free(PortalBits);
\r
222 GHook.Printf("Total visible areas : %5i\n", TotalVisibleLeafs);
\r
223 GHook.Printf("Average visible from each area: %5i\n", TotalVisibleLeafs / NumVisLeafs);
\r
230 // Free all the global vis data
\r
237 //=======================================================================================
\r
238 // CollectLeafVisBits
\r
239 //=======================================================================================
\r
240 geBoolean CollectLeafVisBits(int32 LeafNum)
\r
242 VIS_Portal *Portal, *SPortal;
\r
244 uint8 *LeafBits, *VisBits;
\r
245 int32 k, Bit, SLeaf;
\r
247 Leaf = &VisLeafs[LeafNum];
\r
249 LeafBits = &LeafVisBits[LeafNum * NumVisLeafBytes];
\r
251 memset(PortalBits, 0, NumVisPortalBytes);
\r
253 // 'OR' all portals that this portal can see into one list
\r
254 for (Portal = Leaf->Portals; Portal; Portal = Portal->Next)
\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
262 GHook.Error("No VisInfo for portal.\n");
\r
266 for (k=0; k< NumVisPortalBytes; k++)
\r
267 PortalBits[k] |= VisBits[k];
\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
274 Portal->VisBits = NULL;
\r
275 Portal->FinalVisBits = NULL;
\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
281 if (PortalBits[k>>3] & (1<<(k&7)) )
\r
283 SPortal = VisPortals+k;
\r
284 SLeaf = SPortal->Leaf;
\r
285 LeafBits[SLeaf>>3] |= 1<<(SLeaf&7);
\r
289 Bit = 1<<(LeafNum&7);
\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
295 LeafBits[LeafNum>>3] |= Bit; // Make sure he can see himself!!!
\r
297 for (k=0; k< NumVisLeafs; k++)
\r
300 if ((LeafBits[k>>3] & Bit) )
\r
306 GHook.Error("CollectLeafVisBits: Leaf can't see nothing.\n");
\r
310 GFXClusters[LeafNum].VisOfs = (int32)(LeafBits - LeafVisBits);
\r
315 //=======================================================================================
\r
317 //=======================================================================================
\r
318 geBoolean LoadPortalFile(char *FileName)
\r
320 int32 LeafFrom, LeafTo;
\r
321 VIS_Portal *pPortal;
\r
331 f = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_DOS, FileName, NULL, GE_VFILE_OPEN_READONLY);
\r
335 GHook.Error("LoadPortalFile: Could not open %s for reading.\n", FileName);
\r
336 goto ExitWithError;
\r
342 if (geVFile_Read(f, TAG, sizeof(char) * 12) != GE_TRUE)
\r
344 GHook.Error("LoadPortalFile: Error reading portal file TAG.\n");
\r
345 goto ExitWithError;
\r
348 if (strncmp(TAG, "GBSP_PRTFILE", 12))
\r
350 GHook.Error("LoadPortalFile: %s is not a GBSP Portal file.\n", FileName);
\r
351 goto ExitWithError;
\r
355 // Get the number of portals
\r
357 if (geVFile_Read(f, &NumVisPortals, sizeof(int32)) != GE_TRUE)
\r
359 GHook.Error("LoadPortalFile: Error reading NumVisPortals.\n");
\r
360 goto ExitWithError;
\r
363 if (NumVisPortals >= MAX_TEMP_PORTALS)
\r
365 GHook.Error("LoadPortalFile: Max portals for temp buffers.\n");
\r
366 goto ExitWithError;
\r
369 VisPortals = GE_RAM_ALLOCATE_ARRAY(VIS_Portal,NumVisPortals);
\r
373 GHook.Error("LoadPortalFile: Out of memory for VisPortals.\n");
\r
374 goto ExitWithError;
\r
377 memset(VisPortals, 0, sizeof(VIS_Portal)*NumVisPortals);
\r
379 VisSortedPortals = GE_RAM_ALLOCATE_ARRAY(pVIS_Portal,NumVisPortals);
\r
381 if (!VisSortedPortals)
\r
383 GHook.Error("LoadPortalFile: Out of memory for VisSortedPortals.\n");
\r
384 goto ExitWithError;
\r
388 // Get the number of leafs
\r
390 if (geVFile_Read(f, &NumVisLeafs, sizeof(int32)) != GE_TRUE)
\r
392 GHook.Error("LoadPortalFile: Error reading NumVisLeafs.\n");
\r
393 goto ExitWithError;
\r
396 if (NumVisLeafs > NumGFXLeafs)
\r
397 goto ExitWithError;
\r
399 VisLeafs = GE_RAM_ALLOCATE_ARRAY(VIS_Leaf,NumVisLeafs);
\r
402 GHook.Error("LoadPortalFile: Out of memory for VisLeafs.\n");
\r
403 goto ExitWithError;
\r
406 memset(VisLeafs, 0, sizeof(VIS_Leaf)*NumVisLeafs);
\r
409 // Load in the portals
\r
411 for (i=0; i< NumVisPortals; i++)
\r
413 if (geVFile_Read(f, &NumVerts, sizeof(int32)) != GE_TRUE)
\r
415 GHook.Error("LoadPortalFile: Error reading NumVerts.\n");
\r
416 goto ExitWithError;
\r
419 pPoly = AllocPoly(NumVerts);
\r
422 goto ExitWithError;
\r
424 if (geVFile_Read(f, pPoly->Verts, sizeof(geVec3d) * NumVerts) != GE_TRUE)
\r
426 GHook.Error("LoadPortalFile: Error reading portal vertices.\n");
\r
427 goto ExitWithError;
\r
430 if (geVFile_Read(f, &LeafFrom, sizeof(int32)) != GE_TRUE)
\r
432 GHook.Error("LoadPortalFile: Error reading portal LeafFrom.\n");
\r
433 goto ExitWithError;
\r
436 if (geVFile_Read(f, &LeafTo, sizeof(int32)) != GE_TRUE)
\r
438 GHook.Error("LoadPortalFile: Error reading portal LeafTo.\n");
\r
439 goto ExitWithError;
\r
442 if (LeafFrom >= NumVisLeafs || LeafFrom < 0)
\r
444 GHook.Error("LoadPortalFile: Invalid LeafFrom: %i.\n", LeafFrom);
\r
445 goto ExitWithError;
\r
448 if (LeafTo >= NumVisLeafs || LeafTo < 0)
\r
450 GHook.Error("LoadPortalFile: Invalid LeafTo: %i.\n", LeafTo);
\r
451 goto ExitWithError;
\r
454 pLeaf = &VisLeafs[LeafFrom];
\r
455 pPortal = &VisPortals[i];
\r
457 pPortal->Poly = pPoly;
\r
458 pPortal->Leaf = LeafTo;
\r
459 PlaneFromVerts(pPoly->Verts, &pPortal->Plane);
\r
461 pPortal->Next = pLeaf->Portals;
\r
462 pLeaf->Portals = pPortal;
\r
464 CalcPortalInfo(pPortal);
\r
467 NumVisLeafBytes = ((NumVisLeafs+63)&~63) >> 3;
\r
468 NumVisPortalBytes = ((NumVisPortals+63)&~63) >> 3;
\r
470 NumVisPortalLongs = NumVisPortalBytes/sizeof(uint32);
\r
471 NumVisLeafLongs = NumVisLeafBytes/sizeof(uint32);
\r
484 geRam_Free(VisPortals);
\r
485 if (VisSortedPortals)
\r
486 geRam_Free(VisSortedPortals);
\r
488 geRam_Free(VisLeafs);
\r
494 VisSortedPortals = NULL;
\r
502 //================================================================================
\r
504 //================================================================================
\r
505 geBoolean StartWritingVis(geVFile *f)
\r
507 // Write out everything but the vis data
\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
534 if (!WriteChunks(CurrentChunkData, sizeof(CurrentChunkData) / sizeof(CurrentChunkData[0]), f))
\r
536 GHook.Error("leaf StartWritingVis: Could not write ChunkData.\n");
\r
543 //================================================================================
\r
544 // FinishWritingVis
\r
545 //================================================================================
\r
546 geBoolean FinishWritingVis(geVFile *f)
\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
555 if (!WriteChunks(ChunkDataEnd, 4, f))
\r
557 GHook.Error("FinishWritingVis: Could not write ChunkData.\n");
\r
564 //================================================================================
\r
566 //================================================================================
\r
567 void FreeAllVisData(void)
\r
573 geRam_Free(LeafVisBits);
\r
574 LeafVisBits = NULL;
\r
581 for (i=0; i< NumVisPortals; i++)
\r
583 FreePoly(VisPortals[i].Poly);
\r
585 if (VisPortals[i].FinalVisBits)
\r
586 geRam_Free(VisPortals[i].FinalVisBits);
\r
588 if (VisPortals[i].VisBits)
\r
589 geRam_Free(VisPortals[i].VisBits);
\r
592 geRam_Free(VisPortals);
\r
595 if (VisSortedPortals)
\r
596 geRam_Free(VisSortedPortals);
\r
598 geRam_Free(PortalSeen);
\r
600 geRam_Free(VisLeafs);
\r
603 VisSortedPortals = NULL;
\r
607 FreeGBSPFile(); // Free rest of GBSP GFX data
\r
610 //================================================================================
\r
612 //================================================================================
\r
613 void CleanupVis(void)
\r
618 //================================================================================
\r
620 //================================================================================
\r
621 int PComp(const void *a, const void *b)
\r
623 if ( (*(VIS_Portal**)a)->MightSee == (*(VIS_Portal **)b)->MightSee)
\r
625 if ( (*(VIS_Portal**)a)->MightSee < (*(VIS_Portal**)b)->MightSee)
\r
630 //================================================================================
\r
632 //================================================================================
\r
633 void SortPortals(void)
\r
637 for (i=0 ; i<NumVisPortals ; i++)
\r
638 VisSortedPortals[i] = &VisPortals[i];
\r
643 qsort(VisSortedPortals, NumVisPortals, sizeof(VisSortedPortals[0]), PComp);
\r
646 //================================================================================
\r
648 //================================================================================
\r
649 geBoolean CalcPortalInfo(VIS_Portal *Portal)
\r
651 geFloat BestDist, Dist;
\r
656 Poly = Portal->Poly;
\r
658 PolyCenter(Poly, &Portal->Center);
\r
662 for (i=0; i< Poly->NumVerts; i++)
\r
664 geVec3d_Subtract(&Poly->Verts[i], &Portal->Center, &Vect);
\r
666 Dist = geVec3d_Length(&Vect);
\r
668 if (Dist > BestDist)
\r
672 Portal->Radius = BestDist;
\r