X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=tools%2Fquake3%2Fq3map2%2Fvis.c;h=fb560d511311c911499c1719e50ed63376cb1757;hb=7fc621fc78d0e040dc2c12f38dc53dd9048215dc;hp=f3b2f4ae51d4ee97da956ba5e9fc32c6697e80ff;hpb=80378101101ca1762bbf5638a9e3566893096d8a;p=xonotic%2Fnetradiant.git diff --git a/tools/quake3/q3map2/vis.c b/tools/quake3/q3map2/vis.c index f3b2f4ae..fb560d51 100644 --- a/tools/quake3/q3map2/vis.c +++ b/tools/quake3/q3map2/vis.c @@ -1,1122 +1,1221 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - ----------------------------------------------------------------------------------- - -This code has been altered significantly from its original form, to support -several games based on the Quake III Arena engine, in the form of "Q3Map2." - -------------------------------------------------------------------------------- */ - - - -/* marker */ -#define VIS_C - - - -/* dependencies */ -#include "q3map2.h" - - - - -void PlaneFromWinding (fixedWinding_t *w, visPlane_t *plane) -{ - vec3_t v1, v2; - -// calc plane - VectorSubtract (w->points[2], w->points[1], v1); - VectorSubtract (w->points[0], w->points[1], v2); - CrossProduct (v2, v1, plane->normal); - VectorNormalize (plane->normal, plane->normal); - plane->dist = DotProduct (w->points[0], plane->normal); -} - - -/* -NewFixedWinding() -returns a new fixed winding -ydnar: altered this a bit to reconcile multiply-defined winding_t -*/ - -fixedWinding_t *NewFixedWinding( int points ) -{ - fixedWinding_t *w; - int size; - - if (points > MAX_POINTS_ON_WINDING) - Error ("NewWinding: %i points", points); - - size = (int)((fixedWinding_t *)0)->points[points]; - w = safe_malloc (size); - memset (w, 0, size); - - return w; -} - - - -void prl(leaf_t *l) -{ - int i; - vportal_t *p; - visPlane_t pl; - - for (i=0 ; inumportals ; i++) - { - p = l->portals[i]; - pl = p->plane; - Sys_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]); - } -} - - -//============================================================================= - -/* -============= -SortPortals - -Sorts the portals from the least complex, so the later ones can reuse -the earlier information. -============= -*/ -int PComp (const void *a, const void *b) -{ - if ( (*(vportal_t **)a)->nummightsee == (*(vportal_t **)b)->nummightsee) - return 0; - if ( (*(vportal_t **)a)->nummightsee < (*(vportal_t **)b)->nummightsee) - return -1; - return 1; -} -void SortPortals (void) -{ - int i; - - for (i=0 ; i>3] & (1<<(i&7)) ) - { - p = portals+i; - leafbits[p->leaf>>3] |= (1<<(p->leaf&7)); - } - } - - for (j = 0; j < portalclusters; j++) - { - leafnum = j; - while (leafs[leafnum].merged >= 0) - leafnum = leafs[leafnum].merged; - //if the merged leaf is visible then the original leaf is visible - if (leafbits[leafnum>>3] & (1<<(leafnum&7))) - { - leafbits[j>>3] |= (1<<(j&7)); - } - } - - c_leafs = CountBits (leafbits, portalclusters); - - return c_leafs; -} - - -/* -=============== -ClusterMerge - -Merges the portal visibility for a leaf -=============== -*/ -void ClusterMerge (int leafnum) -{ - leaf_t *leaf; - byte portalvector[MAX_PORTALS/8]; - byte uncompressed[MAX_MAP_LEAFS/8]; - int i, j; - int numvis, mergedleafnum; - vportal_t *p; - int pnum; - - // OR together all the portalvis bits - - mergedleafnum = leafnum; - while(leafs[mergedleafnum].merged >= 0) - mergedleafnum = leafs[mergedleafnum].merged; - - memset (portalvector, 0, portalbytes); - leaf = &leafs[mergedleafnum]; - for (i = 0; i < leaf->numportals; i++) - { - p = leaf->portals[i]; - if (p->removed) - continue; - - if (p->status != stat_done) - Error ("portal not done"); - for (j=0 ; jportalvis)[j]; - pnum = p - portals; - portalvector[pnum>>3] |= 1<<(pnum&7); - } - - memset (uncompressed, 0, leafbytes); - - uncompressed[mergedleafnum>>3] |= (1<<(mergedleafnum&7)); - // convert portal bits to leaf bits - numvis = LeafVectorFromPortalVector (portalvector, uncompressed); - -// if (uncompressed[leafnum>>3] & (1<<(leafnum&7))) -// Sys_Printf ("WARNING: Leaf portals saw into leaf\n"); - -// uncompressed[leafnum>>3] |= (1<<(leafnum&7)); - - numvis++; // count the leaf itself - - totalvis += numvis; - - Sys_FPrintf (SYS_VRB,"cluster %4i : %4i visible\n", leafnum, numvis); - - memcpy (bspVisBytes + VIS_HEADER_SIZE + leafnum*leafbytes, uncompressed, leafbytes); -} - -/* -================== -CalcPortalVis -================== -*/ -void CalcPortalVis (void) -{ -#ifdef MREDEBUG - Sys_Printf("%6d portals out of %d", 0, numportals*2); - //get rid of the counter - RunThreadsOnIndividual (numportals*2, qfalse, PortalFlow); -#else - RunThreadsOnIndividual (numportals*2, qtrue, PortalFlow); -#endif - -} - -/* -================== -CalcPassageVis -================== -*/ -void CalcPassageVis(void) -{ - PassageMemory(); - -#ifdef MREDEBUG - _printf("%6d portals out of %d", 0, numportals*2); - RunThreadsOnIndividual (numportals*2, qfalse, CreatePassages); - _printf("\n"); - _printf("%6d portals out of %d", 0, numportals*2); - RunThreadsOnIndividual (numportals*2, qfalse, PassageFlow); - _printf("\n"); -#else - Sys_Printf( "\n--- CreatePassages (%d) ---\n", numportals * 2 ); - RunThreadsOnIndividual( numportals*2, qtrue, CreatePassages ); - - Sys_Printf( "\n--- PassageFlow (%d) ---\n", numportals * 2 ); - RunThreadsOnIndividual( numportals * 2, qtrue, PassageFlow ); -#endif -} - -/* -================== -CalcPassagePortalVis -================== -*/ -void CalcPassagePortalVis(void) -{ - PassageMemory(); - -#ifdef MREDEBUG - Sys_Printf("%6d portals out of %d", 0, numportals*2); - RunThreadsOnIndividual (numportals*2, qfalse, CreatePassages); - Sys_Printf("\n"); - Sys_Printf("%6d portals out of %d", 0, numportals*2); - RunThreadsOnIndividual (numportals*2, qfalse, PassagePortalFlow); - Sys_Printf("\n"); -#else - Sys_Printf( "\n--- CreatePassages (%d) ---\n", numportals * 2 ); - RunThreadsOnIndividual( numportals * 2, qtrue, CreatePassages); - - Sys_Printf( "\n--- PassagePortalFlow (%d) ---\n", numportals * 2 ); - RunThreadsOnIndividual( numportals * 2, qtrue, PassagePortalFlow ); -#endif -} - -/* -================== -CalcFastVis -================== -*/ -void CalcFastVis(void) -{ - int i; - - // fastvis just uses mightsee for a very loose bound - for (i=0 ; i 0.0f ) - Sys_Printf( "farplane distance = %.1f\n", farPlaneDist ); - else - farPlaneDist = 0.0f; - } - - - - Sys_Printf( "\n--- BasePortalVis (%d) ---\n", numportals * 2 ); - RunThreadsOnIndividual( numportals * 2, qtrue, BasePortalVis ); - -// RunThreadsOnIndividual (numportals*2, qtrue, BetterPortalVis); - - SortPortals (); - - if (fastvis) { - CalcFastVis(); - } - else if ( noPassageVis ) { - CalcPortalVis(); - } - else if ( passageVisOnly ) { - CalcPassageVis(); - } - else { - CalcPassagePortalVis(); - } - // - // assemble the leaf vis lists by oring and compressing the portal lists - // - Sys_Printf("creating leaf vis...\n"); - for (i=0 ; iwinding; - VectorCopy (vec3_origin, total); - for (i=0 ; inumpoints ; i++) - { - VectorAdd (total, w->points[i], total); - } - - for (i=0 ; i<3 ; i++) - total[i] /= w->numpoints; - - bestr = 0; - for (i=0 ; inumpoints ; i++) - { - VectorSubtract (w->points[i], total, dist); - r = VectorLength (dist); - if (r > bestr) - bestr = r; - } - VectorCopy (total, p->origin); - p->radius = bestr; -} - -/* -============= -Winding_PlanesConcave -============= -*/ -#define WCONVEX_EPSILON 0.2 - -int Winding_PlanesConcave(fixedWinding_t *w1, fixedWinding_t *w2, - vec3_t normal1, vec3_t normal2, - float dist1, float dist2) -{ - int i; - - if (!w1 || !w2) return qfalse; - - // check if one of the points of winding 1 is at the front of the plane of winding 2 - for (i = 0; i < w1->numpoints; i++) - { - if (DotProduct(normal2, w1->points[i]) - dist2 > WCONVEX_EPSILON) return qtrue; - } - // check if one of the points of winding 2 is at the front of the plane of winding 1 - for (i = 0; i < w2->numpoints; i++) - { - if (DotProduct(normal1, w2->points[i]) - dist1 > WCONVEX_EPSILON) return qtrue; - } - - return qfalse; -} - -/* -============ -TryMergeLeaves -============ -*/ -int TryMergeLeaves(int l1num, int l2num) -{ - int i, j, k, n, numportals; - visPlane_t plane1, plane2; - leaf_t *l1, *l2; - vportal_t *p1, *p2; - vportal_t *portals[MAX_PORTALS_ON_LEAF]; - - for (k = 0; k < 2; k++) - { - if (k) l1 = &leafs[l1num]; - else l1 = &faceleafs[l1num]; - for (i = 0; i < l1->numportals; i++) - { - p1 = l1->portals[i]; - if (p1->leaf == l2num) continue; - for (n = 0; n < 2; n++) - { - if (n) l2 = &leafs[l2num]; - else l2 = &faceleafs[l2num]; - for (j = 0; j < l2->numportals; j++) - { - p2 = l2->portals[j]; - if (p2->leaf == l1num) continue; - // - plane1 = p1->plane; - plane2 = p2->plane; - if (Winding_PlanesConcave(p1->winding, p2->winding, plane1.normal, plane2.normal, plane1.dist, plane2.dist)) - return qfalse; - } - } - } - } - for (k = 0; k < 2; k++) - { - if (k) - { - l1 = &leafs[l1num]; - l2 = &leafs[l2num]; - } - else - { - l1 = &faceleafs[l1num]; - l2 = &faceleafs[l2num]; - } - numportals = 0; - //the leaves can be merged now - for (i = 0; i < l1->numportals; i++) - { - p1 = l1->portals[i]; - if (p1->leaf == l2num) - { - p1->removed = qtrue; - continue; - } - portals[numportals++] = p1; - } - for (j = 0; j < l2->numportals; j++) - { - p2 = l2->portals[j]; - if (p2->leaf == l1num) - { - p2->removed = qtrue; - continue; - } - portals[numportals++] = p2; - } - for (i = 0; i < numportals; i++) - { - l2->portals[i] = portals[i]; - } - l2->numportals = numportals; - l1->merged = l2num; - } - return qtrue; -} - -/* -============ -UpdatePortals -============ -*/ -void UpdatePortals(void) -{ - int i; - vportal_t *p; - - for (i = 0; i < numportals * 2; i++) - { - p = &portals[i]; - if (p->removed) - continue; - while(leafs[p->leaf].merged >= 0) - p->leaf = leafs[p->leaf].merged; - } -} - -/* -============ -MergeLeaves - -try to merge leaves but don't merge through hint splitters -============ -*/ -void MergeLeaves(void) -{ - int i, j, nummerges, totalnummerges; - leaf_t *leaf; - vportal_t *p; - - totalnummerges = 0; - do - { - nummerges = 0; - for (i = 0; i < portalclusters; i++) - { - leaf = &leafs[i]; - //if this leaf is merged already - - /* ydnar: vmods: merge all non-hint portals */ - if( leaf->merged >= 0 && hint == qfalse ) - continue; - - - for (j = 0; j < leaf->numportals; j++) - { - p = leaf->portals[j]; - // - if (p->removed) - continue; - //never merge through hint portals - if (p->hint) - continue; - if (TryMergeLeaves(i, p->leaf)) - { - UpdatePortals(); - nummerges++; - break; - } - } - } - totalnummerges += nummerges; - } while (nummerges); - Sys_Printf("%6d leaves merged\n", totalnummerges); -} - -/* -============ -TryMergeWinding -============ -*/ -#define CONTINUOUS_EPSILON 0.005 - -fixedWinding_t *TryMergeWinding (fixedWinding_t *f1, fixedWinding_t *f2, vec3_t planenormal) -{ - vec_t *p1, *p2, *p3, *p4, *back; - fixedWinding_t *newf; - int i, j, k, l; - vec3_t normal, delta; - vec_t dot; - qboolean keep1, keep2; - - - // - // find a common edge - // - p1 = p2 = NULL; // stop compiler warning - j = 0; // - - for (i = 0; i < f1->numpoints; i++) - { - p1 = f1->points[i]; - p2 = f1->points[(i+1) % f1->numpoints]; - for (j = 0; j < f2->numpoints; j++) - { - p3 = f2->points[j]; - p4 = f2->points[(j+1) % f2->numpoints]; - for (k = 0; k < 3; k++) - { - if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME - break; - if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME - break; - } //end for - if (k==3) - break; - } //end for - if (j < f2->numpoints) - break; - } //end for - - if (i == f1->numpoints) - return NULL; // no matching edges - - // - // check slope of connected lines - // if the slopes are colinear, the point can be removed - // - back = f1->points[(i+f1->numpoints-1)%f1->numpoints]; - VectorSubtract (p1, back, delta); - CrossProduct (planenormal, delta, normal); - VectorNormalize (normal, normal); - - back = f2->points[(j+2)%f2->numpoints]; - VectorSubtract (back, p1, delta); - dot = DotProduct (delta, normal); - if (dot > CONTINUOUS_EPSILON) - return NULL; // not a convex polygon - keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON); - - back = f1->points[(i+2)%f1->numpoints]; - VectorSubtract (back, p2, delta); - CrossProduct (planenormal, delta, normal); - VectorNormalize (normal, normal); - - back = f2->points[(j+f2->numpoints-1)%f2->numpoints]; - VectorSubtract (back, p2, delta); - dot = DotProduct (delta, normal); - if (dot > CONTINUOUS_EPSILON) - return NULL; // not a convex polygon - keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON); - - // - // build the new polygon - // - newf = NewFixedWinding (f1->numpoints + f2->numpoints); - - // copy first polygon - for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints) - { - if (k==(i+1)%f1->numpoints && !keep2) - continue; - - VectorCopy (f1->points[k], newf->points[newf->numpoints]); - newf->numpoints++; - } - - // copy second polygon - for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints) - { - if (l==(j+1)%f2->numpoints && !keep1) - continue; - VectorCopy (f2->points[l], newf->points[newf->numpoints]); - newf->numpoints++; - } - - return newf; -} - -/* -============ -MergeLeafPortals -============ -*/ -void MergeLeafPortals(void) -{ - int i, j, k, nummerges, hintsmerged; - leaf_t *leaf; - vportal_t *p1, *p2; - fixedWinding_t *w; - - nummerges = 0; - hintsmerged = 0; - for (i = 0; i < portalclusters; i++) - { - leaf = &leafs[i]; - if (leaf->merged >= 0) continue; - for (j = 0; j < leaf->numportals; j++) - { - p1 = leaf->portals[j]; - if (p1->removed) - continue; - for (k = j+1; k < leaf->numportals; k++) - { - p2 = leaf->portals[k]; - if (p2->removed) - continue; - if (p1->leaf == p2->leaf) - { - w = TryMergeWinding(p1->winding, p2->winding, p1->plane.normal); - if (w) - { - free( p1->winding ); //% FreeWinding(p1->winding); - p1->winding = w; - if (p1->hint && p2->hint) - hintsmerged++; - p1->hint |= p2->hint; - SetPortalSphere(p1); - p2->removed = qtrue; - nummerges++; - i--; - break; - } - } - } - if (k < leaf->numportals) - break; - } - } - Sys_Printf("%6d portals merged\n", nummerges); - Sys_Printf("%6d hint portals merged\n", hintsmerged); -} - - -/* -============ -WritePortals -============ -*/ -int CountActivePortals(void) -{ - int num, hints, j; - vportal_t *p; - - num = 0; - hints = 0; - for (j = 0; j < numportals * 2; j++) - { - p = portals + j; - if (p->removed) - continue; - if (p->hint) - hints++; - num++; - } - Sys_Printf("%6d active portals\n", num); - Sys_Printf("%6d hint portals\n", hints); - return num; -} - -/* -============ -WritePortals -============ -*/ -void WriteFloat (FILE *f, vec_t v); - -void WritePortals(char *filename) -{ - int i, j, num; - FILE *pf; - vportal_t *p; - fixedWinding_t *w; - - // write the file - pf = fopen (filename, "w"); - if (!pf) - Error ("Error opening %s", filename); - - num = 0; - for (j = 0; j < numportals * 2; j++) - { - p = portals + j; - if (p->removed) - continue; -// if (!p->hint) -// continue; - num++; - } - - fprintf (pf, "%s\n", PORTALFILE); - fprintf (pf, "%i\n", 0); - fprintf (pf, "%i\n", num);// + numfaces); - fprintf (pf, "%i\n", 0); - - for (j = 0; j < numportals * 2; j++) - { - p = portals + j; - if (p->removed) - continue; -// if (!p->hint) -// continue; - w = p->winding; - fprintf (pf,"%i %i %i ",w->numpoints, 0, 0); - fprintf (pf, "%d ", p->hint); - for (i=0 ; inumpoints ; i++) - { - fprintf (pf,"("); - WriteFloat (pf, w->points[i][0]); - WriteFloat (pf, w->points[i][1]); - WriteFloat (pf, w->points[i][2]); - fprintf (pf,") "); - } - fprintf (pf,"\n"); - } - - /* - for (j = 0; j < numfaces; j++) - { - p = faces + j; - w = p->winding; - fprintf (pf,"%i %i %i ",w->numpoints, 0, 0); - fprintf (pf, "0 "); - for (i=0 ; inumpoints ; i++) - { - fprintf (pf,"("); - WriteFloat (pf, w->points[i][0]); - WriteFloat (pf, w->points[i][1]); - WriteFloat (pf, w->points[i][2]); - fprintf (pf,") "); - } - fprintf (pf,"\n"); - }*/ - - fclose (pf); -} - -/* -============ -LoadPortals -============ -*/ -void LoadPortals (char *name) -{ - int i, j, hint; - vportal_t *p; - leaf_t *l; - char magic[80]; - FILE *f; - int numpoints; - fixedWinding_t *w; - int leafnums[2]; - visPlane_t plane; - - if (!strcmp(name,"-")) - f = stdin; - else - { - f = fopen(name, "r"); - if (!f) - Error ("LoadPortals: couldn't read %s\n",name); - } - - if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4) - Error ("LoadPortals: failed to read header"); - if (strcmp(magic,PORTALFILE)) - Error ("LoadPortals: not a portal file"); - - Sys_Printf ("%6i portalclusters\n", portalclusters); - Sys_Printf ("%6i numportals\n", numportals); - Sys_Printf ("%6i numfaces\n", numfaces); - - // these counts should take advantage of 64 bit systems automatically - leafbytes = ((portalclusters+63)&~63)>>3; - leaflongs = leafbytes/sizeof(long); - - portalbytes = ((numportals*2+63)&~63)>>3; - portallongs = portalbytes/sizeof(long); - - // each file portal is split into two memory portals - portals = safe_malloc(2*numportals*sizeof(vportal_t)); - memset (portals, 0, 2*numportals*sizeof(vportal_t)); - - leafs = safe_malloc(portalclusters*sizeof(leaf_t)); - memset (leafs, 0, portalclusters*sizeof(leaf_t)); - - for (i = 0; i < portalclusters; i++) - leafs[i].merged = -1; - - numBSPVisBytes = VIS_HEADER_SIZE + portalclusters*leafbytes; - - if (numBSPVisBytes > MAX_MAP_VISIBILITY) - Error("MAX_MAP_VISIBILITY exceeded"); - - ((int *)bspVisBytes)[0] = portalclusters; - ((int *)bspVisBytes)[1] = leafbytes; - - for (i=0, p=portals ; i MAX_POINTS_ON_WINDING) - Error ("LoadPortals: portal %i has too many points", i); - if ( (unsigned)leafnums[0] > portalclusters - || (unsigned)leafnums[1] > portalclusters) - Error ("LoadPortals: reading portal %i", i); - if (fscanf (f, "%i ", &hint) != 1) - Error ("LoadPortals: reading hint state"); - - w = p->winding = NewFixedWinding (numpoints); - w->numpoints = numpoints; - - for (j=0 ; jpoints[j][k] = v[k]; - } - fscanf (f, "\n"); - - // calc plane - PlaneFromWinding (w, &plane); - - // create forward portal - l = &leafs[leafnums[0]]; - if (l->numportals == MAX_PORTALS_ON_LEAF) - Error ("Leaf with too many portals"); - l->portals[l->numportals] = p; - l->numportals++; - - p->num = i+1; - p->hint = hint; - p->winding = w; - VectorSubtract (vec3_origin, plane.normal, p->plane.normal); - p->plane.dist = -plane.dist; - p->leaf = leafnums[1]; - SetPortalSphere (p); - p++; - - // create backwards portal - l = &leafs[leafnums[1]]; - if (l->numportals == MAX_PORTALS_ON_LEAF) - Error ("Leaf with too many portals"); - l->portals[l->numportals] = p; - l->numportals++; - - p->num = i+1; - p->hint = hint; - p->winding = NewFixedWinding(w->numpoints); - p->winding->numpoints = w->numpoints; - for (j=0 ; jnumpoints ; j++) - { - VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]); - } - - p->plane = plane; - p->leaf = leafnums[0]; - SetPortalSphere (p); - p++; - - } - - faces = safe_malloc(2*numfaces*sizeof(vportal_t)); - memset (faces, 0, 2*numfaces*sizeof(vportal_t)); - - faceleafs = safe_malloc(portalclusters*sizeof(leaf_t)); - memset(faceleafs, 0, portalclusters*sizeof(leaf_t)); - - for (i = 0, p = faces; i < numfaces; i++) - { - if (fscanf (f, "%i %i ", &numpoints, &leafnums[0]) != 2) - Error ("LoadPortals: reading portal %i", i); - - w = p->winding = NewFixedWinding (numpoints); - w->numpoints = numpoints; - - for (j=0 ; jpoints[j][k] = v[k]; - } - fscanf (f, "\n"); - - // calc plane - PlaneFromWinding (w, &plane); - - l = &faceleafs[leafnums[0]]; - l->merged = -1; - if (l->numportals == MAX_PORTALS_ON_LEAF) - Error ("Leaf with too many faces"); - l->portals[l->numportals] = p; - l->numportals++; - - p->num = i+1; - p->winding = w; - // normal pointing out of the leaf - VectorSubtract (vec3_origin, plane.normal, p->plane.normal); - p->plane.dist = -plane.dist; - p->leaf = -1; - SetPortalSphere (p); - p++; - } - - fclose (f); -} - - - -/* -=========== -VisMain -=========== -*/ -int VisMain (int argc, char **argv) -{ - char portalfile[1024]; - int i; - - - /* note it */ - Sys_Printf( "--- Vis ---\n" ); - - /* process arguments */ - for (i=1 ; i < (argc - 1) ; i++) - { - if (!strcmp(argv[i], "-fast")) { - Sys_Printf ("fastvis = true\n"); - fastvis = qtrue; - } else if (!strcmp(argv[i], "-merge")) { - Sys_Printf ("merge = true\n"); - mergevis = qtrue; - } else if (!strcmp(argv[i], "-nopassage")) { - Sys_Printf ("nopassage = true\n"); - noPassageVis = qtrue; - } else if (!strcmp(argv[i], "-passageOnly")) { - Sys_Printf ("passageOnly = true\n"); - passageVisOnly = qtrue; - } else if (!strcmp (argv[i],"-nosort")) { - Sys_Printf ("nosort = true\n"); - nosort = qtrue; - } else if (!strcmp (argv[i],"-saveprt")) { - Sys_Printf ("saveprt = true\n"); - saveprt = qtrue; - } else if (!strcmp (argv[i],"-tmpin")) { - strcpy (inbase, "/tmp"); - } else if (!strcmp (argv[i],"-tmpout")) { - strcpy (outbase, "/tmp"); - } - - - /* ydnar: -hint to merge all but hint portals */ - else if( !strcmp( argv[ i ], "-hint" ) ) - { - Sys_Printf( "hint = true\n" ); - hint = qtrue; - mergevis = qtrue; - } - - else - Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] ); - } - - if( i != argc - 1 ) - Error( "usage: vis [-threads #] [-level 0-4] [-fast] [-v] bspfile" ); - - - /* load the bsp */ - sprintf( source, "%s%s", inbase, ExpandArg( argv[ i ] ) ); - StripExtension( source ); - strcat( source, ".bsp" ); - Sys_Printf( "Loading %s\n", source ); - LoadBSPFile( source ); - - /* load the portal file */ - sprintf( portalfile, "%s%s", inbase, ExpandArg( argv[ i ] ) ); - StripExtension( portalfile ); - strcat( portalfile, ".prt" ); - Sys_Printf( "Loading %s\n", portalfile ); - LoadPortals( portalfile ); - - /* ydnar: for getting far plane */ - ParseEntities(); - - if( mergevis ) - { - MergeLeaves(); - MergeLeafPortals(); - } - - CountActivePortals(); - /* WritePortals( "maps/hints.prs" );*/ - - Sys_Printf( "visdatasize:%i\n", numBSPVisBytes ); - - CalcVis(); - - /* delete the prt file */ - if( !saveprt ) - remove( portalfile ); - - /* write the bsp file */ - Sys_Printf( "Writing %s\n", source ); - WriteBSPFile( source ); - - return 0; -} +/* ------------------------------------------------------------------------------- + + Copyright (C) 1999-2007 id Software, Inc. and contributors. + For a list of contributors, see the accompanying CONTRIBUTORS file. + + This file is part of GtkRadiant. + + GtkRadiant is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + GtkRadiant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + ---------------------------------------------------------------------------------- + + This code has been altered significantly from its original form, to support + several games based on the Quake III Arena engine, in the form of "Q3Map2." + + ------------------------------------------------------------------------------- */ + + + +/* marker */ +#define VIS_C + + + +/* dependencies */ +#include "q3map2.h" + + + + +void PlaneFromWinding( fixedWinding_t *w, visPlane_t *plane ){ + vec3_t v1, v2; + +// calc plane + VectorSubtract( w->points[2], w->points[1], v1 ); + VectorSubtract( w->points[0], w->points[1], v2 ); + CrossProduct( v2, v1, plane->normal ); + VectorNormalize( plane->normal, plane->normal ); + plane->dist = DotProduct( w->points[0], plane->normal ); +} + + +/* + NewFixedWinding() + returns a new fixed winding + ydnar: altered this a bit to reconcile multiply-defined winding_t + */ + +fixedWinding_t *NewFixedWinding( int points ){ + fixedWinding_t *w; + int size; + + if ( points > MAX_POINTS_ON_WINDING ) { + Error( "NewWinding: %i points", points ); + } + + size = (int)( (size_t)( (fixedWinding_t *)0 )->points[points] ); + w = safe_malloc( size ); + memset( w, 0, size ); + + return w; +} + + + +void prl( leaf_t *l ){ + int i; + vportal_t *p; + visPlane_t pl; + + for ( i = 0 ; i < l->numportals ; i++ ) + { + p = l->portals[i]; + pl = p->plane; + Sys_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] ); + } +} + + +//============================================================================= + +/* + ============= + SortPortals + + Sorts the portals from the least complex, so the later ones can reuse + the earlier information. + ============= + */ +int PComp( const void *a, const void *b ){ + if ( ( *(const vportal_t *const *)a )->nummightsee == ( *(const vportal_t *const *)b )->nummightsee ) { + return 0; + } + if ( ( *(const vportal_t *const *)a )->nummightsee < ( *(const vportal_t *const *)b )->nummightsee ) { + return -1; + } + return 1; +} +void SortPortals( void ){ + int i; + + for ( i = 0 ; i < numportals * 2 ; i++ ) + sorted_portals[i] = &portals[i]; + + if ( nosort ) { + return; + } + qsort( sorted_portals, numportals * 2, sizeof( sorted_portals[0] ), PComp ); +} + + +/* + ============== + LeafVectorFromPortalVector + ============== + */ +int LeafVectorFromPortalVector( byte *portalbits, byte *leafbits ){ + int i, j, leafnum; + vportal_t *p; + int c_leafs; + + + for ( i = 0 ; i < numportals * 2 ; i++ ) + { + if ( portalbits[i >> 3] & ( 1 << ( i & 7 ) ) ) { + p = portals + i; + leafbits[p->leaf >> 3] |= ( 1 << ( p->leaf & 7 ) ); + } + } + + for ( j = 0; j < portalclusters; j++ ) + { + leafnum = j; + while ( leafs[leafnum].merged >= 0 ) + leafnum = leafs[leafnum].merged; + //if the merged leaf is visible then the original leaf is visible + if ( leafbits[leafnum >> 3] & ( 1 << ( leafnum & 7 ) ) ) { + leafbits[j >> 3] |= ( 1 << ( j & 7 ) ); + } + } + + c_leafs = CountBits( leafbits, portalclusters ); + + return c_leafs; +} + + +/* + =============== + ClusterMerge + + Merges the portal visibility for a leaf + =============== + */ +static int clustersizehistogram[MAX_MAP_LEAFS] = {0}; +void ClusterMerge( int leafnum ){ + leaf_t *leaf; + byte portalvector[MAX_PORTALS / 8]; + byte uncompressed[MAX_MAP_LEAFS / 8]; + int i, j; + int numvis, mergedleafnum; + vportal_t *p; + int pnum; + + // OR together all the portalvis bits + + mergedleafnum = leafnum; + while ( leafs[mergedleafnum].merged >= 0 ) + mergedleafnum = leafs[mergedleafnum].merged; + + memset( portalvector, 0, portalbytes ); + leaf = &leafs[mergedleafnum]; + for ( i = 0; i < leaf->numportals; i++ ) + { + p = leaf->portals[i]; + if ( p->removed ) { + continue; + } + + if ( p->status != stat_done ) { + Error( "portal not done" ); + } + for ( j = 0 ; j < portallongs ; j++ ) + ( (long *)portalvector )[j] |= ( (long *)p->portalvis )[j]; + pnum = p - portals; + portalvector[pnum >> 3] |= 1 << ( pnum & 7 ); + } + + memset( uncompressed, 0, leafbytes ); + + uncompressed[mergedleafnum >> 3] |= ( 1 << ( mergedleafnum & 7 ) ); + // convert portal bits to leaf bits + numvis = LeafVectorFromPortalVector( portalvector, uncompressed ); + +// if (uncompressed[leafnum>>3] & (1<<(leafnum&7))) +// Sys_Printf ("WARNING: Leaf portals saw into leaf\n"); + +// uncompressed[leafnum>>3] |= (1<<(leafnum&7)); + + numvis++; // count the leaf itself + + //Sys_FPrintf (SYS_VRB,"cluster %4i : %4i visible\n", leafnum, numvis); + ++clustersizehistogram[numvis]; + + memcpy( bspVisBytes + VIS_HEADER_SIZE + leafnum * leafbytes, uncompressed, leafbytes ); +} + +/* + ================== + CalcPortalVis + ================== + */ +void CalcPortalVis( void ){ +#ifdef MREDEBUG + Sys_Printf( "%6d portals out of %d", 0, numportals * 2 ); + //get rid of the counter + RunThreadsOnIndividual( numportals * 2, qfalse, PortalFlow ); +#else + RunThreadsOnIndividual( numportals * 2, qtrue, PortalFlow ); +#endif + +} + +/* + ================== + CalcPassageVis + ================== + */ +void CalcPassageVis( void ){ + PassageMemory(); + +#ifdef MREDEBUG + _printf( "%6d portals out of %d", 0, numportals * 2 ); + RunThreadsOnIndividual( numportals * 2, qfalse, CreatePassages ); + _printf( "\n" ); + _printf( "%6d portals out of %d", 0, numportals * 2 ); + RunThreadsOnIndividual( numportals * 2, qfalse, PassageFlow ); + _printf( "\n" ); +#else + Sys_Printf( "\n--- CreatePassages (%d) ---\n", numportals * 2 ); + RunThreadsOnIndividual( numportals * 2, qtrue, CreatePassages ); + + Sys_Printf( "\n--- PassageFlow (%d) ---\n", numportals * 2 ); + RunThreadsOnIndividual( numportals * 2, qtrue, PassageFlow ); +#endif +} + +/* + ================== + CalcPassagePortalVis + ================== + */ +void CalcPassagePortalVis( void ){ + PassageMemory(); + +#ifdef MREDEBUG + Sys_Printf( "%6d portals out of %d", 0, numportals * 2 ); + RunThreadsOnIndividual( numportals * 2, qfalse, CreatePassages ); + Sys_Printf( "\n" ); + Sys_Printf( "%6d portals out of %d", 0, numportals * 2 ); + RunThreadsOnIndividual( numportals * 2, qfalse, PassagePortalFlow ); + Sys_Printf( "\n" ); +#else + Sys_Printf( "\n--- CreatePassages (%d) ---\n", numportals * 2 ); + RunThreadsOnIndividual( numportals * 2, qtrue, CreatePassages ); + + Sys_Printf( "\n--- PassagePortalFlow (%d) ---\n", numportals * 2 ); + RunThreadsOnIndividual( numportals * 2, qtrue, PassagePortalFlow ); +#endif +} + +/* + ================== + CalcFastVis + ================== + */ +void CalcFastVis( void ){ + int i; + + // fastvis just uses mightsee for a very loose bound + for ( i = 0 ; i < numportals * 2 ; i++ ) + { + portals[i].portalvis = portals[i].portalflood; + portals[i].status = stat_done; + } +} + +/* + ================== + CalcVis + ================== + */ +void CalcVis( void ){ + int i, minvis, maxvis; + const char *value; + double mu, sigma, totalvis, totalvis2; + + + /* ydnar: rr2do2's farplane code */ + farPlaneDist = 0.0f; + value = ValueForKey( &entities[ 0 ], "_farplanedist" ); /* proper '_' prefixed key */ + if ( value[ 0 ] == '\0' ) { + value = ValueForKey( &entities[ 0 ], "fogclip" ); /* wolf compatibility */ + } + if ( value[ 0 ] == '\0' ) { + value = ValueForKey( &entities[ 0 ], "distancecull" ); /* sof2 compatibility */ + } + if ( value[ 0 ] != '\0' ) { + farPlaneDist = atof( value ); + if ( farPlaneDist > 0.0f ) { + Sys_Printf( "farplane distance = %.1f\n", farPlaneDist ); + } + else{ + farPlaneDist = 0.0f; + } + } + + + + Sys_Printf( "\n--- BasePortalVis (%d) ---\n", numportals * 2 ); + RunThreadsOnIndividual( numportals * 2, qtrue, BasePortalVis ); + +// RunThreadsOnIndividual (numportals*2, qtrue, BetterPortalVis); + + SortPortals(); + + if ( fastvis ) { + CalcFastVis(); + } + else if ( noPassageVis ) { + CalcPortalVis(); + } + else if ( passageVisOnly ) { + CalcPassageVis(); + } + else { + CalcPassagePortalVis(); + } + // + // assemble the leaf vis lists by oring and compressing the portal lists + // + Sys_Printf( "creating leaf vis...\n" ); + for ( i = 0 ; i < portalclusters ; i++ ) + ClusterMerge( i ); + + totalvis = 0; + totalvis2 = 0; + minvis = -1; + maxvis = -1; + for ( i = 0; i < MAX_MAP_LEAFS; ++i ) + if ( clustersizehistogram[i] ) { + if ( debugCluster ) { + Sys_FPrintf( SYS_VRB, "%4i clusters have exactly %4i visible clusters\n", clustersizehistogram[i], i ); + } + /* cast is to prevent integer overflow */ + totalvis += ( (double) i ) * ( (double) clustersizehistogram[i] ); + totalvis2 += ( (double) i ) * ( (double) i ) * ( (double) clustersizehistogram[i] ); + + if ( minvis < 0 ) { + minvis = i; + } + maxvis = i; + } + + mu = totalvis / portalclusters; + sigma = sqrt( totalvis2 / portalclusters - mu * mu ); + + Sys_Printf( "Total clusters: %i\n", portalclusters ); + Sys_Printf( "Total visible clusters: %.0f\n", totalvis ); + Sys_Printf( "Average clusters visible: %.2f (%.3f%%/total)\n", mu, mu / portalclusters * 100.0 ); + Sys_Printf( " Standard deviation: %.2f (%.3f%%/total, %.3f%%/avg)\n", sigma, sigma / portalclusters * 100.0, sigma / mu * 100.0 ); + Sys_Printf( " Minimum: %i (%.3f%%/total, %.3f%%/avg)\n", minvis, minvis / (double) portalclusters * 100.0, minvis / mu * 100.0 ); + Sys_Printf( " Maximum: %i (%.3f%%/total, %.3f%%/avg)\n", maxvis, maxvis / (double) portalclusters * 100.0, maxvis / mu * 100.0 ); +} + +/* + ================== + SetPortalSphere + ================== + */ +void SetPortalSphere( vportal_t *p ){ + int i; + vec3_t total, dist; + fixedWinding_t *w; + float r, bestr; + + w = p->winding; + VectorCopy( vec3_origin, total ); + for ( i = 0 ; i < w->numpoints ; i++ ) + { + VectorAdd( total, w->points[i], total ); + } + + for ( i = 0 ; i < 3 ; i++ ) + total[i] /= w->numpoints; + + bestr = 0; + for ( i = 0 ; i < w->numpoints ; i++ ) + { + VectorSubtract( w->points[i], total, dist ); + r = VectorLength( dist ); + if ( r > bestr ) { + bestr = r; + } + } + VectorCopy( total, p->origin ); + p->radius = bestr; +} + +/* + ============= + Winding_PlanesConcave + ============= + */ +#define WCONVEX_EPSILON 0.2 + +int Winding_PlanesConcave( fixedWinding_t *w1, fixedWinding_t *w2, + vec3_t normal1, vec3_t normal2, + float dist1, float dist2 ){ + int i; + + if ( !w1 || !w2 ) { + return qfalse; + } + + // check if one of the points of winding 1 is at the front of the plane of winding 2 + for ( i = 0; i < w1->numpoints; i++ ) + { + if ( DotProduct( normal2, w1->points[i] ) - dist2 > WCONVEX_EPSILON ) { + return qtrue; + } + } + // check if one of the points of winding 2 is at the front of the plane of winding 1 + for ( i = 0; i < w2->numpoints; i++ ) + { + if ( DotProduct( normal1, w2->points[i] ) - dist1 > WCONVEX_EPSILON ) { + return qtrue; + } + } + + return qfalse; +} + +/* + ============ + TryMergeLeaves + ============ + */ +int TryMergeLeaves( int l1num, int l2num ){ + int i, j, k, n, numportals; + visPlane_t plane1, plane2; + leaf_t *l1, *l2; + vportal_t *p1, *p2; + vportal_t *portals[MAX_PORTALS_ON_LEAF]; + + for ( k = 0; k < 2; k++ ) + { + if ( k ) { + l1 = &leafs[l1num]; + } + else{l1 = &faceleafs[l1num]; } + for ( i = 0; i < l1->numportals; i++ ) + { + p1 = l1->portals[i]; + if ( p1->leaf == l2num ) { + continue; + } + for ( n = 0; n < 2; n++ ) + { + if ( n ) { + l2 = &leafs[l2num]; + } + else{l2 = &faceleafs[l2num]; } + for ( j = 0; j < l2->numportals; j++ ) + { + p2 = l2->portals[j]; + if ( p2->leaf == l1num ) { + continue; + } + // + plane1 = p1->plane; + plane2 = p2->plane; + if ( Winding_PlanesConcave( p1->winding, p2->winding, plane1.normal, plane2.normal, plane1.dist, plane2.dist ) ) { + return qfalse; + } + } + } + } + } + for ( k = 0; k < 2; k++ ) + { + if ( k ) { + l1 = &leafs[l1num]; + l2 = &leafs[l2num]; + } + else + { + l1 = &faceleafs[l1num]; + l2 = &faceleafs[l2num]; + } + numportals = 0; + //the leaves can be merged now + for ( i = 0; i < l1->numportals; i++ ) + { + p1 = l1->portals[i]; + if ( p1->leaf == l2num ) { + p1->removed = qtrue; + continue; + } + portals[numportals++] = p1; + } + for ( j = 0; j < l2->numportals; j++ ) + { + p2 = l2->portals[j]; + if ( p2->leaf == l1num ) { + p2->removed = qtrue; + continue; + } + portals[numportals++] = p2; + } + for ( i = 0; i < numportals; i++ ) + { + l2->portals[i] = portals[i]; + } + l2->numportals = numportals; + l1->merged = l2num; + } + return qtrue; +} + +/* + ============ + UpdatePortals + ============ + */ +void UpdatePortals( void ){ + int i; + vportal_t *p; + + for ( i = 0; i < numportals * 2; i++ ) + { + p = &portals[i]; + if ( p->removed ) { + continue; + } + while ( leafs[p->leaf].merged >= 0 ) + p->leaf = leafs[p->leaf].merged; + } +} + +/* + ============ + MergeLeaves + + try to merge leaves but don't merge through hint splitters + ============ + */ +void MergeLeaves( void ){ + int i, j, nummerges, totalnummerges; + leaf_t *leaf; + vportal_t *p; + + totalnummerges = 0; + do + { + nummerges = 0; + for ( i = 0; i < portalclusters; i++ ) + { + leaf = &leafs[i]; + //if this leaf is merged already + + /* ydnar: vmods: merge all non-hint portals */ + if ( leaf->merged >= 0 && hint == qfalse ) { + continue; + } + + + for ( j = 0; j < leaf->numportals; j++ ) + { + p = leaf->portals[j]; + // + if ( p->removed ) { + continue; + } + //never merge through hint portals + if ( p->hint ) { + continue; + } + if ( TryMergeLeaves( i, p->leaf ) ) { + UpdatePortals(); + nummerges++; + break; + } + } + } + totalnummerges += nummerges; + } while ( nummerges ); + Sys_Printf( "%6d leaves merged\n", totalnummerges ); +} + +/* + ============ + TryMergeWinding + ============ + */ +#define CONTINUOUS_EPSILON 0.005 + +fixedWinding_t *TryMergeWinding( fixedWinding_t *f1, fixedWinding_t *f2, vec3_t planenormal ){ + vec_t *p1, *p2, *p3, *p4, *back; + fixedWinding_t *newf; + int i, j, k, l; + vec3_t normal, delta; + vec_t dot; + qboolean keep1, keep2; + + + // + // find a common edge + // + p1 = p2 = NULL; // stop compiler warning + j = 0; // + + for ( i = 0; i < f1->numpoints; i++ ) + { + p1 = f1->points[i]; + p2 = f1->points[( i + 1 ) % f1->numpoints]; + for ( j = 0; j < f2->numpoints; j++ ) + { + p3 = f2->points[j]; + p4 = f2->points[( j + 1 ) % f2->numpoints]; + for ( k = 0; k < 3; k++ ) + { + if ( fabs( p1[k] - p4[k] ) > 0.1 ) { //EQUAL_EPSILON) //ME + break; + } + if ( fabs( p2[k] - p3[k] ) > 0.1 ) { //EQUAL_EPSILON) //ME + break; + } + } //end for + if ( k == 3 ) { + break; + } + } //end for + if ( j < f2->numpoints ) { + break; + } + } //end for + + if ( i == f1->numpoints ) { + return NULL; // no matching edges + + } + // + // check slope of connected lines + // if the slopes are colinear, the point can be removed + // + back = f1->points[( i + f1->numpoints - 1 ) % f1->numpoints]; + VectorSubtract( p1, back, delta ); + CrossProduct( planenormal, delta, normal ); + VectorNormalize( normal, normal ); + + back = f2->points[( j + 2 ) % f2->numpoints]; + VectorSubtract( back, p1, delta ); + dot = DotProduct( delta, normal ); + if ( dot > CONTINUOUS_EPSILON ) { + return NULL; // not a convex polygon + } + keep1 = (qboolean)( dot < -CONTINUOUS_EPSILON ); + + back = f1->points[( i + 2 ) % f1->numpoints]; + VectorSubtract( back, p2, delta ); + CrossProduct( planenormal, delta, normal ); + VectorNormalize( normal, normal ); + + back = f2->points[( j + f2->numpoints - 1 ) % f2->numpoints]; + VectorSubtract( back, p2, delta ); + dot = DotProduct( delta, normal ); + if ( dot > CONTINUOUS_EPSILON ) { + return NULL; // not a convex polygon + } + keep2 = (qboolean)( dot < -CONTINUOUS_EPSILON ); + + // + // build the new polygon + // + newf = NewFixedWinding( f1->numpoints + f2->numpoints ); + + // copy first polygon + for ( k = ( i + 1 ) % f1->numpoints ; k != i ; k = ( k + 1 ) % f1->numpoints ) + { + if ( k == ( i + 1 ) % f1->numpoints && !keep2 ) { + continue; + } + + VectorCopy( f1->points[k], newf->points[newf->numpoints] ); + newf->numpoints++; + } + + // copy second polygon + for ( l = ( j + 1 ) % f2->numpoints ; l != j ; l = ( l + 1 ) % f2->numpoints ) + { + if ( l == ( j + 1 ) % f2->numpoints && !keep1 ) { + continue; + } + VectorCopy( f2->points[l], newf->points[newf->numpoints] ); + newf->numpoints++; + } + + return newf; +} + +/* + ============ + MergeLeafPortals + ============ + */ +void MergeLeafPortals( void ){ + int i, j, k, nummerges, hintsmerged; + leaf_t *leaf; + vportal_t *p1, *p2; + fixedWinding_t *w; + + nummerges = 0; + hintsmerged = 0; + for ( i = 0; i < portalclusters; i++ ) + { + leaf = &leafs[i]; + if ( leaf->merged >= 0 ) { + continue; + } + for ( j = 0; j < leaf->numportals; j++ ) + { + p1 = leaf->portals[j]; + if ( p1->removed ) { + continue; + } + for ( k = j + 1; k < leaf->numportals; k++ ) + { + p2 = leaf->portals[k]; + if ( p2->removed ) { + continue; + } + if ( p1->leaf == p2->leaf ) { + w = TryMergeWinding( p1->winding, p2->winding, p1->plane.normal ); + if ( w ) { + free( p1->winding ); //% FreeWinding(p1->winding); + p1->winding = w; + if ( p1->hint && p2->hint ) { + hintsmerged++; + } + p1->hint |= p2->hint; + SetPortalSphere( p1 ); + p2->removed = qtrue; + nummerges++; + i--; + break; + } + } + } + if ( k < leaf->numportals ) { + break; + } + } + } + Sys_Printf( "%6d portals merged\n", nummerges ); + Sys_Printf( "%6d hint portals merged\n", hintsmerged ); +} + + +/* + ============ + WritePortals + ============ + */ +int CountActivePortals( void ){ + int num, hints, j; + vportal_t *p; + + num = 0; + hints = 0; + for ( j = 0; j < numportals * 2; j++ ) + { + p = portals + j; + if ( p->removed ) { + continue; + } + if ( p->hint ) { + hints++; + } + num++; + } + Sys_Printf( "%6d active portals\n", num ); + Sys_Printf( "%6d hint portals\n", hints ); + return num; +} + +/* + ============ + WritePortals + ============ + */ +void WriteFloat( FILE *f, vec_t v ); + +void WritePortals( char *filename ){ + int i, j, num; + FILE *pf; + vportal_t *p; + fixedWinding_t *w; + + // write the file + pf = fopen( filename, "w" ); + if ( !pf ) { + Error( "Error opening %s", filename ); + } + + num = 0; + for ( j = 0; j < numportals * 2; j++ ) + { + p = portals + j; + if ( p->removed ) { + continue; + } +// if (!p->hint) +// continue; + num++; + } + + fprintf( pf, "%s\n", PORTALFILE ); + fprintf( pf, "%i\n", 0 ); + fprintf( pf, "%i\n", num ); // + numfaces); + fprintf( pf, "%i\n", 0 ); + + for ( j = 0; j < numportals * 2; j++ ) + { + p = portals + j; + if ( p->removed ) { + continue; + } +// if (!p->hint) +// continue; + w = p->winding; + fprintf( pf,"%i %i %i ",w->numpoints, 0, 0 ); + fprintf( pf, "%d ", p->hint ); + for ( i = 0 ; i < w->numpoints ; i++ ) + { + fprintf( pf,"(" ); + WriteFloat( pf, w->points[i][0] ); + WriteFloat( pf, w->points[i][1] ); + WriteFloat( pf, w->points[i][2] ); + fprintf( pf,") " ); + } + fprintf( pf,"\n" ); + } + + /* + for (j = 0; j < numfaces; j++) + { + p = faces + j; + w = p->winding; + fprintf (pf,"%i %i %i ",w->numpoints, 0, 0); + fprintf (pf, "0 "); + for (i=0 ; inumpoints ; i++) + { + fprintf (pf,"("); + WriteFloat (pf, w->points[i][0]); + WriteFloat (pf, w->points[i][1]); + WriteFloat (pf, w->points[i][2]); + fprintf (pf,") "); + } + fprintf (pf,"\n"); + }*/ + + fclose( pf ); +} + +/* + ============ + LoadPortals + ============ + */ +void LoadPortals( char *name ){ + int i, j, hint; + vportal_t *p; + leaf_t *l; + char magic[80]; + FILE *f; + int numpoints; + fixedWinding_t *w; + int leafnums[2]; + visPlane_t plane; + + if ( !strcmp( name,"-" ) ) { + f = stdin; + } + else + { + f = fopen( name, "r" ); + if ( !f ) { + Error( "LoadPortals: couldn't read %s\n",name ); + } + } + + if ( fscanf( f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces ) != 4 ) { + Error( "LoadPortals: failed to read header" ); + } + if ( strcmp( magic,PORTALFILE ) ) { + Error( "LoadPortals: not a portal file" ); + } + + Sys_Printf( "%6i portalclusters\n", portalclusters ); + Sys_Printf( "%6i numportals\n", numportals ); + Sys_Printf( "%6i numfaces\n", numfaces ); + + if ( numportals > MAX_PORTALS ) { + Error( "MAX_PORTALS" ); + } + + // these counts should take advantage of 64 bit systems automatically + leafbytes = ( ( portalclusters + 63 ) & ~63 ) >> 3; + leaflongs = leafbytes / sizeof( long ); + + portalbytes = ( ( numportals * 2 + 63 ) & ~63 ) >> 3; + portallongs = portalbytes / sizeof( long ); + + // each file portal is split into two memory portals + portals = safe_malloc( 2 * numportals * sizeof( vportal_t ) ); + memset( portals, 0, 2 * numportals * sizeof( vportal_t ) ); + + leafs = safe_malloc( portalclusters * sizeof( leaf_t ) ); + memset( leafs, 0, portalclusters * sizeof( leaf_t ) ); + + for ( i = 0; i < portalclusters; i++ ) + leafs[i].merged = -1; + + numBSPVisBytes = VIS_HEADER_SIZE + portalclusters * leafbytes; + + if ( numBSPVisBytes > MAX_MAP_VISIBILITY ) { + Error( "MAX_MAP_VISIBILITY exceeded" ); + } + + ( (int *)bspVisBytes )[0] = portalclusters; + ( (int *)bspVisBytes )[1] = leafbytes; + + for ( i = 0, p = portals ; i < numportals ; i++ ) + { + if ( fscanf( f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1] ) != 3 ) { + Error( "LoadPortals: reading portal %i", i ); + } + if ( numpoints > MAX_POINTS_ON_WINDING ) { + Error( "LoadPortals: portal %i has too many points", i ); + } + if ( leafnums[0] > portalclusters + || leafnums[1] > portalclusters ) { + Error( "LoadPortals: reading portal %i", i ); + } + if ( fscanf( f, "%i ", &hint ) != 1 ) { + Error( "LoadPortals: reading hint state" ); + } + + w = p->winding = NewFixedWinding( numpoints ); + w->numpoints = numpoints; + + for ( j = 0 ; j < numpoints ; j++ ) + { + double v[3]; + int k; + + // scanf into double, then assign to vec_t + // so we don't care what size vec_t is + if ( fscanf( f, "(%lf %lf %lf ) " + , &v[0], &v[1], &v[2] ) != 3 ) { + Error( "LoadPortals: reading portal %i", i ); + } + for ( k = 0 ; k < 3 ; k++ ) + w->points[j][k] = v[k]; + } + if ( fscanf( f, "\n" ) != 0 ) { + // silence gcc warning + } + + // calc plane + PlaneFromWinding( w, &plane ); + + // create forward portal + l = &leafs[leafnums[0]]; + if ( l->numportals == MAX_PORTALS_ON_LEAF ) { + Error( "Leaf with too many portals" ); + } + l->portals[l->numportals] = p; + l->numportals++; + + p->num = i + 1; + p->hint = hint; + p->winding = w; + VectorSubtract( vec3_origin, plane.normal, p->plane.normal ); + p->plane.dist = -plane.dist; + p->leaf = leafnums[1]; + SetPortalSphere( p ); + p++; + + // create backwards portal + l = &leafs[leafnums[1]]; + if ( l->numportals == MAX_PORTALS_ON_LEAF ) { + Error( "Leaf with too many portals" ); + } + l->portals[l->numportals] = p; + l->numportals++; + + p->num = i + 1; + p->hint = hint; + p->winding = NewFixedWinding( w->numpoints ); + p->winding->numpoints = w->numpoints; + for ( j = 0 ; j < w->numpoints ; j++ ) + { + VectorCopy( w->points[w->numpoints - 1 - j], p->winding->points[j] ); + } + + p->plane = plane; + p->leaf = leafnums[0]; + SetPortalSphere( p ); + p++; + + } + + faces = safe_malloc( 2 * numfaces * sizeof( vportal_t ) ); + memset( faces, 0, 2 * numfaces * sizeof( vportal_t ) ); + + faceleafs = safe_malloc( portalclusters * sizeof( leaf_t ) ); + memset( faceleafs, 0, portalclusters * sizeof( leaf_t ) ); + + for ( i = 0, p = faces; i < numfaces; i++ ) + { + if ( fscanf( f, "%i %i ", &numpoints, &leafnums[0] ) != 2 ) { + Error( "LoadPortals: reading portal %i", i ); + } + + w = p->winding = NewFixedWinding( numpoints ); + w->numpoints = numpoints; + + for ( j = 0 ; j < numpoints ; j++ ) + { + double v[3]; + int k; + + // scanf into double, then assign to vec_t + // so we don't care what size vec_t is + if ( fscanf( f, "(%lf %lf %lf ) " + , &v[0], &v[1], &v[2] ) != 3 ) { + Error( "LoadPortals: reading portal %i", i ); + } + for ( k = 0 ; k < 3 ; k++ ) + w->points[j][k] = v[k]; + } + if ( fscanf( f, "\n" ) != 0 ) { + // silence gcc warning + } + + // calc plane + PlaneFromWinding( w, &plane ); + + l = &faceleafs[leafnums[0]]; + l->merged = -1; + if ( l->numportals == MAX_PORTALS_ON_LEAF ) { + Error( "Leaf with too many faces" ); + } + l->portals[l->numportals] = p; + l->numportals++; + + p->num = i + 1; + p->winding = w; + // normal pointing out of the leaf + VectorSubtract( vec3_origin, plane.normal, p->plane.normal ); + p->plane.dist = -plane.dist; + p->leaf = -1; + SetPortalSphere( p ); + p++; + } + + fclose( f ); +} + + + +/* + =========== + VisMain + =========== + */ +int VisMain( int argc, char **argv ){ + char portalfile[1024]; + int i; + + + /* note it */ + Sys_Printf( "--- Vis ---\n" ); + + /* process arguments */ + for ( i = 1 ; i < ( argc - 1 ) ; i++ ) + { + if ( !strcmp( argv[i], "-fast" ) ) { + Sys_Printf( "fastvis = true\n" ); + fastvis = qtrue; + } + else if ( !strcmp( argv[i], "-merge" ) ) { + Sys_Printf( "merge = true\n" ); + mergevis = qtrue; + } + else if ( !strcmp( argv[i], "-mergeportals" ) ) { + Sys_Printf( "mergeportals = true\n" ); + mergevisportals = qtrue; + } + else if ( !strcmp( argv[i], "-nopassage" ) ) { + Sys_Printf( "nopassage = true\n" ); + noPassageVis = qtrue; + } + else if ( !strcmp( argv[i], "-passageOnly" ) ) { + Sys_Printf( "passageOnly = true\n" ); + passageVisOnly = qtrue; + } + else if ( !strcmp( argv[i],"-nosort" ) ) { + Sys_Printf( "nosort = true\n" ); + nosort = qtrue; + } + else if ( !strcmp( argv[i],"-saveprt" ) ) { + Sys_Printf( "saveprt = true\n" ); + saveprt = qtrue; + } + else if ( !strcmp( argv[ i ], "-v" ) ) { + debugCluster = qtrue; + Sys_Printf( "Extra verbous mode enabled\n" ); + } + else if ( !strcmp( argv[i],"-tmpin" ) ) { + strcpy( inbase, "/tmp" ); + } + else if ( !strcmp( argv[i],"-tmpout" ) ) { + strcpy( outbase, "/tmp" ); + } + + + /* ydnar: -hint to merge all but hint portals */ + else if ( !strcmp( argv[ i ], "-hint" ) ) { + Sys_Printf( "hint = true\n" ); + hint = qtrue; + mergevis = qtrue; + } + + else + { + Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] ); + } + } + + if ( i != argc - 1 ) { + Error( "usage: vis [-threads #] [-level 0-4] [-fast] [-v] bspfile" ); + } + + + /* load the bsp */ + sprintf( source, "%s%s", inbase, ExpandArg( argv[ i ] ) ); + StripExtension( source ); + strcat( source, ".bsp" ); + Sys_Printf( "Loading %s\n", source ); + LoadBSPFile( source ); + + /* load the portal file */ + sprintf( portalfile, "%s%s", inbase, ExpandArg( argv[ i ] ) ); + StripExtension( portalfile ); + strcat( portalfile, ".prt" ); + Sys_Printf( "Loading %s\n", portalfile ); + LoadPortals( portalfile ); + + /* ydnar: exit if no portals, hence no vis */ + if ( numportals == 0 ) { + Sys_Printf( "No portals means no vis, exiting.\n" ); + return 0; + } + + /* ydnar: for getting far plane */ + ParseEntities(); + + /* inject command line parameters */ + InjectCommandLine( argv, 0, argc - 1 ); + UnparseEntities(); + + if ( mergevis ) { + MergeLeaves(); + } + + if ( mergevis || mergevisportals ) { + MergeLeafPortals(); + } + + CountActivePortals(); + /* WritePortals( "maps/hints.prs" );*/ + + Sys_Printf( "visdatasize:%i\n", numBSPVisBytes ); + + CalcVis(); + + /* delete the prt file */ + if ( !saveprt ) { + remove( portalfile ); + } + + /* write the bsp file */ + Sys_Printf( "Writing %s\n", source ); + WriteBSPFile( source ); + + return 0; +}