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