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