]> icculus.org git repositories - divverent/netradiant.git/blob - tools/quake3/q3map2/map.c
Turn some UT stuff into options, as it is broken for Nexuiz. Also add -nodeluxenormal...
[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 brush_t *FinishBrush( void )
599 {
600         brush_t         *b;
601         
602         
603         /* create windings for sides and bounds for brush */
604         if ( !CreateBrushWindings( buildBrush ) )
605                 return NULL;
606
607         /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
608            after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
609         if( buildBrush->compileFlags & C_ORIGIN )
610         {
611                 char    string[ 32 ];
612                 vec3_t  origin;
613
614                 if( numEntities == 1 )
615                 {
616                         Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n", 
617                                 mapEnt->mapEntityNum, entitySourceBrushes );
618                         return NULL;
619                 }
620                 
621                 VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
622                 VectorScale (origin, 0.5, origin);
623
624                 sprintf( string, "%i %i %i", (int) origin[ 0 ], (int) origin[ 1 ], (int) origin[ 2 ] );
625                 SetKeyValue( &entities[ numEntities - 1 ], "origin", string);
626
627                 VectorCopy( origin, entities[ numEntities - 1 ].origin);
628
629                 /* don't keep this brush */
630                 return NULL;
631         }
632         
633         /* determine if the brush is an area portal */
634         if( buildBrush->compileFlags & C_AREAPORTAL )
635         {
636                 if( numEntities != 1 )
637                 {
638                         Sys_Printf ("Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
639                         return NULL;
640                 }
641         }
642         
643         /* add bevel planes */
644         AddBrushBevels();
645         
646         /* keep it */
647         b = CopyBrush( buildBrush );
648         
649         /* set map entity and brush numbering */
650         b->entityNum = mapEnt->mapEntityNum;
651         b->brushNum = entitySourceBrushes;
652         
653         /* set original */
654         b->original = b;
655         
656         /* link opaque brushes to head of list, translucent brushes to end */
657         if( b->opaque || mapEnt->lastBrush == NULL )
658         {
659                 b->next = mapEnt->brushes;
660                 mapEnt->brushes = b;
661                 if( mapEnt->lastBrush == NULL )
662                         mapEnt->lastBrush = b;
663         }
664         else
665         {
666                 b->next = NULL;
667                 mapEnt->lastBrush->next = b;
668                 mapEnt->lastBrush = b;
669         }
670         
671         /* link colorMod volume brushes to the entity directly */
672         if( b->contentShader != NULL &&
673                 b->contentShader->colorMod != NULL &&
674                 b->contentShader->colorMod->type == CM_VOLUME )
675         {
676                 b->nextColorModBrush = mapEnt->colorModBrushes;
677                 mapEnt->colorModBrushes = b;
678         }
679         
680         /* return to sender */
681         return b;
682 }
683
684
685
686 /*
687 TextureAxisFromPlane()
688 determines best orthagonal axis to project a texture onto a wall
689 (must be identical in radiant!)
690 */
691
692 vec3_t  baseaxis[18] =
693 {
694         {0,0,1}, {1,0,0}, {0,-1,0},                     // floor
695         {0,0,-1}, {1,0,0}, {0,-1,0},            // ceiling
696         {1,0,0}, {0,1,0}, {0,0,-1},                     // west wall
697         {-1,0,0}, {0,1,0}, {0,0,-1},            // east wall
698         {0,1,0}, {1,0,0}, {0,0,-1},                     // south wall
699         {0,-1,0}, {1,0,0}, {0,0,-1}                     // north wall
700 };
701
702 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv )
703 {
704         int             bestaxis;
705         vec_t   dot,best;
706         int             i;
707         
708         best = 0;
709         bestaxis = 0;
710         
711         for (i=0 ; i<6 ; i++)
712         {
713                 dot = DotProduct (pln->normal, baseaxis[i*3]);
714                 if( dot > best + 0.0001f )      /* ydnar: bug 637 fix, suggested by jmonroe */
715                 {
716                         best = dot;
717                         bestaxis = i;
718                 }
719         }
720         
721         VectorCopy (baseaxis[bestaxis*3+1], xv);
722         VectorCopy (baseaxis[bestaxis*3+2], yv);
723 }
724
725
726
727 /*
728 QuakeTextureVecs()
729 creates world-to-texture mapping vecs for crappy quake plane arrangements
730 */
731
732 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] )
733 {
734         vec3_t  vecs[2];
735         int             sv, tv;
736         vec_t   ang, sinv, cosv;
737         vec_t   ns, nt;
738         int             i, j;
739         
740         
741         TextureAxisFromPlane(plane, vecs[0], vecs[1]);
742         
743         if (!scale[0])
744                 scale[0] = 1;
745         if (!scale[1])
746                 scale[1] = 1;
747
748         // rotate axis
749         if (rotate == 0)
750                 { sinv = 0 ; cosv = 1; }
751         else if (rotate == 90)
752                 { sinv = 1 ; cosv = 0; }
753         else if (rotate == 180)
754                 { sinv = 0 ; cosv = -1; }
755         else if (rotate == 270)
756                 { sinv = -1 ; cosv = 0; }
757         else
758         {       
759                 ang = rotate / 180 * Q_PI;
760                 sinv = sin(ang);
761                 cosv = cos(ang);
762         }
763
764         if (vecs[0][0])
765                 sv = 0;
766         else if (vecs[0][1])
767                 sv = 1;
768         else
769                 sv = 2;
770                                 
771         if (vecs[1][0])
772                 tv = 0;
773         else if (vecs[1][1])
774                 tv = 1;
775         else
776                 tv = 2;
777                                         
778         for (i=0 ; i<2 ; i++) {
779                 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
780                 nt = sinv * vecs[i][sv] +  cosv * vecs[i][tv];
781                 vecs[i][sv] = ns;
782                 vecs[i][tv] = nt;
783         }
784
785         for (i=0 ; i<2 ; i++)
786                 for (j=0 ; j<3 ; j++)
787                         mappingVecs[i][j] = vecs[i][j] / scale[i];
788
789         mappingVecs[0][3] = shift[0];
790         mappingVecs[1][3] = shift[1];
791 }
792
793
794
795 /*
796 ParseRawBrush()
797 parses the sides into buildBrush->sides[], nothing else.
798 no validation, back plane removal, etc.
799
800 Timo - 08/26/99
801 added brush epairs parsing ( ignoring actually )
802 Timo - 08/04/99
803 added exclusive brush primitive parsing
804 Timo - 08/08/99
805 support for old brush format back in
806 NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
807 */
808
809 static void ParseRawBrush( qboolean onlyLights )
810 {
811         side_t                  *side;
812         vec3_t                  planePoints[ 3 ];
813         int                             planenum;
814         shaderInfo_t    *si;
815         vec_t                   shift[ 2 ];
816         vec_t                   rotate;
817         vec_t                   scale[ 2 ];
818         char                    name[ MAX_QPATH ];
819         char                    shader[ MAX_QPATH ];
820         int                             flags;
821         
822         
823         /* initial setup */
824         buildBrush->numsides = 0;
825         buildBrush->detail = qfalse;
826         
827         /* bp */
828         if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
829                 MatchToken( "{" );
830         
831         /* parse sides */
832         while( 1 )
833         {
834                 if( !GetToken( qtrue ) )
835                         break;
836                 if( !strcmp( token, "}" ) )
837                         break;
838                  
839                 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
840                 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
841                 {
842                         while( 1 )
843                         {
844                                 if( strcmp( token, "(" ) )
845                                         GetToken( qfalse );
846                                 else
847                                         break;
848                                 GetToken( qtrue );
849                         }
850                 }
851                 UnGetToken();
852                 
853                 /* test side count */
854                 if( buildBrush->numsides >= MAX_BUILD_SIDES )
855                         xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
856                 
857                 /* add side */
858                 side = &buildBrush->sides[ buildBrush->numsides ];
859                 memset( side, 0, sizeof( *side ) );
860                 buildBrush->numsides++;
861                 
862                 /* read the three point plane definition */
863                 Parse1DMatrix( 3, planePoints[ 0 ] );
864                 Parse1DMatrix( 3, planePoints[ 1 ] );
865                 Parse1DMatrix( 3, planePoints[ 2 ] );
866                 
867                 /* bp: read the texture matrix */
868                 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
869                         Parse2DMatrix( 2, 3, (float*) side->texMat );
870                 
871                 /* read shader name */
872                 GetToken( qfalse );
873                 strcpy( name, token );
874                 
875                 /* bp */
876                 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
877                 {
878                         GetToken( qfalse );
879                         shift[ 0 ] = atof( token );
880                         GetToken( qfalse );
881                         shift[ 1 ] = atof( token );
882                         GetToken( qfalse );
883                         rotate = atof( token ); 
884                         GetToken( qfalse );
885                         scale[ 0 ] = atof( token );
886                         GetToken( qfalse );
887                         scale[ 1 ] = atof( token );
888                 }
889                 
890                 /* set default flags and values */
891                 sprintf( shader, "textures/%s", name );
892                 if( onlyLights )
893                         si = &shaderInfo[ 0 ];
894                 else
895                         si = ShaderInfoForShader( shader );
896                 side->shaderInfo = si;
897                 side->surfaceFlags = si->surfaceFlags;
898                 side->contentFlags = si->contentFlags;
899                 side->compileFlags = si->compileFlags;
900                 side->value = si->value;
901                 
902                 /* ydnar: gs mods: bias texture shift */
903                 if( si->globalTexture == qfalse )
904                 {
905                         shift[ 0 ] -= (floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth);
906                         shift[ 1 ] -= (floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight);
907                 }
908                 
909                 /*
910                         historically, there are 3 integer values at the end of a brushside line in a .map file.
911                         in quake 3, the only thing that mattered was the first of these three values, which
912                         was previously the content flags. and only then did a single bit matter, the detail
913                         bit. because every game has its own special flags for specifying detail, the
914                         traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
915                         by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
916                         is stored in compileFlags, as opposed to contentFlags, for multiple-game
917                         portability. :sigh:
918                 */
919                 
920                 if( TokenAvailable() )
921                 {
922                         /* get detail bit from map content flags */
923                         GetToken( qfalse );
924                         flags = atoi( token );
925                         if( flags & C_DETAIL )
926                                 side->compileFlags |= C_DETAIL;
927                         
928                         /* historical */
929                         GetToken( qfalse );
930                         //% td.flags = atoi( token );
931                         GetToken( qfalse );
932                         //% td.value = atoi( token );
933                 }
934                 
935                 /* find the plane number */
936                 planenum = MapPlaneFromPoints( planePoints );
937                 side->planenum = planenum;
938                 
939                 /* bp: get the texture mapping for this texturedef / plane combination */
940                 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
941                         QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
942         }
943         
944         /* bp */
945         if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
946         {
947                 UnGetToken();
948                 MatchToken( "}" );
949                 MatchToken( "}" );
950         }
951 }
952
953
954
955 /*
956 RemoveDuplicateBrushPlanes
957 returns false if the brush has a mirrored set of planes,
958 meaning it encloses no volume.
959 also removes planes without any normal
960 */
961
962 qboolean RemoveDuplicateBrushPlanes( brush_t *b )
963 {
964         int                     i, j, k;
965         side_t          *sides;
966
967         sides = b->sides;
968
969         for ( i = 1 ; i < b->numsides ; i++ ) {
970
971                 // check for a degenerate plane
972                 if ( sides[i].planenum == -1) {
973                   xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
974                         // remove it
975                         for ( k = i + 1 ; k < b->numsides ; k++ ) {
976                                 sides[k-1] = sides[k];
977                         }
978                         b->numsides--;
979                         i--;
980                         continue;
981                 }
982
983                 // check for duplication and mirroring
984                 for ( j = 0 ; j < i ; j++ ) {
985                         if ( sides[i].planenum == sides[j].planenum ) {
986                           xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
987                                 // remove the second duplicate
988                                 for ( k = i + 1 ; k < b->numsides ; k++ ) {
989                                         sides[k-1] = sides[k];
990                                 }
991                                 b->numsides--;
992                                 i--;
993                                 break;
994                         }
995
996                         if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
997                                 // mirror plane, brush is invalid
998                           xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
999                                 return qfalse;
1000                         }
1001                 }
1002         }
1003         return qtrue;
1004 }
1005
1006
1007
1008 /*
1009 ParseBrush()
1010 parses a brush out of a map file and sets it up
1011 */
1012
1013 static void ParseBrush( qboolean onlyLights )
1014 {
1015         brush_t *b;
1016         
1017         
1018         /* parse the brush out of the map */
1019         ParseRawBrush( onlyLights );
1020         
1021         /* only go this far? */
1022         if( onlyLights )
1023                 return;
1024         
1025         /* set some defaults */
1026         buildBrush->portalareas[ 0 ] = -1;
1027         buildBrush->portalareas[ 1 ] = -1;
1028         buildBrush->entityNum = numMapEntities - 1;
1029         buildBrush->brushNum = entitySourceBrushes;
1030         
1031         /* if there are mirrored planes, the entire brush is invalid */
1032         if( !RemoveDuplicateBrushPlanes( buildBrush ) )
1033                 return;
1034         
1035         /* get the content for the entire brush */
1036         SetBrushContents( buildBrush );
1037         
1038         /* allow detail brushes to be removed */
1039         if( nodetail && (buildBrush->compileFlags & C_DETAIL) )
1040         {
1041                 //%     FreeBrush( buildBrush );
1042                 return;
1043         }
1044         
1045         /* allow liquid brushes to be removed */
1046         if( nowater && (buildBrush->compileFlags & C_LIQUID ) )
1047         {
1048                 //%     FreeBrush( buildBrush );
1049                 return;
1050         }
1051         
1052         /* ydnar: allow hint brushes to be removed */
1053         if( noHint && (buildBrush->compileFlags & C_HINT) )
1054         {
1055                 //%     FreeBrush( buildBrush );
1056                 return;
1057         }
1058         
1059         /* finish the brush */
1060         b = FinishBrush();
1061 }
1062
1063
1064
1065 /*
1066 MoveBrushesToWorld()
1067 takes all of the brushes from the current entity and
1068 adds them to the world's brush list
1069 (used by func_group)
1070 */
1071
1072 void MoveBrushesToWorld( entity_t *ent )
1073 {
1074         brush_t         *b, *next;
1075         parseMesh_t     *pm;
1076
1077         
1078         /* move brushes */
1079         for( b = ent->brushes; b != NULL; b = next )
1080         {
1081                 /* get next brush */
1082                 next = b->next;
1083                 
1084                 /* link opaque brushes to head of list, translucent brushes to end */
1085                 if( b->opaque || entities[ 0 ].lastBrush == NULL )
1086                 {
1087                         b->next = entities[ 0 ].brushes;
1088                         entities[ 0 ].brushes = b;
1089                         if( entities[ 0 ].lastBrush == NULL )
1090                                 entities[ 0 ].lastBrush = b;
1091                 }
1092                 else
1093                 {
1094                         b->next = NULL;
1095                         entities[ 0 ].lastBrush->next = b;
1096                         entities[ 0 ].lastBrush = b;
1097                 }
1098         }
1099         ent->brushes = NULL;
1100         
1101         /* ydnar: move colormod brushes */
1102         if( ent->colorModBrushes != NULL )
1103         {
1104                 for( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush );
1105                 
1106                 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1107                 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1108                 
1109                 ent->colorModBrushes = NULL;
1110         }
1111         
1112         /* move patches */
1113         if( ent->patches != NULL )
1114         {
1115                 for( pm = ent->patches; pm->next != NULL; pm = pm->next );
1116                 
1117                 pm->next = entities[ 0 ].patches;
1118                 entities[ 0 ].patches = ent->patches;
1119                 
1120                 ent->patches = NULL;
1121         }
1122 }
1123
1124
1125
1126 /*
1127 AdjustBrushesForOrigin()
1128 */
1129
1130 void AdjustBrushesForOrigin( entity_t *ent )
1131 {
1132         
1133         int                     i;
1134         side_t          *s;
1135         vec_t           newdist;
1136         brush_t         *b;
1137         parseMesh_t     *p;
1138         
1139         
1140         /* walk brush list */
1141         for( b = ent->brushes; b != NULL; b = b->next )
1142         {
1143                 /* offset brush planes */
1144                 for( i = 0; i < b->numsides; i++)
1145                 {
1146                         /* get brush side */
1147                         s = &b->sides[ i ];
1148                         
1149                         /* offset side plane */
1150                         newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin );
1151                         
1152                         /* find a new plane */
1153                         s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1154                 }
1155                 
1156                 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1157                 CreateBrushWindings( b );
1158         }
1159         
1160         /* walk patch list */
1161         for( p = ent->patches; p != NULL; p = p->next )
1162         {
1163                 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1164                         VectorSubtract( p->mesh.verts[ i ].xyz, ent->origin, p->mesh.verts[ i ].xyz );
1165         }
1166 }
1167
1168
1169
1170 /*
1171 SetEntityBounds() - ydnar
1172 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1173 */
1174
1175 void SetEntityBounds( entity_t *e )
1176 {
1177         int                     i;
1178         brush_t *b;
1179         parseMesh_t     *p;
1180         vec3_t          mins, maxs;
1181         const char      *value;
1182
1183         
1184         
1185
1186         /* walk the entity's brushes/patches and determine bounds */
1187         ClearBounds( mins, maxs );
1188         for( b = e->brushes; b; b = b->next )
1189         {
1190                 AddPointToBounds( b->mins, mins, maxs );
1191                 AddPointToBounds( b->maxs, mins, maxs );
1192         }
1193         for( p = e->patches; p; p = p->next )
1194         {
1195                 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1196                         AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1197         }
1198         
1199         /* try to find explicit min/max key */
1200         value = ValueForKey( e, "min" ); 
1201         if( value[ 0 ] != '\0' )
1202                 GetVectorForKey( e, "min", mins );
1203         value = ValueForKey( e, "max" ); 
1204         if( value[ 0 ] != '\0' )
1205                 GetVectorForKey( e, "max", maxs );
1206         
1207         /* store the bounds */
1208         for( b = e->brushes; b; b = b->next )
1209         {
1210                 VectorCopy( mins, b->eMins );
1211                 VectorCopy( maxs, b->eMaxs );
1212         }
1213         for( p = e->patches; p; p = p->next )
1214         {
1215                 VectorCopy( mins, p->eMins );
1216                 VectorCopy( maxs, p->eMaxs );
1217         }
1218 }
1219
1220
1221
1222 /*
1223 LoadEntityIndexMap() - ydnar
1224 based on LoadAlphaMap() from terrain.c, a little more generic
1225 */
1226
1227 void LoadEntityIndexMap( entity_t *e )
1228 {
1229         int                             i, size, numLayers, w, h;
1230         const char              *value, *indexMapFilename, *shader;
1231         char                    ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1232         byte                    *pixels;
1233         unsigned int    *pixels32;
1234         indexMap_t              *im;
1235         brush_t                 *b;
1236         parseMesh_t             *p;
1237         
1238         
1239         /* this only works with bmodel ents */
1240         if( e->brushes == NULL && e->patches == NULL )
1241                 return;
1242         
1243         /* determine if there is an index map (support legacy "alphamap" key as well) */
1244         value = ValueForKey( e, "_indexmap" );
1245         if( value[ 0 ] == '\0' )
1246                 value = ValueForKey( e, "alphamap" );
1247         if( value[ 0 ] == '\0' )
1248                 return;
1249         indexMapFilename = value;
1250         
1251         /* get number of layers (support legacy "layers" key as well) */
1252         value = ValueForKey( e, "_layers" );
1253         if( value[ 0 ] == '\0' )
1254                 value = ValueForKey( e, "layers" );
1255         if( value[ 0 ] == '\0' )
1256         {
1257                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1258                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1259                 return;
1260         }
1261         numLayers = atoi( value );
1262         if( numLayers < 1 )
1263         {
1264                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1265                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1266                 return;
1267         }
1268         
1269         /* get base shader name (support legacy "shader" key as well) */
1270         value = ValueForKey( mapEnt, "_shader" );
1271         if( value[ 0 ] == '\0' )
1272                 value = ValueForKey( e, "shader" );
1273         if( value[ 0 ] == '\0' )
1274         {
1275                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1276                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1277                 return;
1278         }
1279         shader = value;
1280         
1281         /* note it */
1282         Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n",  mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1283         
1284         /* get index map file extension */
1285         ExtractFileExtension( indexMapFilename, ext );
1286         
1287         /* handle tga image */
1288         if( !Q_stricmp( ext, "tga" ) )
1289         {
1290                 /* load it */
1291                 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1292                 
1293                 /* convert to bytes */
1294                 size = w * h;
1295                 pixels = safe_malloc( size );
1296                 for( i = 0; i < size; i++ )
1297                 {
1298                         pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1299                         if( pixels[ i ] >= numLayers )
1300                                 pixels[ i ] = numLayers - 1;
1301                 }
1302                 
1303                 /* free the 32 bit image */
1304                 free( pixels32 );
1305         }
1306         else
1307         {
1308                 /* load it */
1309                 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1310                 
1311                 /* debug code */
1312                 //%     Sys_Printf( "-------------------------------" );
1313                 
1314                 /* fix up out-of-range values */
1315                 size = w * h;
1316                 for( i = 0; i < size; i++ )
1317                 {
1318                         if( pixels[ i ] >= numLayers )
1319                                 pixels[ i ] = numLayers - 1;
1320                         
1321                         /* debug code */
1322                         //%     if( (i % w) == 0 )
1323                         //%             Sys_Printf( "\n" );
1324                         //%     Sys_Printf( "%c", pixels[ i ] + '0' );
1325                 }
1326                 
1327                 /* debug code */
1328                 //%     Sys_Printf( "\n-------------------------------\n" );
1329         }
1330         
1331         /* the index map must be at least 2x2 pixels */
1332         if( w < 2 || h < 2 )
1333         {
1334                 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1335                 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1336                 free( pixels );
1337                 return;
1338         }
1339
1340         /* create a new index map */
1341         im = safe_malloc( sizeof( *im ) );
1342         memset( im, 0, sizeof( *im ) );
1343         
1344         /* set it up */
1345         im->w = w;
1346         im->h = h;
1347         im->numLayers = numLayers;
1348         strcpy( im->name, indexMapFilename );
1349         strcpy( im->shader, shader );
1350         im->pixels = pixels;
1351         
1352         /* get height offsets */
1353         value = ValueForKey( mapEnt, "_offsets" );
1354         if( value[ 0 ] == '\0' )
1355                 value = ValueForKey( e, "offsets" );
1356         if( value[ 0 ] != '\0' )
1357         {
1358                 /* value is a space-seperated set of numbers */
1359                 strcpy( offset, value );
1360                 search = offset;
1361                 
1362                 /* get each value */
1363                 for( i = 0; i < 256 && *search != '\0'; i++ )
1364                 {
1365                         space = strstr( search, " " );
1366                         if( space != NULL )
1367                                 *space = '\0';
1368                         im->offsets[ i ] = atof( search );
1369                         if( space == NULL )
1370                                 break;
1371                         search = space + 1;
1372                 }
1373         }
1374         
1375         /* store the index map in every brush/patch in the entity */
1376         for( b = e->brushes; b != NULL; b = b->next )
1377                 b->im = im;
1378         for( p = e->patches; p != NULL; p = p->next )
1379                 p->im = im;
1380 }
1381
1382
1383
1384
1385
1386
1387
1388 /*
1389 ParseMapEntity()
1390 parses a single entity out of a map file
1391 */
1392
1393 static qboolean ParseMapEntity( qboolean onlyLights )
1394 {
1395         epair_t                 *ep;
1396         const char              *classname, *value;
1397         float                   lightmapScale;
1398         char                    shader[ MAX_QPATH ];
1399         shaderInfo_t    *celShader = NULL;
1400         brush_t                 *brush;
1401         parseMesh_t             *patch;
1402         qboolean                funcGroup;
1403         int                             castShadows, recvShadows;
1404         
1405         
1406         /* eof check */
1407         if( !GetToken( qtrue ) )
1408                 return qfalse;
1409         
1410         /* conformance check */
1411         if( strcmp( token, "{" ) )
1412         {
1413                 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1414                         "Continuing to process map, but resulting BSP may be invalid.\n",
1415                         token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1416                 return qfalse;
1417         }
1418         
1419         /* range check */
1420         if( numEntities >= MAX_MAP_ENTITIES )
1421                 Error( "numEntities == MAX_MAP_ENTITIES" );
1422         
1423         /* setup */
1424         entitySourceBrushes = 0;
1425         mapEnt = &entities[ numEntities ];
1426         numEntities++;
1427         memset( mapEnt, 0, sizeof( *mapEnt ) );
1428         
1429         /* ydnar: true entity numbering */
1430         mapEnt->mapEntityNum = numMapEntities;
1431         numMapEntities++;
1432         
1433         /* loop */
1434         while( 1 )
1435         {
1436                 /* get initial token */
1437                 if( !GetToken( qtrue ) )
1438                 {
1439                         Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1440                                 "Continuing to process map, but resulting BSP may be invalid.\n" );
1441                         return qfalse;
1442                 }
1443                 
1444                 if( !strcmp( token, "}" ) )
1445                         break;
1446                 
1447                 if( !strcmp( token, "{" ) )
1448                 {
1449                         /* parse a brush or patch */
1450                         if( !GetToken( qtrue ) )
1451                                 break;
1452                         
1453                         /* check */
1454                         if( !strcmp( token, "patchDef2" ) )
1455                         {
1456                                 numMapPatches++;
1457                                 ParsePatch( onlyLights );
1458                         }
1459                         else if( !strcmp( token, "terrainDef" ) )
1460                         {
1461                                 //% ParseTerrain();
1462                                 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1463                         }
1464                         else if( !strcmp( token, "brushDef" ) )
1465                         {
1466                                 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1467                                         Error( "Old brush format not allowed in new brush format map" );
1468                                 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1469                                 
1470                                 /* parse brush primitive */
1471                                 ParseBrush( onlyLights );
1472                         }
1473                         else
1474                         {
1475                                 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1476                                         Error( "New brush format not allowed in old brush format map" );
1477                                 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1478                                 
1479                                 /* parse old brush format */
1480                                 UnGetToken();
1481                                 ParseBrush( onlyLights );
1482                         }
1483                         entitySourceBrushes++;
1484                 }
1485                 else
1486                 {
1487                         /* parse a key / value pair */
1488                         ep = ParseEPair();
1489                         
1490                         /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1491                         if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1492                         {
1493                                 ep->next = mapEnt->epairs;
1494                                 mapEnt->epairs = ep;
1495                         }
1496                 }
1497         }
1498         
1499         /* ydnar: get classname */
1500         classname = ValueForKey( mapEnt, "classname" );
1501         
1502         /* ydnar: only lights? */
1503         if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1504         {
1505                 numEntities--;
1506                 return qtrue;
1507         }
1508         
1509         /* ydnar: determine if this is a func_group */
1510         if( !Q_stricmp( "func_group", classname ) )
1511                 funcGroup = qtrue;
1512         else
1513                 funcGroup = qfalse;
1514         
1515         /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1516         if( funcGroup || mapEnt->mapEntityNum == 0 )
1517         {
1518                 //%     Sys_Printf( "World:  %d\n", mapEnt->mapEntityNum );
1519                 castShadows = WORLDSPAWN_CAST_SHADOWS;
1520                 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1521         }
1522         
1523         /* other entities don't cast any shadows, but recv worldspawn shadows */
1524         else
1525         {
1526                 //%     Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1527                 castShadows = ENTITY_CAST_SHADOWS;
1528                 recvShadows = ENTITY_RECV_SHADOWS;
1529         }
1530         
1531         /* get explicit shadow flags */
1532         GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1533         
1534         /* ydnar: get lightmap scaling value for this entity */
1535         if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1536                 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) )
1537         {
1538                 /* get lightmap scale from entity */
1539                 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1540                 if( lightmapScale <= 0.0f )
1541                         lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1542                 if( lightmapScale > 0.0f )
1543                         Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1544         }
1545         else
1546                 lightmapScale = 0.0f;
1547         
1548         /* ydnar: get cel shader :) for this entity */
1549         value = ValueForKey( mapEnt, "_celshader" );
1550         if( value[ 0 ] == '\0' )        
1551                 value = ValueForKey( &entities[ 0 ], "_celshader" );
1552         if( value[ 0 ] != '\0' )
1553         {
1554                 sprintf( shader, "textures/%s", value );
1555                 celShader = ShaderInfoForShader( shader );
1556                 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1557         }
1558         else
1559                 celShader = NULL;
1560         
1561         /* attach stuff to everything in the entity */
1562         for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1563         {
1564                 brush->entityNum = mapEnt->mapEntityNum;
1565                 brush->castShadows = castShadows;
1566                 brush->recvShadows = recvShadows;
1567                 brush->lightmapScale = lightmapScale;
1568                 brush->celShader = celShader;
1569         }
1570         
1571         for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1572         {
1573                 patch->entityNum = mapEnt->mapEntityNum;
1574                 patch->castShadows = castShadows;
1575                 patch->recvShadows = recvShadows;
1576                 patch->lightmapScale = lightmapScale;
1577                 patch->celShader = celShader;
1578         }
1579         
1580         /* ydnar: gs mods: set entity bounds */
1581         SetEntityBounds( mapEnt );
1582         
1583         /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1584         LoadEntityIndexMap( mapEnt );
1585         
1586         /* get entity origin and adjust brushes */
1587         GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1588         if( mapEnt->origin[ 0 ] || mapEnt->origin[ 1 ] || mapEnt->origin[ 2 ] )
1589                 AdjustBrushesForOrigin( mapEnt );
1590
1591         /* group_info entities are just for editor grouping (fixme: leak!) */
1592         if( !Q_stricmp( "group_info", classname ) )
1593         {
1594                 numEntities--;
1595                 return qtrue;
1596         }
1597         
1598         /* group entities are just for editor convenience, toss all brushes into worldspawn */
1599         if( funcGroup )
1600         {
1601                 MoveBrushesToWorld( mapEnt );
1602                 numEntities--;
1603                 return qtrue;
1604         }
1605         
1606         /* done */
1607         return qtrue;
1608 }
1609
1610
1611
1612 /*
1613 LoadMapFile()
1614 loads a map file into a list of entities
1615 */
1616
1617 void LoadMapFile( char *filename, qboolean onlyLights )
1618 {               
1619         FILE            *file;
1620         brush_t         *b;
1621         int                     oldNumEntities, numMapBrushes;
1622         
1623         
1624         /* note it */
1625         Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1626         Sys_Printf( "Loading %s\n", filename );
1627         
1628         /* hack */
1629         file = SafeOpenRead( filename );
1630         fclose( file );
1631         
1632         /* load the map file */
1633         LoadScriptFile( filename, -1 );
1634         
1635         /* setup */
1636         if( onlyLights )
1637                 oldNumEntities = numEntities;
1638         else
1639                 numEntities = 0;
1640         
1641         /* initial setup */
1642         numMapDrawSurfs = 0;
1643         c_detail = 0;
1644         g_bBrushPrimit = BPRIMIT_UNDEFINED;
1645         
1646         /* allocate a very large temporary brush for building the brushes as they are loaded */
1647         buildBrush = AllocBrush( MAX_BUILD_SIDES );
1648         
1649         /* parse the map file */
1650         while( ParseMapEntity( onlyLights ) );
1651         
1652         /* light loading */
1653         if( onlyLights )
1654         {
1655                 /* emit some statistics */
1656                 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1657         }
1658         else
1659         {
1660                 /* set map bounds */
1661                 ClearBounds( mapMins, mapMaxs );
1662                 for( b = entities[ 0 ].brushes; b; b = b->next )
1663                 {
1664                         AddPointToBounds( b->mins, mapMins, mapMaxs );
1665                         AddPointToBounds( b->maxs, mapMins, mapMaxs );
1666                 }
1667                 
1668                 /* get brush counts */
1669                 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1670                 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1671                         Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1672                 
1673                 /* emit some statistics */
1674                 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1675                 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1676                 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1677                 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1678                 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1679                 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1680                 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1681                 Sys_Printf( "%9d areaportals\n", c_areaportals);
1682                 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1683                         mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1684                         mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1685                 
1686                 /* write bogus map */
1687                 if( fakemap )
1688                         WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );
1689         }
1690 }