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