]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/map.c
Merge commit 'e744bb6dadcd57fff460b7e6409ecd61bfe272c7' into master-merge
[xonotic/netradiant.git] / tools / quake3 / q3map2 / map.c
1 /* -------------------------------------------------------------------------------
2
3    Copyright (C) 1999-2007 id Software, Inc. and contributors.
4    For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6    This file is part of GtkRadiant.
7
8    GtkRadiant is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    GtkRadiant is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with GtkRadiant; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22    ----------------------------------------------------------------------------------
23
24    This code has been altered significantly from its original form, to support
25    several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27    ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define MAP_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41 /* FIXME: remove these vars */
42
43 /* undefine to make plane finding use linear sort (note: really slow) */
44 #define USE_HASHING
45 #define PLANE_HASHES    8192
46
47 int planehash[ PLANE_HASHES ];
48
49 int c_boxbevels;
50 int c_edgebevels;
51 int c_areaportals;
52 int c_detail;
53 int c_structural;
54
55
56
57 /*
58    PlaneEqual()
59    ydnar: replaced with variable epsilon for djbob
60  */
61
62 qboolean PlaneEqual( plane_t *p, vec3_t normal, vec_t dist ){
63         float ne, de;
64
65
66         /* get local copies */
67         ne = normalEpsilon;
68         de = distanceEpsilon;
69
70         /* compare */
71         // We check equality of each component since we're using '<', not '<='
72         // (the epsilons may be zero).  We want to use '<' instead of '<=' to be
73         // consistent with the true meaning of "epsilon", and also because other
74         // parts of the code uses this inequality.
75         if ( ( p->dist == dist || fabs( p->dist - dist ) < de ) &&
76                  ( p->normal[0] == normal[0] || fabs( p->normal[0] - normal[0] ) < ne ) &&
77                  ( p->normal[1] == normal[1] || fabs( p->normal[1] - normal[1] ) < ne ) &&
78                  ( p->normal[2] == normal[2] || fabs( p->normal[2] - normal[2] ) < ne ) ) {
79                 return qtrue;
80         }
81
82         /* different */
83         return qfalse;
84 }
85
86
87
88 /*
89    AddPlaneToHash()
90  */
91
92 void AddPlaneToHash( plane_t *p ){
93         int hash;
94
95
96         hash = ( PLANE_HASHES - 1 ) & (int) fabs( p->dist );
97
98         p->hash_chain = planehash[hash];
99         planehash[hash] = p - mapplanes + 1;
100 }
101
102 /*
103    ================
104    CreateNewFloatPlane
105    ================
106  */
107 int CreateNewFloatPlane( vec3_t normal, vec_t dist ){
108         plane_t *p, temp;
109
110         if ( VectorLength( normal ) < 0.5 ) {
111                 Sys_Printf( "FloatPlane: bad normal\n" );
112                 return -1;
113         }
114
115         // create a new plane
116         AUTOEXPAND_BY_REALLOC( mapplanes, nummapplanes + 1, allocatedmapplanes, 1024 );
117
118         p = &mapplanes[nummapplanes];
119         VectorCopy( normal, p->normal );
120         p->dist = dist;
121         p->type = ( p + 1 )->type = PlaneTypeForNormal( p->normal );
122
123         VectorSubtract( vec3_origin, normal, ( p + 1 )->normal );
124         ( p + 1 )->dist = -dist;
125
126         nummapplanes += 2;
127
128         // allways put axial planes facing positive first
129         if ( p->type < 3 ) {
130                 if ( p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0 ) {
131                         // flip order
132                         temp = *p;
133                         *p = *( p + 1 );
134                         *( p + 1 ) = temp;
135
136                         AddPlaneToHash( p );
137                         AddPlaneToHash( p + 1 );
138                         return nummapplanes - 1;
139                 }
140         }
141
142         AddPlaneToHash( p );
143         AddPlaneToHash( p + 1 );
144         return nummapplanes - 2;
145 }
146
147
148
149 /*
150    SnapNormal()
151    Snaps a near-axial normal vector.
152    Returns qtrue if and only if the normal was adjusted.
153  */
154
155 qboolean SnapNormal( vec3_t normal ){
156 #if Q3MAP2_EXPERIMENTAL_SNAP_NORMAL_FIX
157         int i;
158         qboolean adjusted = qfalse;
159
160         // A change from the original SnapNormal() is that we snap each
161         // component that's close to 0.  So for example if a normal is
162         // (0.707, 0.707, 0.0000001), it will get snapped to lie perfectly in the
163         // XY plane (its Z component will be set to 0 and its length will be
164         // normalized).  The original SnapNormal() didn't snap such vectors - it
165         // only snapped vectors that were near a perfect axis.
166
167         //adjusting vectors, that are near perfect axis, with bigger epsilon
168         //they cause precision errors
169
170
171         if ( ( normal[0] != 0.0 || normal[1] != 0.0 ) && fabs(normal[0]) < 0.00025 && fabs(normal[1]) < 0.00025){
172                 normal[0] = normal[1] = 0.0;
173                 adjusted = qtrue;
174         }
175         else if ( ( normal[0] != 0.0 || normal[2] != 0.0 ) && fabs(normal[0]) < 0.00025 && fabs(normal[2]) < 0.00025){
176                 normal[0] = normal[2] = 0.0;
177                 adjusted = qtrue;
178         }
179         else if ( ( normal[2] != 0.0 || normal[1] != 0.0 ) && fabs(normal[2]) < 0.00025 && fabs(normal[1]) < 0.00025){
180                 normal[2] = normal[1] = 0.0;
181                 adjusted = qtrue;
182         }
183
184
185         /*
186         for ( i=0; i<30; i++ )
187         {
188                 double x, y, z, length;
189                 x=(double) 1.0;
190                 y=(double) ( 0.00001 * i );
191                 z=(double) 0.0;
192
193                 Sys_Printf("(%6.18f %6.18f %6.18f)inNormal\n", x,y,z );
194
195                 length = sqrt( ( x * x ) + ( y * y ) + ( z * z ) );
196                 Sys_Printf("(%6.18f)length\n", length);
197                 x = (vec_t) ( x / length );
198                 y = (vec_t) ( y / length );
199                 z = (vec_t) ( z / length );
200                 Sys_Printf("(%6.18f %6.18f %6.18f)outNormal\n\n", x,y,z );
201         }
202         Error("vectorNormalize test completed");
203         */
204
205         for ( i = 0; i < 3; i++ )
206         {
207                 if ( normal[i] != 0.0 && -normalEpsilon < normal[i] && normal[i] < normalEpsilon ) {
208                         normal[i] = 0.0;
209                         adjusted = qtrue;
210                 }
211         }
212
213         if ( adjusted ) {
214                 VectorNormalize( normal, normal );
215                 return qtrue;
216         }
217         return qfalse;
218 #else
219         int i;
220
221         // I would suggest that you uncomment the following code and look at the
222         // results:
223
224         /*
225            Sys_Printf("normalEpsilon is %f\n", normalEpsilon);
226            for (i = 0;; i++)
227            {
228             normal[0] = 1.0;
229             normal[1] = 0.0;
230             normal[2] = i * 0.000001;
231             VectorNormalize(normal, normal);
232             if (1.0 - normal[0] >= normalEpsilon) {
233                 Sys_Printf("(%f %f %f)\n", normal[0], normal[1], normal[2]);
234                 Error("SnapNormal: test completed");
235             }
236            }
237          */
238
239         // When the normalEpsilon is 0.00001, the loop will break out when normal is
240         // (0.999990 0.000000 0.004469).  In other words, this is the vector closest
241         // to axial that will NOT be snapped.  Anything closer will be snaped.  Now,
242         // 0.004469 is close to 1/225.  The length of a circular quarter-arc of radius
243         // 1 is PI/2, or about 1.57.  And 0.004469/1.57 is about 0.0028, or about
244         // 1/350.  Expressed a different way, 1/350 is also about 0.26/90.
245         // This means is that a normal with an angle that is within 1/4 of a degree
246         // from axial will be "snapped".  My belief is that the person who wrote the
247         // code below did not intend it this way.  I think the person intended that
248         // the epsilon be measured against the vector components close to 0, not 1.0.
249         // I think the logic should be: if 2 of the normal components are within
250         // epsilon of 0, then the vector can be snapped to be perfectly axial.
251         // We may consider adjusting the epsilon to a larger value when we make this
252         // code fix.
253
254         for ( i = 0; i < 3; i++ )
255         {
256                 if ( fabs( normal[ i ] - 1 ) < normalEpsilon ) {
257                         VectorClear( normal );
258                         normal[ i ] = 1;
259                         return qtrue;
260                 }
261                 if ( fabs( normal[ i ] - -1 ) < normalEpsilon ) {
262                         VectorClear( normal );
263                         normal[ i ] = -1;
264                         return qtrue;
265                 }
266         }
267         return qfalse;
268 #endif
269 }
270
271
272
273 /*
274    SnapPlane()
275    snaps a plane to normal/distance epsilons
276  */
277
278 void SnapPlane( vec3_t normal, vec_t *dist ){
279 // SnapPlane disabled by LordHavoc because it often messes up collision
280 // brushes made from triangles of embedded models, and it has little effect
281 // on anything else (axial planes are usually derived from snapped points)
282 /*
283    SnapPlane reenabled by namespace because of multiple reports of
284    q3map2-crashes which were triggered by this patch.
285  */
286         SnapNormal( normal );
287
288         // TODO: Rambetter has some serious comments here as well.  First off,
289         // in the case where a normal is non-axial, there is nothing special
290         // about integer distances.  I would think that snapping a distance might
291         // make sense for axial normals, but I'm not so sure about snapping
292         // non-axial normals.  A shift by 0.01 in a plane, multiplied by a clipping
293         // against another plane that is 5 degrees off, and we introduce 0.1 error
294         // easily.  A 0.1 error in a vertex is where problems start to happen, such
295         // as disappearing triangles.
296
297         // Second, assuming we have snapped the normal above, let's say that the
298         // plane we just snapped was defined for some points that are actually
299         // quite far away from normal * dist.  Well, snapping the normal in this
300         // case means that we've just moved those points by potentially many units!
301         // Therefore, if we are going to snap the normal, we need to know the
302         // points we're snapping for so that the plane snaps with those points in
303         // mind (points remain close to the plane).
304
305         // I would like to know exactly which problems SnapPlane() is trying to
306         // solve so that we can better engineer it (I'm not saying that SnapPlane()
307         // should be removed altogether).  Fix all this snapping code at some point!
308
309         if ( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon ) {
310                 *dist = Q_rint( *dist );
311         }
312 }
313
314 /*
315    SnapPlaneImproved()
316    snaps a plane to normal/distance epsilons, improved code
317  */
318 void SnapPlaneImproved( vec3_t normal, vec_t *dist, int numPoints, const vec3_t *points ){
319         int i;
320         vec3_t center;
321         vec_t distNearestInt;
322
323         if ( SnapNormal( normal ) ) {
324                 if ( numPoints > 0 ) {
325                         // Adjust the dist so that the provided points don't drift away.
326                         VectorClear( center );
327                         for ( i = 0; i < numPoints; i++ )
328                         {
329                                 VectorAdd( center, points[i], center );
330                         }
331                         for ( i = 0; i < 3; i++ ) { center[i] = center[i] / numPoints; }
332                         *dist = DotProduct( normal, center );
333                 }
334         }
335
336         if ( VectorIsOnAxis( normal ) ) {
337                 // Only snap distance if the normal is an axis.  Otherwise there
338                 // is nothing "natural" about snapping the distance to an integer.
339                 distNearestInt = Q_rint( *dist );
340                 if ( -distanceEpsilon < *dist - distNearestInt && *dist - distNearestInt < distanceEpsilon ) {
341                         *dist = distNearestInt;
342                 }
343         }
344 }
345
346
347
348 /*
349    FindFloatPlane()
350    ydnar: changed to allow a number of test points to be supplied that
351    must be within an epsilon distance of the plane
352  */
353
354 int FindFloatPlane( vec3_t innormal, vec_t dist, int numPoints, vec3_t *points ) // NOTE: this has a side effect on the normal. Good or bad?
355
356 #ifdef USE_HASHING
357
358 {
359         int i, j, hash, h;
360         int pidx;
361         plane_t *p;
362         vec_t d;
363         vec3_t normal;
364
365         VectorCopy( innormal, normal );
366 #if Q3MAP2_EXPERIMENTAL_SNAP_PLANE_FIX
367         SnapPlaneImproved( normal, &dist, numPoints, (const vec3_t *) points );
368 #else
369         SnapPlane( normal, &dist );
370 #endif
371         /* hash the plane */
372         hash = ( PLANE_HASHES - 1 ) & (int) fabs( dist );
373
374         /* search the border bins as well */
375         for ( i = -1; i <= 1; i++ )
376         {
377                 h = ( hash + i ) & ( PLANE_HASHES - 1 );
378                 for ( pidx = planehash[ h ] - 1; pidx != -1; pidx = mapplanes[pidx].hash_chain - 1 )
379                 {
380                         p = &mapplanes[pidx];
381
382                         /* do standard plane compare */
383                         if ( !PlaneEqual( p, normal, dist ) ) {
384                                 continue;
385                         }
386
387                         /* ydnar: uncomment the following line for old-style plane finding */
388                         //%     return p - mapplanes;
389
390                         /* ydnar: test supplied points against this plane */
391                         for ( j = 0; j < numPoints; j++ )
392                         {
393                                 // NOTE: When dist approaches 2^16, the resolution of 32 bit floating
394                                 // point number is greatly decreased.  The distanceEpsilon cannot be
395                                 // very small when world coordinates extend to 2^16.  Making the
396                                 // dot product here in 64 bit land will not really help the situation
397                                 // because the error will already be carried in dist.
398                                 d = DotProduct( points[ j ], p->normal ) - p->dist;
399                                 d = fabs( d );
400                                 if ( d != 0.0 && d >= distanceEpsilon ) {
401                                         break; // Point is too far from plane.
402                                 }
403                         }
404
405                         /* found a matching plane */
406                         if ( j >= numPoints ) {
407                                 return p - mapplanes;
408                         }
409                 }
410         }
411
412         /* none found, so create a new one */
413         return CreateNewFloatPlane( normal, dist );
414 }
415
416 #else
417
418 {
419         int i;
420         plane_t *p;
421         vec3_t normal;
422
423         VectorCopy( innormal, normal );
424 #if Q3MAP2_EXPERIMENTAL_SNAP_PLANE_FIX
425         SnapPlaneImproved( normal, &dist, numPoints, (const vec3_t *) points );
426 #else
427         SnapPlane( normal, &dist );
428 #endif
429         for ( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
430         {
431                 if ( !PlaneEqual( p, normal, dist ) ) {
432                         continue;
433                 }
434
435                 /* ydnar: uncomment the following line for old-style plane finding */
436                 //%     return i;
437
438                 /* ydnar: test supplied points against this plane */
439                 for ( j = 0; j < numPoints; j++ )
440                 {
441                         d = DotProduct( points[ j ], p->normal ) - p->dist;
442                         if ( fabs( d ) > distanceEpsilon ) {
443                                 break;
444                         }
445                 }
446
447                 /* found a matching plane */
448                 if ( j >= numPoints ) {
449                         return i;
450                 }
451                 // TODO: Note that the non-USE_HASHING code does not compute epsilons
452                 // for the provided points.  It should do that.  I think this code
453                 // is unmaintained because nobody sets USE_HASHING to off.
454         }
455
456         return CreateNewFloatPlane( normal, dist );
457 }
458
459 #endif
460
461
462
463 /*
464    MapPlaneFromPoints()
465    takes 3 points and finds the plane they lie in
466  */
467
468 int MapPlaneFromPoints( vec3_t *p ){
469 #if Q3MAP2_EXPERIMENTAL_HIGH_PRECISION_MATH_FIXES
470         vec3_accu_t paccu[3];
471         vec3_accu_t t1, t2, normalAccu;
472         vec3_t normal;
473         vec_t dist;
474
475         VectorCopyRegularToAccu( p[0], paccu[0] );
476         VectorCopyRegularToAccu( p[1], paccu[1] );
477         VectorCopyRegularToAccu( p[2], paccu[2] );
478
479         VectorSubtractAccu( paccu[0], paccu[1], t1 );
480         VectorSubtractAccu( paccu[2], paccu[1], t2 );
481         CrossProductAccu( t1, t2, normalAccu );
482         VectorNormalizeAccu( normalAccu, normalAccu );
483         // TODO: A 32 bit float for the plane distance isn't enough resolution
484         // if the plane is 2^16 units away from the origin (the "epsilon" approaches
485         // 0.01 in that case).
486         dist = (vec_t) DotProductAccu( paccu[0], normalAccu );
487         VectorCopyAccuToRegular( normalAccu, normal );
488
489         return FindFloatPlane( normal, dist, 3, p );
490 #else
491         vec3_t t1, t2, normal;
492         vec_t dist;
493
494
495         /* calc plane normal */
496         VectorSubtract( p[ 0 ], p[ 1 ], t1 );
497         VectorSubtract( p[ 2 ], p[ 1 ], t2 );
498         CrossProduct( t1, t2, normal );
499         VectorNormalize( normal, normal );
500
501         /* calc plane distance */
502         dist = DotProduct( p[ 0 ], normal );
503
504         /* store the plane */
505         return FindFloatPlane( normal, dist, 3, p );
506 #endif
507 }
508
509
510
511 /*
512    SetBrushContents()
513    the content flags and compile flags on all sides of a brush should be the same
514  */
515
516 void SetBrushContents( brush_t *b ){
517         int contentFlags, compileFlags;
518         side_t      *s;
519         int i;
520         //%     qboolean        mixed;
521
522
523         /* get initial compile flags from first side */
524         s = &b->sides[ 0 ];
525         contentFlags = s->contentFlags;
526         compileFlags = s->compileFlags;
527         b->contentShader = s->shaderInfo;
528         //%     mixed = qfalse;
529
530         /* get the content/compile flags for every side in the brush */
531         for ( i = 1; i < b->numsides; i++, s++ )
532         {
533                 s = &b->sides[ i ];
534                 if ( s->shaderInfo == NULL ) {
535                         continue;
536                 }
537                 //%     if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
538                 //%             mixed = qtrue;
539
540                 contentFlags |= s->contentFlags;
541                 compileFlags |= s->compileFlags;
542         }
543
544         /* ydnar: getting rid of this stupid warning */
545         //%     if( mixed )
546         //%             Sys_FPrintf( SYS_VRB,"Entity %i, Brush %i: mixed face contentFlags\n", b->entitynum, b->brushnum );
547
548         /* check for detail & structural */
549         if ( ( compileFlags & C_DETAIL ) && ( compileFlags & C_STRUCTURAL ) ) {
550                 xml_Select( "Mixed detail and structural (defaulting to structural)", mapEnt->mapEntityNum, entitySourceBrushes, qfalse );
551                 compileFlags &= ~C_DETAIL;
552         }
553
554         /* the fulldetail flag will cause detail brushes to be treated like normal brushes */
555         if ( fulldetail ) {
556                 compileFlags &= ~C_DETAIL;
557         }
558
559         /* all translucent brushes that aren't specifically made structural will be detail */
560         if ( ( compileFlags & C_TRANSLUCENT ) && !( compileFlags & C_STRUCTURAL ) ) {
561                 compileFlags |= C_DETAIL;
562         }
563
564         /* detail? */
565         if ( compileFlags & C_DETAIL ) {
566                 c_detail++;
567                 b->detail = qtrue;
568         }
569         else
570         {
571                 c_structural++;
572                 b->detail = qfalse;
573         }
574
575         /* opaque? */
576         if ( compileFlags & C_TRANSLUCENT ) {
577                 b->opaque = qfalse;
578         }
579         else{
580                 b->opaque = qtrue;
581         }
582
583         /* areaportal? */
584         if ( compileFlags & C_AREAPORTAL ) {
585                 c_areaportals++;
586         }
587
588         /* set brush flags */
589         b->contentFlags = contentFlags;
590         b->compileFlags = compileFlags;
591 }
592
593
594
595 /*
596    AddBrushBevels()
597    adds any additional planes necessary to allow the brush being
598    built to be expanded against axial bounding boxes
599    ydnar 2003-01-20: added mrelusive fixes
600  */
601
602 void AddBrushBevels( void ){
603         int axis, dir;
604         int i, j, k, l, order;
605         side_t sidetemp;
606         side_t      *s, *s2;
607         winding_t   *w, *w2;
608         vec3_t normal;
609         float dist;
610         vec3_t vec, vec2;
611         float d, minBack;
612
613         //
614         // add the axial planes
615         //
616         order = 0;
617         for ( axis = 0; axis < 3; axis++ ) {
618                 for ( dir = -1; dir <= 1; dir += 2, order++ ) {
619                         // see if the plane is allready present
620                         for ( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
621                         {
622                                 /* ydnar: testing disabling of mre code */
623                                 #if 0
624                                 if ( dir > 0 ) {
625                                         if ( mapplanes[s->planenum].normal[axis] >= 0.9999f ) {
626                                                 break;
627                                         }
628                                 }
629                                 else {
630                                         if ( mapplanes[s->planenum].normal[axis] <= -0.9999f ) {
631                                                 break;
632                                         }
633                                 }
634                                 #else
635                                 if ( ( dir > 0 && mapplanes[ s->planenum ].normal[ axis ] == 1.0f ) ||
636                                          ( dir < 0 && mapplanes[ s->planenum ].normal[ axis ] == -1.0f ) ) {
637                                         break;
638                                 }
639                                 #endif
640                         }
641
642                         if ( i == buildBrush->numsides ) {
643                                 // add a new side
644                                 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
645                                         xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
646                                 }
647                                 memset( s, 0, sizeof( *s ) );
648                                 buildBrush->numsides++;
649                                 VectorClear( normal );
650                                 normal[axis] = dir;
651
652                                 if ( dir == 1 ) {
653                                         /* ydnar: adding bevel plane snapping for fewer bsp planes */
654                                         if ( bevelSnap > 0 ) {
655                                                 dist = floor( buildBrush->maxs[ axis ] / bevelSnap ) * bevelSnap;
656                                         }
657                                         else{
658                                                 dist = buildBrush->maxs[ axis ];
659                                         }
660                                 }
661                                 else
662                                 {
663                                         /* ydnar: adding bevel plane snapping for fewer bsp planes */
664                                         if ( bevelSnap > 0 ) {
665                                                 dist = -ceil( buildBrush->mins[ axis ] / bevelSnap ) * bevelSnap;
666                                         }
667                                         else{
668                                                 dist = -buildBrush->mins[ axis ];
669                                         }
670                                 }
671
672                                 s->planenum = FindFloatPlane( normal, dist, 0, NULL );
673                                 s->contentFlags = buildBrush->sides[ 0 ].contentFlags;
674                                 s->bevel = qtrue;
675                                 c_boxbevels++;
676                         }
677
678                         // if the plane is not in it canonical order, swap it
679                         if ( i != order ) {
680                                 sidetemp = buildBrush->sides[order];
681                                 buildBrush->sides[order] = buildBrush->sides[i];
682                                 buildBrush->sides[i] = sidetemp;
683                         }
684                 }
685         }
686
687         //
688         // add the edge bevels
689         //
690         if ( buildBrush->numsides == 6 ) {
691                 return;     // pure axial
692         }
693
694         // test the non-axial plane edges
695         for ( i = 6; i < buildBrush->numsides; i++ ) {
696                 s = buildBrush->sides + i;
697                 w = s->winding;
698                 if ( !w ) {
699                         continue;
700                 }
701                 for ( j = 0; j < w->numpoints; j++ ) {
702                         k = ( j + 1 ) % w->numpoints;
703                         VectorSubtract( w->p[j], w->p[k], vec );
704                         if ( VectorNormalize( vec, vec ) < 0.5f ) {
705                                 continue;
706                         }
707                         SnapNormal( vec );
708                         for ( k = 0; k < 3; k++ ) {
709                                 if ( vec[k] == -1.0f || vec[k] == 1.0f || ( vec[k] == 0.0f && vec[( k + 1 ) % 3] == 0.0f ) ) {
710                                         break;  // axial
711                                 }
712                         }
713                         if ( k != 3 ) {
714                                 continue;   // only test non-axial edges
715                         }
716
717                         /* debug code */
718                         //%     Sys_Printf( "-------------\n" );
719
720                         // try the six possible slanted axials from this edge
721                         for ( axis = 0; axis < 3; axis++ ) {
722                                 for ( dir = -1; dir <= 1; dir += 2 ) {
723                                         // construct a plane
724                                         VectorClear( vec2 );
725                                         vec2[axis] = dir;
726                                         CrossProduct( vec, vec2, normal );
727                                         if ( VectorNormalize( normal, normal ) < 0.5f ) {
728                                                 continue;
729                                         }
730                                         dist = DotProduct( w->p[j], normal );
731
732                                         // if all the points on all the sides are
733                                         // behind this plane, it is a proper edge bevel
734                                         for ( k = 0; k < buildBrush->numsides; k++ ) {
735
736                                                 // if this plane has allready been used, skip it
737                                                 if ( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ) ) {
738                                                         break;
739                                                 }
740
741                                                 w2 = buildBrush->sides[k].winding;
742                                                 if ( !w2 ) {
743                                                         continue;
744                                                 }
745                                                 minBack = 0.0f;
746                                                 for ( l = 0; l < w2->numpoints; l++ ) {
747                                                         d = DotProduct( w2->p[l], normal ) - dist;
748                                                         if ( d > 0.1f ) {
749                                                                 break;  // point in front
750                                                         }
751                                                         if ( d < minBack ) {
752                                                                 minBack = d;
753                                                         }
754                                                 }
755                                                 // if some point was at the front
756                                                 if ( l != w2->numpoints ) {
757                                                         break;
758                                                 }
759
760                                                 // if no points at the back then the winding is on the bevel plane
761                                                 if ( minBack > -0.1f ) {
762                                                         //%     Sys_Printf( "On bevel plane\n" );
763                                                         break;
764                                                 }
765                                         }
766
767                                         if ( k != buildBrush->numsides ) {
768                                                 continue;   // wasn't part of the outer hull
769                                         }
770
771                                         /* debug code */
772                                         //%     Sys_Printf( "n = %f %f %f\n", normal[ 0 ], normal[ 1 ], normal[ 2 ] );
773
774                                         // add this plane
775                                         if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
776                                                 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
777                                         }
778                                         s2 = &buildBrush->sides[buildBrush->numsides];
779                                         buildBrush->numsides++;
780                                         memset( s2, 0, sizeof( *s2 ) );
781
782                                         s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[ j ] );
783                                         s2->contentFlags = buildBrush->sides[0].contentFlags;
784                                         s2->bevel = qtrue;
785                                         c_edgebevels++;
786                                 }
787                         }
788                 }
789         }
790 }
791
792
793
794 /*
795    FinishBrush()
796    produces a final brush based on the buildBrush->sides array
797    and links it to the current entity
798  */
799
800 static void MergeOrigin( entity_t *ent, vec3_t origin ){
801         vec3_t adjustment;
802         char string[128];
803
804         /* we have not parsed the brush completely yet... */
805         GetVectorForKey( ent, "origin", ent->origin );
806
807         VectorMA( origin, -1, ent->originbrush_origin, adjustment );
808         VectorAdd( adjustment, ent->origin, ent->origin );
809         VectorCopy( origin, ent->originbrush_origin );
810
811         sprintf( string, "%f %f %f", ent->origin[0], ent->origin[1], ent->origin[2] );
812         SetKeyValue( ent, "origin", string );
813 }
814
815 brush_t *FinishBrush( qboolean noCollapseGroups ){
816         brush_t     *b;
817
818
819         /* create windings for sides and bounds for brush */
820         if ( !CreateBrushWindings( buildBrush ) ) {
821                 return NULL;
822         }
823
824         /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
825            after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
826         if ( buildBrush->compileFlags & C_ORIGIN ) {
827                 vec3_t origin;
828
829                 Sys_Printf( "Entity %i, Brush %i: origin brush detected\n",
830                                         mapEnt->mapEntityNum, entitySourceBrushes );
831
832                 if ( numEntities == 1 ) {
833                         Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n",
834                                                 mapEnt->mapEntityNum, entitySourceBrushes );
835                         return NULL;
836                 }
837
838                 VectorAdd( buildBrush->mins, buildBrush->maxs, origin );
839                 VectorScale( origin, 0.5, origin );
840
841                 MergeOrigin( &entities[ numEntities - 1 ], origin );
842
843                 /* don't keep this brush */
844                 return NULL;
845         }
846
847         /* determine if the brush is an area portal */
848         if ( buildBrush->compileFlags & C_AREAPORTAL ) {
849                 if ( numEntities != 1 ) {
850                         Sys_Printf( "Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
851                         return NULL;
852                 }
853         }
854
855         /* add bevel planes */
856         if ( !noCollapseGroups ) {
857                 AddBrushBevels();
858         }
859
860         /* keep it */
861         b = CopyBrush( buildBrush );
862
863         /* set map entity and brush numbering */
864         b->entityNum = mapEnt->mapEntityNum;
865         b->brushNum = entitySourceBrushes;
866
867         /* set original */
868         b->original = b;
869
870         /* link opaque brushes to head of list, translucent brushes to end */
871         if ( b->opaque || mapEnt->lastBrush == NULL ) {
872                 b->next = mapEnt->brushes;
873                 mapEnt->brushes = b;
874                 if ( mapEnt->lastBrush == NULL ) {
875                         mapEnt->lastBrush = b;
876                 }
877         }
878         else
879         {
880                 b->next = NULL;
881                 mapEnt->lastBrush->next = b;
882                 mapEnt->lastBrush = b;
883         }
884
885         /* link colorMod volume brushes to the entity directly */
886         if ( b->contentShader != NULL &&
887                  b->contentShader->colorMod != NULL &&
888                  b->contentShader->colorMod->type == CM_VOLUME ) {
889                 b->nextColorModBrush = mapEnt->colorModBrushes;
890                 mapEnt->colorModBrushes = b;
891         }
892
893         /* return to sender */
894         return b;
895 }
896
897
898
899 /*
900    TextureAxisFromPlane()
901    determines best orthagonal axis to project a texture onto a wall
902    (must be identical in radiant!)
903  */
904
905 vec3_t baseaxis[18] =
906 {
907         {0,0,1}, {1,0,0}, {0,-1,0},         // floor
908         {0,0,-1}, {1,0,0}, {0,-1,0},        // ceiling
909         {1,0,0}, {0,1,0}, {0,0,-1},         // west wall
910         {-1,0,0}, {0,1,0}, {0,0,-1},        // east wall
911         {0,1,0}, {1,0,0}, {0,0,-1},         // south wall
912         {0,-1,0}, {1,0,0}, {0,0,-1}         // north wall
913 };
914
915 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv ){
916         int bestaxis;
917         vec_t dot,best;
918         int i;
919
920         best = 0;
921         bestaxis = 0;
922
923         for ( i = 0 ; i < 6 ; i++ )
924         {
925                 dot = DotProduct( pln->normal, baseaxis[i * 3] );
926                 if ( dot > best + 0.0001f ) { /* ydnar: bug 637 fix, suggested by jmonroe */
927                         best = dot;
928                         bestaxis = i;
929                 }
930         }
931
932         VectorCopy( baseaxis[bestaxis * 3 + 1], xv );
933         VectorCopy( baseaxis[bestaxis * 3 + 2], yv );
934 }
935
936
937
938 /*
939    QuakeTextureVecs()
940    creates world-to-texture mapping vecs for crappy quake plane arrangements
941  */
942
943 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] ){
944         vec3_t vecs[2];
945         int sv, tv;
946         vec_t ang, sinv, cosv;
947         vec_t ns, nt;
948         int i, j;
949
950
951         TextureAxisFromPlane( plane, vecs[0], vecs[1] );
952
953         if ( !scale[0] ) {
954                 scale[0] = 1;
955         }
956         if ( !scale[1] ) {
957                 scale[1] = 1;
958         }
959
960         // rotate axis
961         if ( rotate == 0 ) {
962                 sinv = 0 ; cosv = 1;
963         }
964         else if ( rotate == 90 ) {
965                 sinv = 1 ; cosv = 0;
966         }
967         else if ( rotate == 180 ) {
968                 sinv = 0 ; cosv = -1;
969         }
970         else if ( rotate == 270 ) {
971                 sinv = -1 ; cosv = 0;
972         }
973         else
974         {
975                 ang = rotate / 180 * Q_PI;
976                 sinv = sin( ang );
977                 cosv = cos( ang );
978         }
979
980         if ( vecs[0][0] ) {
981                 sv = 0;
982         }
983         else if ( vecs[0][1] ) {
984                 sv = 1;
985         }
986         else{
987                 sv = 2;
988         }
989
990         if ( vecs[1][0] ) {
991                 tv = 0;
992         }
993         else if ( vecs[1][1] ) {
994                 tv = 1;
995         }
996         else{
997                 tv = 2;
998         }
999
1000         for ( i = 0 ; i < 2 ; i++ ) {
1001                 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
1002                 nt = sinv * vecs[i][sv] +  cosv * vecs[i][tv];
1003                 vecs[i][sv] = ns;
1004                 vecs[i][tv] = nt;
1005         }
1006
1007         for ( i = 0 ; i < 2 ; i++ )
1008                 for ( j = 0 ; j < 3 ; j++ )
1009                         mappingVecs[i][j] = vecs[i][j] / scale[i];
1010
1011         mappingVecs[0][3] = shift[0];
1012         mappingVecs[1][3] = shift[1];
1013 }
1014
1015
1016
1017 /*
1018    ParseRawBrush()
1019    parses the sides into buildBrush->sides[], nothing else.
1020    no validation, back plane removal, etc.
1021
1022    Timo - 08/26/99
1023    added brush epairs parsing ( ignoring actually )
1024    Timo - 08/04/99
1025    added exclusive brush primitive parsing
1026    Timo - 08/08/99
1027    support for old brush format back in
1028    NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
1029  */
1030
1031 static void ParseRawBrush( qboolean onlyLights ){
1032         side_t          *side;
1033         vec3_t planePoints[ 3 ];
1034         int planenum;
1035         shaderInfo_t    *si;
1036         vec_t shift[ 2 ];
1037         vec_t rotate = 0;
1038         vec_t scale[ 2 ];
1039         char name[ MAX_QPATH ];
1040         char shader[ MAX_QPATH ];
1041         int flags;
1042
1043
1044         /* initial setup */
1045         buildBrush->numsides = 0;
1046         buildBrush->detail = qfalse;
1047
1048         /* bp */
1049         if ( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) {
1050                 MatchToken( "{" );
1051         }
1052
1053         /* parse sides */
1054         while ( 1 )
1055         {
1056                 if ( !GetToken( qtrue ) ) {
1057                         break;
1058                 }
1059                 if ( !strcmp( token, "}" ) ) {
1060                         break;
1061                 }
1062
1063                 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
1064                 if ( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) {
1065                         while ( 1 )
1066                         {
1067                                 if ( strcmp( token, "(" ) ) {
1068                                         GetToken( qfalse );
1069                                 }
1070                                 else{
1071                                         break;
1072                                 }
1073                                 GetToken( qtrue );
1074                         }
1075                 }
1076                 UnGetToken();
1077
1078                 /* test side count */
1079                 if ( buildBrush->numsides >= MAX_BUILD_SIDES ) {
1080                         xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
1081                 }
1082
1083                 /* add side */
1084                 side = &buildBrush->sides[ buildBrush->numsides ];
1085                 memset( side, 0, sizeof( *side ) );
1086                 buildBrush->numsides++;
1087
1088                 /* read the three point plane definition */
1089                 Parse1DMatrix( 3, planePoints[ 0 ] );
1090                 Parse1DMatrix( 3, planePoints[ 1 ] );
1091                 Parse1DMatrix( 3, planePoints[ 2 ] );
1092
1093                 /* bp: read the texture matrix */
1094                 if ( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) {
1095                         Parse2DMatrix( 2, 3, (float*) side->texMat );
1096                 }
1097
1098                 /* read shader name */
1099                 GetToken( qfalse );
1100                 strcpy( name, token );
1101
1102                 /* bp */
1103                 if ( g_bBrushPrimit == BPRIMIT_OLDBRUSHES ) {
1104                         GetToken( qfalse );
1105                         shift[ 0 ] = atof( token );
1106                         GetToken( qfalse );
1107                         shift[ 1 ] = atof( token );
1108                         GetToken( qfalse );
1109                         rotate = atof( token );
1110                         GetToken( qfalse );
1111                         scale[ 0 ] = atof( token );
1112                         GetToken( qfalse );
1113                         scale[ 1 ] = atof( token );
1114                 }
1115
1116                 /* set default flags and values */
1117                 sprintf( shader, "textures/%s", name );
1118                 if ( onlyLights ) {
1119                         si = &shaderInfo[ 0 ];
1120                 }
1121                 else{
1122                         si = ShaderInfoForShader( shader );
1123                 }
1124                 side->shaderInfo = si;
1125                 side->surfaceFlags = si->surfaceFlags;
1126                 side->contentFlags = si->contentFlags;
1127                 side->compileFlags = si->compileFlags;
1128                 side->value = si->value;
1129
1130                 /* ydnar: gs mods: bias texture shift */
1131                 if ( si->globalTexture == qfalse ) {
1132                         shift[ 0 ] -= ( floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth );
1133                         shift[ 1 ] -= ( floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight );
1134                 }
1135
1136                 /*
1137                     historically, there are 3 integer values at the end of a brushside line in a .map file.
1138                     in quake 3, the only thing that mattered was the first of these three values, which
1139                     was previously the content flags. and only then did a single bit matter, the detail
1140                     bit. because every game has its own special flags for specifying detail, the
1141                     traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
1142                     by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
1143                     is stored in compileFlags, as opposed to contentFlags, for multiple-game
1144                     portability. :sigh:
1145                  */
1146
1147                 if ( TokenAvailable() ) {
1148                         /* get detail bit from map content flags */
1149                         GetToken( qfalse );
1150                         flags = atoi( token );
1151                         if ( flags & C_DETAIL ) {
1152                                 side->compileFlags |= C_DETAIL;
1153                         }
1154
1155                         /* historical */
1156                         GetToken( qfalse );
1157                         //% td.flags = atoi( token );
1158                         GetToken( qfalse );
1159                         //% td.value = atoi( token );
1160                 }
1161
1162                 /* find the plane number */
1163                 planenum = MapPlaneFromPoints( planePoints );
1164                 side->planenum = planenum;
1165
1166                 /* bp: get the texture mapping for this texturedef / plane combination */
1167                 if ( g_bBrushPrimit == BPRIMIT_OLDBRUSHES ) {
1168                         QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
1169                 }
1170         }
1171
1172         /* bp */
1173         if ( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) {
1174                 UnGetToken();
1175                 MatchToken( "}" );
1176                 MatchToken( "}" );
1177         }
1178 }
1179
1180
1181
1182 /*
1183    RemoveDuplicateBrushPlanes
1184    returns false if the brush has a mirrored set of planes,
1185    meaning it encloses no volume.
1186    also removes planes without any normal
1187  */
1188
1189 qboolean RemoveDuplicateBrushPlanes( brush_t *b ){
1190         int i, j, k;
1191         side_t      *sides;
1192
1193         sides = b->sides;
1194
1195         for ( i = 1 ; i < b->numsides ; i++ ) {
1196
1197                 // check for a degenerate plane
1198                 if ( sides[i].planenum == -1 ) {
1199                         xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
1200                         // remove it
1201                         for ( k = i + 1 ; k < b->numsides ; k++ ) {
1202                                 sides[k - 1] = sides[k];
1203                         }
1204                         b->numsides--;
1205                         i--;
1206                         continue;
1207                 }
1208
1209                 // check for duplication and mirroring
1210                 for ( j = 0 ; j < i ; j++ ) {
1211                         if ( sides[i].planenum == sides[j].planenum ) {
1212                                 xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
1213                                 // remove the second duplicate
1214                                 for ( k = i + 1 ; k < b->numsides ; k++ ) {
1215                                         sides[k - 1] = sides[k];
1216                                 }
1217                                 b->numsides--;
1218                                 i--;
1219                                 break;
1220                         }
1221
1222                         if ( sides[i].planenum == ( sides[j].planenum ^ 1 ) ) {
1223                                 // mirror plane, brush is invalid
1224                                 xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
1225                                 return qfalse;
1226                         }
1227                 }
1228         }
1229         return qtrue;
1230 }
1231
1232
1233
1234 /*
1235    ParseBrush()
1236    parses a brush out of a map file and sets it up
1237  */
1238
1239 static void ParseBrush( qboolean onlyLights, qboolean noCollapseGroups ){
1240         /* parse the brush out of the map */
1241         ParseRawBrush( onlyLights );
1242
1243         /* only go this far? */
1244         if ( onlyLights ) {
1245                 return;
1246         }
1247
1248         /* set some defaults */
1249         buildBrush->portalareas[ 0 ] = -1;
1250         buildBrush->portalareas[ 1 ] = -1;
1251         buildBrush->entityNum = numMapEntities - 1;
1252         buildBrush->brushNum = entitySourceBrushes;
1253
1254         /* if there are mirrored planes, the entire brush is invalid */
1255         if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
1256                 return;
1257         }
1258
1259         /* get the content for the entire brush */
1260         SetBrushContents( buildBrush );
1261
1262         /* allow detail brushes to be removed */
1263         if ( nodetail && ( buildBrush->compileFlags & C_DETAIL ) ) {
1264                 //%     FreeBrush( buildBrush );
1265                 return;
1266         }
1267
1268         /* allow liquid brushes to be removed */
1269         if ( nowater && ( buildBrush->compileFlags & C_LIQUID ) ) {
1270                 //%     FreeBrush( buildBrush );
1271                 return;
1272         }
1273
1274         /* ydnar: allow hint brushes to be removed */
1275         if ( noHint && ( buildBrush->compileFlags & C_HINT ) ) {
1276                 //%     FreeBrush( buildBrush );
1277                 return;
1278         }
1279
1280         /* finish the brush */
1281         FinishBrush( noCollapseGroups );
1282 }
1283
1284
1285
1286 /*
1287    MoveBrushesToWorld()
1288    takes all of the brushes from the current entity and
1289    adds them to the world's brush list
1290    (used by func_group)
1291  */
1292
1293 void AdjustBrushesForOrigin( entity_t *ent );
1294 void MoveBrushesToWorld( entity_t *ent ){
1295         brush_t     *b, *next;
1296         parseMesh_t *pm;
1297
1298         /* we need to undo the common/origin adjustment, and instead shift them by the entity key origin */
1299         VectorScale( ent->origin, -1, ent->originbrush_origin );
1300         AdjustBrushesForOrigin( ent );
1301         VectorClear( ent->originbrush_origin );
1302
1303         /* move brushes */
1304         for ( b = ent->brushes; b != NULL; b = next )
1305         {
1306                 /* get next brush */
1307                 next = b->next;
1308
1309                 /* link opaque brushes to head of list, translucent brushes to end */
1310                 if ( b->opaque || entities[ 0 ].lastBrush == NULL ) {
1311                         b->next = entities[ 0 ].brushes;
1312                         entities[ 0 ].brushes = b;
1313                         if ( entities[ 0 ].lastBrush == NULL ) {
1314                                 entities[ 0 ].lastBrush = b;
1315                         }
1316                 }
1317                 else
1318                 {
1319                         b->next = NULL;
1320                         entities[ 0 ].lastBrush->next = b;
1321                         entities[ 0 ].lastBrush = b;
1322                 }
1323         }
1324         ent->brushes = NULL;
1325
1326         /* ydnar: move colormod brushes */
1327         if ( ent->colorModBrushes != NULL ) {
1328                 for ( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush ) ;
1329
1330                 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1331                 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1332
1333                 ent->colorModBrushes = NULL;
1334         }
1335
1336         /* move patches */
1337         if ( ent->patches != NULL ) {
1338                 for ( pm = ent->patches; pm->next != NULL; pm = pm->next ) ;
1339
1340                 pm->next = entities[ 0 ].patches;
1341                 entities[ 0 ].patches = ent->patches;
1342
1343                 ent->patches = NULL;
1344         }
1345 }
1346
1347
1348
1349 /*
1350    AdjustBrushesForOrigin()
1351  */
1352
1353 void AdjustBrushesForOrigin( entity_t *ent ){
1354
1355         int i;
1356         side_t      *s;
1357         vec_t newdist;
1358         brush_t     *b;
1359         parseMesh_t *p;
1360
1361         /* walk brush list */
1362         for ( b = ent->brushes; b != NULL; b = b->next )
1363         {
1364                 /* offset brush planes */
1365                 for ( i = 0; i < b->numsides; i++ )
1366                 {
1367                         /* get brush side */
1368                         s = &b->sides[ i ];
1369
1370                         /* offset side plane */
1371                         newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->originbrush_origin );
1372
1373                         /* find a new plane */
1374                         s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1375                 }
1376
1377                 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1378                 CreateBrushWindings( b );
1379         }
1380
1381         /* walk patch list */
1382         for ( p = ent->patches; p != NULL; p = p->next )
1383         {
1384                 for ( i = 0; i < ( p->mesh.width * p->mesh.height ); i++ )
1385                         VectorSubtract( p->mesh.verts[ i ].xyz, ent->originbrush_origin, p->mesh.verts[ i ].xyz );
1386         }
1387 }
1388
1389
1390
1391 /*
1392    SetEntityBounds() - ydnar
1393    finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1394  */
1395
1396 void SetEntityBounds( entity_t *e ){
1397         int i;
1398         brush_t *b;
1399         parseMesh_t *p;
1400         vec3_t mins, maxs;
1401         const char  *value;
1402
1403
1404
1405
1406         /* walk the entity's brushes/patches and determine bounds */
1407         ClearBounds( mins, maxs );
1408         for ( b = e->brushes; b; b = b->next )
1409         {
1410                 AddPointToBounds( b->mins, mins, maxs );
1411                 AddPointToBounds( b->maxs, mins, maxs );
1412         }
1413         for ( p = e->patches; p; p = p->next )
1414         {
1415                 for ( i = 0; i < ( p->mesh.width * p->mesh.height ); i++ )
1416                         AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1417         }
1418
1419         /* try to find explicit min/max key */
1420         value = ValueForKey( e, "min" );
1421         if ( value[ 0 ] != '\0' ) {
1422                 GetVectorForKey( e, "min", mins );
1423         }
1424         value = ValueForKey( e, "max" );
1425         if ( value[ 0 ] != '\0' ) {
1426                 GetVectorForKey( e, "max", maxs );
1427         }
1428
1429         /* store the bounds */
1430         for ( b = e->brushes; b; b = b->next )
1431         {
1432                 VectorCopy( mins, b->eMins );
1433                 VectorCopy( maxs, b->eMaxs );
1434         }
1435         for ( p = e->patches; p; p = p->next )
1436         {
1437                 VectorCopy( mins, p->eMins );
1438                 VectorCopy( maxs, p->eMaxs );
1439         }
1440 }
1441
1442
1443
1444 /*
1445    LoadEntityIndexMap() - ydnar
1446    based on LoadAlphaMap() from terrain.c, a little more generic
1447  */
1448
1449 void LoadEntityIndexMap( entity_t *e ){
1450         int i, size, numLayers, w, h;
1451         const char      *value, *indexMapFilename, *shader;
1452         char ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1453         byte            *pixels;
1454         unsigned int    *pixels32;
1455         indexMap_t      *im;
1456         brush_t         *b;
1457         parseMesh_t     *p;
1458
1459
1460         /* this only works with bmodel ents */
1461         if ( e->brushes == NULL && e->patches == NULL ) {
1462                 return;
1463         }
1464
1465         /* determine if there is an index map (support legacy "alphamap" key as well) */
1466         value = ValueForKey( e, "_indexmap" );
1467         if ( value[ 0 ] == '\0' ) {
1468                 value = ValueForKey( e, "alphamap" );
1469         }
1470         if ( value[ 0 ] == '\0' ) {
1471                 return;
1472         }
1473         indexMapFilename = value;
1474
1475         /* get number of layers (support legacy "layers" key as well) */
1476         value = ValueForKey( e, "_layers" );
1477         if ( value[ 0 ] == '\0' ) {
1478                 value = ValueForKey( e, "layers" );
1479         }
1480         if ( value[ 0 ] == '\0' ) {
1481                 Sys_FPrintf( SYS_WRN, "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1482                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1483                 return;
1484         }
1485         numLayers = atoi( value );
1486         if ( numLayers < 1 ) {
1487                 Sys_FPrintf( SYS_WRN, "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1488                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1489                 return;
1490         }
1491
1492         /* get base shader name (support legacy "shader" key as well) */
1493         value = ValueForKey( mapEnt, "_shader" );
1494         if ( value[ 0 ] == '\0' ) {
1495                 value = ValueForKey( e, "shader" );
1496         }
1497         if ( value[ 0 ] == '\0' ) {
1498                 Sys_FPrintf( SYS_WRN, "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1499                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1500                 return;
1501         }
1502         shader = value;
1503
1504         /* note it */
1505         Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n",  mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1506
1507         /* get index map file extension */
1508         ExtractFileExtension( indexMapFilename, ext );
1509
1510         /* handle tga image */
1511         if ( !Q_stricmp( ext, "tga" ) ) {
1512                 /* load it */
1513                 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1514
1515                 /* convert to bytes */
1516                 size = w * h;
1517                 pixels = safe_malloc( size );
1518                 for ( i = 0; i < size; i++ )
1519                 {
1520                         pixels[ i ] = ( ( pixels32[ i ] & 0xFF ) * numLayers ) / 256;
1521                         if ( pixels[ i ] >= numLayers ) {
1522                                 pixels[ i ] = numLayers - 1;
1523                         }
1524                 }
1525
1526                 /* free the 32 bit image */
1527                 free( pixels32 );
1528         }
1529         else
1530         {
1531                 /* load it */
1532                 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1533
1534                 /* debug code */
1535                 //%     Sys_Printf( "-------------------------------" );
1536
1537                 /* fix up out-of-range values */
1538                 size = w * h;
1539                 for ( i = 0; i < size; i++ )
1540                 {
1541                         if ( pixels[ i ] >= numLayers ) {
1542                                 pixels[ i ] = numLayers - 1;
1543                         }
1544
1545                         /* debug code */
1546                         //%     if( (i % w) == 0 )
1547                         //%             Sys_Printf( "\n" );
1548                         //%     Sys_Printf( "%c", pixels[ i ] + '0' );
1549                 }
1550
1551                 /* debug code */
1552                 //%     Sys_Printf( "\n-------------------------------\n" );
1553         }
1554
1555         /* the index map must be at least 2x2 pixels */
1556         if ( w < 2 || h < 2 ) {
1557                 Sys_FPrintf( SYS_WRN, "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1558                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1559                 free( pixels );
1560                 return;
1561         }
1562
1563         /* create a new index map */
1564         im = safe_malloc0( sizeof( *im ) );
1565
1566         /* set it up */
1567         im->w = w;
1568         im->h = h;
1569         im->numLayers = numLayers;
1570         strcpy( im->name, indexMapFilename );
1571         strcpy( im->shader, shader );
1572         im->pixels = pixels;
1573
1574         /* get height offsets */
1575         value = ValueForKey( mapEnt, "_offsets" );
1576         if ( value[ 0 ] == '\0' ) {
1577                 value = ValueForKey( e, "offsets" );
1578         }
1579         if ( value[ 0 ] != '\0' ) {
1580                 /* value is a space-seperated set of numbers */
1581                 strcpy( offset, value );
1582                 search = offset;
1583
1584                 /* get each value */
1585                 for ( i = 0; i < 256 && *search != '\0'; i++ )
1586                 {
1587                         space = strstr( search, " " );
1588                         if ( space != NULL ) {
1589                                 *space = '\0';
1590                         }
1591                         im->offsets[ i ] = atof( search );
1592                         if ( space == NULL ) {
1593                                 break;
1594                         }
1595                         search = space + 1;
1596                 }
1597         }
1598
1599         /* store the index map in every brush/patch in the entity */
1600         for ( b = e->brushes; b != NULL; b = b->next )
1601                 b->im = im;
1602         for ( p = e->patches; p != NULL; p = p->next )
1603                 p->im = im;
1604 }
1605
1606
1607
1608
1609
1610
1611
1612 /*
1613    ParseMapEntity()
1614    parses a single entity out of a map file
1615  */
1616
1617 static qboolean ParseMapEntity( qboolean onlyLights, qboolean noCollapseGroups ){
1618         epair_t         *ep;
1619         const char      *classname, *value;
1620         float lightmapScale, shadeAngle;
1621         int lightmapSampleSize;
1622         char shader[ MAX_QPATH ];
1623         shaderInfo_t    *celShader = NULL;
1624         brush_t         *brush;
1625         parseMesh_t     *patch;
1626         qboolean funcGroup;
1627         int castShadows, recvShadows;
1628
1629
1630         /* eof check */
1631         if ( !GetToken( qtrue ) ) {
1632                 return qfalse;
1633         }
1634
1635         /* conformance check */
1636         if ( strcmp( token, "{" ) ) {
1637                 Sys_FPrintf( SYS_WRN, "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1638                                         "Continuing to process map, but resulting BSP may be invalid.\n",
1639                                         token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1640                 return qfalse;
1641         }
1642
1643         /* range check */
1644         AUTOEXPAND_BY_REALLOC( entities, numEntities, allocatedEntities, 32 );
1645
1646         /* setup */
1647         entitySourceBrushes = 0;
1648         mapEnt = &entities[ numEntities ];
1649         numEntities++;
1650         memset( mapEnt, 0, sizeof( *mapEnt ) );
1651
1652         /* ydnar: true entity numbering */
1653         mapEnt->mapEntityNum = numMapEntities;
1654         numMapEntities++;
1655
1656         /* loop */
1657         while ( 1 )
1658         {
1659                 /* get initial token */
1660                 if ( !GetToken( qtrue ) ) {
1661                         Sys_FPrintf( SYS_WRN, "WARNING: ParseEntity: EOF without closing brace\n"
1662                                                 "Continuing to process map, but resulting BSP may be invalid.\n" );
1663                         return qfalse;
1664                 }
1665
1666                 if ( !strcmp( token, "}" ) ) {
1667                         break;
1668                 }
1669
1670                 if ( !strcmp( token, "{" ) ) {
1671                         /* parse a brush or patch */
1672                         if ( !GetToken( qtrue ) ) {
1673                                 break;
1674                         }
1675
1676                         /* check */
1677                         if ( !strcmp( token, "patchDef2" ) ) {
1678                                 numMapPatches++;
1679                                 ParsePatch( onlyLights );
1680                         }
1681                         else if ( !strcmp( token, "terrainDef" ) ) {
1682                                 //% ParseTerrain();
1683                                 Sys_FPrintf( SYS_WRN, "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1684                         }
1685                         else if ( !strcmp( token, "brushDef" ) ) {
1686                                 if ( g_bBrushPrimit == BPRIMIT_OLDBRUSHES ) {
1687                                         Error( "Old brush format not allowed in new brush format map" );
1688                                 }
1689                                 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1690
1691                                 /* parse brush primitive */
1692                                 ParseBrush( onlyLights, noCollapseGroups );
1693                         }
1694                         else
1695                         {
1696                                 if ( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) {
1697                                         Error( "New brush format not allowed in old brush format map" );
1698                                 }
1699                                 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1700
1701                                 /* parse old brush format */
1702                                 UnGetToken();
1703                                 ParseBrush( onlyLights, noCollapseGroups );
1704                         }
1705                         entitySourceBrushes++;
1706                 }
1707                 else
1708                 {
1709                         /* parse a key / value pair */
1710                         ep = ParseEPair();
1711
1712                         /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1713                         if ( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' ) {
1714                                 ep->next = mapEnt->epairs;
1715                                 mapEnt->epairs = ep;
1716                         }
1717                 }
1718         }
1719
1720         /* ydnar: get classname */
1721         classname = ValueForKey( mapEnt, "classname" );
1722
1723         /* ydnar: only lights? */
1724         if ( onlyLights && Q_strncasecmp( classname, "light", 5 ) ) {
1725                 numEntities--;
1726                 return qtrue;
1727         }
1728
1729         /* ydnar: determine if this is a func_group */
1730         if ( !Q_stricmp( "func_group", classname ) ) {
1731                 funcGroup = qtrue;
1732         }
1733         else{
1734                 funcGroup = qfalse;
1735         }
1736
1737         /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1738         if ( funcGroup || mapEnt->mapEntityNum == 0 ) {
1739                 //%     Sys_Printf( "World:  %d\n", mapEnt->mapEntityNum );
1740                 castShadows = WORLDSPAWN_CAST_SHADOWS;
1741                 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1742         }
1743
1744         /* other entities don't cast any shadows, but recv worldspawn shadows */
1745         else
1746         {
1747                 //%     Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1748                 castShadows = ENTITY_CAST_SHADOWS;
1749                 recvShadows = ENTITY_RECV_SHADOWS;
1750         }
1751
1752         /* get explicit shadow flags */
1753         GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1754
1755         /* vortex: added _ls key (short name of lightmapscale) */
1756         /* ydnar: get lightmap scaling value for this entity */
1757         lightmapScale = 0.0f;
1758         if ( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1759                  strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) ||
1760                  strcmp( "", ValueForKey( mapEnt, "_ls" ) ) ) {
1761                 /* get lightmap scale from entity */
1762                 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1763                 if ( lightmapScale <= 0.0f ) {
1764                         lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1765                 }
1766                 if ( lightmapScale <= 0.0f ) {
1767                         lightmapScale = FloatForKey( mapEnt, "_ls" );
1768                 }
1769                 if ( lightmapScale < 0.0f ) {
1770                         lightmapScale = 0.0f;
1771                 }
1772                 if ( lightmapScale > 0.0f ) {
1773                         Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1774                 }
1775         }
1776
1777         /* ydnar: get cel shader :) for this entity */
1778         value = ValueForKey( mapEnt, "_celshader" );
1779         if ( value[ 0 ] == '\0' ) {
1780                 value = ValueForKey( &entities[ 0 ], "_celshader" );
1781         }
1782         if ( value[ 0 ] != '\0' ) {
1783                 if ( strcmp( value, "none" ) ) {
1784                         sprintf( shader, "textures/%s", value );
1785                         celShader = ShaderInfoForShader( shader );
1786                         Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1787                 }
1788                 else
1789                 {
1790                         celShader = NULL;
1791                 }
1792         }
1793         else{
1794                 celShader = ( *globalCelShader ? ShaderInfoForShader( globalCelShader ) : NULL );
1795         }
1796
1797         /* jal : entity based _shadeangle */
1798         shadeAngle = 0.0f;
1799         if ( strcmp( "", ValueForKey( mapEnt, "_shadeangle" ) ) ) {
1800                 shadeAngle = FloatForKey( mapEnt, "_shadeangle" );
1801         }
1802         /* vortex' aliases */
1803         else if ( strcmp( "", ValueForKey( mapEnt, "_smoothnormals" ) ) ) {
1804                 shadeAngle = FloatForKey( mapEnt, "_smoothnormals" );
1805         }
1806         else if ( strcmp( "", ValueForKey( mapEnt, "_sn" ) ) ) {
1807                 shadeAngle = FloatForKey( mapEnt, "_sn" );
1808         }
1809         else if ( strcmp( "", ValueForKey( mapEnt, "_sa" ) ) ) {
1810                 shadeAngle = FloatForKey( mapEnt, "_sa" );
1811         }
1812         else if ( strcmp( "", ValueForKey( mapEnt, "_smooth" ) ) ) {
1813                 shadeAngle = FloatForKey( mapEnt, "_smooth" );
1814         }
1815
1816         if ( shadeAngle < 0.0f ) {
1817                 shadeAngle = 0.0f;
1818         }
1819
1820         if ( shadeAngle > 0.0f ) {
1821                 Sys_Printf( "Entity %d (%s) has shading angle of %.4f\n", mapEnt->mapEntityNum, classname, shadeAngle );
1822         }
1823
1824         /* jal : entity based _samplesize */
1825         lightmapSampleSize = 0;
1826         if ( strcmp( "", ValueForKey( mapEnt, "_lightmapsamplesize" ) ) ) {
1827                 lightmapSampleSize = IntForKey( mapEnt, "_lightmapsamplesize" );
1828         }
1829         else if ( strcmp( "", ValueForKey( mapEnt, "_samplesize" ) ) ) {
1830                 lightmapSampleSize = IntForKey( mapEnt, "_samplesize" );
1831         }
1832         else if ( strcmp( "", ValueForKey( mapEnt, "_ss" ) ) ) {
1833                 lightmapSampleSize = IntForKey( mapEnt, "_ss" );
1834         }
1835
1836         if ( lightmapSampleSize < 0 ) {
1837                 lightmapSampleSize = 0;
1838         }
1839
1840         if ( lightmapSampleSize > 0 ) {
1841                 Sys_Printf( "Entity %d (%s) has lightmap sample size of %d\n", mapEnt->mapEntityNum, classname, lightmapSampleSize );
1842         }
1843
1844         /* attach stuff to everything in the entity */
1845         for ( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1846         {
1847                 brush->entityNum = mapEnt->mapEntityNum;
1848                 brush->castShadows = castShadows;
1849                 brush->recvShadows = recvShadows;
1850                 brush->lightmapSampleSize = lightmapSampleSize;
1851                 brush->lightmapScale = lightmapScale;
1852                 brush->celShader = celShader;
1853                 brush->shadeAngleDegrees = shadeAngle;
1854         }
1855
1856         for ( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1857         {
1858                 patch->entityNum = mapEnt->mapEntityNum;
1859                 patch->castShadows = castShadows;
1860                 patch->recvShadows = recvShadows;
1861                 patch->lightmapSampleSize = lightmapSampleSize;
1862                 patch->lightmapScale = lightmapScale;
1863                 patch->celShader = celShader;
1864         }
1865
1866         /* ydnar: gs mods: set entity bounds */
1867         SetEntityBounds( mapEnt );
1868
1869         /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1870         LoadEntityIndexMap( mapEnt );
1871
1872         /* get entity origin and adjust brushes */
1873         GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1874         if ( mapEnt->originbrush_origin[ 0 ] || mapEnt->originbrush_origin[ 1 ] || mapEnt->originbrush_origin[ 2 ] ) {
1875                 AdjustBrushesForOrigin( mapEnt );
1876         }
1877
1878         /* group_info entities are just for editor grouping (fixme: leak!) */
1879         if ( !noCollapseGroups && !Q_stricmp( "group_info", classname ) ) {
1880                 numEntities--;
1881                 return qtrue;
1882         }
1883
1884         /* group entities are just for editor convenience, toss all brushes into worldspawn */
1885         if ( !noCollapseGroups && funcGroup ) {
1886                 MoveBrushesToWorld( mapEnt );
1887                 numEntities--;
1888                 return qtrue;
1889         }
1890
1891         /* done */
1892         return qtrue;
1893 }
1894
1895
1896
1897 /*
1898    LoadMapFile()
1899    loads a map file into a list of entities
1900  */
1901
1902 void LoadMapFile( char *filename, qboolean onlyLights, qboolean noCollapseGroups ){
1903         FILE        *file;
1904         brush_t     *b;
1905         int oldNumEntities = 0, numMapBrushes;
1906
1907
1908         /* note it */
1909         Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1910         Sys_Printf( "Loading %s\n", filename );
1911
1912         /* hack */
1913         file = SafeOpenRead( filename );
1914         fclose( file );
1915
1916         /* load the map file */
1917         LoadScriptFile( filename, -1 );
1918
1919         /* setup */
1920         if ( onlyLights ) {
1921                 oldNumEntities = numEntities;
1922         }
1923         else{
1924                 numEntities = 0;
1925         }
1926
1927         /* initial setup */
1928         numMapDrawSurfs = 0;
1929         c_detail = 0;
1930         g_bBrushPrimit = BPRIMIT_UNDEFINED;
1931
1932         /* allocate a very large temporary brush for building the brushes as they are loaded */
1933         buildBrush = AllocBrush( MAX_BUILD_SIDES );
1934
1935         /* parse the map file */
1936         while ( ParseMapEntity( onlyLights, noCollapseGroups ) ) ;
1937
1938         /* light loading */
1939         if ( onlyLights ) {
1940                 /* emit some statistics */
1941                 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1942         }
1943         else
1944         {
1945                 /* set map bounds */
1946                 ClearBounds( mapMins, mapMaxs );
1947                 for ( b = entities[ 0 ].brushes; b; b = b->next )
1948                 {
1949                         AddPointToBounds( b->mins, mapMins, mapMaxs );
1950                         AddPointToBounds( b->maxs, mapMins, mapMaxs );
1951                 }
1952
1953                 /* get brush counts */
1954                 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1955                 if ( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 ) {
1956                         Sys_FPrintf( SYS_WRN, "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1957                 }
1958
1959                 /* emit some statistics */
1960                 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1961                 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1962                 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches );
1963                 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels );
1964                 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels );
1965                 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1966                 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes );
1967                 Sys_Printf( "%9d areaportals\n", c_areaportals );
1968                 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1969                                         mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1970                                         mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ] );
1971
1972                 /* write bogus map */
1973                 if ( fakemap ) {
1974                         WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );
1975                 }
1976         }
1977 }