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