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