1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
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.
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.
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
22 ----------------------------------------------------------------------------------
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."
27 ------------------------------------------------------------------------------- */
41 /* FIXME: remove these vars */
43 /* undefine to make plane finding use linear sort (note: really slow) */
45 #define PLANE_HASHES 8192
47 plane_t *planehash[ PLANE_HASHES ];
59 ydnar: replaced with variable epsilon for djbob
62 qboolean PlaneEqual( plane_t *p, vec3_t normal, vec_t dist )
67 /* get local copies */
72 // We check equality of each component since we're using '<', not '<='
73 // (the epsilons may be zero). We want to use '<' intead of '<=' to be
74 // consistent with the true meaning of "epsilon", and also because other
75 // parts of the code uses this inequality.
76 if ((p->dist == dist || fabs(p->dist - dist) < de) &&
77 (p->normal[0] == normal[0] || fabs(p->normal[0] - normal[0]) < ne) &&
78 (p->normal[1] == normal[1] || fabs(p->normal[1] - normal[1]) < ne) &&
79 (p->normal[2] == normal[2] || fabs(p->normal[2] - normal[2]) < ne))
92 void AddPlaneToHash( plane_t *p )
97 hash = (PLANE_HASHES - 1) & (int) fabs( p->dist );
99 p->hash_chain = planehash[hash];
108 int CreateNewFloatPlane (vec3_t normal, vec_t dist)
112 if (VectorLength(normal) < 0.5)
114 Sys_Printf( "FloatPlane: bad normal\n");
118 // create a new plane
119 if (nummapplanes+2 > MAX_MAP_PLANES)
120 Error ("MAX_MAP_PLANES");
122 p = &mapplanes[nummapplanes];
123 VectorCopy (normal, p->normal);
125 p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
127 VectorSubtract (vec3_origin, normal, (p+1)->normal);
132 // allways put axial planes facing positive first
135 if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
143 AddPlaneToHash (p+1);
144 return nummapplanes - 1;
149 AddPlaneToHash (p+1);
150 return nummapplanes - 2;
157 Snaps a near-axial normal vector.
158 Returns qtrue if and only if the normal was adjusted.
161 qboolean SnapNormal( vec3_t normal )
163 #if EXPERIMENTAL_SNAP_NORMAL_FIX
165 qboolean adjusted = qfalse;
167 // A change from the original SnapNormal() is that we snap each
168 // component that's close to 0. So for example if a normal is
169 // (0.707, 0.707, 0.0000001), it will get snapped to lie perfectly in the
170 // XY plane (its Z component will be set to 0 and its length will be
171 // normalized). The original SnapNormal() didn't snap such vectors - it
172 // only snapped vectors that were near a perfect axis.
174 for (i = 0; i < 3; i++)
176 if (normal[i] != 0.0 && -normalEpsilon < normal[i] && normal[i] < normalEpsilon)
185 VectorNormalize(normal, normal);
192 // I would suggest that you uncomment the following code and look at the
196 Sys_Printf("normalEpsilon is %f\n", normalEpsilon);
201 normal[2] = i * 0.000001;
202 VectorNormalize(normal, normal);
203 if (1.0 - normal[0] >= normalEpsilon) {
204 Sys_Printf("(%f %f %f)\n", normal[0], normal[1], normal[2]);
205 Error("SnapNormal: test completed");
210 // When the normalEpsilon is 0.00001, the loop will break out when normal is
211 // (0.999990 0.000000 0.004469). In other words, this is the vector closest
212 // to axial that will NOT be snapped. Anything closer will be snaped. Now,
213 // 0.004469 is close to 1/225. The length of a circular quarter-arc of radius
214 // 1 is PI/2, or about 1.57. And 0.004469/1.57 is about 0.0028, or about
215 // 1/350. Expressed a different way, 1/350 is also about 0.26/90.
216 // This means is that a normal with an angle that is within 1/4 of a degree
217 // from axial will be "snapped". My belief is that the person who wrote the
218 // code below did not intend it this way. I think the person intended that
219 // the epsilon be measured against the vector components close to 0, not 1.0.
220 // I think the logic should be: if 2 of the normal components are within
221 // epsilon of 0, then the vector can be snapped to be perfectly axial.
222 // We may consider adjusting the epsilon to a larger value when we make this
225 for( i = 0; i < 3; i++ )
227 if( fabs( normal[ i ] - 1 ) < normalEpsilon )
229 VectorClear( normal );
233 if( fabs( normal[ i ] - -1 ) < normalEpsilon )
235 VectorClear( normal );
248 snaps a plane to normal/distance epsilons
251 void SnapPlane( vec3_t normal, vec_t *dist )
253 // SnapPlane disabled by LordHavoc because it often messes up collision
254 // brushes made from triangles of embedded models, and it has little effect
255 // on anything else (axial planes are usually derived from snapped points)
257 SnapPlane reenabled by namespace because of multiple reports of
258 q3map2-crashes which were triggered by this patch.
260 SnapNormal( normal );
262 // TODO: Rambetter has some serious comments here as well. First off,
263 // in the case where a normal is non-axial, there is nothing special
264 // about integer distances. I would think that snapping a distance might
265 // make sense for axial normals, but I'm not so sure about snapping
266 // non-axial normals. A shift by 0.01 in a plane, multiplied by a clipping
267 // against another plane that is 5 degrees off, and we introduce 0.1 error
268 // easily. A 0.1 error in a vertex is where problems start to happen, such
269 // as disappearing triangles.
271 // Second, assuming we have snapped the normal above, let's say that the
272 // plane we just snapped was defined for some points that are actually
273 // quite far away from normal * dist. Well, snapping the normal in this
274 // case means that we've just moved those points by potentially many units!
275 // Therefore, if we are going to snap the normal, we need to know the
276 // points we're snapping for so that the plane snaps with those points in
277 // mind (points remain close to the plane).
279 // I would like to know exactly which problems SnapPlane() is trying to
280 // solve so that we can better engineer it (I'm not saying that SnapPlane()
281 // should be removed altogether). Fix all this snapping code at some point!
283 if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
284 *dist = Q_rint( *dist );
289 snaps a plane to normal/distance epsilons, improved code
291 void SnapPlaneImproved(vec3_t normal, vec_t *dist, int numPoints, const vec3_t *points)
295 vec_t distNearestInt;
297 if (SnapNormal(normal))
301 // Adjust the dist so that the provided points don't drift away.
303 for (i = 0; i < numPoints; i++)
305 VectorAdd(center, points[i], center);
307 for (i = 0; i < 3; i++) { center[i] = center[i] / numPoints; }
308 *dist = DotProduct(normal, center);
312 if (VectorIsOnAxis(normal))
314 // Only snap distance if the normal is an axis. Otherwise there
315 // is nothing "natural" about snapping the distance to an integer.
316 distNearestInt = Q_rint(*dist);
317 if (-distanceEpsilon < *dist - distNearestInt && *dist - distNearestInt < distanceEpsilon)
319 *dist = distNearestInt;
327 ydnar: changed to allow a number of test points to be supplied that
328 must be within an epsilon distance of the plane
331 int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
341 #if EXPERIMENTAL_SNAP_PLANE_FIX
342 SnapPlaneImproved(normal, &dist, numPoints, (const vec3_t *) points);
344 SnapPlane( normal, &dist );
347 hash = (PLANE_HASHES - 1) & (int) fabs( dist );
349 /* search the border bins as well */
350 for( i = -1; i <= 1; i++ )
352 h = (hash + i) & (PLANE_HASHES - 1);
353 for( p = planehash[ h ]; p != NULL; p = p->hash_chain )
355 /* do standard plane compare */
356 if( !PlaneEqual( p, normal, dist ) )
359 /* ydnar: uncomment the following line for old-style plane finding */
360 //% return p - mapplanes;
362 /* ydnar: test supplied points against this plane */
363 for( j = 0; j < numPoints; j++ )
365 // NOTE: When dist approaches 2^16, the resolution of 32 bit floating
366 // point number is greatly decreased. The distanceEpsilon cannot be
367 // very small when world coordinates extend to 2^16. Making the
368 // dot product here in 64 bit land will not really help the situation
369 // because the error will already be carried in dist.
370 d = DotProduct( points[ j ], normal ) - dist;
372 if (d != 0.0 && d >= distanceEpsilon)
373 break; // Point is too far from plane.
376 /* found a matching plane */
378 return p - mapplanes;
382 /* none found, so create a new one */
383 return CreateNewFloatPlane( normal, dist );
392 #if EXPERIMENTAL_SNAP_PLANE_FIX
393 SnapPlaneImproved(normal, &dist, numPoints, (const vec3_t *) points);
395 SnapPlane( normal, &dist );
397 for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
399 if( PlaneEqual( p, normal, dist ) )
401 // TODO: Note that the non-USE_HASHING code does not compute epsilons
402 // for the provided points. It should do that. I think this code
403 // is unmaintained because nobody sets USE_HASHING to off.
406 return CreateNewFloatPlane( normal, dist );
415 takes 3 points and finds the plane they lie in
418 int MapPlaneFromPoints( vec3_t *p )
420 #if EXPERIMENTAL_HIGH_PRECISION_MATH_Q3MAP2_FIXES
421 vec3_accu_t paccu[3];
422 vec3_accu_t t1, t2, normalAccu;
426 VectorCopyRegularToAccu(p[0], paccu[0]);
427 VectorCopyRegularToAccu(p[1], paccu[1]);
428 VectorCopyRegularToAccu(p[2], paccu[2]);
430 VectorSubtractAccu(paccu[0], paccu[1], t1);
431 VectorSubtractAccu(paccu[2], paccu[1], t2);
432 CrossProductAccu(t1, t2, normalAccu);
433 VectorNormalizeAccu(normalAccu, normalAccu);
434 // TODO: A 32 bit float for the plane distance isn't enough resolution
435 // if the plane is 2^16 units away from the origin (the "epsilon" approaches
436 // 0.01 in that case).
437 dist = (vec_t) DotProductAccu(paccu[0], normalAccu);
438 VectorCopyAccuToRegular(normalAccu, normal);
440 return FindFloatPlane(normal, dist, 3, p);
442 vec3_t t1, t2, normal;
446 /* calc plane normal */
447 VectorSubtract( p[ 0 ], p[ 1 ], t1 );
448 VectorSubtract( p[ 2 ], p[ 1 ], t2 );
449 CrossProduct( t1, t2, normal );
450 VectorNormalize( normal, normal );
452 /* calc plane distance */
453 dist = DotProduct( p[ 0 ], normal );
455 /* store the plane */
456 return FindFloatPlane( normal, dist, 3, p );
464 the content flags and compile flags on all sides of a brush should be the same
467 void SetBrushContents( brush_t *b )
469 int contentFlags, compileFlags;
475 /* get initial compile flags from first side */
477 contentFlags = s->contentFlags;
478 compileFlags = s->compileFlags;
479 b->contentShader = s->shaderInfo;
482 /* get the content/compile flags for every side in the brush */
483 for( i = 1; i < b->numsides; i++, s++ )
486 if( s->shaderInfo == NULL )
488 if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
492 /* ydnar: getting rid of this stupid warning */
494 //% Sys_FPrintf( SYS_VRB,"Entity %i, Brush %i: mixed face contentFlags\n", b->entitynum, b->brushnum );
496 /* check for detail & structural */
497 if( (compileFlags & C_DETAIL) && (compileFlags & C_STRUCTURAL) )
499 xml_Select( "Mixed detail and structural (defaulting to structural)", mapEnt->mapEntityNum, entitySourceBrushes, qfalse );
500 compileFlags &= ~C_DETAIL;
503 /* the fulldetail flag will cause detail brushes to be treated like normal brushes */
505 compileFlags &= ~C_DETAIL;
507 /* all translucent brushes that aren't specifically made structural will be detail */
508 if( (compileFlags & C_TRANSLUCENT) && !(compileFlags & C_STRUCTURAL) )
509 compileFlags |= C_DETAIL;
512 if( compileFlags & C_DETAIL )
524 if( compileFlags & C_TRANSLUCENT )
530 if( compileFlags & C_AREAPORTAL )
533 /* set brush flags */
534 b->contentFlags = contentFlags;
535 b->compileFlags = compileFlags;
542 adds any additional planes necessary to allow the brush being
543 built to be expanded against axial bounding boxes
544 ydnar 2003-01-20: added mrelusive fixes
547 void AddBrushBevels( void )
550 int i, j, k, l, order;
560 // add the axial planes
563 for ( axis = 0; axis < 3; axis++ ) {
564 for ( dir = -1; dir <= 1; dir += 2, order++ ) {
565 // see if the plane is allready present
566 for ( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
568 /* ydnar: testing disabling of mre code */
571 if ( mapplanes[s->planenum].normal[axis] >= 0.9999f ) {
576 if ( mapplanes[s->planenum].normal[axis] <= -0.9999f ) {
581 if( (dir > 0 && mapplanes[ s->planenum ].normal[ axis ] == 1.0f ) ||
582 (dir < 0 && mapplanes[ s->planenum ].normal[ axis ] == -1.0f) )
587 if ( i == buildBrush->numsides ) {
589 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
590 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
592 memset( s, 0, sizeof( *s ) );
593 buildBrush->numsides++;
594 VectorClear (normal);
599 /* ydnar: adding bevel plane snapping for fewer bsp planes */
601 dist = floor( buildBrush->maxs[ axis ] / bevelSnap ) * bevelSnap;
603 dist = buildBrush->maxs[ axis ];
607 /* ydnar: adding bevel plane snapping for fewer bsp planes */
609 dist = -ceil( buildBrush->mins[ axis ] / bevelSnap ) * bevelSnap;
611 dist = -buildBrush->mins[ axis ];
614 s->planenum = FindFloatPlane( normal, dist, 0, NULL );
615 s->contentFlags = buildBrush->sides[ 0 ].contentFlags;
620 // if the plane is not in it canonical order, swap it
622 sidetemp = buildBrush->sides[order];
623 buildBrush->sides[order] = buildBrush->sides[i];
624 buildBrush->sides[i] = sidetemp;
630 // add the edge bevels
632 if ( buildBrush->numsides == 6 ) {
633 return; // pure axial
636 // test the non-axial plane edges
637 for ( i = 6; i < buildBrush->numsides; i++ ) {
638 s = buildBrush->sides + i;
643 for ( j = 0; j < w->numpoints; j++) {
644 k = (j+1)%w->numpoints;
645 VectorSubtract( w->p[j], w->p[k], vec );
646 if ( VectorNormalize( vec, vec ) < 0.5f ) {
650 for ( k = 0; k < 3; k++ ) {
651 if ( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f) ) {
656 continue; // only test non-axial edges
660 //% Sys_Printf( "-------------\n" );
662 // try the six possible slanted axials from this edge
663 for ( axis = 0; axis < 3; axis++ ) {
664 for ( dir = -1; dir <= 1; dir += 2 ) {
668 CrossProduct( vec, vec2, normal );
669 if ( VectorNormalize( normal, normal ) < 0.5f ) {
672 dist = DotProduct( w->p[j], normal );
674 // if all the points on all the sides are
675 // behind this plane, it is a proper edge bevel
676 for ( k = 0; k < buildBrush->numsides; k++ ) {
678 // if this plane has allready been used, skip it
679 if ( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ) ) {
683 w2 = buildBrush->sides[k].winding;
688 for ( l = 0; l < w2->numpoints; l++ ) {
689 d = DotProduct( w2->p[l], normal ) - dist;
691 break; // point in front
697 // if some point was at the front
698 if ( l != w2->numpoints ) {
702 // if no points at the back then the winding is on the bevel plane
703 if ( minBack > -0.1f ) {
704 //% Sys_Printf( "On bevel plane\n" );
709 if ( k != buildBrush->numsides ) {
710 continue; // wasn't part of the outer hull
714 //% Sys_Printf( "n = %f %f %f\n", normal[ 0 ], normal[ 1 ], normal[ 2 ] );
717 if( buildBrush->numsides == MAX_BUILD_SIDES ) {
718 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
720 s2 = &buildBrush->sides[buildBrush->numsides];
721 buildBrush->numsides++;
722 memset( s2, 0, sizeof( *s2 ) );
724 s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[ j ] );
725 s2->contentFlags = buildBrush->sides[0].contentFlags;
738 produces a final brush based on the buildBrush->sides array
739 and links it to the current entity
742 brush_t *FinishBrush( void )
747 /* create windings for sides and bounds for brush */
748 if ( !CreateBrushWindings( buildBrush ) )
751 /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
752 after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
753 if( buildBrush->compileFlags & C_ORIGIN )
758 if( numEntities == 1 )
760 Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n",
761 mapEnt->mapEntityNum, entitySourceBrushes );
765 VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
766 VectorScale (origin, 0.5, origin);
768 sprintf( string, "%i %i %i", (int) origin[ 0 ], (int) origin[ 1 ], (int) origin[ 2 ] );
769 SetKeyValue( &entities[ numEntities - 1 ], "origin", string);
771 VectorCopy( origin, entities[ numEntities - 1 ].origin);
773 /* don't keep this brush */
777 /* determine if the brush is an area portal */
778 if( buildBrush->compileFlags & C_AREAPORTAL )
780 if( numEntities != 1 )
782 Sys_Printf ("Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
787 /* add bevel planes */
791 b = CopyBrush( buildBrush );
793 /* set map entity and brush numbering */
794 b->entityNum = mapEnt->mapEntityNum;
795 b->brushNum = entitySourceBrushes;
800 /* link opaque brushes to head of list, translucent brushes to end */
801 if( b->opaque || mapEnt->lastBrush == NULL )
803 b->next = mapEnt->brushes;
805 if( mapEnt->lastBrush == NULL )
806 mapEnt->lastBrush = b;
811 mapEnt->lastBrush->next = b;
812 mapEnt->lastBrush = b;
815 /* link colorMod volume brushes to the entity directly */
816 if( b->contentShader != NULL &&
817 b->contentShader->colorMod != NULL &&
818 b->contentShader->colorMod->type == CM_VOLUME )
820 b->nextColorModBrush = mapEnt->colorModBrushes;
821 mapEnt->colorModBrushes = b;
824 /* return to sender */
831 TextureAxisFromPlane()
832 determines best orthagonal axis to project a texture onto a wall
833 (must be identical in radiant!)
836 vec3_t baseaxis[18] =
838 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
839 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
840 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
841 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
842 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
843 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
846 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv )
855 for (i=0 ; i<6 ; i++)
857 dot = DotProduct (pln->normal, baseaxis[i*3]);
858 if( dot > best + 0.0001f ) /* ydnar: bug 637 fix, suggested by jmonroe */
865 VectorCopy (baseaxis[bestaxis*3+1], xv);
866 VectorCopy (baseaxis[bestaxis*3+2], yv);
873 creates world-to-texture mapping vecs for crappy quake plane arrangements
876 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] )
880 vec_t ang, sinv, cosv;
885 TextureAxisFromPlane(plane, vecs[0], vecs[1]);
894 { sinv = 0 ; cosv = 1; }
895 else if (rotate == 90)
896 { sinv = 1 ; cosv = 0; }
897 else if (rotate == 180)
898 { sinv = 0 ; cosv = -1; }
899 else if (rotate == 270)
900 { sinv = -1 ; cosv = 0; }
903 ang = rotate / 180 * Q_PI;
922 for (i=0 ; i<2 ; i++) {
923 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
924 nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
929 for (i=0 ; i<2 ; i++)
930 for (j=0 ; j<3 ; j++)
931 mappingVecs[i][j] = vecs[i][j] / scale[i];
933 mappingVecs[0][3] = shift[0];
934 mappingVecs[1][3] = shift[1];
941 parses the sides into buildBrush->sides[], nothing else.
942 no validation, back plane removal, etc.
945 added brush epairs parsing ( ignoring actually )
947 added exclusive brush primitive parsing
949 support for old brush format back in
950 NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
953 static void ParseRawBrush( qboolean onlyLights )
956 vec3_t planePoints[ 3 ];
962 char name[ MAX_QPATH ];
963 char shader[ MAX_QPATH ];
968 buildBrush->numsides = 0;
969 buildBrush->detail = qfalse;
972 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
978 if( !GetToken( qtrue ) )
980 if( !strcmp( token, "}" ) )
983 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
984 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
988 if( strcmp( token, "(" ) )
997 /* test side count */
998 if( buildBrush->numsides >= MAX_BUILD_SIDES )
999 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
1002 side = &buildBrush->sides[ buildBrush->numsides ];
1003 memset( side, 0, sizeof( *side ) );
1004 buildBrush->numsides++;
1006 /* read the three point plane definition */
1007 Parse1DMatrix( 3, planePoints[ 0 ] );
1008 Parse1DMatrix( 3, planePoints[ 1 ] );
1009 Parse1DMatrix( 3, planePoints[ 2 ] );
1011 /* bp: read the texture matrix */
1012 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1013 Parse2DMatrix( 2, 3, (float*) side->texMat );
1015 /* read shader name */
1017 strcpy( name, token );
1020 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1023 shift[ 0 ] = atof( token );
1025 shift[ 1 ] = atof( token );
1027 rotate = atof( token );
1029 scale[ 0 ] = atof( token );
1031 scale[ 1 ] = atof( token );
1034 /* set default flags and values */
1035 sprintf( shader, "textures/%s", name );
1037 si = &shaderInfo[ 0 ];
1039 si = ShaderInfoForShader( shader );
1040 side->shaderInfo = si;
1041 side->surfaceFlags = si->surfaceFlags;
1042 side->contentFlags = si->contentFlags;
1043 side->compileFlags = si->compileFlags;
1044 side->value = si->value;
1046 /* ydnar: gs mods: bias texture shift */
1047 if( si->globalTexture == qfalse )
1049 shift[ 0 ] -= (floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth);
1050 shift[ 1 ] -= (floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight);
1054 historically, there are 3 integer values at the end of a brushside line in a .map file.
1055 in quake 3, the only thing that mattered was the first of these three values, which
1056 was previously the content flags. and only then did a single bit matter, the detail
1057 bit. because every game has its own special flags for specifying detail, the
1058 traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
1059 by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
1060 is stored in compileFlags, as opposed to contentFlags, for multiple-game
1064 if( TokenAvailable() )
1066 /* get detail bit from map content flags */
1068 flags = atoi( token );
1069 if( flags & C_DETAIL )
1070 side->compileFlags |= C_DETAIL;
1074 //% td.flags = atoi( token );
1076 //% td.value = atoi( token );
1079 /* find the plane number */
1080 planenum = MapPlaneFromPoints( planePoints );
1081 side->planenum = planenum;
1083 /* bp: get the texture mapping for this texturedef / plane combination */
1084 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1085 QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
1089 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1100 RemoveDuplicateBrushPlanes
1101 returns false if the brush has a mirrored set of planes,
1102 meaning it encloses no volume.
1103 also removes planes without any normal
1106 qboolean RemoveDuplicateBrushPlanes( brush_t *b )
1113 for ( i = 1 ; i < b->numsides ; i++ ) {
1115 // check for a degenerate plane
1116 if ( sides[i].planenum == -1) {
1117 xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
1119 for ( k = i + 1 ; k < b->numsides ; k++ ) {
1120 sides[k-1] = sides[k];
1127 // check for duplication and mirroring
1128 for ( j = 0 ; j < i ; j++ ) {
1129 if ( sides[i].planenum == sides[j].planenum ) {
1130 xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
1131 // remove the second duplicate
1132 for ( k = i + 1 ; k < b->numsides ; k++ ) {
1133 sides[k-1] = sides[k];
1140 if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
1141 // mirror plane, brush is invalid
1142 xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
1154 parses a brush out of a map file and sets it up
1157 static void ParseBrush( qboolean onlyLights )
1162 /* parse the brush out of the map */
1163 ParseRawBrush( onlyLights );
1165 /* only go this far? */
1169 /* set some defaults */
1170 buildBrush->portalareas[ 0 ] = -1;
1171 buildBrush->portalareas[ 1 ] = -1;
1172 buildBrush->entityNum = numMapEntities - 1;
1173 buildBrush->brushNum = entitySourceBrushes;
1175 /* if there are mirrored planes, the entire brush is invalid */
1176 if( !RemoveDuplicateBrushPlanes( buildBrush ) )
1179 /* get the content for the entire brush */
1180 SetBrushContents( buildBrush );
1182 /* allow detail brushes to be removed */
1183 if( nodetail && (buildBrush->compileFlags & C_DETAIL) )
1185 //% FreeBrush( buildBrush );
1189 /* allow liquid brushes to be removed */
1190 if( nowater && (buildBrush->compileFlags & C_LIQUID ) )
1192 //% FreeBrush( buildBrush );
1196 /* ydnar: allow hint brushes to be removed */
1197 if( noHint && (buildBrush->compileFlags & C_HINT) )
1199 //% FreeBrush( buildBrush );
1203 /* finish the brush */
1210 MoveBrushesToWorld()
1211 takes all of the brushes from the current entity and
1212 adds them to the world's brush list
1213 (used by func_group)
1216 void MoveBrushesToWorld( entity_t *ent )
1223 for( b = ent->brushes; b != NULL; b = next )
1225 /* get next brush */
1228 /* link opaque brushes to head of list, translucent brushes to end */
1229 if( b->opaque || entities[ 0 ].lastBrush == NULL )
1231 b->next = entities[ 0 ].brushes;
1232 entities[ 0 ].brushes = b;
1233 if( entities[ 0 ].lastBrush == NULL )
1234 entities[ 0 ].lastBrush = b;
1239 entities[ 0 ].lastBrush->next = b;
1240 entities[ 0 ].lastBrush = b;
1243 ent->brushes = NULL;
1245 /* ydnar: move colormod brushes */
1246 if( ent->colorModBrushes != NULL )
1248 for( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush );
1250 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1251 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1253 ent->colorModBrushes = NULL;
1257 if( ent->patches != NULL )
1259 for( pm = ent->patches; pm->next != NULL; pm = pm->next );
1261 pm->next = entities[ 0 ].patches;
1262 entities[ 0 ].patches = ent->patches;
1264 ent->patches = NULL;
1271 AdjustBrushesForOrigin()
1274 void AdjustBrushesForOrigin( entity_t *ent )
1284 /* walk brush list */
1285 for( b = ent->brushes; b != NULL; b = b->next )
1287 /* offset brush planes */
1288 for( i = 0; i < b->numsides; i++)
1290 /* get brush side */
1293 /* offset side plane */
1294 newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin );
1296 /* find a new plane */
1297 s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1300 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1301 CreateBrushWindings( b );
1304 /* walk patch list */
1305 for( p = ent->patches; p != NULL; p = p->next )
1307 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1308 VectorSubtract( p->mesh.verts[ i ].xyz, ent->origin, p->mesh.verts[ i ].xyz );
1315 SetEntityBounds() - ydnar
1316 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1319 void SetEntityBounds( entity_t *e )
1330 /* walk the entity's brushes/patches and determine bounds */
1331 ClearBounds( mins, maxs );
1332 for( b = e->brushes; b; b = b->next )
1334 AddPointToBounds( b->mins, mins, maxs );
1335 AddPointToBounds( b->maxs, mins, maxs );
1337 for( p = e->patches; p; p = p->next )
1339 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1340 AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1343 /* try to find explicit min/max key */
1344 value = ValueForKey( e, "min" );
1345 if( value[ 0 ] != '\0' )
1346 GetVectorForKey( e, "min", mins );
1347 value = ValueForKey( e, "max" );
1348 if( value[ 0 ] != '\0' )
1349 GetVectorForKey( e, "max", maxs );
1351 /* store the bounds */
1352 for( b = e->brushes; b; b = b->next )
1354 VectorCopy( mins, b->eMins );
1355 VectorCopy( maxs, b->eMaxs );
1357 for( p = e->patches; p; p = p->next )
1359 VectorCopy( mins, p->eMins );
1360 VectorCopy( maxs, p->eMaxs );
1367 LoadEntityIndexMap() - ydnar
1368 based on LoadAlphaMap() from terrain.c, a little more generic
1371 void LoadEntityIndexMap( entity_t *e )
1373 int i, size, numLayers, w, h;
1374 const char *value, *indexMapFilename, *shader;
1375 char ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1377 unsigned int *pixels32;
1383 /* this only works with bmodel ents */
1384 if( e->brushes == NULL && e->patches == NULL )
1387 /* determine if there is an index map (support legacy "alphamap" key as well) */
1388 value = ValueForKey( e, "_indexmap" );
1389 if( value[ 0 ] == '\0' )
1390 value = ValueForKey( e, "alphamap" );
1391 if( value[ 0 ] == '\0' )
1393 indexMapFilename = value;
1395 /* get number of layers (support legacy "layers" key as well) */
1396 value = ValueForKey( e, "_layers" );
1397 if( value[ 0 ] == '\0' )
1398 value = ValueForKey( e, "layers" );
1399 if( value[ 0 ] == '\0' )
1401 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1402 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1405 numLayers = atoi( value );
1408 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1409 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1413 /* get base shader name (support legacy "shader" key as well) */
1414 value = ValueForKey( mapEnt, "_shader" );
1415 if( value[ 0 ] == '\0' )
1416 value = ValueForKey( e, "shader" );
1417 if( value[ 0 ] == '\0' )
1419 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1420 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1426 Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n", mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1428 /* get index map file extension */
1429 ExtractFileExtension( indexMapFilename, ext );
1431 /* handle tga image */
1432 if( !Q_stricmp( ext, "tga" ) )
1435 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1437 /* convert to bytes */
1439 pixels = safe_malloc( size );
1440 for( i = 0; i < size; i++ )
1442 pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1443 if( pixels[ i ] >= numLayers )
1444 pixels[ i ] = numLayers - 1;
1447 /* free the 32 bit image */
1453 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1456 //% Sys_Printf( "-------------------------------" );
1458 /* fix up out-of-range values */
1460 for( i = 0; i < size; i++ )
1462 if( pixels[ i ] >= numLayers )
1463 pixels[ i ] = numLayers - 1;
1466 //% if( (i % w) == 0 )
1467 //% Sys_Printf( "\n" );
1468 //% Sys_Printf( "%c", pixels[ i ] + '0' );
1472 //% Sys_Printf( "\n-------------------------------\n" );
1475 /* the index map must be at least 2x2 pixels */
1476 if( w < 2 || h < 2 )
1478 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1479 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1484 /* create a new index map */
1485 im = safe_malloc( sizeof( *im ) );
1486 memset( im, 0, sizeof( *im ) );
1491 im->numLayers = numLayers;
1492 strcpy( im->name, indexMapFilename );
1493 strcpy( im->shader, shader );
1494 im->pixels = pixels;
1496 /* get height offsets */
1497 value = ValueForKey( mapEnt, "_offsets" );
1498 if( value[ 0 ] == '\0' )
1499 value = ValueForKey( e, "offsets" );
1500 if( value[ 0 ] != '\0' )
1502 /* value is a space-seperated set of numbers */
1503 strcpy( offset, value );
1506 /* get each value */
1507 for( i = 0; i < 256 && *search != '\0'; i++ )
1509 space = strstr( search, " " );
1512 im->offsets[ i ] = atof( search );
1519 /* store the index map in every brush/patch in the entity */
1520 for( b = e->brushes; b != NULL; b = b->next )
1522 for( p = e->patches; p != NULL; p = p->next )
1534 parses a single entity out of a map file
1537 static qboolean ParseMapEntity( qboolean onlyLights )
1540 const char *classname, *value;
1541 float lightmapScale;
1542 char shader[ MAX_QPATH ];
1543 shaderInfo_t *celShader = NULL;
1547 int castShadows, recvShadows;
1551 if( !GetToken( qtrue ) )
1554 /* conformance check */
1555 if( strcmp( token, "{" ) )
1557 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1558 "Continuing to process map, but resulting BSP may be invalid.\n",
1559 token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1564 if( numEntities >= MAX_MAP_ENTITIES )
1565 Error( "numEntities == MAX_MAP_ENTITIES" );
1568 entitySourceBrushes = 0;
1569 mapEnt = &entities[ numEntities ];
1571 memset( mapEnt, 0, sizeof( *mapEnt ) );
1573 /* ydnar: true entity numbering */
1574 mapEnt->mapEntityNum = numMapEntities;
1580 /* get initial token */
1581 if( !GetToken( qtrue ) )
1583 Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1584 "Continuing to process map, but resulting BSP may be invalid.\n" );
1588 if( !strcmp( token, "}" ) )
1591 if( !strcmp( token, "{" ) )
1593 /* parse a brush or patch */
1594 if( !GetToken( qtrue ) )
1598 if( !strcmp( token, "patchDef2" ) )
1601 ParsePatch( onlyLights );
1603 else if( !strcmp( token, "terrainDef" ) )
1606 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1608 else if( !strcmp( token, "brushDef" ) )
1610 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1611 Error( "Old brush format not allowed in new brush format map" );
1612 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1614 /* parse brush primitive */
1615 ParseBrush( onlyLights );
1619 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1620 Error( "New brush format not allowed in old brush format map" );
1621 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1623 /* parse old brush format */
1625 ParseBrush( onlyLights );
1627 entitySourceBrushes++;
1631 /* parse a key / value pair */
1634 /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1635 if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1637 ep->next = mapEnt->epairs;
1638 mapEnt->epairs = ep;
1643 /* ydnar: get classname */
1644 classname = ValueForKey( mapEnt, "classname" );
1646 /* ydnar: only lights? */
1647 if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1653 /* ydnar: determine if this is a func_group */
1654 if( !Q_stricmp( "func_group", classname ) )
1659 /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1660 if( funcGroup || mapEnt->mapEntityNum == 0 )
1662 //% Sys_Printf( "World: %d\n", mapEnt->mapEntityNum );
1663 castShadows = WORLDSPAWN_CAST_SHADOWS;
1664 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1667 /* other entities don't cast any shadows, but recv worldspawn shadows */
1670 //% Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1671 castShadows = ENTITY_CAST_SHADOWS;
1672 recvShadows = ENTITY_RECV_SHADOWS;
1675 /* get explicit shadow flags */
1676 GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1678 /* ydnar: get lightmap scaling value for this entity */
1679 if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1680 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) )
1682 /* get lightmap scale from entity */
1683 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1684 if( lightmapScale <= 0.0f )
1685 lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1686 if( lightmapScale > 0.0f )
1687 Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1690 lightmapScale = 0.0f;
1692 /* ydnar: get cel shader :) for this entity */
1693 value = ValueForKey( mapEnt, "_celshader" );
1694 if( value[ 0 ] == '\0' )
1695 value = ValueForKey( &entities[ 0 ], "_celshader" );
1696 if( value[ 0 ] != '\0' )
1698 sprintf( shader, "textures/%s", value );
1699 celShader = ShaderInfoForShader( shader );
1700 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1705 /* attach stuff to everything in the entity */
1706 for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1708 brush->entityNum = mapEnt->mapEntityNum;
1709 brush->castShadows = castShadows;
1710 brush->recvShadows = recvShadows;
1711 brush->lightmapScale = lightmapScale;
1712 brush->celShader = celShader;
1715 for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1717 patch->entityNum = mapEnt->mapEntityNum;
1718 patch->castShadows = castShadows;
1719 patch->recvShadows = recvShadows;
1720 patch->lightmapScale = lightmapScale;
1721 patch->celShader = celShader;
1724 /* ydnar: gs mods: set entity bounds */
1725 SetEntityBounds( mapEnt );
1727 /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1728 LoadEntityIndexMap( mapEnt );
1730 /* get entity origin and adjust brushes */
1731 GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1732 if( mapEnt->origin[ 0 ] || mapEnt->origin[ 1 ] || mapEnt->origin[ 2 ] )
1733 AdjustBrushesForOrigin( mapEnt );
1735 /* group_info entities are just for editor grouping (fixme: leak!) */
1736 if( !Q_stricmp( "group_info", classname ) )
1742 /* group entities are just for editor convenience, toss all brushes into worldspawn */
1745 MoveBrushesToWorld( mapEnt );
1758 loads a map file into a list of entities
1761 void LoadMapFile( char *filename, qboolean onlyLights )
1765 int oldNumEntities, numMapBrushes;
1769 Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1770 Sys_Printf( "Loading %s\n", filename );
1773 file = SafeOpenRead( filename );
1776 /* load the map file */
1777 LoadScriptFile( filename, -1 );
1781 oldNumEntities = numEntities;
1786 numMapDrawSurfs = 0;
1788 g_bBrushPrimit = BPRIMIT_UNDEFINED;
1790 /* allocate a very large temporary brush for building the brushes as they are loaded */
1791 buildBrush = AllocBrush( MAX_BUILD_SIDES );
1793 /* parse the map file */
1794 while( ParseMapEntity( onlyLights ) );
1799 /* emit some statistics */
1800 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1804 /* set map bounds */
1805 ClearBounds( mapMins, mapMaxs );
1806 for( b = entities[ 0 ].brushes; b; b = b->next )
1808 AddPointToBounds( b->mins, mapMins, mapMaxs );
1809 AddPointToBounds( b->maxs, mapMins, mapMaxs );
1812 /* get brush counts */
1813 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1814 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1815 Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1817 /* emit some statistics */
1818 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1819 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1820 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1821 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1822 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1823 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1824 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1825 Sys_Printf( "%9d areaportals\n", c_areaportals);
1826 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1827 mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1828 mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1830 /* write bogus map */
1832 WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );