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