]> icculus.org git repositories - divverent/netradiant.git/blob - tools/quake3/q3map2/map.c
if an origin brush exists, ALSO take into account the "origin" key (add the two)
[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         VectorMA(origin, -1, ent->originbrush_origin, adjustment);
603         VectorAdd(adjustment, ent->origin, ent->origin);
604         VectorCopy(origin, ent->originbrush_origin);
605
606         char string[128];
607         sprintf(string, "%f %f %f", ent->origin[0], ent->origin[1], ent->origin[2]);
608         SetKeyValue(ent, "origin", string);
609 }
610
611 brush_t *FinishBrush( void )
612 {
613         brush_t         *b;
614         
615         
616         /* create windings for sides and bounds for brush */
617         if ( !CreateBrushWindings( buildBrush ) )
618                 return NULL;
619
620         /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
621            after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
622         if( buildBrush->compileFlags & C_ORIGIN )
623         {
624                 char    string[ 32 ];
625                 vec3_t  origin;
626
627                 if( numEntities == 1 )
628                 {
629                         Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n", 
630                                 mapEnt->mapEntityNum, entitySourceBrushes );
631                         return NULL;
632                 }
633                 
634                 VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
635                 VectorScale (origin, 0.5, origin);
636
637                 MergeOrigin(&entities[ numEntities - 1 ], origin);
638
639                 /* don't keep this brush */
640                 return NULL;
641         }
642         
643         /* determine if the brush is an area portal */
644         if( buildBrush->compileFlags & C_AREAPORTAL )
645         {
646                 if( numEntities != 1 )
647                 {
648                         Sys_Printf ("Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
649                         return NULL;
650                 }
651         }
652         
653         /* add bevel planes */
654         AddBrushBevels();
655         
656         /* keep it */
657         b = CopyBrush( buildBrush );
658         
659         /* set map entity and brush numbering */
660         b->entityNum = mapEnt->mapEntityNum;
661         b->brushNum = entitySourceBrushes;
662         
663         /* set original */
664         b->original = b;
665         
666         /* link opaque brushes to head of list, translucent brushes to end */
667         if( b->opaque || mapEnt->lastBrush == NULL )
668         {
669                 b->next = mapEnt->brushes;
670                 mapEnt->brushes = b;
671                 if( mapEnt->lastBrush == NULL )
672                         mapEnt->lastBrush = b;
673         }
674         else
675         {
676                 b->next = NULL;
677                 mapEnt->lastBrush->next = b;
678                 mapEnt->lastBrush = b;
679         }
680         
681         /* link colorMod volume brushes to the entity directly */
682         if( b->contentShader != NULL &&
683                 b->contentShader->colorMod != NULL &&
684                 b->contentShader->colorMod->type == CM_VOLUME )
685         {
686                 b->nextColorModBrush = mapEnt->colorModBrushes;
687                 mapEnt->colorModBrushes = b;
688         }
689         
690         /* return to sender */
691         return b;
692 }
693
694
695
696 /*
697 TextureAxisFromPlane()
698 determines best orthagonal axis to project a texture onto a wall
699 (must be identical in radiant!)
700 */
701
702 vec3_t  baseaxis[18] =
703 {
704         {0,0,1}, {1,0,0}, {0,-1,0},                     // floor
705         {0,0,-1}, {1,0,0}, {0,-1,0},            // ceiling
706         {1,0,0}, {0,1,0}, {0,0,-1},                     // west wall
707         {-1,0,0}, {0,1,0}, {0,0,-1},            // east wall
708         {0,1,0}, {1,0,0}, {0,0,-1},                     // south wall
709         {0,-1,0}, {1,0,0}, {0,0,-1}                     // north wall
710 };
711
712 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv )
713 {
714         int             bestaxis;
715         vec_t   dot,best;
716         int             i;
717         
718         best = 0;
719         bestaxis = 0;
720         
721         for (i=0 ; i<6 ; i++)
722         {
723                 dot = DotProduct (pln->normal, baseaxis[i*3]);
724                 if( dot > best + 0.0001f )      /* ydnar: bug 637 fix, suggested by jmonroe */
725                 {
726                         best = dot;
727                         bestaxis = i;
728                 }
729         }
730         
731         VectorCopy (baseaxis[bestaxis*3+1], xv);
732         VectorCopy (baseaxis[bestaxis*3+2], yv);
733 }
734
735
736
737 /*
738 QuakeTextureVecs()
739 creates world-to-texture mapping vecs for crappy quake plane arrangements
740 */
741
742 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] )
743 {
744         vec3_t  vecs[2];
745         int             sv, tv;
746         vec_t   ang, sinv, cosv;
747         vec_t   ns, nt;
748         int             i, j;
749         
750         
751         TextureAxisFromPlane(plane, vecs[0], vecs[1]);
752         
753         if (!scale[0])
754                 scale[0] = 1;
755         if (!scale[1])
756                 scale[1] = 1;
757
758         // rotate axis
759         if (rotate == 0)
760                 { sinv = 0 ; cosv = 1; }
761         else if (rotate == 90)
762                 { sinv = 1 ; cosv = 0; }
763         else if (rotate == 180)
764                 { sinv = 0 ; cosv = -1; }
765         else if (rotate == 270)
766                 { sinv = -1 ; cosv = 0; }
767         else
768         {       
769                 ang = rotate / 180 * Q_PI;
770                 sinv = sin(ang);
771                 cosv = cos(ang);
772         }
773
774         if (vecs[0][0])
775                 sv = 0;
776         else if (vecs[0][1])
777                 sv = 1;
778         else
779                 sv = 2;
780                                 
781         if (vecs[1][0])
782                 tv = 0;
783         else if (vecs[1][1])
784                 tv = 1;
785         else
786                 tv = 2;
787                                         
788         for (i=0 ; i<2 ; i++) {
789                 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
790                 nt = sinv * vecs[i][sv] +  cosv * vecs[i][tv];
791                 vecs[i][sv] = ns;
792                 vecs[i][tv] = nt;
793         }
794
795         for (i=0 ; i<2 ; i++)
796                 for (j=0 ; j<3 ; j++)
797                         mappingVecs[i][j] = vecs[i][j] / scale[i];
798
799         mappingVecs[0][3] = shift[0];
800         mappingVecs[1][3] = shift[1];
801 }
802
803
804
805 /*
806 ParseRawBrush()
807 parses the sides into buildBrush->sides[], nothing else.
808 no validation, back plane removal, etc.
809
810 Timo - 08/26/99
811 added brush epairs parsing ( ignoring actually )
812 Timo - 08/04/99
813 added exclusive brush primitive parsing
814 Timo - 08/08/99
815 support for old brush format back in
816 NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
817 */
818
819 static void ParseRawBrush( qboolean onlyLights )
820 {
821         side_t                  *side;
822         vec3_t                  planePoints[ 3 ];
823         int                             planenum;
824         shaderInfo_t    *si;
825         vec_t                   shift[ 2 ];
826         vec_t                   rotate;
827         vec_t                   scale[ 2 ];
828         char                    name[ MAX_QPATH ];
829         char                    shader[ MAX_QPATH ];
830         int                             flags;
831         
832         
833         /* initial setup */
834         buildBrush->numsides = 0;
835         buildBrush->detail = qfalse;
836         
837         /* bp */
838         if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
839                 MatchToken( "{" );
840         
841         /* parse sides */
842         while( 1 )
843         {
844                 if( !GetToken( qtrue ) )
845                         break;
846                 if( !strcmp( token, "}" ) )
847                         break;
848                  
849                 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
850                 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
851                 {
852                         while( 1 )
853                         {
854                                 if( strcmp( token, "(" ) )
855                                         GetToken( qfalse );
856                                 else
857                                         break;
858                                 GetToken( qtrue );
859                         }
860                 }
861                 UnGetToken();
862                 
863                 /* test side count */
864                 if( buildBrush->numsides >= MAX_BUILD_SIDES )
865                         xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
866                 
867                 /* add side */
868                 side = &buildBrush->sides[ buildBrush->numsides ];
869                 memset( side, 0, sizeof( *side ) );
870                 buildBrush->numsides++;
871                 
872                 /* read the three point plane definition */
873                 Parse1DMatrix( 3, planePoints[ 0 ] );
874                 Parse1DMatrix( 3, planePoints[ 1 ] );
875                 Parse1DMatrix( 3, planePoints[ 2 ] );
876                 
877                 /* bp: read the texture matrix */
878                 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
879                         Parse2DMatrix( 2, 3, (float*) side->texMat );
880                 
881                 /* read shader name */
882                 GetToken( qfalse );
883                 strcpy( name, token );
884                 
885                 /* bp */
886                 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
887                 {
888                         GetToken( qfalse );
889                         shift[ 0 ] = atof( token );
890                         GetToken( qfalse );
891                         shift[ 1 ] = atof( token );
892                         GetToken( qfalse );
893                         rotate = atof( token ); 
894                         GetToken( qfalse );
895                         scale[ 0 ] = atof( token );
896                         GetToken( qfalse );
897                         scale[ 1 ] = atof( token );
898                 }
899                 
900                 /* set default flags and values */
901                 sprintf( shader, "textures/%s", name );
902                 if( onlyLights )
903                         si = &shaderInfo[ 0 ];
904                 else
905                         si = ShaderInfoForShader( shader );
906                 side->shaderInfo = si;
907                 side->surfaceFlags = si->surfaceFlags;
908                 side->contentFlags = si->contentFlags;
909                 side->compileFlags = si->compileFlags;
910                 side->value = si->value;
911                 
912                 /* ydnar: gs mods: bias texture shift */
913                 if( si->globalTexture == qfalse )
914                 {
915                         shift[ 0 ] -= (floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth);
916                         shift[ 1 ] -= (floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight);
917                 }
918                 
919                 /*
920                         historically, there are 3 integer values at the end of a brushside line in a .map file.
921                         in quake 3, the only thing that mattered was the first of these three values, which
922                         was previously the content flags. and only then did a single bit matter, the detail
923                         bit. because every game has its own special flags for specifying detail, the
924                         traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
925                         by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
926                         is stored in compileFlags, as opposed to contentFlags, for multiple-game
927                         portability. :sigh:
928                 */
929                 
930                 if( TokenAvailable() )
931                 {
932                         /* get detail bit from map content flags */
933                         GetToken( qfalse );
934                         flags = atoi( token );
935                         if( flags & C_DETAIL )
936                                 side->compileFlags |= C_DETAIL;
937                         
938                         /* historical */
939                         GetToken( qfalse );
940                         //% td.flags = atoi( token );
941                         GetToken( qfalse );
942                         //% td.value = atoi( token );
943                 }
944                 
945                 /* find the plane number */
946                 planenum = MapPlaneFromPoints( planePoints );
947                 side->planenum = planenum;
948                 
949                 /* bp: get the texture mapping for this texturedef / plane combination */
950                 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
951                         QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
952         }
953         
954         /* bp */
955         if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
956         {
957                 UnGetToken();
958                 MatchToken( "}" );
959                 MatchToken( "}" );
960         }
961 }
962
963
964
965 /*
966 RemoveDuplicateBrushPlanes
967 returns false if the brush has a mirrored set of planes,
968 meaning it encloses no volume.
969 also removes planes without any normal
970 */
971
972 qboolean RemoveDuplicateBrushPlanes( brush_t *b )
973 {
974         int                     i, j, k;
975         side_t          *sides;
976
977         sides = b->sides;
978
979         for ( i = 1 ; i < b->numsides ; i++ ) {
980
981                 // check for a degenerate plane
982                 if ( sides[i].planenum == -1) {
983                   xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
984                         // remove it
985                         for ( k = i + 1 ; k < b->numsides ; k++ ) {
986                                 sides[k-1] = sides[k];
987                         }
988                         b->numsides--;
989                         i--;
990                         continue;
991                 }
992
993                 // check for duplication and mirroring
994                 for ( j = 0 ; j < i ; j++ ) {
995                         if ( sides[i].planenum == sides[j].planenum ) {
996                           xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
997                                 // remove the second duplicate
998                                 for ( k = i + 1 ; k < b->numsides ; k++ ) {
999                                         sides[k-1] = sides[k];
1000                                 }
1001                                 b->numsides--;
1002                                 i--;
1003                                 break;
1004                         }
1005
1006                         if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
1007                                 // mirror plane, brush is invalid
1008                           xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
1009                                 return qfalse;
1010                         }
1011                 }
1012         }
1013         return qtrue;
1014 }
1015
1016
1017
1018 /*
1019 ParseBrush()
1020 parses a brush out of a map file and sets it up
1021 */
1022
1023 static void ParseBrush( qboolean onlyLights )
1024 {
1025         brush_t *b;
1026         
1027         
1028         /* parse the brush out of the map */
1029         ParseRawBrush( onlyLights );
1030         
1031         /* only go this far? */
1032         if( onlyLights )
1033                 return;
1034         
1035         /* set some defaults */
1036         buildBrush->portalareas[ 0 ] = -1;
1037         buildBrush->portalareas[ 1 ] = -1;
1038         buildBrush->entityNum = numMapEntities - 1;
1039         buildBrush->brushNum = entitySourceBrushes;
1040         
1041         /* if there are mirrored planes, the entire brush is invalid */
1042         if( !RemoveDuplicateBrushPlanes( buildBrush ) )
1043                 return;
1044         
1045         /* get the content for the entire brush */
1046         SetBrushContents( buildBrush );
1047         
1048         /* allow detail brushes to be removed */
1049         if( nodetail && (buildBrush->compileFlags & C_DETAIL) )
1050         {
1051                 //%     FreeBrush( buildBrush );
1052                 return;
1053         }
1054         
1055         /* allow liquid brushes to be removed */
1056         if( nowater && (buildBrush->compileFlags & C_LIQUID ) )
1057         {
1058                 //%     FreeBrush( buildBrush );
1059                 return;
1060         }
1061         
1062         /* ydnar: allow hint brushes to be removed */
1063         if( noHint && (buildBrush->compileFlags & C_HINT) )
1064         {
1065                 //%     FreeBrush( buildBrush );
1066                 return;
1067         }
1068         
1069         /* finish the brush */
1070         b = FinishBrush();
1071 }
1072
1073
1074
1075 /*
1076 MoveBrushesToWorld()
1077 takes all of the brushes from the current entity and
1078 adds them to the world's brush list
1079 (used by func_group)
1080 */
1081
1082 void MoveBrushesToWorld( entity_t *ent )
1083 {
1084         brush_t         *b, *next;
1085         parseMesh_t     *pm;
1086
1087         
1088         /* move brushes */
1089         for( b = ent->brushes; b != NULL; b = next )
1090         {
1091                 /* get next brush */
1092                 next = b->next;
1093                 
1094                 /* link opaque brushes to head of list, translucent brushes to end */
1095                 if( b->opaque || entities[ 0 ].lastBrush == NULL )
1096                 {
1097                         b->next = entities[ 0 ].brushes;
1098                         entities[ 0 ].brushes = b;
1099                         if( entities[ 0 ].lastBrush == NULL )
1100                                 entities[ 0 ].lastBrush = b;
1101                 }
1102                 else
1103                 {
1104                         b->next = NULL;
1105                         entities[ 0 ].lastBrush->next = b;
1106                         entities[ 0 ].lastBrush = b;
1107                 }
1108         }
1109         ent->brushes = NULL;
1110         
1111         /* ydnar: move colormod brushes */
1112         if( ent->colorModBrushes != NULL )
1113         {
1114                 for( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush );
1115                 
1116                 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1117                 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1118                 
1119                 ent->colorModBrushes = NULL;
1120         }
1121         
1122         /* move patches */
1123         if( ent->patches != NULL )
1124         {
1125                 for( pm = ent->patches; pm->next != NULL; pm = pm->next );
1126                 
1127                 pm->next = entities[ 0 ].patches;
1128                 entities[ 0 ].patches = ent->patches;
1129                 
1130                 ent->patches = NULL;
1131         }
1132 }
1133
1134
1135
1136 /*
1137 AdjustBrushesForOrigin()
1138 */
1139
1140 void AdjustBrushesForOrigin( entity_t *ent )
1141 {
1142         
1143         int                     i;
1144         side_t          *s;
1145         vec_t           newdist;
1146         brush_t         *b;
1147         parseMesh_t     *p;
1148         
1149         
1150         /* walk brush list */
1151         for( b = ent->brushes; b != NULL; b = b->next )
1152         {
1153                 /* offset brush planes */
1154                 for( i = 0; i < b->numsides; i++)
1155                 {
1156                         /* get brush side */
1157                         s = &b->sides[ i ];
1158                         
1159                         /* offset side plane */
1160                         newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin );
1161                         
1162                         /* find a new plane */
1163                         s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1164                 }
1165                 
1166                 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1167                 CreateBrushWindings( b );
1168         }
1169         
1170         /* walk patch list */
1171         for( p = ent->patches; p != NULL; p = p->next )
1172         {
1173                 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1174                         VectorSubtract( p->mesh.verts[ i ].xyz, ent->origin, p->mesh.verts[ i ].xyz );
1175         }
1176 }
1177
1178
1179
1180 /*
1181 SetEntityBounds() - ydnar
1182 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1183 */
1184
1185 void SetEntityBounds( entity_t *e )
1186 {
1187         int                     i;
1188         brush_t *b;
1189         parseMesh_t     *p;
1190         vec3_t          mins, maxs;
1191         const char      *value;
1192
1193         
1194         
1195
1196         /* walk the entity's brushes/patches and determine bounds */
1197         ClearBounds( mins, maxs );
1198         for( b = e->brushes; b; b = b->next )
1199         {
1200                 AddPointToBounds( b->mins, mins, maxs );
1201                 AddPointToBounds( b->maxs, mins, maxs );
1202         }
1203         for( p = e->patches; p; p = p->next )
1204         {
1205                 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1206                         AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1207         }
1208         
1209         /* try to find explicit min/max key */
1210         value = ValueForKey( e, "min" ); 
1211         if( value[ 0 ] != '\0' )
1212                 GetVectorForKey( e, "min", mins );
1213         value = ValueForKey( e, "max" ); 
1214         if( value[ 0 ] != '\0' )
1215                 GetVectorForKey( e, "max", maxs );
1216         
1217         /* store the bounds */
1218         for( b = e->brushes; b; b = b->next )
1219         {
1220                 VectorCopy( mins, b->eMins );
1221                 VectorCopy( maxs, b->eMaxs );
1222         }
1223         for( p = e->patches; p; p = p->next )
1224         {
1225                 VectorCopy( mins, p->eMins );
1226                 VectorCopy( maxs, p->eMaxs );
1227         }
1228 }
1229
1230
1231
1232 /*
1233 LoadEntityIndexMap() - ydnar
1234 based on LoadAlphaMap() from terrain.c, a little more generic
1235 */
1236
1237 void LoadEntityIndexMap( entity_t *e )
1238 {
1239         int                             i, size, numLayers, w, h;
1240         const char              *value, *indexMapFilename, *shader;
1241         char                    ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1242         byte                    *pixels;
1243         unsigned int    *pixels32;
1244         indexMap_t              *im;
1245         brush_t                 *b;
1246         parseMesh_t             *p;
1247         
1248         
1249         /* this only works with bmodel ents */
1250         if( e->brushes == NULL && e->patches == NULL )
1251                 return;
1252         
1253         /* determine if there is an index map (support legacy "alphamap" key as well) */
1254         value = ValueForKey( e, "_indexmap" );
1255         if( value[ 0 ] == '\0' )
1256                 value = ValueForKey( e, "alphamap" );
1257         if( value[ 0 ] == '\0' )
1258                 return;
1259         indexMapFilename = value;
1260         
1261         /* get number of layers (support legacy "layers" key as well) */
1262         value = ValueForKey( e, "_layers" );
1263         if( value[ 0 ] == '\0' )
1264                 value = ValueForKey( e, "layers" );
1265         if( value[ 0 ] == '\0' )
1266         {
1267                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1268                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1269                 return;
1270         }
1271         numLayers = atoi( value );
1272         if( numLayers < 1 )
1273         {
1274                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1275                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1276                 return;
1277         }
1278         
1279         /* get base shader name (support legacy "shader" key as well) */
1280         value = ValueForKey( mapEnt, "_shader" );
1281         if( value[ 0 ] == '\0' )
1282                 value = ValueForKey( e, "shader" );
1283         if( value[ 0 ] == '\0' )
1284         {
1285                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1286                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1287                 return;
1288         }
1289         shader = value;
1290         
1291         /* note it */
1292         Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n",  mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1293         
1294         /* get index map file extension */
1295         ExtractFileExtension( indexMapFilename, ext );
1296         
1297         /* handle tga image */
1298         if( !Q_stricmp( ext, "tga" ) )
1299         {
1300                 /* load it */
1301                 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1302                 
1303                 /* convert to bytes */
1304                 size = w * h;
1305                 pixels = safe_malloc( size );
1306                 for( i = 0; i < size; i++ )
1307                 {
1308                         pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1309                         if( pixels[ i ] >= numLayers )
1310                                 pixels[ i ] = numLayers - 1;
1311                 }
1312                 
1313                 /* free the 32 bit image */
1314                 free( pixels32 );
1315         }
1316         else
1317         {
1318                 /* load it */
1319                 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1320                 
1321                 /* debug code */
1322                 //%     Sys_Printf( "-------------------------------" );
1323                 
1324                 /* fix up out-of-range values */
1325                 size = w * h;
1326                 for( i = 0; i < size; i++ )
1327                 {
1328                         if( pixels[ i ] >= numLayers )
1329                                 pixels[ i ] = numLayers - 1;
1330                         
1331                         /* debug code */
1332                         //%     if( (i % w) == 0 )
1333                         //%             Sys_Printf( "\n" );
1334                         //%     Sys_Printf( "%c", pixels[ i ] + '0' );
1335                 }
1336                 
1337                 /* debug code */
1338                 //%     Sys_Printf( "\n-------------------------------\n" );
1339         }
1340         
1341         /* the index map must be at least 2x2 pixels */
1342         if( w < 2 || h < 2 )
1343         {
1344                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1345                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1346                 free( pixels );
1347                 return;
1348         }
1349
1350         /* create a new index map */
1351         im = safe_malloc( sizeof( *im ) );
1352         memset( im, 0, sizeof( *im ) );
1353         
1354         /* set it up */
1355         im->w = w;
1356         im->h = h;
1357         im->numLayers = numLayers;
1358         strcpy( im->name, indexMapFilename );
1359         strcpy( im->shader, shader );
1360         im->pixels = pixels;
1361         
1362         /* get height offsets */
1363         value = ValueForKey( mapEnt, "_offsets" );
1364         if( value[ 0 ] == '\0' )
1365                 value = ValueForKey( e, "offsets" );
1366         if( value[ 0 ] != '\0' )
1367         {
1368                 /* value is a space-seperated set of numbers */
1369                 strcpy( offset, value );
1370                 search = offset;
1371                 
1372                 /* get each value */
1373                 for( i = 0; i < 256 && *search != '\0'; i++ )
1374                 {
1375                         space = strstr( search, " " );
1376                         if( space != NULL )
1377                                 *space = '\0';
1378                         im->offsets[ i ] = atof( search );
1379                         if( space == NULL )
1380                                 break;
1381                         search = space + 1;
1382                 }
1383         }
1384         
1385         /* store the index map in every brush/patch in the entity */
1386         for( b = e->brushes; b != NULL; b = b->next )
1387                 b->im = im;
1388         for( p = e->patches; p != NULL; p = p->next )
1389                 p->im = im;
1390 }
1391
1392
1393
1394
1395
1396
1397
1398 /*
1399 ParseMapEntity()
1400 parses a single entity out of a map file
1401 */
1402
1403 static qboolean ParseMapEntity( qboolean onlyLights )
1404 {
1405         epair_t                 *ep;
1406         const char              *classname, *value;
1407         float                   lightmapScale;
1408         char                    shader[ MAX_QPATH ];
1409         shaderInfo_t    *celShader = NULL;
1410         brush_t                 *brush;
1411         parseMesh_t             *patch;
1412         qboolean                funcGroup;
1413         int                             castShadows, recvShadows;
1414         
1415         
1416         /* eof check */
1417         if( !GetToken( qtrue ) )
1418                 return qfalse;
1419         
1420         /* conformance check */
1421         if( strcmp( token, "{" ) )
1422         {
1423                 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1424                         "Continuing to process map, but resulting BSP may be invalid.\n",
1425                         token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1426                 return qfalse;
1427         }
1428         
1429         /* range check */
1430         if( numEntities >= MAX_MAP_ENTITIES )
1431                 Error( "numEntities == MAX_MAP_ENTITIES" );
1432         
1433         /* setup */
1434         entitySourceBrushes = 0;
1435         mapEnt = &entities[ numEntities ];
1436         numEntities++;
1437         memset( mapEnt, 0, sizeof( *mapEnt ) );
1438         
1439         /* ydnar: true entity numbering */
1440         mapEnt->mapEntityNum = numMapEntities;
1441         numMapEntities++;
1442         
1443         /* loop */
1444         while( 1 )
1445         {
1446                 /* get initial token */
1447                 if( !GetToken( qtrue ) )
1448                 {
1449                         Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1450                                 "Continuing to process map, but resulting BSP may be invalid.\n" );
1451                         return qfalse;
1452                 }
1453                 
1454                 if( !strcmp( token, "}" ) )
1455                         break;
1456                 
1457                 if( !strcmp( token, "{" ) )
1458                 {
1459                         /* parse a brush or patch */
1460                         if( !GetToken( qtrue ) )
1461                                 break;
1462                         
1463                         /* check */
1464                         if( !strcmp( token, "patchDef2" ) )
1465                         {
1466                                 numMapPatches++;
1467                                 ParsePatch( onlyLights );
1468                         }
1469                         else if( !strcmp( token, "terrainDef" ) )
1470                         {
1471                                 //% ParseTerrain();
1472                                 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1473                         }
1474                         else if( !strcmp( token, "brushDef" ) )
1475                         {
1476                                 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1477                                         Error( "Old brush format not allowed in new brush format map" );
1478                                 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1479                                 
1480                                 /* parse brush primitive */
1481                                 ParseBrush( onlyLights );
1482                         }
1483                         else
1484                         {
1485                                 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1486                                         Error( "New brush format not allowed in old brush format map" );
1487                                 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1488                                 
1489                                 /* parse old brush format */
1490                                 UnGetToken();
1491                                 ParseBrush( onlyLights );
1492                         }
1493                         entitySourceBrushes++;
1494                 }
1495                 else
1496                 {
1497                         /* parse a key / value pair */
1498                         ep = ParseEPair();
1499                         
1500                         /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1501                         if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1502                         {
1503                                 ep->next = mapEnt->epairs;
1504                                 mapEnt->epairs = ep;
1505                         }
1506                 }
1507         }
1508         
1509         /* ydnar: get classname */
1510         classname = ValueForKey( mapEnt, "classname" );
1511         
1512         /* ydnar: only lights? */
1513         if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1514         {
1515                 numEntities--;
1516                 return qtrue;
1517         }
1518         
1519         /* ydnar: determine if this is a func_group */
1520         if( !Q_stricmp( "func_group", classname ) )
1521                 funcGroup = qtrue;
1522         else
1523                 funcGroup = qfalse;
1524         
1525         /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1526         if( funcGroup || mapEnt->mapEntityNum == 0 )
1527         {
1528                 //%     Sys_Printf( "World:  %d\n", mapEnt->mapEntityNum );
1529                 castShadows = WORLDSPAWN_CAST_SHADOWS;
1530                 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1531         }
1532         
1533         /* other entities don't cast any shadows, but recv worldspawn shadows */
1534         else
1535         {
1536                 //%     Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1537                 castShadows = ENTITY_CAST_SHADOWS;
1538                 recvShadows = ENTITY_RECV_SHADOWS;
1539         }
1540         
1541         /* get explicit shadow flags */
1542         GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1543         
1544         /* ydnar: get lightmap scaling value for this entity */
1545         if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1546                 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) )
1547         {
1548                 /* get lightmap scale from entity */
1549                 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1550                 if( lightmapScale <= 0.0f )
1551                         lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1552                 if( lightmapScale > 0.0f )
1553                         Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1554         }
1555         else
1556                 lightmapScale = 0.0f;
1557         
1558         /* ydnar: get cel shader :) for this entity */
1559         value = ValueForKey( mapEnt, "_celshader" );
1560         if( value[ 0 ] == '\0' )        
1561                 value = ValueForKey( &entities[ 0 ], "_celshader" );
1562         if( value[ 0 ] != '\0' )
1563         {
1564                 sprintf( shader, "textures/%s", value );
1565                 celShader = ShaderInfoForShader( shader );
1566                 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1567         }
1568         else
1569                 celShader = NULL;
1570         
1571         /* attach stuff to everything in the entity */
1572         for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1573         {
1574                 brush->entityNum = mapEnt->mapEntityNum;
1575                 brush->castShadows = castShadows;
1576                 brush->recvShadows = recvShadows;
1577                 brush->lightmapScale = lightmapScale;
1578                 brush->celShader = celShader;
1579         }
1580         
1581         for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1582         {
1583                 patch->entityNum = mapEnt->mapEntityNum;
1584                 patch->castShadows = castShadows;
1585                 patch->recvShadows = recvShadows;
1586                 patch->lightmapScale = lightmapScale;
1587                 patch->celShader = celShader;
1588         }
1589         
1590         /* ydnar: gs mods: set entity bounds */
1591         SetEntityBounds( mapEnt );
1592         
1593         /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1594         LoadEntityIndexMap( mapEnt );
1595         
1596         /* get entity origin and adjust brushes */
1597         GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1598         if( mapEnt->origin[ 0 ] || mapEnt->origin[ 1 ] || mapEnt->origin[ 2 ] )
1599                 AdjustBrushesForOrigin( mapEnt );
1600
1601         /* group_info entities are just for editor grouping (fixme: leak!) */
1602         if( !Q_stricmp( "group_info", classname ) )
1603         {
1604                 numEntities--;
1605                 return qtrue;
1606         }
1607         
1608         /* group entities are just for editor convenience, toss all brushes into worldspawn */
1609         if( funcGroup )
1610         {
1611                 MoveBrushesToWorld( mapEnt );
1612                 numEntities--;
1613                 return qtrue;
1614         }
1615         
1616         /* done */
1617         return qtrue;
1618 }
1619
1620
1621
1622 /*
1623 LoadMapFile()
1624 loads a map file into a list of entities
1625 */
1626
1627 void LoadMapFile( char *filename, qboolean onlyLights )
1628 {               
1629         FILE            *file;
1630         brush_t         *b;
1631         int                     oldNumEntities, numMapBrushes;
1632         
1633         
1634         /* note it */
1635         Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1636         Sys_Printf( "Loading %s\n", filename );
1637         
1638         /* hack */
1639         file = SafeOpenRead( filename );
1640         fclose( file );
1641         
1642         /* load the map file */
1643         LoadScriptFile( filename, -1 );
1644         
1645         /* setup */
1646         if( onlyLights )
1647                 oldNumEntities = numEntities;
1648         else
1649                 numEntities = 0;
1650         
1651         /* initial setup */
1652         numMapDrawSurfs = 0;
1653         c_detail = 0;
1654         g_bBrushPrimit = BPRIMIT_UNDEFINED;
1655         
1656         /* allocate a very large temporary brush for building the brushes as they are loaded */
1657         buildBrush = AllocBrush( MAX_BUILD_SIDES );
1658         
1659         /* parse the map file */
1660         while( ParseMapEntity( onlyLights ) );
1661         
1662         /* light loading */
1663         if( onlyLights )
1664         {
1665                 /* emit some statistics */
1666                 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1667         }
1668         else
1669         {
1670                 /* set map bounds */
1671                 ClearBounds( mapMins, mapMaxs );
1672                 for( b = entities[ 0 ].brushes; b; b = b->next )
1673                 {
1674                         AddPointToBounds( b->mins, mapMins, mapMaxs );
1675                         AddPointToBounds( b->maxs, mapMins, mapMaxs );
1676                 }
1677                 
1678                 /* get brush counts */
1679                 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1680                 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1681                         Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1682                 
1683                 /* emit some statistics */
1684                 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1685                 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1686                 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1687                 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1688                 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1689                 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1690                 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1691                 Sys_Printf( "%9d areaportals\n", c_areaportals);
1692                 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1693                         mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1694                         mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1695                 
1696                 /* write bogus map */
1697                 if( fakemap )
1698                         WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );
1699         }
1700 }