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