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