]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/map.c
Merge commit 'f73cc19a6166fc04269f953c980175779f81b9b0' 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 '<' 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 were near a 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_malloc( sizeof( *im ) );
1565         memset( im, 0, sizeof( *im ) );
1566
1567         /* set it up */
1568         im->w = w;
1569         im->h = h;
1570         im->numLayers = numLayers;
1571         strcpy( im->name, indexMapFilename );
1572         strcpy( im->shader, shader );
1573         im->pixels = pixels;
1574
1575         /* get height offsets */
1576         value = ValueForKey( mapEnt, "_offsets" );
1577         if ( value[ 0 ] == '\0' ) {
1578                 value = ValueForKey( e, "offsets" );
1579         }
1580         if ( value[ 0 ] != '\0' ) {
1581                 /* value is a space-seperated set of numbers */
1582                 strcpy( offset, value );
1583                 search = offset;
1584
1585                 /* get each value */
1586                 for ( i = 0; i < 256 && *search != '\0'; i++ )
1587                 {
1588                         space = strstr( search, " " );
1589                         if ( space != NULL ) {
1590                                 *space = '\0';
1591                         }
1592                         im->offsets[ i ] = atof( search );
1593                         if ( space == NULL ) {
1594                                 break;
1595                         }
1596                         search = space + 1;
1597                 }
1598         }
1599
1600         /* store the index map in every brush/patch in the entity */
1601         for ( b = e->brushes; b != NULL; b = b->next )
1602                 b->im = im;
1603         for ( p = e->patches; p != NULL; p = p->next )
1604                 p->im = im;
1605 }
1606
1607
1608
1609
1610
1611
1612
1613 /*
1614    ParseMapEntity()
1615    parses a single entity out of a map file
1616  */
1617
1618 static qboolean ParseMapEntity( qboolean onlyLights, qboolean noCollapseGroups ){
1619         epair_t         *ep;
1620         const char      *classname, *value;
1621         float lightmapScale, shadeAngle;
1622         int lightmapSampleSize;
1623         char shader[ MAX_QPATH ];
1624         shaderInfo_t    *celShader = NULL;
1625         brush_t         *brush;
1626         parseMesh_t     *patch;
1627         qboolean funcGroup;
1628         int castShadows, recvShadows;
1629
1630
1631         /* eof check */
1632         if ( !GetToken( qtrue ) ) {
1633                 return qfalse;
1634         }
1635
1636         /* conformance check */
1637         if ( strcmp( token, "{" ) ) {
1638                 Sys_FPrintf( SYS_WRN, "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1639                                         "Continuing to process map, but resulting BSP may be invalid.\n",
1640                                         token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1641                 return qfalse;
1642         }
1643
1644         /* range check */
1645         AUTOEXPAND_BY_REALLOC( entities, numEntities, allocatedEntities, 32 );
1646
1647         /* setup */
1648         entitySourceBrushes = 0;
1649         mapEnt = &entities[ numEntities ];
1650         numEntities++;
1651         memset( mapEnt, 0, sizeof( *mapEnt ) );
1652
1653         /* ydnar: true entity numbering */
1654         mapEnt->mapEntityNum = numMapEntities;
1655         numMapEntities++;
1656
1657         /* loop */
1658         while ( 1 )
1659         {
1660                 /* get initial token */
1661                 if ( !GetToken( qtrue ) ) {
1662                         Sys_FPrintf( SYS_WRN, "WARNING: ParseEntity: EOF without closing brace\n"
1663                                                 "Continuing to process map, but resulting BSP may be invalid.\n" );
1664                         return qfalse;
1665                 }
1666
1667                 if ( !strcmp( token, "}" ) ) {
1668                         break;
1669                 }
1670
1671                 if ( !strcmp( token, "{" ) ) {
1672                         /* parse a brush or patch */
1673                         if ( !GetToken( qtrue ) ) {
1674                                 break;
1675                         }
1676
1677                         /* check */
1678                         if ( !strcmp( token, "patchDef2" ) ) {
1679                                 numMapPatches++;
1680                                 ParsePatch( onlyLights );
1681                         }
1682                         else if ( !strcmp( token, "terrainDef" ) ) {
1683                                 //% ParseTerrain();
1684                                 Sys_FPrintf( SYS_WRN, "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1685                         }
1686                         else if ( !strcmp( token, "brushDef" ) ) {
1687                                 if ( g_bBrushPrimit == BPRIMIT_OLDBRUSHES ) {
1688                                         Error( "Old brush format not allowed in new brush format map" );
1689                                 }
1690                                 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1691
1692                                 /* parse brush primitive */
1693                                 ParseBrush( onlyLights, noCollapseGroups );
1694                         }
1695                         else
1696                         {
1697                                 if ( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) {
1698                                         Error( "New brush format not allowed in old brush format map" );
1699                                 }
1700                                 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1701
1702                                 /* parse old brush format */
1703                                 UnGetToken();
1704                                 ParseBrush( onlyLights, noCollapseGroups );
1705                         }
1706                         entitySourceBrushes++;
1707                 }
1708                 else
1709                 {
1710                         /* parse a key / value pair */
1711                         ep = ParseEPair();
1712
1713                         /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1714                         if ( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' ) {
1715                                 ep->next = mapEnt->epairs;
1716                                 mapEnt->epairs = ep;
1717                         }
1718                 }
1719         }
1720
1721         /* ydnar: get classname */
1722         classname = ValueForKey( mapEnt, "classname" );
1723
1724         /* ydnar: only lights? */
1725         if ( onlyLights && Q_strncasecmp( classname, "light", 5 ) ) {
1726                 numEntities--;
1727                 return qtrue;
1728         }
1729
1730         /* ydnar: determine if this is a func_group */
1731         if ( !Q_stricmp( "func_group", classname ) ) {
1732                 funcGroup = qtrue;
1733         }
1734         else{
1735                 funcGroup = qfalse;
1736         }
1737
1738         /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1739         if ( funcGroup || mapEnt->mapEntityNum == 0 ) {
1740                 //%     Sys_Printf( "World:  %d\n", mapEnt->mapEntityNum );
1741                 castShadows = WORLDSPAWN_CAST_SHADOWS;
1742                 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1743         }
1744
1745         /* other entities don't cast any shadows, but recv worldspawn shadows */
1746         else
1747         {
1748                 //%     Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1749                 castShadows = ENTITY_CAST_SHADOWS;
1750                 recvShadows = ENTITY_RECV_SHADOWS;
1751         }
1752
1753         /* get explicit shadow flags */
1754         GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1755
1756         /* vortex: added _ls key (short name of lightmapscale) */
1757         /* ydnar: get lightmap scaling value for this entity */
1758         lightmapScale = 0.0f;
1759         if ( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1760                  strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) ||
1761                  strcmp( "", ValueForKey( mapEnt, "_ls" ) ) ) {
1762                 /* get lightmap scale from entity */
1763                 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1764                 if ( lightmapScale <= 0.0f ) {
1765                         lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1766                 }
1767                 if ( lightmapScale <= 0.0f ) {
1768                         lightmapScale = FloatForKey( mapEnt, "_ls" );
1769                 }
1770                 if ( lightmapScale < 0.0f ) {
1771                         lightmapScale = 0.0f;
1772                 }
1773                 if ( lightmapScale > 0.0f ) {
1774                         Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1775                 }
1776         }
1777
1778         /* ydnar: get cel shader :) for this entity */
1779         value = ValueForKey( mapEnt, "_celshader" );
1780         if ( value[ 0 ] == '\0' ) {
1781                 value = ValueForKey( &entities[ 0 ], "_celshader" );
1782         }
1783         if ( value[ 0 ] != '\0' ) {
1784                 if ( strcmp( value, "none" ) ) {
1785                         sprintf( shader, "textures/%s", value );
1786                         celShader = ShaderInfoForShader( shader );
1787                         Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1788                 }
1789                 else
1790                 {
1791                         celShader = NULL;
1792                 }
1793         }
1794         else{
1795                 celShader = ( *globalCelShader ? ShaderInfoForShader( globalCelShader ) : NULL );
1796         }
1797
1798         /* jal : entity based _shadeangle */
1799         shadeAngle = 0.0f;
1800         if ( strcmp( "", ValueForKey( mapEnt, "_shadeangle" ) ) ) {
1801                 shadeAngle = FloatForKey( mapEnt, "_shadeangle" );
1802         }
1803         /* vortex' aliases */
1804         else if ( strcmp( "", ValueForKey( mapEnt, "_smoothnormals" ) ) ) {
1805                 shadeAngle = FloatForKey( mapEnt, "_smoothnormals" );
1806         }
1807         else if ( strcmp( "", ValueForKey( mapEnt, "_sn" ) ) ) {
1808                 shadeAngle = FloatForKey( mapEnt, "_sn" );
1809         }
1810         else if ( strcmp( "", ValueForKey( mapEnt, "_sa" ) ) ) {
1811                 shadeAngle = FloatForKey( mapEnt, "_sa" );
1812         }
1813         else if ( strcmp( "", ValueForKey( mapEnt, "_smooth" ) ) ) {
1814                 shadeAngle = FloatForKey( mapEnt, "_smooth" );
1815         }
1816
1817         if ( shadeAngle < 0.0f ) {
1818                 shadeAngle = 0.0f;
1819         }
1820
1821         if ( shadeAngle > 0.0f ) {
1822                 Sys_Printf( "Entity %d (%s) has shading angle of %.4f\n", mapEnt->mapEntityNum, classname, shadeAngle );
1823         }
1824
1825         /* jal : entity based _samplesize */
1826         lightmapSampleSize = 0;
1827         if ( strcmp( "", ValueForKey( mapEnt, "_lightmapsamplesize" ) ) ) {
1828                 lightmapSampleSize = IntForKey( mapEnt, "_lightmapsamplesize" );
1829         }
1830         else if ( strcmp( "", ValueForKey( mapEnt, "_samplesize" ) ) ) {
1831                 lightmapSampleSize = IntForKey( mapEnt, "_samplesize" );
1832         }
1833         else if ( strcmp( "", ValueForKey( mapEnt, "_ss" ) ) ) {
1834                 lightmapSampleSize = IntForKey( mapEnt, "_ss" );
1835         }
1836
1837         if ( lightmapSampleSize < 0 ) {
1838                 lightmapSampleSize = 0;
1839         }
1840
1841         if ( lightmapSampleSize > 0 ) {
1842                 Sys_Printf( "Entity %d (%s) has lightmap sample size of %d\n", mapEnt->mapEntityNum, classname, lightmapSampleSize );
1843         }
1844
1845         /* attach stuff to everything in the entity */
1846         for ( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1847         {
1848                 brush->entityNum = mapEnt->mapEntityNum;
1849                 brush->castShadows = castShadows;
1850                 brush->recvShadows = recvShadows;
1851                 brush->lightmapSampleSize = lightmapSampleSize;
1852                 brush->lightmapScale = lightmapScale;
1853                 brush->celShader = celShader;
1854                 brush->shadeAngleDegrees = shadeAngle;
1855         }
1856
1857         for ( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1858         {
1859                 patch->entityNum = mapEnt->mapEntityNum;
1860                 patch->castShadows = castShadows;
1861                 patch->recvShadows = recvShadows;
1862                 patch->lightmapSampleSize = lightmapSampleSize;
1863                 patch->lightmapScale = lightmapScale;
1864                 patch->celShader = celShader;
1865         }
1866
1867         /* ydnar: gs mods: set entity bounds */
1868         SetEntityBounds( mapEnt );
1869
1870         /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1871         LoadEntityIndexMap( mapEnt );
1872
1873         /* get entity origin and adjust brushes */
1874         GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1875         if ( mapEnt->originbrush_origin[ 0 ] || mapEnt->originbrush_origin[ 1 ] || mapEnt->originbrush_origin[ 2 ] ) {
1876                 AdjustBrushesForOrigin( mapEnt );
1877         }
1878
1879         /* group_info entities are just for editor grouping (fixme: leak!) */
1880         if ( !noCollapseGroups && !Q_stricmp( "group_info", classname ) ) {
1881                 numEntities--;
1882                 return qtrue;
1883         }
1884
1885         /* group entities are just for editor convenience, toss all brushes into worldspawn */
1886         if ( !noCollapseGroups && funcGroup ) {
1887                 MoveBrushesToWorld( mapEnt );
1888                 numEntities--;
1889                 return qtrue;
1890         }
1891
1892         /* done */
1893         return qtrue;
1894 }
1895
1896
1897
1898 /*
1899    LoadMapFile()
1900    loads a map file into a list of entities
1901  */
1902
1903 void LoadMapFile( char *filename, qboolean onlyLights, qboolean noCollapseGroups ){
1904         FILE        *file;
1905         brush_t     *b;
1906         int oldNumEntities = 0, numMapBrushes;
1907
1908
1909         /* note it */
1910         Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1911         Sys_Printf( "Loading %s\n", filename );
1912
1913         /* hack */
1914         file = SafeOpenRead( filename );
1915         fclose( file );
1916
1917         /* load the map file */
1918         LoadScriptFile( filename, -1 );
1919
1920         /* setup */
1921         if ( onlyLights ) {
1922                 oldNumEntities = numEntities;
1923         }
1924         else{
1925                 numEntities = 0;
1926         }
1927
1928         /* initial setup */
1929         numMapDrawSurfs = 0;
1930         c_detail = 0;
1931         g_bBrushPrimit = BPRIMIT_UNDEFINED;
1932
1933         /* allocate a very large temporary brush for building the brushes as they are loaded */
1934         buildBrush = AllocBrush( MAX_BUILD_SIDES );
1935
1936         /* parse the map file */
1937         while ( ParseMapEntity( onlyLights, noCollapseGroups ) ) ;
1938
1939         /* light loading */
1940         if ( onlyLights ) {
1941                 /* emit some statistics */
1942                 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1943         }
1944         else
1945         {
1946                 /* set map bounds */
1947                 ClearBounds( mapMins, mapMaxs );
1948                 for ( b = entities[ 0 ].brushes; b; b = b->next )
1949                 {
1950                         AddPointToBounds( b->mins, mapMins, mapMaxs );
1951                         AddPointToBounds( b->maxs, mapMins, mapMaxs );
1952                 }
1953
1954                 /* get brush counts */
1955                 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1956                 if ( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 ) {
1957                         Sys_FPrintf( SYS_WRN, "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1958                 }
1959
1960                 /* emit some statistics */
1961                 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1962                 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1963                 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches );
1964                 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels );
1965                 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels );
1966                 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1967                 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes );
1968                 Sys_Printf( "%9d areaportals\n", c_areaportals );
1969                 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1970                                         mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1971                                         mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ] );
1972
1973                 /* write bogus map */
1974                 if ( fakemap ) {
1975                         WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );
1976                 }
1977         }
1978 }