]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/vis.c
eol style
[xonotic/netradiant.git] / tools / quake3 / q3map2 / vis.c
1 /*
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
21 ----------------------------------------------------------------------------------
22
23 This code has been altered significantly from its original form, to support
24 several games based on the Quake III Arena engine, in the form of "Q3Map2."
25
26 ------------------------------------------------------------------------------- */
27
28
29
30 /* marker */
31 #define VIS_C
32
33
34
35 /* dependencies */
36 #include "q3map2.h"
37
38
39
40
41 void PlaneFromWinding (fixedWinding_t *w, visPlane_t *plane)
42 {
43         vec3_t          v1, v2;
44
45 // calc plane
46         VectorSubtract (w->points[2], w->points[1], v1);
47         VectorSubtract (w->points[0], w->points[1], v2);
48         CrossProduct (v2, v1, plane->normal);
49         VectorNormalize (plane->normal, plane->normal);
50         plane->dist = DotProduct (w->points[0], plane->normal);
51 }
52
53
54 /*
55 NewFixedWinding()
56 returns a new fixed winding
57 ydnar: altered this a bit to reconcile multiply-defined winding_t
58 */
59
60 fixedWinding_t *NewFixedWinding( int points )
61 {
62         fixedWinding_t  *w;
63         int                     size;
64         
65         if (points > MAX_POINTS_ON_WINDING)
66                 Error ("NewWinding: %i points", points);
67         
68         size = (int)((fixedWinding_t *)0)->points[points];
69         w = safe_malloc (size);
70         memset (w, 0, size);
71         
72         return w;
73 }
74
75
76
77 void prl(leaf_t *l)
78 {
79         int                     i;
80         vportal_t       *p;
81         visPlane_t      pl;
82         
83         for (i=0 ; i<l->numportals ; i++)
84         {
85                 p = l->portals[i];
86                 pl = p->plane;
87                 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]);
88         }
89 }
90
91
92 //=============================================================================
93
94 /*
95 =============
96 SortPortals
97
98 Sorts the portals from the least complex, so the later ones can reuse
99 the earlier information.
100 =============
101 */
102 int PComp (const void *a, const void *b)
103 {
104         if ( (*(vportal_t **)a)->nummightsee == (*(vportal_t **)b)->nummightsee)
105                 return 0;
106         if ( (*(vportal_t **)a)->nummightsee < (*(vportal_t **)b)->nummightsee)
107                 return -1;
108         return 1;
109 }
110 void SortPortals (void)
111 {
112         int             i;
113         
114         for (i=0 ; i<numportals*2 ; i++)
115                 sorted_portals[i] = &portals[i];
116
117         if (nosort)
118                 return;
119         qsort (sorted_portals, numportals*2, sizeof(sorted_portals[0]), PComp);
120 }
121
122
123 /*
124 ==============
125 LeafVectorFromPortalVector
126 ==============
127 */
128 int LeafVectorFromPortalVector (byte *portalbits, byte *leafbits)
129 {
130         int                     i, j, leafnum;
131         vportal_t       *p;
132         int                     c_leafs;
133
134
135         for (i=0 ; i<numportals*2 ; i++)
136         {
137                 if (portalbits[i>>3] & (1<<(i&7)) )
138                 {
139                         p = portals+i;
140                         leafbits[p->leaf>>3] |= (1<<(p->leaf&7));
141                 }
142         }
143
144         for (j = 0; j < portalclusters; j++)
145         {
146                 leafnum = j;
147                 while (leafs[leafnum].merged >= 0)
148                         leafnum = leafs[leafnum].merged;
149                 //if the merged leaf is visible then the original leaf is visible
150                 if (leafbits[leafnum>>3] & (1<<(leafnum&7)))
151                 {
152                         leafbits[j>>3] |= (1<<(j&7));
153                 }
154         }
155
156         c_leafs = CountBits (leafbits, portalclusters);
157
158         return c_leafs;
159 }
160
161
162 /*
163 ===============
164 ClusterMerge
165
166 Merges the portal visibility for a leaf
167 ===============
168 */
169 void ClusterMerge (int leafnum)
170 {
171         leaf_t          *leaf;
172         byte            portalvector[MAX_PORTALS/8];
173         byte            uncompressed[MAX_MAP_LEAFS/8];
174         int                     i, j;
175         int                     numvis, mergedleafnum;
176         vportal_t       *p;
177         int                     pnum;
178
179         // OR together all the portalvis bits
180
181         mergedleafnum = leafnum;
182         while(leafs[mergedleafnum].merged >= 0)
183                 mergedleafnum = leafs[mergedleafnum].merged;
184
185         memset (portalvector, 0, portalbytes);
186         leaf = &leafs[mergedleafnum];
187         for (i = 0; i < leaf->numportals; i++)
188         {
189                 p = leaf->portals[i];
190                 if (p->removed)
191                         continue;
192
193                 if (p->status != stat_done)
194                         Error ("portal not done");
195                 for (j=0 ; j<portallongs ; j++)
196                         ((long *)portalvector)[j] |= ((long *)p->portalvis)[j];
197                 pnum = p - portals;
198                 portalvector[pnum>>3] |= 1<<(pnum&7);
199         }
200
201         memset (uncompressed, 0, leafbytes);
202
203         uncompressed[mergedleafnum>>3] |= (1<<(mergedleafnum&7));
204         // convert portal bits to leaf bits
205         numvis = LeafVectorFromPortalVector (portalvector, uncompressed);
206
207 //      if (uncompressed[leafnum>>3] & (1<<(leafnum&7)))
208 //              Sys_Printf ("WARNING: Leaf portals saw into leaf\n");
209                 
210 //      uncompressed[leafnum>>3] |= (1<<(leafnum&7));
211
212         numvis++;               // count the leaf itself
213
214         totalvis += numvis;
215
216         Sys_FPrintf (SYS_VRB,"cluster %4i : %4i visible\n", leafnum, numvis);
217
218         memcpy (bspVisBytes + VIS_HEADER_SIZE + leafnum*leafbytes, uncompressed, leafbytes);
219 }
220
221 /*
222 ==================
223 CalcPortalVis
224 ==================
225 */
226 void CalcPortalVis (void)
227 {
228 #ifdef MREDEBUG
229         Sys_Printf("%6d portals out of %d", 0, numportals*2);
230         //get rid of the counter
231         RunThreadsOnIndividual (numportals*2, qfalse, PortalFlow);
232 #else
233         RunThreadsOnIndividual (numportals*2, qtrue, PortalFlow);
234 #endif
235
236 }
237
238 /*
239 ==================
240 CalcPassageVis
241 ==================
242 */
243 void CalcPassageVis(void)
244 {
245         PassageMemory();
246
247 #ifdef MREDEBUG
248         _printf("%6d portals out of %d", 0, numportals*2);
249         RunThreadsOnIndividual (numportals*2, qfalse, CreatePassages);
250         _printf("\n");
251         _printf("%6d portals out of %d", 0, numportals*2);
252         RunThreadsOnIndividual (numportals*2, qfalse, PassageFlow);
253         _printf("\n");
254 #else
255         Sys_Printf( "\n--- CreatePassages (%d) ---\n", numportals * 2 );
256         RunThreadsOnIndividual( numportals*2, qtrue, CreatePassages );
257         
258         Sys_Printf( "\n--- PassageFlow (%d) ---\n", numportals * 2 );
259         RunThreadsOnIndividual( numportals * 2, qtrue, PassageFlow );
260 #endif
261 }
262
263 /*
264 ==================
265 CalcPassagePortalVis
266 ==================
267 */
268 void CalcPassagePortalVis(void)
269 {
270         PassageMemory();
271
272 #ifdef MREDEBUG
273         Sys_Printf("%6d portals out of %d", 0, numportals*2);
274         RunThreadsOnIndividual (numportals*2, qfalse, CreatePassages);
275         Sys_Printf("\n");
276         Sys_Printf("%6d portals out of %d", 0, numportals*2);
277         RunThreadsOnIndividual (numportals*2, qfalse, PassagePortalFlow);
278         Sys_Printf("\n");
279 #else
280         Sys_Printf( "\n--- CreatePassages (%d) ---\n", numportals * 2 );
281         RunThreadsOnIndividual( numportals * 2, qtrue, CreatePassages);
282         
283         Sys_Printf( "\n--- PassagePortalFlow (%d) ---\n", numportals * 2 );
284         RunThreadsOnIndividual( numportals * 2, qtrue, PassagePortalFlow );
285 #endif
286 }
287
288 /*
289 ==================
290 CalcFastVis
291 ==================
292 */
293 void CalcFastVis(void)
294 {
295         int             i;
296
297         // fastvis just uses mightsee for a very loose bound
298         for (i=0 ; i<numportals*2 ; i++)
299         {
300                 portals[i].portalvis = portals[i].portalflood;
301                 portals[i].status = stat_done;
302         }
303 }
304
305 /*
306 ==================
307 CalcVis
308 ==================
309 */
310 void CalcVis (void)
311 {
312         int                     i;
313         const char      *value;
314         
315         
316         /* ydnar: rr2do2's farplane code */
317         farPlaneDist = 0.0f;
318         value = ValueForKey( &entities[ 0 ], "_farplanedist" );         /* proper '_' prefixed key */
319         if( value[ 0 ] == '\0' )
320                 value = ValueForKey( &entities[ 0 ], "fogclip" );               /* wolf compatibility */
321         if( value[ 0 ] == '\0' )
322                 value = ValueForKey( &entities[ 0 ], "distancecull" );  /* sof2 compatibility */
323         if( value[ 0 ] != '\0' )
324         {
325                 farPlaneDist = atof( value );
326                 if( farPlaneDist > 0.0f )
327                         Sys_Printf( "farplane distance = %.1f\n", farPlaneDist );
328                 else
329                         farPlaneDist = 0.0f;
330         }
331         
332         
333         
334         Sys_Printf( "\n--- BasePortalVis (%d) ---\n", numportals * 2 );
335         RunThreadsOnIndividual( numportals * 2, qtrue, BasePortalVis );
336         
337 //      RunThreadsOnIndividual (numportals*2, qtrue, BetterPortalVis);
338
339         SortPortals ();
340
341   if (fastvis) {
342     CalcFastVis();
343   }
344   else if ( noPassageVis ) {
345     CalcPortalVis();
346   }
347   else if ( passageVisOnly ) {
348     CalcPassageVis();
349   }
350   else {
351     CalcPassagePortalVis();
352   }
353         //
354         // assemble the leaf vis lists by oring and compressing the portal lists
355         //
356         Sys_Printf("creating leaf vis...\n");
357         for (i=0 ; i<portalclusters ; i++)
358                 ClusterMerge (i);
359
360   Sys_Printf( "Total visible clusters: %i\n", totalvis );
361   Sys_Printf( "Average clusters visible: %i\n", totalvis / portalclusters );
362 }
363
364 /*
365 ==================
366 SetPortalSphere
367 ==================
368 */
369 void SetPortalSphere (vportal_t *p)
370 {
371         int             i;
372         vec3_t  total, dist;
373         fixedWinding_t  *w;
374         float   r, bestr;
375
376         w = p->winding;
377         VectorCopy (vec3_origin, total);
378         for (i=0 ; i<w->numpoints ; i++)
379         {
380                 VectorAdd (total, w->points[i], total);
381         }
382         
383         for (i=0 ; i<3 ; i++)
384                 total[i] /= w->numpoints;
385
386         bestr = 0;              
387         for (i=0 ; i<w->numpoints ; i++)
388         {
389                 VectorSubtract (w->points[i], total, dist);
390                 r = VectorLength (dist);
391                 if (r > bestr)
392                         bestr = r;
393         }
394         VectorCopy (total, p->origin);
395         p->radius = bestr;
396 }
397
398 /*
399 =============
400 Winding_PlanesConcave
401 =============
402 */
403 #define WCONVEX_EPSILON         0.2
404
405 int Winding_PlanesConcave(fixedWinding_t *w1, fixedWinding_t *w2,
406                                                          vec3_t normal1, vec3_t normal2,
407                                                          float dist1, float dist2)
408 {
409         int i;
410
411         if (!w1 || !w2) return qfalse;
412
413         // check if one of the points of winding 1 is at the front of the plane of winding 2
414         for (i = 0; i < w1->numpoints; i++)
415         {
416                 if (DotProduct(normal2, w1->points[i]) - dist2 > WCONVEX_EPSILON) return qtrue;
417         }
418         // check if one of the points of winding 2 is at the front of the plane of winding 1
419         for (i = 0; i < w2->numpoints; i++)
420         {
421                 if (DotProduct(normal1, w2->points[i]) - dist1 > WCONVEX_EPSILON) return qtrue;
422         }
423
424         return qfalse;
425 }
426
427 /*
428 ============
429 TryMergeLeaves
430 ============
431 */
432 int TryMergeLeaves(int l1num, int l2num)
433 {
434         int i, j, k, n, numportals;
435         visPlane_t plane1, plane2;
436         leaf_t *l1, *l2;
437         vportal_t *p1, *p2;
438         vportal_t *portals[MAX_PORTALS_ON_LEAF];
439
440         for (k = 0; k < 2; k++)
441         {
442                 if (k) l1 = &leafs[l1num];
443                 else l1 = &faceleafs[l1num];
444                 for (i = 0; i < l1->numportals; i++)
445                 {
446                         p1 = l1->portals[i];
447                         if (p1->leaf == l2num) continue;
448                         for (n = 0; n < 2; n++)
449                         {
450                                 if (n) l2 = &leafs[l2num];
451                                 else l2 = &faceleafs[l2num];
452                                 for (j = 0; j < l2->numportals; j++)
453                                 {
454                                         p2 = l2->portals[j];
455                                         if (p2->leaf == l1num) continue;
456                                         //
457                                         plane1 = p1->plane;
458                                         plane2 = p2->plane;
459                                         if (Winding_PlanesConcave(p1->winding, p2->winding, plane1.normal, plane2.normal, plane1.dist, plane2.dist))
460                                                 return qfalse;
461                                 }
462                         }
463                 }
464         }
465         for (k = 0; k < 2; k++)
466         {
467                 if (k)
468                 {
469                         l1 = &leafs[l1num];
470                         l2 = &leafs[l2num];
471                 }
472                 else
473                 {
474                         l1 = &faceleafs[l1num];
475                         l2 = &faceleafs[l2num];
476                 }
477                 numportals = 0;
478                 //the leaves can be merged now
479                 for (i = 0; i < l1->numportals; i++)
480                 {
481                         p1 = l1->portals[i];
482                         if (p1->leaf == l2num)
483                         {
484                                 p1->removed = qtrue;
485                                 continue;
486                         }
487                         portals[numportals++] = p1;
488                 }
489                 for (j = 0; j < l2->numportals; j++)
490                 {
491                         p2 = l2->portals[j];
492                         if (p2->leaf == l1num)
493                         {
494                                 p2->removed = qtrue;
495                                 continue;
496                         }
497                         portals[numportals++] = p2;
498                 }
499                 for (i = 0; i < numportals; i++)
500                 {
501                         l2->portals[i] = portals[i];
502                 }
503                 l2->numportals = numportals;
504                 l1->merged = l2num;
505         }
506         return qtrue;
507 }
508
509 /*
510 ============
511 UpdatePortals
512 ============
513 */
514 void UpdatePortals(void)
515 {
516         int i;
517         vportal_t *p;
518
519         for (i = 0; i < numportals * 2; i++)
520         {
521                 p = &portals[i];
522                 if (p->removed)
523                         continue;
524                 while(leafs[p->leaf].merged >= 0)
525                         p->leaf = leafs[p->leaf].merged;
526         }
527 }
528
529 /*
530 ============
531 MergeLeaves
532
533 try to merge leaves but don't merge through hint splitters
534 ============
535 */
536 void MergeLeaves(void)
537 {
538         int i, j, nummerges, totalnummerges;
539         leaf_t *leaf;
540         vportal_t *p;
541
542         totalnummerges = 0;
543         do
544         {
545                 nummerges = 0;
546                 for (i = 0; i < portalclusters; i++)
547                 {
548                         leaf = &leafs[i];
549                         //if this leaf is merged already
550
551                         /* ydnar: vmods: merge all non-hint portals */
552                         if( leaf->merged >= 0 && hint == qfalse )
553                                 continue;
554
555
556                         for (j = 0; j < leaf->numportals; j++)
557                         {
558                                 p = leaf->portals[j];
559                                 //
560                                 if (p->removed)
561                                         continue;
562                                 //never merge through hint portals
563                                 if (p->hint)
564                                         continue;
565                                 if (TryMergeLeaves(i, p->leaf))
566                                 {
567                                         UpdatePortals();
568                                         nummerges++;
569                                         break;
570                                 }
571                         }
572                 }
573                 totalnummerges += nummerges;
574         } while (nummerges);
575         Sys_Printf("%6d leaves merged\n", totalnummerges);
576 }
577
578 /*
579 ============
580 TryMergeWinding
581 ============
582 */
583 #define CONTINUOUS_EPSILON      0.005
584
585 fixedWinding_t *TryMergeWinding (fixedWinding_t *f1, fixedWinding_t *f2, vec3_t planenormal)
586 {
587         vec_t           *p1, *p2, *p3, *p4, *back;
588         fixedWinding_t  *newf;
589         int                     i, j, k, l;
590         vec3_t          normal, delta;
591         vec_t           dot;
592         qboolean        keep1, keep2;
593         
594
595         //
596         // find a common edge
597         //      
598         p1 = p2 = NULL; // stop compiler warning
599         j = 0;                  // 
600         
601         for (i = 0; i < f1->numpoints; i++)
602         {
603                 p1 = f1->points[i];
604                 p2 = f1->points[(i+1) % f1->numpoints];
605                 for (j = 0; j < f2->numpoints; j++)
606                 {
607                         p3 = f2->points[j];
608                         p4 = f2->points[(j+1) % f2->numpoints];
609                         for (k = 0; k < 3; k++)
610                         {
611                                 if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME
612                                         break;
613                                 if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME
614                                         break;
615                         } //end for
616                         if (k==3)
617                                 break;
618                 } //end for
619                 if (j < f2->numpoints)
620                         break;
621         } //end for
622         
623         if (i == f1->numpoints)
624                 return NULL;                    // no matching edges
625
626         //
627         // check slope of connected lines
628         // if the slopes are colinear, the point can be removed
629         //
630         back = f1->points[(i+f1->numpoints-1)%f1->numpoints];
631         VectorSubtract (p1, back, delta);
632         CrossProduct (planenormal, delta, normal);
633         VectorNormalize (normal, normal);
634         
635         back = f2->points[(j+2)%f2->numpoints];
636         VectorSubtract (back, p1, delta);
637         dot = DotProduct (delta, normal);
638         if (dot > CONTINUOUS_EPSILON)
639                 return NULL;                    // not a convex polygon
640         keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON);
641         
642         back = f1->points[(i+2)%f1->numpoints];
643         VectorSubtract (back, p2, delta);
644         CrossProduct (planenormal, delta, normal);
645         VectorNormalize (normal, normal);
646
647         back = f2->points[(j+f2->numpoints-1)%f2->numpoints];
648         VectorSubtract (back, p2, delta);
649         dot = DotProduct (delta, normal);
650         if (dot > CONTINUOUS_EPSILON)
651                 return NULL;                    // not a convex polygon
652         keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON);
653
654         //
655         // build the new polygon
656         //
657         newf = NewFixedWinding (f1->numpoints + f2->numpoints);
658         
659         // copy first polygon
660         for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
661         {
662                 if (k==(i+1)%f1->numpoints && !keep2)
663                         continue;
664                 
665                 VectorCopy (f1->points[k], newf->points[newf->numpoints]);
666                 newf->numpoints++;
667         }
668         
669         // copy second polygon
670         for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
671         {
672                 if (l==(j+1)%f2->numpoints && !keep1)
673                         continue;
674                 VectorCopy (f2->points[l], newf->points[newf->numpoints]);
675                 newf->numpoints++;
676         }
677
678         return newf;
679 }
680
681 /*
682 ============
683 MergeLeafPortals
684 ============
685 */
686 void MergeLeafPortals(void)
687 {
688         int i, j, k, nummerges, hintsmerged;
689         leaf_t *leaf;
690         vportal_t *p1, *p2;
691         fixedWinding_t *w;
692
693         nummerges = 0;
694         hintsmerged = 0;
695         for (i = 0; i < portalclusters; i++)
696         {
697                 leaf = &leafs[i];
698                 if (leaf->merged >= 0) continue;
699                 for (j = 0; j < leaf->numportals; j++)
700                 {
701                         p1 = leaf->portals[j];
702                         if (p1->removed)
703                                 continue;
704                         for (k = j+1; k < leaf->numportals; k++)
705                         {
706                                 p2 = leaf->portals[k];
707                                 if (p2->removed)
708                                         continue;
709                                 if (p1->leaf == p2->leaf)
710                                 {
711                                         w = TryMergeWinding(p1->winding, p2->winding, p1->plane.normal);
712                                         if (w)
713                                         {
714                                                 free( p1->winding );    //% FreeWinding(p1->winding);
715                                                 p1->winding = w;
716                                                 if (p1->hint && p2->hint)
717                                                         hintsmerged++;
718                                                 p1->hint |= p2->hint;
719                                                 SetPortalSphere(p1);
720                                                 p2->removed = qtrue;
721                                                 nummerges++;
722                                                 i--;
723                                                 break;
724                                         }
725                                 }
726                         }
727                         if (k < leaf->numportals)
728                                 break;
729                 }
730         }
731         Sys_Printf("%6d portals merged\n", nummerges);
732         Sys_Printf("%6d hint portals merged\n", hintsmerged);
733 }
734
735
736 /*
737 ============
738 WritePortals
739 ============
740 */
741 int CountActivePortals(void)
742 {
743         int num, hints, j;
744         vportal_t *p;
745
746         num = 0;
747         hints = 0;
748         for (j = 0; j < numportals * 2; j++)
749         {
750                 p = portals + j;
751                 if (p->removed)
752                         continue;
753                 if (p->hint)
754                         hints++;
755                 num++;
756         }
757         Sys_Printf("%6d active portals\n", num);
758         Sys_Printf("%6d hint portals\n", hints);
759         return num;
760 }
761
762 /*
763 ============
764 WritePortals
765 ============
766 */
767 void WriteFloat (FILE *f, vec_t v);
768
769 void WritePortals(char *filename)
770 {
771         int i, j, num;
772         FILE *pf;
773         vportal_t *p;
774         fixedWinding_t *w;
775
776         // write the file
777         pf = fopen (filename, "w");
778         if (!pf)
779                 Error ("Error opening %s", filename);
780
781         num = 0;
782         for (j = 0; j < numportals * 2; j++)
783         {
784                 p = portals + j;
785                 if (p->removed)
786                         continue;
787 //              if (!p->hint)
788 //                      continue;
789                 num++;
790         }
791
792         fprintf (pf, "%s\n", PORTALFILE);
793         fprintf (pf, "%i\n", 0);
794         fprintf (pf, "%i\n", num);// + numfaces);
795         fprintf (pf, "%i\n", 0);
796
797         for (j = 0; j < numportals * 2; j++)
798         {
799                 p = portals + j;
800                 if (p->removed)
801                         continue;
802 //              if (!p->hint)
803 //                      continue;
804                 w = p->winding;
805                 fprintf (pf,"%i %i %i ",w->numpoints, 0, 0);
806                 fprintf (pf, "%d ", p->hint);
807                 for (i=0 ; i<w->numpoints ; i++)
808                 {
809                         fprintf (pf,"(");
810                         WriteFloat (pf, w->points[i][0]);
811                         WriteFloat (pf, w->points[i][1]);
812                         WriteFloat (pf, w->points[i][2]);
813                         fprintf (pf,") ");
814                 }
815                 fprintf (pf,"\n");
816         }
817
818         /*
819         for (j = 0; j < numfaces; j++)
820         {
821                 p = faces + j;
822                 w = p->winding;
823                 fprintf (pf,"%i %i %i ",w->numpoints, 0, 0);
824                 fprintf (pf, "0 ");
825                 for (i=0 ; i<w->numpoints ; i++)
826                 {
827                         fprintf (pf,"(");
828                         WriteFloat (pf, w->points[i][0]);
829                         WriteFloat (pf, w->points[i][1]);
830                         WriteFloat (pf, w->points[i][2]);
831                         fprintf (pf,") ");
832                 }
833                 fprintf (pf,"\n");
834         }*/
835
836         fclose (pf);
837 }
838
839 /*
840 ============
841 LoadPortals
842 ============
843 */
844 void LoadPortals (char *name)
845 {
846         int                     i, j, hint;
847         vportal_t       *p;
848         leaf_t          *l;
849         char            magic[80];
850         FILE            *f;
851         int                     numpoints;
852         fixedWinding_t  *w;
853         int                     leafnums[2];
854         visPlane_t      plane;
855         
856         if (!strcmp(name,"-"))
857                 f = stdin;
858         else
859         {
860                 f = fopen(name, "r");
861                 if (!f)
862                         Error ("LoadPortals: couldn't read %s\n",name);
863         }
864
865         if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4)
866                 Error ("LoadPortals: failed to read header");
867         if (strcmp(magic,PORTALFILE))
868                 Error ("LoadPortals: not a portal file");
869
870         Sys_Printf ("%6i portalclusters\n", portalclusters);
871         Sys_Printf ("%6i numportals\n", numportals);
872         Sys_Printf ("%6i numfaces\n", numfaces);
873
874         // these counts should take advantage of 64 bit systems automatically
875         leafbytes = ((portalclusters+63)&~63)>>3;
876         leaflongs = leafbytes/sizeof(long);
877         
878         portalbytes = ((numportals*2+63)&~63)>>3;
879         portallongs = portalbytes/sizeof(long);
880
881         // each file portal is split into two memory portals
882         portals = safe_malloc(2*numportals*sizeof(vportal_t));
883         memset (portals, 0, 2*numportals*sizeof(vportal_t));
884         
885         leafs = safe_malloc(portalclusters*sizeof(leaf_t));
886         memset (leafs, 0, portalclusters*sizeof(leaf_t));
887
888         for (i = 0; i < portalclusters; i++)
889                 leafs[i].merged = -1;
890
891         numBSPVisBytes = VIS_HEADER_SIZE + portalclusters*leafbytes;
892
893         if (numBSPVisBytes > MAX_MAP_VISIBILITY)
894           Error("MAX_MAP_VISIBILITY exceeded");
895
896         ((int *)bspVisBytes)[0] = portalclusters;
897         ((int *)bspVisBytes)[1] = leafbytes;
898                 
899         for (i=0, p=portals ; i<numportals ; i++)
900         {
901                 if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3)
902                         Error ("LoadPortals: reading portal %i", i);
903                 if (numpoints > MAX_POINTS_ON_WINDING)
904                         Error ("LoadPortals: portal %i has too many points", i);
905                 if ( (unsigned)leafnums[0] > portalclusters
906                 || (unsigned)leafnums[1] > portalclusters)
907                         Error ("LoadPortals: reading portal %i", i);
908                 if (fscanf (f, "%i ", &hint) != 1)
909                         Error ("LoadPortals: reading hint state");
910                 
911                 w = p->winding = NewFixedWinding (numpoints);
912                 w->numpoints = numpoints;
913                 
914                 for (j=0 ; j<numpoints ; j++)
915                 {
916                         double  v[3];
917                         int             k;
918
919                         // scanf into double, then assign to vec_t
920                         // so we don't care what size vec_t is
921                         if (fscanf (f, "(%lf %lf %lf ) "
922                         , &v[0], &v[1], &v[2]) != 3)
923                                 Error ("LoadPortals: reading portal %i", i);
924                         for (k=0 ; k<3 ; k++)
925                                 w->points[j][k] = v[k];
926                 }
927                 fscanf (f, "\n");
928                 
929                 // calc plane
930                 PlaneFromWinding (w, &plane);
931
932                 // create forward portal
933                 l = &leafs[leafnums[0]];
934                 if (l->numportals == MAX_PORTALS_ON_LEAF)
935                         Error ("Leaf with too many portals");
936                 l->portals[l->numportals] = p;
937                 l->numportals++;
938                 
939                 p->num = i+1;
940                 p->hint = hint;
941                 p->winding = w;
942                 VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
943                 p->plane.dist = -plane.dist;
944                 p->leaf = leafnums[1];
945                 SetPortalSphere (p);
946                 p++;
947                 
948                 // create backwards portal
949                 l = &leafs[leafnums[1]];
950                 if (l->numportals == MAX_PORTALS_ON_LEAF)
951                         Error ("Leaf with too many portals");
952                 l->portals[l->numportals] = p;
953                 l->numportals++;
954                 
955                 p->num = i+1;
956                 p->hint = hint;
957                 p->winding = NewFixedWinding(w->numpoints);
958                 p->winding->numpoints = w->numpoints;
959                 for (j=0 ; j<w->numpoints ; j++)
960                 {
961                         VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]);
962                 }
963
964                 p->plane = plane;
965                 p->leaf = leafnums[0];
966                 SetPortalSphere (p);
967                 p++;
968
969         }
970
971         faces = safe_malloc(2*numfaces*sizeof(vportal_t));
972         memset (faces, 0, 2*numfaces*sizeof(vportal_t));
973
974         faceleafs = safe_malloc(portalclusters*sizeof(leaf_t));
975         memset(faceleafs, 0, portalclusters*sizeof(leaf_t));
976
977         for (i = 0, p = faces; i < numfaces; i++)
978         {
979                 if (fscanf (f, "%i %i ", &numpoints, &leafnums[0]) != 2)
980                         Error ("LoadPortals: reading portal %i", i);
981
982                 w = p->winding = NewFixedWinding (numpoints);
983                 w->numpoints = numpoints;
984                 
985                 for (j=0 ; j<numpoints ; j++)
986                 {
987                         double  v[3];
988                         int             k;
989
990                         // scanf into double, then assign to vec_t
991                         // so we don't care what size vec_t is
992                         if (fscanf (f, "(%lf %lf %lf ) "
993                         , &v[0], &v[1], &v[2]) != 3)
994                                 Error ("LoadPortals: reading portal %i", i);
995                         for (k=0 ; k<3 ; k++)
996                                 w->points[j][k] = v[k];
997                 }
998                 fscanf (f, "\n");
999                 
1000                 // calc plane
1001                 PlaneFromWinding (w, &plane);
1002
1003                 l = &faceleafs[leafnums[0]];
1004                 l->merged = -1;
1005                 if (l->numportals == MAX_PORTALS_ON_LEAF)
1006                         Error ("Leaf with too many faces");
1007                 l->portals[l->numportals] = p;
1008                 l->numportals++;
1009                 
1010                 p->num = i+1;
1011                 p->winding = w;
1012                 // normal pointing out of the leaf
1013                 VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
1014                 p->plane.dist = -plane.dist;
1015                 p->leaf = -1;
1016                 SetPortalSphere (p);
1017                 p++;
1018         }
1019         
1020         fclose (f);
1021 }
1022
1023
1024
1025 /*
1026 ===========
1027 VisMain
1028 ===========
1029 */
1030 int VisMain (int argc, char **argv)
1031 {
1032         char            portalfile[1024];
1033         int                     i;
1034         
1035         
1036         /* note it */
1037         Sys_Printf( "--- Vis ---\n" );
1038         
1039         /* process arguments */
1040         for (i=1 ; i < (argc - 1) ; i++)
1041         {
1042                 if (!strcmp(argv[i], "-fast")) {
1043                         Sys_Printf ("fastvis = true\n");
1044                         fastvis = qtrue;
1045                 } else if (!strcmp(argv[i], "-merge")) {
1046                         Sys_Printf ("merge = true\n");
1047                         mergevis = qtrue;
1048                 } else if (!strcmp(argv[i], "-nopassage")) {
1049                         Sys_Printf ("nopassage = true\n");
1050                         noPassageVis = qtrue;
1051                 } else if (!strcmp(argv[i], "-passageOnly")) {
1052                         Sys_Printf ("passageOnly = true\n");
1053                         passageVisOnly = qtrue;
1054                 } else if (!strcmp (argv[i],"-nosort")) {
1055                         Sys_Printf ("nosort = true\n");
1056                         nosort = qtrue;
1057                 } else if (!strcmp (argv[i],"-saveprt")) {
1058                         Sys_Printf ("saveprt = true\n");
1059                         saveprt = qtrue;
1060                 } else if (!strcmp (argv[i],"-tmpin")) {
1061                         strcpy (inbase, "/tmp");
1062                 } else if (!strcmp (argv[i],"-tmpout")) {
1063                         strcpy (outbase, "/tmp");
1064                 }
1065                 
1066         
1067                 /* ydnar: -hint to merge all but hint portals */
1068                 else if( !strcmp( argv[ i ], "-hint" ) )
1069                 {
1070                         Sys_Printf( "hint = true\n" );
1071                         hint = qtrue;
1072                         mergevis = qtrue;
1073                 }
1074                 
1075                 else
1076                         Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
1077         }
1078
1079         if( i != argc - 1 )
1080                 Error( "usage: vis [-threads #] [-level 0-4] [-fast] [-v] bspfile" );
1081         
1082
1083         /* load the bsp */
1084         sprintf( source, "%s%s", inbase, ExpandArg( argv[ i ] ) );
1085         StripExtension( source );
1086         strcat( source, ".bsp" );
1087         Sys_Printf( "Loading %s\n", source );
1088         LoadBSPFile( source );
1089         
1090         /* load the portal file */
1091         sprintf( portalfile, "%s%s", inbase, ExpandArg( argv[ i ] ) );
1092         StripExtension( portalfile );
1093         strcat( portalfile, ".prt" );
1094         Sys_Printf( "Loading %s\n", portalfile );
1095         LoadPortals( portalfile );
1096         
1097         /* ydnar: for getting far plane */
1098         ParseEntities();
1099         
1100         if( mergevis )
1101         {
1102                 MergeLeaves();
1103                 MergeLeafPortals();
1104         }
1105         
1106         CountActivePortals();
1107         /* WritePortals( "maps/hints.prs" );*/
1108         
1109         Sys_Printf( "visdatasize:%i\n", numBSPVisBytes );
1110         
1111         CalcVis();
1112         
1113         /* delete the prt file */
1114         if( !saveprt )
1115                 remove( portalfile );
1116
1117         /* write the bsp file */
1118         Sys_Printf( "Writing %s\n", source );
1119         WriteBSPFile( source );
1120
1121         return 0;
1122 }