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 Q3MAP2_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 Q3MAP2_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 Q3MAP2_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 Q3MAP2_EXPERIMENTAL_HIGH_PRECISION_MATH_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 )
1283 /* walk brush list */
1284 for( b = ent->brushes; b != NULL; b = b->next )
1286 /* offset brush planes */
1287 for( i = 0; i < b->numsides; i++)
1289 /* get brush side */
1292 /* offset side plane */
1293 newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin );
1295 /* find a new plane */
1296 s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1299 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1300 CreateBrushWindings( b );
1303 /* walk patch list */
1304 for( p = ent->patches; p != NULL; p = p->next )
1306 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1307 VectorSubtract( p->mesh.verts[ i ].xyz, ent->origin, p->mesh.verts[ i ].xyz );
1314 SetEntityBounds() - ydnar
1315 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1318 void SetEntityBounds( entity_t *e )
1329 /* walk the entity's brushes/patches and determine bounds */
1330 ClearBounds( mins, maxs );
1331 for( b = e->brushes; b; b = b->next )
1333 AddPointToBounds( b->mins, mins, maxs );
1334 AddPointToBounds( b->maxs, mins, maxs );
1336 for( p = e->patches; p; p = p->next )
1338 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1339 AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1342 /* try to find explicit min/max key */
1343 value = ValueForKey( e, "min" );
1344 if( value[ 0 ] != '\0' )
1345 GetVectorForKey( e, "min", mins );
1346 value = ValueForKey( e, "max" );
1347 if( value[ 0 ] != '\0' )
1348 GetVectorForKey( e, "max", maxs );
1350 /* store the bounds */
1351 for( b = e->brushes; b; b = b->next )
1353 VectorCopy( mins, b->eMins );
1354 VectorCopy( maxs, b->eMaxs );
1356 for( p = e->patches; p; p = p->next )
1358 VectorCopy( mins, p->eMins );
1359 VectorCopy( maxs, p->eMaxs );
1366 LoadEntityIndexMap() - ydnar
1367 based on LoadAlphaMap() from terrain.c, a little more generic
1370 void LoadEntityIndexMap( entity_t *e )
1372 int i, size, numLayers, w, h;
1373 const char *value, *indexMapFilename, *shader;
1374 char ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1376 unsigned int *pixels32;
1382 /* this only works with bmodel ents */
1383 if( e->brushes == NULL && e->patches == NULL )
1386 /* determine if there is an index map (support legacy "alphamap" key as well) */
1387 value = ValueForKey( e, "_indexmap" );
1388 if( value[ 0 ] == '\0' )
1389 value = ValueForKey( e, "alphamap" );
1390 if( value[ 0 ] == '\0' )
1392 indexMapFilename = value;
1394 /* get number of layers (support legacy "layers" key as well) */
1395 value = ValueForKey( e, "_layers" );
1396 if( value[ 0 ] == '\0' )
1397 value = ValueForKey( e, "layers" );
1398 if( value[ 0 ] == '\0' )
1400 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1401 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1404 numLayers = atoi( value );
1407 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1408 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1412 /* get base shader name (support legacy "shader" key as well) */
1413 value = ValueForKey( mapEnt, "_shader" );
1414 if( value[ 0 ] == '\0' )
1415 value = ValueForKey( e, "shader" );
1416 if( value[ 0 ] == '\0' )
1418 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1419 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1425 Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n", mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1427 /* get index map file extension */
1428 ExtractFileExtension( indexMapFilename, ext );
1430 /* handle tga image */
1431 if( !Q_stricmp( ext, "tga" ) )
1434 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1436 /* convert to bytes */
1438 pixels = safe_malloc( size );
1439 for( i = 0; i < size; i++ )
1441 pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1442 if( pixels[ i ] >= numLayers )
1443 pixels[ i ] = numLayers - 1;
1446 /* free the 32 bit image */
1452 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1455 //% Sys_Printf( "-------------------------------" );
1457 /* fix up out-of-range values */
1459 for( i = 0; i < size; i++ )
1461 if( pixels[ i ] >= numLayers )
1462 pixels[ i ] = numLayers - 1;
1465 //% if( (i % w) == 0 )
1466 //% Sys_Printf( "\n" );
1467 //% Sys_Printf( "%c", pixels[ i ] + '0' );
1471 //% Sys_Printf( "\n-------------------------------\n" );
1474 /* the index map must be at least 2x2 pixels */
1475 if( w < 2 || h < 2 )
1477 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1478 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1483 /* create a new index map */
1484 im = safe_malloc( sizeof( *im ) );
1485 memset( im, 0, sizeof( *im ) );
1490 im->numLayers = numLayers;
1491 strcpy( im->name, indexMapFilename );
1492 strcpy( im->shader, shader );
1493 im->pixels = pixels;
1495 /* get height offsets */
1496 value = ValueForKey( mapEnt, "_offsets" );
1497 if( value[ 0 ] == '\0' )
1498 value = ValueForKey( e, "offsets" );
1499 if( value[ 0 ] != '\0' )
1501 /* value is a space-seperated set of numbers */
1502 strcpy( offset, value );
1505 /* get each value */
1506 for( i = 0; i < 256 && *search != '\0'; i++ )
1508 space = strstr( search, " " );
1511 im->offsets[ i ] = atof( search );
1518 /* store the index map in every brush/patch in the entity */
1519 for( b = e->brushes; b != NULL; b = b->next )
1521 for( p = e->patches; p != NULL; p = p->next )
1533 parses a single entity out of a map file
1536 static qboolean ParseMapEntity( qboolean onlyLights )
1539 const char *classname, *value;
1540 float lightmapScale;
1541 char shader[ MAX_QPATH ];
1542 shaderInfo_t *celShader = NULL;
1546 int castShadows, recvShadows;
1550 if( !GetToken( qtrue ) )
1553 /* conformance check */
1554 if( strcmp( token, "{" ) )
1556 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1557 "Continuing to process map, but resulting BSP may be invalid.\n",
1558 token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1563 if( numEntities >= MAX_MAP_ENTITIES )
1564 Error( "numEntities == MAX_MAP_ENTITIES" );
1567 entitySourceBrushes = 0;
1568 mapEnt = &entities[ numEntities ];
1570 memset( mapEnt, 0, sizeof( *mapEnt ) );
1572 /* ydnar: true entity numbering */
1573 mapEnt->mapEntityNum = numMapEntities;
1579 /* get initial token */
1580 if( !GetToken( qtrue ) )
1582 Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1583 "Continuing to process map, but resulting BSP may be invalid.\n" );
1587 if( !strcmp( token, "}" ) )
1590 if( !strcmp( token, "{" ) )
1592 /* parse a brush or patch */
1593 if( !GetToken( qtrue ) )
1597 if( !strcmp( token, "patchDef2" ) )
1600 ParsePatch( onlyLights );
1602 else if( !strcmp( token, "terrainDef" ) )
1605 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1607 else if( !strcmp( token, "brushDef" ) )
1609 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1610 Error( "Old brush format not allowed in new brush format map" );
1611 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1613 /* parse brush primitive */
1614 ParseBrush( onlyLights );
1618 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1619 Error( "New brush format not allowed in old brush format map" );
1620 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1622 /* parse old brush format */
1624 ParseBrush( onlyLights );
1626 entitySourceBrushes++;
1630 /* parse a key / value pair */
1633 /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1634 if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1636 ep->next = mapEnt->epairs;
1637 mapEnt->epairs = ep;
1642 /* ydnar: get classname */
1643 classname = ValueForKey( mapEnt, "classname" );
1645 /* ydnar: only lights? */
1646 if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1652 /* ydnar: determine if this is a func_group */
1653 if( !Q_stricmp( "func_group", classname ) )
1658 /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1659 if( funcGroup || mapEnt->mapEntityNum == 0 )
1661 //% Sys_Printf( "World: %d\n", mapEnt->mapEntityNum );
1662 castShadows = WORLDSPAWN_CAST_SHADOWS;
1663 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1666 /* other entities don't cast any shadows, but recv worldspawn shadows */
1669 //% Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1670 castShadows = ENTITY_CAST_SHADOWS;
1671 recvShadows = ENTITY_RECV_SHADOWS;
1674 /* get explicit shadow flags */
1675 GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1677 /* ydnar: get lightmap scaling value for this entity */
1678 if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1679 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) )
1681 /* get lightmap scale from entity */
1682 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1683 if( lightmapScale <= 0.0f )
1684 lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1685 if( lightmapScale > 0.0f )
1686 Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1689 lightmapScale = 0.0f;
1691 /* ydnar: get cel shader :) for this entity */
1692 value = ValueForKey( mapEnt, "_celshader" );
1693 if( value[ 0 ] == '\0' )
1694 value = ValueForKey( &entities[ 0 ], "_celshader" );
1695 if( value[ 0 ] != '\0' )
1697 sprintf( shader, "textures/%s", value );
1698 celShader = ShaderInfoForShader( shader );
1699 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1704 /* attach stuff to everything in the entity */
1705 for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1707 brush->entityNum = mapEnt->mapEntityNum;
1708 brush->castShadows = castShadows;
1709 brush->recvShadows = recvShadows;
1710 brush->lightmapScale = lightmapScale;
1711 brush->celShader = celShader;
1714 for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1716 patch->entityNum = mapEnt->mapEntityNum;
1717 patch->castShadows = castShadows;
1718 patch->recvShadows = recvShadows;
1719 patch->lightmapScale = lightmapScale;
1720 patch->celShader = celShader;
1723 /* ydnar: gs mods: set entity bounds */
1724 SetEntityBounds( mapEnt );
1726 /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1727 LoadEntityIndexMap( mapEnt );
1729 /* get entity origin and adjust brushes */
1730 GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1731 if( mapEnt->origin[ 0 ] || mapEnt->origin[ 1 ] || mapEnt->origin[ 2 ] )
1732 AdjustBrushesForOrigin( mapEnt );
1734 /* group_info entities are just for editor grouping (fixme: leak!) */
1735 if( !Q_stricmp( "group_info", classname ) )
1741 /* group entities are just for editor convenience, toss all brushes into worldspawn */
1744 MoveBrushesToWorld( mapEnt );
1757 loads a map file into a list of entities
1760 void LoadMapFile( char *filename, qboolean onlyLights )
1764 int oldNumEntities, numMapBrushes;
1768 Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1769 Sys_Printf( "Loading %s\n", filename );
1772 file = SafeOpenRead( filename );
1775 /* load the map file */
1776 LoadScriptFile( filename, -1 );
1780 oldNumEntities = numEntities;
1785 numMapDrawSurfs = 0;
1787 g_bBrushPrimit = BPRIMIT_UNDEFINED;
1789 /* allocate a very large temporary brush for building the brushes as they are loaded */
1790 buildBrush = AllocBrush( MAX_BUILD_SIDES );
1792 /* parse the map file */
1793 while( ParseMapEntity( onlyLights ) );
1798 /* emit some statistics */
1799 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1803 /* set map bounds */
1804 ClearBounds( mapMins, mapMaxs );
1805 for( b = entities[ 0 ].brushes; b; b = b->next )
1807 AddPointToBounds( b->mins, mapMins, mapMaxs );
1808 AddPointToBounds( b->maxs, mapMins, mapMaxs );
1811 /* get brush counts */
1812 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1813 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1814 Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1816 /* emit some statistics */
1817 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1818 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1819 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1820 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1821 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1822 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1823 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1824 Sys_Printf( "%9d areaportals\n", c_areaportals);
1825 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1826 mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1827 mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1829 /* write bogus map */
1831 WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );