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