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