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