Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

vis.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // vis.c
00023 
00024 #include "vis.h"
00025 #include "threads.h"
00026 #include "stdlib.h"
00027 #ifdef _WIN32
00028 #include "../libs/pakstuff.h"
00029 #endif
00030 
00031 
00032 #define VIS_HEADER_SIZE 8
00033 
00034 extern  char        outbase[32];
00035 
00036 int         numportals;
00037 int         portalclusters;
00038 int         numfaces;
00039 
00040 char        inbase[32];
00041 
00042 vportal_t   *portals;
00043 leaf_t      *leafs;
00044 
00045 vportal_t   *faces;
00046 leaf_t      *faceleafs;
00047 
00048 int         c_portaltest, c_portalpass, c_portalcheck;
00049 
00050 int     leafbytes;              // (portalclusters+63)>>3
00051 int     leaflongs;
00052 
00053 int     portalbytes, portallongs;
00054 
00055 qboolean        fastvis;
00056 qboolean        noPassageVis;
00057 qboolean        passageVisOnly;
00058 qboolean        mergevis;
00059 qboolean        nosort;
00060 qboolean        saveprt;
00061 
00062 int         testlevel = 2;
00063 
00064 int     totalvis;
00065 
00066 vportal_t   *sorted_portals[MAX_MAP_PORTALS*2];
00067 
00068 void PassageMemory(void);
00069 
00070 
00071 //=============================================================================
00072 
00073 void PlaneFromWinding (winding_t *w, plane_t *plane)
00074 {
00075     vec3_t      v1, v2;
00076 
00077 // calc plane
00078     VectorSubtract (w->points[2], w->points[1], v1);
00079     VectorSubtract (w->points[0], w->points[1], v2);
00080     CrossProduct (v2, v1, plane->normal);
00081     VectorNormalize (plane->normal, plane->normal);
00082     plane->dist = DotProduct (w->points[0], plane->normal);
00083 }
00084 
00085 
00086 /*
00087 ==================
00088 NewWinding
00089 ==================
00090 */
00091 winding_t *NewWinding (int points)
00092 {
00093     winding_t   *w;
00094     int         size;
00095     
00096     if (points > MAX_POINTS_ON_WINDING)
00097         Error ("NewWinding: %i points", points);
00098     
00099     size = (int)((winding_t *)0)->points[points];
00100     w = malloc (size);
00101     memset (w, 0, size);
00102     
00103     return w;
00104 }
00105 
00106 
00107 
00108 void prl(leaf_t *l)
00109 {
00110     int         i;
00111     vportal_t   *p;
00112     plane_t     pl;
00113     
00114     for (i=0 ; i<l->numportals ; i++)
00115     {
00116         p = l->portals[i];
00117         pl = p->plane;
00118         _printf ("portal %4i to leaf %4i : %7.1f : (%4.1f, %4.1f, %4.1f)\n",(int)(p-portals),p->leaf,pl.dist, pl.normal[0], pl.normal[1], pl.normal[2]);
00119     }
00120 }
00121 
00122 
00123 //=============================================================================
00124 
00125 /*
00126 =============
00127 SortPortals
00128 
00129 Sorts the portals from the least complex, so the later ones can reuse
00130 the earlier information.
00131 =============
00132 */
00133 int PComp (const void *a, const void *b)
00134 {
00135     if ( (*(vportal_t **)a)->nummightsee == (*(vportal_t **)b)->nummightsee)
00136         return 0;
00137     if ( (*(vportal_t **)a)->nummightsee < (*(vportal_t **)b)->nummightsee)
00138         return -1;
00139     return 1;
00140 }
00141 void SortPortals (void)
00142 {
00143     int     i;
00144     
00145     for (i=0 ; i<numportals*2 ; i++)
00146         sorted_portals[i] = &portals[i];
00147 
00148     if (nosort)
00149         return;
00150     qsort (sorted_portals, numportals*2, sizeof(sorted_portals[0]), PComp);
00151 }
00152 
00153 
00154 /*
00155 ==============
00156 LeafVectorFromPortalVector
00157 ==============
00158 */
00159 int LeafVectorFromPortalVector (byte *portalbits, byte *leafbits)
00160 {
00161     int         i, j, leafnum;
00162     vportal_t   *p;
00163     int         c_leafs;
00164 
00165 
00166     for (i=0 ; i<numportals*2 ; i++)
00167     {
00168         if (portalbits[i>>3] & (1<<(i&7)) )
00169         {
00170             p = portals+i;
00171             leafbits[p->leaf>>3] |= (1<<(p->leaf&7));
00172         }
00173     }
00174 
00175     for (j = 0; j < portalclusters; j++)
00176     {
00177         leafnum = j;
00178         while (leafs[leafnum].merged >= 0)
00179             leafnum = leafs[leafnum].merged;
00180         //if the merged leaf is visible then the original leaf is visible
00181         if (leafbits[leafnum>>3] & (1<<(leafnum&7)))
00182         {
00183             leafbits[j>>3] |= (1<<(j&7));
00184         }
00185     }
00186 
00187     c_leafs = CountBits (leafbits, portalclusters);
00188 
00189     return c_leafs;
00190 }
00191 
00192 
00193 /*
00194 ===============
00195 ClusterMerge
00196 
00197 Merges the portal visibility for a leaf
00198 ===============
00199 */
00200 void ClusterMerge (int leafnum)
00201 {
00202     leaf_t      *leaf;
00203     byte        portalvector[MAX_PORTALS/8];
00204     byte        uncompressed[MAX_MAP_LEAFS/8];
00205     int         i, j;
00206     int         numvis, mergedleafnum;
00207     vportal_t   *p;
00208     int         pnum;
00209 
00210     // OR together all the portalvis bits
00211 
00212     mergedleafnum = leafnum;
00213     while(leafs[mergedleafnum].merged >= 0)
00214         mergedleafnum = leafs[mergedleafnum].merged;
00215 
00216     memset (portalvector, 0, portalbytes);
00217     leaf = &leafs[mergedleafnum];
00218     for (i = 0; i < leaf->numportals; i++)
00219     {
00220         p = leaf->portals[i];
00221         if (p->removed)
00222             continue;
00223 
00224         if (p->status != stat_done)
00225             Error ("portal not done");
00226         for (j=0 ; j<portallongs ; j++)
00227             ((long *)portalvector)[j] |= ((long *)p->portalvis)[j];
00228         pnum = p - portals;
00229         portalvector[pnum>>3] |= 1<<(pnum&7);
00230     }
00231 
00232     memset (uncompressed, 0, leafbytes);
00233 
00234     uncompressed[mergedleafnum>>3] |= (1<<(mergedleafnum&7));
00235     // convert portal bits to leaf bits
00236     numvis = LeafVectorFromPortalVector (portalvector, uncompressed);
00237 
00238 //  if (uncompressed[leafnum>>3] & (1<<(leafnum&7)))
00239 //      _printf ("WARNING: Leaf portals saw into leaf\n");
00240         
00241 //  uncompressed[leafnum>>3] |= (1<<(leafnum&7));
00242 
00243     numvis++;       // count the leaf itself
00244 
00245     totalvis += numvis;
00246 
00247     qprintf ("cluster %4i : %4i visible\n", leafnum, numvis);
00248 
00249     memcpy (visBytes + VIS_HEADER_SIZE + leafnum*leafbytes, uncompressed, leafbytes);
00250 }
00251 
00252 /*
00253 ==================
00254 CalcPortalVis
00255 ==================
00256 */
00257 void CalcPortalVis (void)
00258 {
00259 #ifdef MREDEBUG
00260     _printf("%6d portals out of %d", 0, numportals*2);
00261     //get rid of the counter
00262     RunThreadsOnIndividual (numportals*2, qfalse, PortalFlow);
00263 #else
00264     RunThreadsOnIndividual (numportals*2, qtrue, PortalFlow);
00265 #endif
00266 
00267 }
00268 
00269 /*
00270 ==================
00271 CalcPassageVis
00272 ==================
00273 */
00274 void CalcPassageVis(void)
00275 {
00276     PassageMemory();
00277 
00278 #ifdef MREDEBUG
00279     _printf("%6d portals out of %d", 0, numportals*2);
00280     RunThreadsOnIndividual (numportals*2, qfalse, CreatePassages);
00281     _printf("\n");
00282     _printf("%6d portals out of %d", 0, numportals*2);
00283     RunThreadsOnIndividual (numportals*2, qfalse, PassageFlow);
00284     _printf("\n");
00285 #else
00286     RunThreadsOnIndividual (numportals*2, qtrue, CreatePassages);
00287     RunThreadsOnIndividual (numportals*2, qtrue, PassageFlow);
00288 #endif
00289 }
00290 
00291 /*
00292 ==================
00293 CalcPassagePortalVis
00294 ==================
00295 */
00296 void CalcPassagePortalVis(void)
00297 {
00298     PassageMemory();
00299 
00300 #ifdef MREDEBUG
00301     _printf("%6d portals out of %d", 0, numportals*2);
00302     RunThreadsOnIndividual (numportals*2, qfalse, CreatePassages);
00303     _printf("\n");
00304     _printf("%6d portals out of %d", 0, numportals*2);
00305     RunThreadsOnIndividual (numportals*2, qfalse, PassagePortalFlow);
00306     _printf("\n");
00307 #else
00308     RunThreadsOnIndividual (numportals*2, qtrue, CreatePassages);
00309     RunThreadsOnIndividual (numportals*2, qtrue, PassagePortalFlow);
00310 #endif
00311 }
00312 
00313 /*
00314 ==================
00315 CalcFastVis
00316 ==================
00317 */
00318 void CalcFastVis(void)
00319 {
00320     int     i;
00321 
00322     // fastvis just uses mightsee for a very loose bound
00323     for (i=0 ; i<numportals*2 ; i++)
00324     {
00325         portals[i].portalvis = portals[i].portalflood;
00326         portals[i].status = stat_done;
00327     }
00328 }
00329 
00330 /*
00331 ==================
00332 CalcVis
00333 ==================
00334 */
00335 void CalcVis (void)
00336 {
00337     int     i;
00338 
00339     RunThreadsOnIndividual (numportals*2, qtrue, BasePortalVis);
00340 
00341 //  RunThreadsOnIndividual (numportals*2, qtrue, BetterPortalVis);
00342 
00343     SortPortals ();
00344 
00345     if (fastvis) {
00346         CalcFastVis();
00347     }
00348     else if ( noPassageVis ) {
00349         CalcPortalVis();
00350     }
00351     else if ( passageVisOnly ) {
00352         CalcPassageVis();
00353     }
00354     else {
00355         CalcPassagePortalVis();
00356     }
00357     //
00358     // assemble the leaf vis lists by oring and compressing the portal lists
00359     //
00360     _printf("creating leaf vis...\n");
00361     for (i=0 ; i<portalclusters ; i++)
00362         ClusterMerge (i);
00363 
00364     _printf( "Total visible clusters: %i\n", totalvis );
00365     _printf( "Average clusters visible: %i\n", totalvis / portalclusters );
00366 }
00367 
00368 /*
00369 ==================
00370 SetPortalSphere
00371 ==================
00372 */
00373 void SetPortalSphere (vportal_t *p)
00374 {
00375     int     i;
00376     vec3_t  total, dist;
00377     winding_t   *w;
00378     float   r, bestr;
00379 
00380     w = p->winding;
00381     VectorCopy (vec3_origin, total);
00382     for (i=0 ; i<w->numpoints ; i++)
00383     {
00384         VectorAdd (total, w->points[i], total);
00385     }
00386     
00387     for (i=0 ; i<3 ; i++)
00388         total[i] /= w->numpoints;
00389 
00390     bestr = 0;      
00391     for (i=0 ; i<w->numpoints ; i++)
00392     {
00393         VectorSubtract (w->points[i], total, dist);
00394         r = VectorLength (dist);
00395         if (r > bestr)
00396             bestr = r;
00397     }
00398     VectorCopy (total, p->origin);
00399     p->radius = bestr;
00400 }
00401 
00402 /*
00403 =============
00404 Winding_PlanesConcave
00405 =============
00406 */
00407 #define WCONVEX_EPSILON     0.2
00408 
00409 int Winding_PlanesConcave(winding_t *w1, winding_t *w2,
00410                              vec3_t normal1, vec3_t normal2,
00411                              float dist1, float dist2)
00412 {
00413     int i;
00414 
00415     if (!w1 || !w2) return qfalse;
00416 
00417     // check if one of the points of winding 1 is at the front of the plane of winding 2
00418     for (i = 0; i < w1->numpoints; i++)
00419     {
00420         if (DotProduct(normal2, w1->points[i]) - dist2 > WCONVEX_EPSILON) return qtrue;
00421     }
00422     // check if one of the points of winding 2 is at the front of the plane of winding 1
00423     for (i = 0; i < w2->numpoints; i++)
00424     {
00425         if (DotProduct(normal1, w2->points[i]) - dist1 > WCONVEX_EPSILON) return qtrue;
00426     }
00427 
00428     return qfalse;
00429 }
00430 
00431 /*
00432 ============
00433 TryMergeLeaves
00434 ============
00435 */
00436 int TryMergeLeaves(int l1num, int l2num)
00437 {
00438     int i, j, k, n, numportals;
00439     plane_t plane1, plane2;
00440     leaf_t *l1, *l2;
00441     vportal_t *p1, *p2;
00442     vportal_t *portals[MAX_PORTALS_ON_LEAF];
00443 
00444     for (k = 0; k < 2; k++)
00445     {
00446         if (k) l1 = &leafs[l1num];
00447         else l1 = &faceleafs[l1num];
00448         for (i = 0; i < l1->numportals; i++)
00449         {
00450             p1 = l1->portals[i];
00451             if (p1->leaf == l2num) continue;
00452             for (n = 0; n < 2; n++)
00453             {
00454                 if (n) l2 = &leafs[l2num];
00455                 else l2 = &faceleafs[l2num];
00456                 for (j = 0; j < l2->numportals; j++)
00457                 {
00458                     p2 = l2->portals[j];
00459                     if (p2->leaf == l1num) continue;
00460                     //
00461                     plane1 = p1->plane;
00462                     plane2 = p2->plane;
00463                     if (Winding_PlanesConcave(p1->winding, p2->winding, plane1.normal, plane2.normal, plane1.dist, plane2.dist))
00464                         return qfalse;
00465                 }
00466             }
00467         }
00468     }
00469     for (k = 0; k < 2; k++)
00470     {
00471         if (k)
00472         {
00473             l1 = &leafs[l1num];
00474             l2 = &leafs[l2num];
00475         }
00476         else
00477         {
00478             l1 = &faceleafs[l1num];
00479             l2 = &faceleafs[l2num];
00480         }
00481         numportals = 0;
00482         //the leaves can be merged now
00483         for (i = 0; i < l1->numportals; i++)
00484         {
00485             p1 = l1->portals[i];
00486             if (p1->leaf == l2num)
00487             {
00488                 p1->removed = qtrue;
00489                 continue;
00490             }
00491             portals[numportals++] = p1;
00492         }
00493         for (j = 0; j < l2->numportals; j++)
00494         {
00495             p2 = l2->portals[j];
00496             if (p2->leaf == l1num)
00497             {
00498                 p2->removed = qtrue;
00499                 continue;
00500             }
00501             portals[numportals++] = p2;
00502         }
00503         for (i = 0; i < numportals; i++)
00504         {
00505             l2->portals[i] = portals[i];
00506         }
00507         l2->numportals = numportals;
00508         l1->merged = l2num;
00509     }
00510     return qtrue;
00511 }
00512 
00513 /*
00514 ============
00515 UpdatePortals
00516 ============
00517 */
00518 void UpdatePortals(void)
00519 {
00520     int i;
00521     vportal_t *p;
00522 
00523     for (i = 0; i < numportals * 2; i++)
00524     {
00525         p = &portals[i];
00526         if (p->removed)
00527             continue;
00528         while(leafs[p->leaf].merged >= 0)
00529             p->leaf = leafs[p->leaf].merged;
00530     }
00531 }
00532 
00533 /*
00534 ============
00535 MergeLeaves
00536 
00537 try to merge leaves but don't merge through hint splitters
00538 ============
00539 */
00540 void MergeLeaves(void)
00541 {
00542     int i, j, nummerges, totalnummerges;
00543     leaf_t *leaf;
00544     vportal_t *p;
00545 
00546     totalnummerges = 0;
00547     do
00548     {
00549         nummerges = 0;
00550         for (i = 0; i < portalclusters; i++)
00551         {
00552             leaf = &leafs[i];
00553             //if this leaf is merged already
00554             if (leaf->merged >= 0)
00555                 continue;
00556             //
00557             for (j = 0; j < leaf->numportals; j++)
00558             {
00559                 p = leaf->portals[j];
00560                 //
00561                 if (p->removed)
00562                     continue;
00563                 //never merge through hint portals
00564                 if (p->hint)
00565                     continue;
00566                 if (TryMergeLeaves(i, p->leaf))
00567                 {
00568                     UpdatePortals();
00569                     nummerges++;
00570                     break;
00571                 }
00572             }
00573         }
00574         totalnummerges += nummerges;
00575     } while (nummerges);
00576     _printf("%6d leaves merged\n", totalnummerges);
00577 }
00578 
00579 /*
00580 ============
00581 TryMergeWinding
00582 ============
00583 */
00584 #define CONTINUOUS_EPSILON  0.005
00585 
00586 winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal)
00587 {
00588     vec_t       *p1, *p2, *p3, *p4, *back;
00589     winding_t   *newf;
00590     int         i, j, k, l;
00591     vec3_t      normal, delta;
00592     vec_t       dot;
00593     qboolean    keep1, keep2;
00594     
00595 
00596     //
00597     // find a common edge
00598     //  
00599     p1 = p2 = NULL; // stop compiler warning
00600     j = 0;          // 
00601     
00602     for (i = 0; i < f1->numpoints; i++)
00603     {
00604         p1 = f1->points[i];
00605         p2 = f1->points[(i+1) % f1->numpoints];
00606         for (j = 0; j < f2->numpoints; j++)
00607         {
00608             p3 = f2->points[j];
00609             p4 = f2->points[(j+1) % f2->numpoints];
00610             for (k = 0; k < 3; k++)
00611             {
00612                 if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME
00613                     break;
00614                 if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME
00615                     break;
00616             } //end for
00617             if (k==3)
00618                 break;
00619         } //end for
00620         if (j < f2->numpoints)
00621             break;
00622     } //end for
00623     
00624     if (i == f1->numpoints)
00625         return NULL;            // no matching edges
00626 
00627     //
00628     // check slope of connected lines
00629     // if the slopes are colinear, the point can be removed
00630     //
00631     back = f1->points[(i+f1->numpoints-1)%f1->numpoints];
00632     VectorSubtract (p1, back, delta);
00633     CrossProduct (planenormal, delta, normal);
00634     VectorNormalize (normal, normal);
00635     
00636     back = f2->points[(j+2)%f2->numpoints];
00637     VectorSubtract (back, p1, delta);
00638     dot = DotProduct (delta, normal);
00639     if (dot > CONTINUOUS_EPSILON)
00640         return NULL;            // not a convex polygon
00641     keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON);
00642     
00643     back = f1->points[(i+2)%f1->numpoints];
00644     VectorSubtract (back, p2, delta);
00645     CrossProduct (planenormal, delta, normal);
00646     VectorNormalize (normal, normal);
00647 
00648     back = f2->points[(j+f2->numpoints-1)%f2->numpoints];
00649     VectorSubtract (back, p2, delta);
00650     dot = DotProduct (delta, normal);
00651     if (dot > CONTINUOUS_EPSILON)
00652         return NULL;            // not a convex polygon
00653     keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON);
00654 
00655     //
00656     // build the new polygon
00657     //
00658     newf = NewWinding (f1->numpoints + f2->numpoints);
00659     
00660     // copy first polygon
00661     for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
00662     {
00663         if (k==(i+1)%f1->numpoints && !keep2)
00664             continue;
00665         
00666         VectorCopy (f1->points[k], newf->points[newf->numpoints]);
00667         newf->numpoints++;
00668     }
00669     
00670     // copy second polygon
00671     for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
00672     {
00673         if (l==(j+1)%f2->numpoints && !keep1)
00674             continue;
00675         VectorCopy (f2->points[l], newf->points[newf->numpoints]);
00676         newf->numpoints++;
00677     }
00678 
00679     return newf;
00680 }
00681 
00682 /*
00683 ============
00684 MergeLeafPortals
00685 ============
00686 */
00687 void MergeLeafPortals(void)
00688 {
00689     int i, j, k, nummerges, hintsmerged;
00690     leaf_t *leaf;
00691     vportal_t *p1, *p2;
00692     winding_t *w;
00693 
00694     nummerges = 0;
00695     hintsmerged = 0;
00696     for (i = 0; i < portalclusters; i++)
00697     {
00698         leaf = &leafs[i];
00699         if (leaf->merged >= 0) continue;
00700         for (j = 0; j < leaf->numportals; j++)
00701         {
00702             p1 = leaf->portals[j];
00703             if (p1->removed)
00704                 continue;
00705             for (k = j+1; k < leaf->numportals; k++)
00706             {
00707                 p2 = leaf->portals[k];
00708                 if (p2->removed)
00709                     continue;
00710                 if (p1->leaf == p2->leaf)
00711                 {
00712                     w = TryMergeWinding(p1->winding, p2->winding, p1->plane.normal);
00713                     if (w)
00714                     {
00715                         FreeWinding(p1->winding);
00716                         p1->winding = w;
00717                         if (p1->hint && p2->hint)
00718                             hintsmerged++;
00719                         p1->hint |= p2->hint;
00720                         SetPortalSphere(p1);
00721                         p2->removed = qtrue;
00722                         nummerges++;
00723                         i--;
00724                         break;
00725                     }
00726                 }
00727             }
00728             if (k < leaf->numportals)
00729                 break;
00730         }
00731     }
00732     _printf("%6d portals merged\n", nummerges);
00733     _printf("%6d hint portals merged\n", hintsmerged);
00734 }
00735 
00736 
00737 /*
00738 ============
00739 WritePortals
00740 ============
00741 */
00742 int CountActivePortals(void)
00743 {
00744     int num, hints, j;
00745     vportal_t *p;
00746 
00747     num = 0;
00748     hints = 0;
00749     for (j = 0; j < numportals * 2; j++)
00750     {
00751         p = portals + j;
00752         if (p->removed)
00753             continue;
00754         if (p->hint)
00755             hints++;
00756         num++;
00757     }
00758     _printf("%6d active portals\n", num);
00759     _printf("%6d hint portals\n", hints);
00760     return num;
00761 }
00762 
00763 /*
00764 ============
00765 WritePortals
00766 ============
00767 */
00768 void WriteFloat (FILE *f, vec_t v);
00769 
00770 void WritePortals(char *filename)
00771 {
00772     int i, j, num;
00773     FILE *pf;
00774     vportal_t *p;
00775     winding_t *w;
00776 
00777     // write the file
00778     pf = fopen (filename, "w");
00779     if (!pf)
00780         Error ("Error opening %s", filename);
00781 
00782     num = 0;
00783     for (j = 0; j < numportals * 2; j++)
00784     {
00785         p = portals + j;
00786         if (p->removed)
00787             continue;
00788 //      if (!p->hint)
00789 //          continue;
00790         num++;
00791     }
00792 
00793     fprintf (pf, "%s\n", PORTALFILE);
00794     fprintf (pf, "%i\n", 0);
00795     fprintf (pf, "%i\n", num);// + numfaces);
00796     fprintf (pf, "%i\n", 0);
00797 
00798     for (j = 0; j < numportals * 2; j++)
00799     {
00800         p = portals + j;
00801         if (p->removed)
00802             continue;
00803 //      if (!p->hint)
00804 //          continue;
00805         w = p->winding;
00806         fprintf (pf,"%i %i %i ",w->numpoints, 0, 0);
00807         fprintf (pf, "%d ", p->hint);
00808         for (i=0 ; i<w->numpoints ; i++)
00809         {
00810             fprintf (pf,"(");
00811             WriteFloat (pf, w->points[i][0]);
00812             WriteFloat (pf, w->points[i][1]);
00813             WriteFloat (pf, w->points[i][2]);
00814             fprintf (pf,") ");
00815         }
00816         fprintf (pf,"\n");
00817     }
00818 
00819     /*
00820     for (j = 0; j < numfaces; j++)
00821     {
00822         p = faces + j;
00823         w = p->winding;
00824         fprintf (pf,"%i %i %i ",w->numpoints, 0, 0);
00825         fprintf (pf, "0 ");
00826         for (i=0 ; i<w->numpoints ; i++)
00827         {
00828             fprintf (pf,"(");
00829             WriteFloat (pf, w->points[i][0]);
00830             WriteFloat (pf, w->points[i][1]);
00831             WriteFloat (pf, w->points[i][2]);
00832             fprintf (pf,") ");
00833         }
00834         fprintf (pf,"\n");
00835     }*/
00836 
00837     fclose (pf);
00838 }
00839 
00840 /*
00841 ============
00842 LoadPortals
00843 ============
00844 */
00845 void LoadPortals (char *name)
00846 {
00847     int         i, j, hint;
00848     vportal_t   *p;
00849     leaf_t      *l;
00850     char        magic[80];
00851     FILE        *f;
00852     int         numpoints;
00853     winding_t   *w;
00854     int         leafnums[2];
00855     plane_t     plane;
00856     
00857     if (!strcmp(name,"-"))
00858         f = stdin;
00859     else
00860     {
00861         f = fopen(name, "r");
00862         if (!f)
00863             Error ("LoadPortals: couldn't read %s\n",name);
00864     }
00865 
00866     if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4)
00867         Error ("LoadPortals: failed to read header");
00868     if (strcmp(magic,PORTALFILE))
00869         Error ("LoadPortals: not a portal file");
00870 
00871     _printf ("%6i portalclusters\n", portalclusters);
00872     _printf ("%6i numportals\n", numportals);
00873     _printf ("%6i numfaces\n", numfaces);
00874 
00875     // these counts should take advantage of 64 bit systems automatically
00876     leafbytes = ((portalclusters+63)&~63)>>3;
00877     leaflongs = leafbytes/sizeof(long);
00878     
00879     portalbytes = ((numportals*2+63)&~63)>>3;
00880     portallongs = portalbytes/sizeof(long);
00881 
00882     // each file portal is split into two memory portals
00883     portals = malloc(2*numportals*sizeof(vportal_t));
00884     memset (portals, 0, 2*numportals*sizeof(vportal_t));
00885     
00886     leafs = malloc(portalclusters*sizeof(leaf_t));
00887     memset (leafs, 0, portalclusters*sizeof(leaf_t));
00888 
00889     for (i = 0; i < portalclusters; i++)
00890         leafs[i].merged = -1;
00891 
00892     numVisBytes = VIS_HEADER_SIZE + portalclusters*leafbytes;
00893 
00894     ((int *)visBytes)[0] = portalclusters;
00895     ((int *)visBytes)[1] = leafbytes;
00896         
00897     for (i=0, p=portals ; i<numportals ; i++)
00898     {
00899         if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3)
00900             Error ("LoadPortals: reading portal %i", i);
00901         if (numpoints > MAX_POINTS_ON_WINDING)
00902             Error ("LoadPortals: portal %i has too many points", i);
00903         if ( (unsigned)leafnums[0] > portalclusters
00904         || (unsigned)leafnums[1] > portalclusters)
00905             Error ("LoadPortals: reading portal %i", i);
00906         if (fscanf (f, "%i ", &hint) != 1)
00907             Error ("LoadPortals: reading hint state");
00908         
00909         w = p->winding = NewWinding (numpoints);
00910         w->numpoints = numpoints;
00911         
00912         for (j=0 ; j<numpoints ; j++)
00913         {
00914             double  v[3];
00915             int     k;
00916 
00917             // scanf into double, then assign to vec_t
00918             // so we don't care what size vec_t is
00919             if (fscanf (f, "(%lf %lf %lf ) "
00920             , &v[0], &v[1], &v[2]) != 3)
00921                 Error ("LoadPortals: reading portal %i", i);
00922             for (k=0 ; k<3 ; k++)
00923                 w->points[j][k] = v[k];
00924         }
00925         fscanf (f, "\n");
00926         
00927         // calc plane
00928         PlaneFromWinding (w, &plane);
00929 
00930         // create forward portal
00931         l = &leafs[leafnums[0]];
00932         if (l->numportals == MAX_PORTALS_ON_LEAF)
00933             Error ("Leaf with too many portals");
00934         l->portals[l->numportals] = p;
00935         l->numportals++;
00936         
00937         p->num = i+1;
00938         p->hint = hint;
00939         p->winding = w;
00940         VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
00941         p->plane.dist = -plane.dist;
00942         p->leaf = leafnums[1];
00943         SetPortalSphere (p);
00944         p++;
00945         
00946         // create backwards portal
00947         l = &leafs[leafnums[1]];
00948         if (l->numportals == MAX_PORTALS_ON_LEAF)
00949             Error ("Leaf with too many portals");
00950         l->portals[l->numportals] = p;
00951         l->numportals++;
00952         
00953         p->num = i+1;
00954         p->hint = hint;
00955         p->winding = NewWinding(w->numpoints);
00956         p->winding->numpoints = w->numpoints;
00957         for (j=0 ; j<w->numpoints ; j++)
00958         {
00959             VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]);
00960         }
00961 
00962         p->plane = plane;
00963         p->leaf = leafnums[0];
00964         SetPortalSphere (p);
00965         p++;
00966 
00967     }
00968 
00969     faces = malloc(2*numfaces*sizeof(vportal_t));
00970     memset (faces, 0, 2*numfaces*sizeof(vportal_t));
00971 
00972     faceleafs = malloc(portalclusters*sizeof(leaf_t));
00973     memset(faceleafs, 0, portalclusters*sizeof(leaf_t));
00974 
00975     for (i = 0, p = faces; i < numfaces; i++)
00976     {
00977         if (fscanf (f, "%i %i ", &numpoints, &leafnums[0]) != 2)
00978             Error ("LoadPortals: reading portal %i", i);
00979 
00980         w = p->winding = NewWinding (numpoints);
00981         w->numpoints = numpoints;
00982         
00983         for (j=0 ; j<numpoints ; j++)
00984         {
00985             double  v[3];
00986             int     k;
00987 
00988             // scanf into double, then assign to vec_t
00989             // so we don't care what size vec_t is
00990             if (fscanf (f, "(%lf %lf %lf ) "
00991             , &v[0], &v[1], &v[2]) != 3)
00992                 Error ("LoadPortals: reading portal %i", i);
00993             for (k=0 ; k<3 ; k++)
00994                 w->points[j][k] = v[k];
00995         }
00996         fscanf (f, "\n");
00997         
00998         // calc plane
00999         PlaneFromWinding (w, &plane);
01000 
01001         l = &faceleafs[leafnums[0]];
01002         l->merged = -1;
01003         if (l->numportals == MAX_PORTALS_ON_LEAF)
01004             Error ("Leaf with too many faces");
01005         l->portals[l->numportals] = p;
01006         l->numportals++;
01007         
01008         p->num = i+1;
01009         p->winding = w;
01010         // normal pointing out of the leaf
01011         VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
01012         p->plane.dist = -plane.dist;
01013         p->leaf = -1;
01014         SetPortalSphere (p);
01015         p++;
01016     }
01017     
01018     fclose (f);
01019 }
01020 
01021 
01022 /*
01023 ================
01024 CalcPHS
01025 
01026 Calculate the PHS (Potentially Hearable Set)
01027 by ORing together all the PVS visible from a leaf
01028 ================
01029 */
01030 void CalcPHS (void)
01031 {
01032     int     i, j, k, l, index;
01033     int     bitbyte;
01034     long    *dest, *src;
01035     byte    *scan;
01036     int     count;
01037     byte    uncompressed[MAX_MAP_LEAFS/8];
01038 
01039     _printf ("Building PHS...\n");
01040 
01041     count = 0;
01042     for (i=0 ; i<portalclusters ; i++)
01043     {
01044         scan = visBytes + i*leafbytes;
01045         memcpy (uncompressed, scan, leafbytes);
01046         for (j=0 ; j<leafbytes ; j++)
01047         {
01048             bitbyte = scan[j];
01049             if (!bitbyte)
01050                 continue;
01051             for (k=0 ; k<8 ; k++)
01052             {
01053                 if (! (bitbyte & (1<<k)) )
01054                     continue;
01055                 // OR this pvs row into the phs
01056                 index = ((j<<3)+k);
01057                 if (index >= portalclusters)
01058                     Error ("Bad bit in PVS");   // pad bits should be 0
01059                 src = (long *)(visBytes + index*leafbytes);
01060                 dest = (long *)uncompressed;
01061                 for (l=0 ; l<leaflongs ; l++)
01062                     ((long *)uncompressed)[l] |= src[l];
01063             }
01064         }
01065         for (j=0 ; j<portalclusters ; j++)
01066             if (uncompressed[j>>3] & (1<<(j&7)) )
01067                 count++;
01068 
01069         // FIXME: copy it off
01070     }
01071 
01072     _printf ("Average clusters hearable: %i\n", count/portalclusters);
01073 }
01074 
01075 /*
01076 ===========
01077 VisMain
01078 ===========
01079 */
01080 int VisMain (int argc, char **argv)
01081 {
01082     char        portalfile[1024];
01083     char        name[1024];
01084     int     i;
01085     double      start, end;
01086         
01087     _printf ("---- vis ----\n");
01088 
01089     verbose = qfalse;
01090     for (i=1 ; i<argc ; i++) {
01091         if (!strcmp(argv[i],"-threads")) {
01092             numthreads = atoi (argv[i+1]);
01093             i++;
01094         } else if (!strcmp(argv[i],"-threads")) {
01095             numthreads = atoi (argv[i+1]);
01096             i++;
01097         } else if (!strcmp(argv[i], "-fast")) {
01098             _printf ("fastvis = true\n");
01099             fastvis = qtrue;
01100         } else if (!strcmp(argv[i], "-merge")) {
01101             _printf ("merge = true\n");
01102             mergevis = qtrue;
01103         } else if (!strcmp(argv[i], "-nopassage")) {
01104             _printf ("nopassage = true\n");
01105             noPassageVis = qtrue;
01106         } else if (!strcmp(argv[i], "-passageOnly")) {
01107             _printf("passageOnly = true\n");
01108             passageVisOnly = qtrue;
01109         } else if (!strcmp(argv[i], "-level")) {
01110             testlevel = atoi(argv[i+1]);
01111             _printf ("testlevel = %i\n", testlevel);
01112             i++;
01113         } else if (!strcmp(argv[i], "-v")) {
01114             _printf ("verbose = true\n");
01115             verbose = qtrue;
01116         } else if (!strcmp (argv[i],"-nosort")) {
01117             _printf ("nosort = true\n");
01118             nosort = qtrue;
01119         } else if (!strcmp (argv[i],"-saveprt")) {
01120             _printf ("saveprt = true\n");
01121             saveprt = qtrue;
01122         } else if (!strcmp (argv[i],"-tmpin")) {
01123             strcpy (inbase, "/tmp");
01124         } else if (!strcmp (argv[i],"-tmpout")) {
01125             strcpy (outbase, "/tmp");
01126         } else if (argv[i][0] == '-') {
01127             Error ("Unknown option \"%s\"", argv[i]);
01128         } else {
01129             break;
01130         }
01131     }
01132 
01133     if (i != argc - 1)
01134         Error ("usage: vis [-threads #] [-level 0-4] [-fast] [-v] bspfile");
01135 
01136 #ifdef MREDEBUG
01137     start = clock();
01138 #else
01139     start = I_FloatTime ();
01140 #endif
01141     
01142     ThreadSetDefault ();
01143 
01144     SetQdirFromPath (argv[i]);  
01145 
01146 #ifdef _WIN32
01147   InitPakFile(gamedir, NULL);
01148 #endif
01149 
01150     // load the bsp
01151     sprintf (name, "%s%s", inbase, ExpandArg(argv[i]));
01152     StripExtension (name);
01153     strcat (name, ".bsp");
01154     _printf ("reading %s\n", name);
01155     LoadBSPFile (name);
01156 
01157     // load the portal file
01158     sprintf (portalfile, "%s%s", inbase, ExpandArg(argv[i]));
01159     StripExtension (portalfile);
01160     strcat (portalfile, ".prt");
01161     _printf ("reading %s\n", portalfile);
01162     LoadPortals (portalfile);
01163 
01164     if (mergevis)
01165     {
01166         MergeLeaves();
01167         MergeLeafPortals();
01168     }
01169 
01170     CountActivePortals();
01171 //  WritePortals("maps/hints.prs");
01172 
01173     _printf ("visdatasize:%i\n", numVisBytes);
01174 
01175     CalcVis ();
01176 
01177 //  CalcPHS ();
01178 
01179     // delete the prt file
01180     if ( !saveprt ) {
01181         remove( portalfile );
01182     }
01183 
01184     // write the bsp file
01185     _printf ("writing %s\n", name);
01186     WriteBSPFile (name);
01187 
01188 #ifdef MREDEBUG
01189     end = clock();
01190     _printf ("%5.2f seconds elapsed\n", (end-start) / CLK_TCK);
01191 #else
01192     end = I_FloatTime ();
01193     _printf ("%5.2f seconds elapsed\n", end-start);
01194 #endif
01195     return 0;
01196 }
01197 

Generated on Thu Aug 25 12:38:25 2005 for Quake III Arena by  doxygen 1.3.9.1