X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=tools%2Fquake3%2Fq3map2%2Fvis.c;h=464b23ecde6a3b3582820a387d27de152e7f8110;hb=ab3a99dbbe84a0d130fea4d0ceb7b79d7ed07eb7;hp=f3b2f4ae51d4ee97da956ba5e9fc32c6697e80ff;hpb=d59e1dc131ede961a201ab8ca4b836ab9d6cc31a;p=xonotic%2Fnetradiant.git diff --git a/tools/quake3/q3map2/vis.c b/tools/quake3/q3map2/vis.c index f3b2f4ae..464b23ec 100644 --- a/tools/quake3/q3map2/vis.c +++ b/tools/quake3/q3map2/vis.c @@ -1,1122 +1,1122 @@ -/* -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)((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; +}