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