1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2006 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 #define NORMAL_EPSILON 0.00001
63 #define DIST_EPSILON 0.01
65 qboolean PlaneEqual( plane_t *p, vec3_t normal, vec_t dist )
70 /* get local copies */
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 )
91 void AddPlaneToHash( plane_t *p )
96 hash = (PLANE_HASHES - 1) & (int) fabs( p->dist );
98 p->hash_chain = planehash[hash];
107 int CreateNewFloatPlane (vec3_t normal, vec_t dist)
111 if (VectorLength(normal) < 0.5)
113 Sys_Printf( "FloatPlane: bad normal\n");
117 // create a new plane
118 if (nummapplanes+2 > MAX_MAP_PLANES)
119 Error ("MAX_MAP_PLANES");
121 p = &mapplanes[nummapplanes];
122 VectorCopy (normal, p->normal);
124 p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
126 VectorSubtract (vec3_origin, normal, (p+1)->normal);
131 // allways put axial planes facing positive first
134 if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
142 AddPlaneToHash (p+1);
143 return nummapplanes - 1;
148 AddPlaneToHash (p+1);
149 return nummapplanes - 2;
156 snaps a near-axial normal vector
159 void SnapNormal( vec3_t normal )
163 for( i = 0; i < 3; i++ )
165 if( fabs( normal[ i ] - 1 ) < normalEpsilon )
167 VectorClear( normal );
171 if( fabs( normal[ i ] - -1 ) < normalEpsilon )
173 VectorClear( normal );
184 snaps a plane to normal/distance epsilons
187 void SnapPlane( vec3_t normal, vec_t *dist )
189 SnapNormal( normal );
191 if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
192 *dist = Q_rint( *dist );
199 ydnar: changed to allow a number of test points to be supplied that
200 must be within an epsilon distance of the plane
203 int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
214 SnapPlane( normal, &dist );
215 hash = (PLANE_HASHES - 1) & (int) fabs( dist );
217 /* search the border bins as well */
218 for( i = -1; i <= 1; i++ )
220 h = (hash + i) & (PLANE_HASHES - 1);
221 for( p = planehash[ h ]; p != NULL; p = p->hash_chain )
223 /* do standard plane compare */
224 if( !PlaneEqual( p, normal, dist ) )
227 /* ydnar: uncomment the following line for old-style plane finding */
228 //% return p - mapplanes;
230 /* ydnar: test supplied points against this plane */
231 for( j = 0; j < numPoints; j++ )
233 d = DotProduct( points[ j ], normal ) - dist;
234 if( fabs( d ) > distanceEpsilon )
238 /* found a matching plane */
240 return p - mapplanes;
244 /* none found, so create a new one */
245 return CreateNewFloatPlane( normal, dist );
255 SnapPlane( normal, &dist );
256 for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
258 if( PlaneEqual( p, normal, dist ) )
262 return CreateNewFloatPlane( normal, dist );
271 takes 3 points and finds the plane they lie in
274 int MapPlaneFromPoints( vec3_t *p )
276 vec3_t t1, t2, normal;
280 /* calc plane normal */
281 VectorSubtract( p[ 0 ], p[ 1 ], t1 );
282 VectorSubtract( p[ 2 ], p[ 1 ], t2 );
283 CrossProduct( t1, t2, normal );
284 VectorNormalize( normal, normal );
286 /* calc plane distance */
287 dist = DotProduct( p[ 0 ], normal );
289 /* store the plane */
290 return FindFloatPlane( normal, dist, 3, p );
297 the content flags and compile flags on all sides of a brush should be the same
300 void SetBrushContents( brush_t *b )
302 int contentFlags, compileFlags;
308 /* get initial compile flags from first side */
310 contentFlags = s->contentFlags;
311 compileFlags = s->compileFlags;
312 b->contentShader = s->shaderInfo;
315 /* get the content/compile flags for every side in the brush */
316 for( i = 1; i < b->numsides; i++, s++ )
319 if( s->shaderInfo == NULL )
321 if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
325 /* ydnar: getting rid of this stupid warning */
327 //% Sys_FPrintf( SYS_VRB,"Entity %i, Brush %i: mixed face contentFlags\n", b->entitynum, b->brushnum );
329 /* check for detail & structural */
330 if( (compileFlags & C_DETAIL) && (compileFlags & C_STRUCTURAL) )
332 xml_Select( "Mixed detail and structural (defaulting to structural)", mapEnt->mapEntityNum, entitySourceBrushes, qfalse );
333 compileFlags &= ~C_DETAIL;
336 /* the fulldetail flag will cause detail brushes to be treated like normal brushes */
338 compileFlags &= ~C_DETAIL;
340 /* all translucent brushes that aren't specifically made structural will be detail */
341 if( (compileFlags & C_TRANSLUCENT) && !(compileFlags & C_STRUCTURAL) )
342 compileFlags |= C_DETAIL;
345 if( compileFlags & C_DETAIL )
357 if( compileFlags & C_TRANSLUCENT )
363 if( compileFlags & C_AREAPORTAL )
366 /* set brush flags */
367 b->contentFlags = contentFlags;
368 b->compileFlags = compileFlags;
375 adds any additional planes necessary to allow the brush being
376 built to be expanded against axial bounding boxes
377 ydnar 2003-01-20: added mrelusive fixes
380 void AddBrushBevels( void )
383 int i, j, k, l, order;
393 // add the axial planes
396 for ( axis = 0; axis < 3; axis++ ) {
397 for ( dir = -1; dir <= 1; dir += 2, order++ ) {
398 // see if the plane is allready present
399 for ( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
401 /* ydnar: testing disabling of mre code */
404 if ( mapplanes[s->planenum].normal[axis] >= 0.9999f ) {
409 if ( mapplanes[s->planenum].normal[axis] <= -0.9999f ) {
414 if( (dir > 0 && mapplanes[ s->planenum ].normal[ axis ] == 1.0f ) ||
415 (dir < 0 && mapplanes[ s->planenum ].normal[ axis ] == -1.0f) )
420 if ( i == buildBrush->numsides ) {
422 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
423 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
425 memset( s, 0, sizeof( *s ) );
426 buildBrush->numsides++;
427 VectorClear (normal);
432 /* ydnar: adding bevel plane snapping for fewer bsp planes */
434 dist = floor( buildBrush->maxs[ axis ] / bevelSnap ) * bevelSnap;
436 dist = buildBrush->maxs[ axis ];
440 /* ydnar: adding bevel plane snapping for fewer bsp planes */
442 dist = -ceil( buildBrush->mins[ axis ] / bevelSnap ) * bevelSnap;
444 dist = -buildBrush->mins[ axis ];
447 s->planenum = FindFloatPlane( normal, dist, 0, NULL );
448 s->contentFlags = buildBrush->sides[ 0 ].contentFlags;
453 // if the plane is not in it canonical order, swap it
455 sidetemp = buildBrush->sides[order];
456 buildBrush->sides[order] = buildBrush->sides[i];
457 buildBrush->sides[i] = sidetemp;
463 // add the edge bevels
465 if ( buildBrush->numsides == 6 ) {
466 return; // pure axial
469 // test the non-axial plane edges
470 for ( i = 6; i < buildBrush->numsides; i++ ) {
471 s = buildBrush->sides + i;
476 for ( j = 0; j < w->numpoints; j++) {
477 k = (j+1)%w->numpoints;
478 VectorSubtract( w->p[j], w->p[k], vec );
479 if ( VectorNormalize( vec, vec ) < 0.5f ) {
483 for ( k = 0; k < 3; k++ ) {
484 if ( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f) ) {
489 continue; // only test non-axial edges
493 //% Sys_Printf( "-------------\n" );
495 // try the six possible slanted axials from this edge
496 for ( axis = 0; axis < 3; axis++ ) {
497 for ( dir = -1; dir <= 1; dir += 2 ) {
501 CrossProduct( vec, vec2, normal );
502 if ( VectorNormalize( normal, normal ) < 0.5f ) {
505 dist = DotProduct( w->p[j], normal );
507 // if all the points on all the sides are
508 // behind this plane, it is a proper edge bevel
509 for ( k = 0; k < buildBrush->numsides; k++ ) {
511 // if this plane has allready been used, skip it
512 if ( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ) ) {
516 w2 = buildBrush->sides[k].winding;
521 for ( l = 0; l < w2->numpoints; l++ ) {
522 d = DotProduct( w2->p[l], normal ) - dist;
524 break; // point in front
530 // if some point was at the front
531 if ( l != w2->numpoints ) {
535 // if no points at the back then the winding is on the bevel plane
536 if ( minBack > -0.1f ) {
537 //% Sys_Printf( "On bevel plane\n" );
542 if ( k != buildBrush->numsides ) {
543 continue; // wasn't part of the outer hull
547 //% Sys_Printf( "n = %f %f %f\n", normal[ 0 ], normal[ 1 ], normal[ 2 ] );
550 if( buildBrush->numsides == MAX_BUILD_SIDES ) {
551 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
553 s2 = &buildBrush->sides[buildBrush->numsides];
554 buildBrush->numsides++;
555 memset( s2, 0, sizeof( *s2 ) );
557 s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[ j ] );
558 s2->contentFlags = buildBrush->sides[0].contentFlags;
571 produces a final brush based on the buildBrush->sides array
572 and links it to the current entity
575 brush_t *FinishBrush( void )
580 /* create windings for sides and bounds for brush */
581 if ( !CreateBrushWindings( buildBrush ) )
584 /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
585 after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
586 if( buildBrush->compileFlags & C_ORIGIN )
591 if( numEntities == 1 )
593 Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n",
594 mapEnt->mapEntityNum, entitySourceBrushes );
598 VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
599 VectorScale (origin, 0.5, origin);
601 sprintf( string, "%i %i %i", (int) origin[ 0 ], (int) origin[ 1 ], (int) origin[ 2 ] );
602 SetKeyValue( &entities[ numEntities - 1 ], "origin", string);
604 VectorCopy( origin, entities[ numEntities - 1 ].origin);
606 /* don't keep this brush */
610 /* determine if the brush is an area portal */
611 if( buildBrush->compileFlags & C_AREAPORTAL )
613 if( numEntities != 1 )
615 Sys_Printf ("Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
620 /* add bevel planes */
624 b = CopyBrush( buildBrush );
626 /* set map entity and brush numbering */
627 b->entityNum = mapEnt->mapEntityNum;
628 b->brushNum = entitySourceBrushes;
633 /* link opaque brushes to head of list, translucent brushes to end */
634 if( b->opaque || mapEnt->lastBrush == NULL )
636 b->next = mapEnt->brushes;
638 if( mapEnt->lastBrush == NULL )
639 mapEnt->lastBrush = b;
644 mapEnt->lastBrush->next = b;
645 mapEnt->lastBrush = b;
648 /* link colorMod volume brushes to the entity directly */
649 if( b->contentShader != NULL &&
650 b->contentShader->colorMod != NULL &&
651 b->contentShader->colorMod->type == CM_VOLUME )
653 b->nextColorModBrush = mapEnt->colorModBrushes;
654 mapEnt->colorModBrushes = b;
657 /* return to sender */
664 TextureAxisFromPlane()
665 determines best orthagonal axis to project a texture onto a wall
666 (must be identical in radiant!)
669 vec3_t baseaxis[18] =
671 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
672 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
673 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
674 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
675 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
676 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
679 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv )
688 for (i=0 ; i<6 ; i++)
690 dot = DotProduct (pln->normal, baseaxis[i*3]);
691 if( dot > best + 0.0001f ) /* ydnar: bug 637 fix, suggested by jmonroe */
698 VectorCopy (baseaxis[bestaxis*3+1], xv);
699 VectorCopy (baseaxis[bestaxis*3+2], yv);
706 creates world-to-texture mapping vecs for crappy quake plane arrangements
709 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] )
713 vec_t ang, sinv, cosv;
718 TextureAxisFromPlane(plane, vecs[0], vecs[1]);
727 { sinv = 0 ; cosv = 1; }
728 else if (rotate == 90)
729 { sinv = 1 ; cosv = 0; }
730 else if (rotate == 180)
731 { sinv = 0 ; cosv = -1; }
732 else if (rotate == 270)
733 { sinv = -1 ; cosv = 0; }
736 ang = rotate / 180 * Q_PI;
755 for (i=0 ; i<2 ; i++) {
756 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
757 nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
762 for (i=0 ; i<2 ; i++)
763 for (j=0 ; j<3 ; j++)
764 mappingVecs[i][j] = vecs[i][j] / scale[i];
766 mappingVecs[0][3] = shift[0];
767 mappingVecs[1][3] = shift[1];
774 parses the sides into buildBrush->sides[], nothing else.
775 no validation, back plane removal, etc.
778 added brush epairs parsing ( ignoring actually )
780 added exclusive brush primitive parsing
782 support for old brush format back in
783 NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
786 static void ParseRawBrush( qboolean onlyLights )
789 vec3_t planePoints[ 3 ];
795 char name[ MAX_QPATH ];
796 char shader[ MAX_QPATH ];
801 buildBrush->numsides = 0;
802 buildBrush->detail = qfalse;
805 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
811 if( !GetToken( qtrue ) )
813 if( !strcmp( token, "}" ) )
816 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
817 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
821 if( strcmp( token, "(" ) )
830 /* test side count */
831 if( buildBrush->numsides >= MAX_BUILD_SIDES )
832 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
835 side = &buildBrush->sides[ buildBrush->numsides ];
836 memset( side, 0, sizeof( *side ) );
837 buildBrush->numsides++;
839 /* read the three point plane definition */
840 Parse1DMatrix( 3, planePoints[ 0 ] );
841 Parse1DMatrix( 3, planePoints[ 1 ] );
842 Parse1DMatrix( 3, planePoints[ 2 ] );
844 /* bp: read the texture matrix */
845 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
846 Parse2DMatrix( 2, 3, (float*) side->texMat );
848 /* read shader name */
850 strcpy( name, token );
853 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
856 shift[ 0 ] = atof( token );
858 shift[ 1 ] = atof( token );
860 rotate = atof( token );
862 scale[ 0 ] = atof( token );
864 scale[ 1 ] = atof( token );
867 /* set default flags and values */
868 sprintf( shader, "textures/%s", name );
870 si = &shaderInfo[ 0 ];
872 si = ShaderInfoForShader( shader );
873 side->shaderInfo = si;
874 side->surfaceFlags = si->surfaceFlags;
875 side->contentFlags = si->contentFlags;
876 side->compileFlags = si->compileFlags;
877 side->value = si->value;
879 /* ydnar: gs mods: bias texture shift */
880 if( si->globalTexture == qfalse )
882 shift[ 0 ] -= (floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth);
883 shift[ 1 ] -= (floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight);
887 historically, there are 3 integer values at the end of a brushside line in a .map file.
888 in quake 3, the only thing that mattered was the first of these three values, which
889 was previously the content flags. and only then did a single bit matter, the detail
890 bit. because every game has its own special flags for specifying detail, the
891 traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
892 by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
893 is stored in compileFlags, as opposed to contentFlags, for multiple-game
897 if( TokenAvailable() )
899 /* get detail bit from map content flags */
901 flags = atoi( token );
902 if( flags & C_DETAIL )
903 side->compileFlags |= C_DETAIL;
907 //% td.flags = atoi( token );
909 //% td.value = atoi( token );
912 /* find the plane number */
913 planenum = MapPlaneFromPoints( planePoints );
914 side->planenum = planenum;
916 /* bp: get the texture mapping for this texturedef / plane combination */
917 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
918 QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
922 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
933 RemoveDuplicateBrushPlanes
934 returns false if the brush has a mirrored set of planes,
935 meaning it encloses no volume.
936 also removes planes without any normal
939 qboolean RemoveDuplicateBrushPlanes( brush_t *b )
946 for ( i = 1 ; i < b->numsides ; i++ ) {
948 // check for a degenerate plane
949 if ( sides[i].planenum == -1) {
950 xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
952 for ( k = i + 1 ; k < b->numsides ; k++ ) {
953 sides[k-1] = sides[k];
960 // check for duplication and mirroring
961 for ( j = 0 ; j < i ; j++ ) {
962 if ( sides[i].planenum == sides[j].planenum ) {
963 xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
964 // remove the second duplicate
965 for ( k = i + 1 ; k < b->numsides ; k++ ) {
966 sides[k-1] = sides[k];
973 if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
974 // mirror plane, brush is invalid
975 xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
987 parses a brush out of a map file and sets it up
990 static void ParseBrush( qboolean onlyLights )
995 /* parse the brush out of the map */
996 ParseRawBrush( onlyLights );
998 /* only go this far? */
1002 /* set some defaults */
1003 buildBrush->portalareas[ 0 ] = -1;
1004 buildBrush->portalareas[ 1 ] = -1;
1005 buildBrush->entityNum = numMapEntities - 1;
1006 buildBrush->brushNum = entitySourceBrushes;
1008 /* if there are mirrored planes, the entire brush is invalid */
1009 if( !RemoveDuplicateBrushPlanes( buildBrush ) )
1012 /* get the content for the entire brush */
1013 SetBrushContents( buildBrush );
1015 /* allow detail brushes to be removed */
1016 if( nodetail && (buildBrush->compileFlags & C_DETAIL) )
1018 //% FreeBrush( buildBrush );
1022 /* allow liquid brushes to be removed */
1023 if( nowater && (buildBrush->compileFlags & C_LIQUID ) )
1025 //% FreeBrush( buildBrush );
1029 /* ydnar: allow hint brushes to be removed */
1030 if( noHint && (buildBrush->compileFlags & C_HINT) )
1032 //% FreeBrush( buildBrush );
1036 /* finish the brush */
1043 MoveBrushesToWorld()
1044 takes all of the brushes from the current entity and
1045 adds them to the world's brush list
1046 (used by func_group)
1049 void MoveBrushesToWorld( entity_t *ent )
1056 for( b = ent->brushes; b != NULL; b = next )
1058 /* get next brush */
1061 /* link opaque brushes to head of list, translucent brushes to end */
1062 if( b->opaque || entities[ 0 ].lastBrush == NULL )
1064 b->next = entities[ 0 ].brushes;
1065 entities[ 0 ].brushes = b;
1066 if( entities[ 0 ].lastBrush == NULL )
1067 entities[ 0 ].lastBrush = b;
1072 entities[ 0 ].lastBrush->next = b;
1073 entities[ 0 ].lastBrush = b;
1076 ent->brushes = NULL;
1078 /* ydnar: move colormod brushes */
1079 if( ent->colorModBrushes != NULL )
1081 for( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush );
1083 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1084 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1086 ent->colorModBrushes = NULL;
1090 if( ent->patches != NULL )
1092 for( pm = ent->patches; pm->next != NULL; pm = pm->next );
1094 pm->next = entities[ 0 ].patches;
1095 entities[ 0 ].patches = ent->patches;
1097 ent->patches = NULL;
1104 AdjustBrushesForOrigin()
1107 void AdjustBrushesForOrigin( entity_t *ent )
1117 /* walk brush list */
1118 for( b = ent->brushes; b != NULL; b = b->next )
1120 /* offset brush planes */
1121 for( i = 0; i < b->numsides; i++)
1123 /* get brush side */
1126 /* offset side plane */
1127 newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin );
1129 /* find a new plane */
1130 s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1133 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1134 CreateBrushWindings( b );
1137 /* walk patch list */
1138 for( p = ent->patches; p != NULL; p = p->next )
1140 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1141 VectorSubtract( p->mesh.verts[ i ].xyz, ent->origin, p->mesh.verts[ i ].xyz );
1148 SetEntityBounds() - ydnar
1149 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1152 void SetEntityBounds( entity_t *e )
1163 /* walk the entity's brushes/patches and determine bounds */
1164 ClearBounds( mins, maxs );
1165 for( b = e->brushes; b; b = b->next )
1167 AddPointToBounds( b->mins, mins, maxs );
1168 AddPointToBounds( b->maxs, mins, maxs );
1170 for( p = e->patches; p; p = p->next )
1172 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1173 AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1176 /* try to find explicit min/max key */
1177 value = ValueForKey( e, "min" );
1178 if( value[ 0 ] != '\0' )
1179 GetVectorForKey( e, "min", mins );
1180 value = ValueForKey( e, "max" );
1181 if( value[ 0 ] != '\0' )
1182 GetVectorForKey( e, "max", maxs );
1184 /* store the bounds */
1185 for( b = e->brushes; b; b = b->next )
1187 VectorCopy( mins, b->eMins );
1188 VectorCopy( maxs, b->eMaxs );
1190 for( p = e->patches; p; p = p->next )
1192 VectorCopy( mins, p->eMins );
1193 VectorCopy( maxs, p->eMaxs );
1200 LoadEntityIndexMap() - ydnar
1201 based on LoadAlphaMap() from terrain.c, a little more generic
1204 void LoadEntityIndexMap( entity_t *e )
1206 int i, size, numLayers, w, h;
1207 const char *value, *indexMapFilename, *shader;
1208 char ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1210 unsigned int *pixels32;
1216 /* this only works with bmodel ents */
1217 if( e->brushes == NULL && e->patches == NULL )
1220 /* determine if there is an index map (support legacy "alphamap" key as well) */
1221 value = ValueForKey( e, "_indexmap" );
1222 if( value[ 0 ] == '\0' )
1223 value = ValueForKey( e, "alphamap" );
1224 if( value[ 0 ] == '\0' )
1226 indexMapFilename = value;
1228 /* get number of layers (support legacy "layers" key as well) */
1229 value = ValueForKey( e, "_layers" );
1230 if( value[ 0 ] == '\0' )
1231 value = ValueForKey( e, "layers" );
1232 if( value[ 0 ] == '\0' )
1234 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1235 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1238 numLayers = atoi( value );
1241 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1242 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1246 /* get base shader name (support legacy "shader" key as well) */
1247 value = ValueForKey( mapEnt, "_shader" );
1248 if( value[ 0 ] == '\0' )
1249 value = ValueForKey( e, "shader" );
1250 if( value[ 0 ] == '\0' )
1252 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1253 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1259 Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n", mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1261 /* get index map file extension */
1262 ExtractFileExtension( indexMapFilename, ext );
1264 /* handle tga image */
1265 if( !Q_stricmp( ext, "tga" ) )
1268 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1270 /* convert to bytes */
1272 pixels = safe_malloc( size );
1273 for( i = 0; i < size; i++ )
1275 pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1276 if( pixels[ i ] >= numLayers )
1277 pixels[ i ] = numLayers - 1;
1280 /* free the 32 bit image */
1286 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1289 //% Sys_Printf( "-------------------------------" );
1291 /* fix up out-of-range values */
1293 for( i = 0; i < size; i++ )
1295 if( pixels[ i ] >= numLayers )
1296 pixels[ i ] = numLayers - 1;
1299 //% if( (i % w) == 0 )
1300 //% Sys_Printf( "\n" );
1301 //% Sys_Printf( "%c", pixels[ i ] + '0' );
1305 //% Sys_Printf( "\n-------------------------------\n" );
1308 /* the index map must be at least 2x2 pixels */
1309 if( w < 2 || h < 2 )
1311 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1312 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1317 /* create a new index map */
1318 im = safe_malloc( sizeof( *im ) );
1319 memset( im, 0, sizeof( *im ) );
1324 im->numLayers = numLayers;
1325 strcpy( im->name, indexMapFilename );
1326 strcpy( im->shader, shader );
1327 im->pixels = pixels;
1329 /* get height offsets */
1330 value = ValueForKey( mapEnt, "_offsets" );
1331 if( value[ 0 ] == '\0' )
1332 value = ValueForKey( e, "offsets" );
1333 if( value[ 0 ] != '\0' )
1335 /* value is a space-seperated set of numbers */
1336 strcpy( offset, value );
1339 /* get each value */
1340 for( i = 0; i < 256 && *search != '\0'; i++ )
1342 space = strstr( search, " " );
1345 im->offsets[ i ] = atof( search );
1352 /* store the index map in every brush/patch in the entity */
1353 for( b = e->brushes; b != NULL; b = b->next )
1355 for( p = e->patches; p != NULL; p = p->next )
1367 parses a single entity out of a map file
1370 static qboolean ParseMapEntity( qboolean onlyLights )
1373 const char *classname, *value;
1374 float lightmapScale;
1375 char shader[ MAX_QPATH ];
1376 shaderInfo_t *celShader = NULL;
1380 int castShadows, recvShadows;
1384 if( !GetToken( qtrue ) )
1387 /* conformance check */
1388 if( strcmp( token, "{" ) )
1390 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1391 "Continuing to process map, but resulting BSP may be invalid.\n",
1392 token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1397 if( numEntities >= MAX_MAP_ENTITIES )
1398 Error( "numEntities == MAX_MAP_ENTITIES" );
1401 entitySourceBrushes = 0;
1402 mapEnt = &entities[ numEntities ];
1404 memset( mapEnt, 0, sizeof( *mapEnt ) );
1406 /* ydnar: true entity numbering */
1407 mapEnt->mapEntityNum = numMapEntities;
1413 /* get initial token */
1414 if( !GetToken( qtrue ) )
1416 Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1417 "Continuing to process map, but resulting BSP may be invalid.\n" );
1421 if( !strcmp( token, "}" ) )
1424 if( !strcmp( token, "{" ) )
1426 /* parse a brush or patch */
1427 if( !GetToken( qtrue ) )
1431 if( !strcmp( token, "patchDef2" ) )
1434 ParsePatch( onlyLights );
1436 else if( !strcmp( token, "terrainDef" ) )
1439 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1441 else if( !strcmp( token, "brushDef" ) )
1443 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1444 Error( "Old brush format not allowed in new brush format map" );
1445 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1447 /* parse brush primitive */
1448 ParseBrush( onlyLights );
1452 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1453 Error( "New brush format not allowed in old brush format map" );
1454 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1456 /* parse old brush format */
1458 ParseBrush( onlyLights );
1460 entitySourceBrushes++;
1464 /* parse a key / value pair */
1467 /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1468 if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1470 ep->next = mapEnt->epairs;
1471 mapEnt->epairs = ep;
1476 /* ydnar: get classname */
1477 classname = ValueForKey( mapEnt, "classname" );
1479 /* ydnar: only lights? */
1480 if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1486 /* ydnar: determine if this is a func_group */
1487 if( !Q_stricmp( "func_group", classname ) )
1492 /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1493 if( funcGroup || mapEnt->mapEntityNum == 0 )
1495 //% Sys_Printf( "World: %d\n", mapEnt->mapEntityNum );
1496 castShadows = WORLDSPAWN_CAST_SHADOWS;
1497 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1500 /* other entities don't cast any shadows, but recv worldspawn shadows */
1503 //% Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1504 castShadows = ENTITY_CAST_SHADOWS;
1505 recvShadows = ENTITY_RECV_SHADOWS;
1508 /* get explicit shadow flags */
1509 GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1511 /* ydnar: get lightmap scaling value for this entity */
1512 if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1513 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) )
1515 /* get lightmap scale from entity */
1516 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1517 if( lightmapScale <= 0.0f )
1518 lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1519 if( lightmapScale > 0.0f )
1520 Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1523 lightmapScale = 0.0f;
1525 /* ydnar: get cel shader :) for this entity */
1526 value = ValueForKey( mapEnt, "_celshader" );
1527 if( value[ 0 ] == '\0' )
1528 value = ValueForKey( &entities[ 0 ], "_celshader" );
1529 if( value[ 0 ] != '\0' )
1531 sprintf( shader, "textures/%s", value );
1532 celShader = ShaderInfoForShader( shader );
1533 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1538 /* attach stuff to everything in the entity */
1539 for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1541 brush->entityNum = mapEnt->mapEntityNum;
1542 brush->castShadows = castShadows;
1543 brush->recvShadows = recvShadows;
1544 brush->lightmapScale = lightmapScale;
1545 brush->celShader = celShader;
1548 for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1550 patch->entityNum = mapEnt->mapEntityNum;
1551 patch->castShadows = castShadows;
1552 patch->recvShadows = recvShadows;
1553 patch->lightmapScale = lightmapScale;
1554 patch->celShader = celShader;
1557 /* ydnar: gs mods: set entity bounds */
1558 SetEntityBounds( mapEnt );
1560 /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1561 LoadEntityIndexMap( mapEnt );
1563 /* get entity origin and adjust brushes */
1564 GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1565 if( mapEnt->origin[ 0 ] || mapEnt->origin[ 1 ] || mapEnt->origin[ 2 ] )
1566 AdjustBrushesForOrigin( mapEnt );
1568 /* group_info entities are just for editor grouping (fixme: leak!) */
1569 if( !Q_stricmp( "group_info", classname ) )
1575 /* group entities are just for editor convenience, toss all brushes into worldspawn */
1578 MoveBrushesToWorld( mapEnt );
1591 loads a map file into a list of entities
1594 void LoadMapFile( char *filename, qboolean onlyLights )
1598 int oldNumEntities, numMapBrushes;
1602 Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1603 Sys_Printf( "Loading %s\n", filename );
1606 file = SafeOpenRead( filename );
1609 /* load the map file */
1610 LoadScriptFile( filename, -1 );
1614 oldNumEntities = numEntities;
1619 numMapDrawSurfs = 0;
1621 g_bBrushPrimit = BPRIMIT_UNDEFINED;
1623 /* allocate a very large temporary brush for building the brushes as they are loaded */
1624 buildBrush = AllocBrush( MAX_BUILD_SIDES );
1626 /* parse the map file */
1627 while( ParseMapEntity( onlyLights ) );
1632 /* emit some statistics */
1633 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1637 /* set map bounds */
1638 ClearBounds( mapMins, mapMaxs );
1639 for( b = entities[ 0 ].brushes; b; b = b->next )
1641 AddPointToBounds( b->mins, mapMins, mapMaxs );
1642 AddPointToBounds( b->maxs, mapMins, mapMaxs );
1645 /* get brush counts */
1646 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1647 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1648 Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1650 /* emit some statistics */
1651 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1652 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1653 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1654 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1655 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1656 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1657 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1658 Sys_Printf( "%9d areaportals\n", c_areaportals);
1659 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1660 mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1661 mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1663 /* write bogus map */
1665 WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );