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