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 // SnapPlane disabled by LordHavoc because it often messes up collision
190 // brushes made from triangles of embedded models, and it has little effect
191 // on anything else (axial planes are usually derived from snapped points)
193 SnapNormal( normal );
195 if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
196 *dist = Q_rint( *dist );
204 ydnar: changed to allow a number of test points to be supplied that
205 must be within an epsilon distance of the plane
208 int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
219 SnapPlane( normal, &dist );
220 hash = (PLANE_HASHES - 1) & (int) fabs( dist );
222 /* search the border bins as well */
223 for( i = -1; i <= 1; i++ )
225 h = (hash + i) & (PLANE_HASHES - 1);
226 for( p = planehash[ h ]; p != NULL; p = p->hash_chain )
228 /* do standard plane compare */
229 if( !PlaneEqual( p, normal, dist ) )
232 /* ydnar: uncomment the following line for old-style plane finding */
233 //% return p - mapplanes;
235 /* ydnar: test supplied points against this plane */
236 for( j = 0; j < numPoints; j++ )
238 d = DotProduct( points[ j ], normal ) - dist;
239 if( fabs( d ) > distanceEpsilon )
243 /* found a matching plane */
245 return p - mapplanes;
249 /* none found, so create a new one */
250 return CreateNewFloatPlane( normal, dist );
260 SnapPlane( normal, &dist );
261 for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
263 if( PlaneEqual( p, normal, dist ) )
267 return CreateNewFloatPlane( normal, dist );
276 takes 3 points and finds the plane they lie in
279 int MapPlaneFromPoints( vec3_t *p )
281 vec3_t t1, t2, normal;
285 /* calc plane normal */
286 VectorSubtract( p[ 0 ], p[ 1 ], t1 );
287 VectorSubtract( p[ 2 ], p[ 1 ], t2 );
288 CrossProduct( t1, t2, normal );
289 VectorNormalize( normal, normal );
291 /* calc plane distance */
292 dist = DotProduct( p[ 0 ], normal );
294 /* store the plane */
295 return FindFloatPlane( normal, dist, 3, p );
302 the content flags and compile flags on all sides of a brush should be the same
305 void SetBrushContents( brush_t *b )
307 int contentFlags, compileFlags;
313 /* get initial compile flags from first side */
315 contentFlags = s->contentFlags;
316 compileFlags = s->compileFlags;
317 b->contentShader = s->shaderInfo;
320 /* get the content/compile flags for every side in the brush */
321 for( i = 1; i < b->numsides; i++, s++ )
324 if( s->shaderInfo == NULL )
326 if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
330 /* ydnar: getting rid of this stupid warning */
332 //% Sys_FPrintf( SYS_VRB,"Entity %i, Brush %i: mixed face contentFlags\n", b->entitynum, b->brushnum );
334 /* check for detail & structural */
335 if( (compileFlags & C_DETAIL) && (compileFlags & C_STRUCTURAL) )
337 xml_Select( "Mixed detail and structural (defaulting to structural)", mapEnt->mapEntityNum, entitySourceBrushes, qfalse );
338 compileFlags &= ~C_DETAIL;
341 /* the fulldetail flag will cause detail brushes to be treated like normal brushes */
343 compileFlags &= ~C_DETAIL;
345 /* all translucent brushes that aren't specifically made structural will be detail */
346 if( (compileFlags & C_TRANSLUCENT) && !(compileFlags & C_STRUCTURAL) )
347 compileFlags |= C_DETAIL;
350 if( compileFlags & C_DETAIL )
362 if( compileFlags & C_TRANSLUCENT )
368 if( compileFlags & C_AREAPORTAL )
371 /* set brush flags */
372 b->contentFlags = contentFlags;
373 b->compileFlags = compileFlags;
380 adds any additional planes necessary to allow the brush being
381 built to be expanded against axial bounding boxes
382 ydnar 2003-01-20: added mrelusive fixes
385 void AddBrushBevels( void )
388 int i, j, k, l, order;
398 // add the axial planes
401 for ( axis = 0; axis < 3; axis++ ) {
402 for ( dir = -1; dir <= 1; dir += 2, order++ ) {
403 // see if the plane is allready present
404 for ( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
406 /* ydnar: testing disabling of mre code */
409 if ( mapplanes[s->planenum].normal[axis] >= 0.9999f ) {
414 if ( mapplanes[s->planenum].normal[axis] <= -0.9999f ) {
419 if( (dir > 0 && mapplanes[ s->planenum ].normal[ axis ] == 1.0f ) ||
420 (dir < 0 && mapplanes[ s->planenum ].normal[ axis ] == -1.0f) )
425 if ( i == buildBrush->numsides ) {
427 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
428 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
430 memset( s, 0, sizeof( *s ) );
431 buildBrush->numsides++;
432 VectorClear (normal);
437 /* ydnar: adding bevel plane snapping for fewer bsp planes */
439 dist = floor( buildBrush->maxs[ axis ] / bevelSnap ) * bevelSnap;
441 dist = buildBrush->maxs[ axis ];
445 /* ydnar: adding bevel plane snapping for fewer bsp planes */
447 dist = -ceil( buildBrush->mins[ axis ] / bevelSnap ) * bevelSnap;
449 dist = -buildBrush->mins[ axis ];
452 s->planenum = FindFloatPlane( normal, dist, 0, NULL );
453 s->contentFlags = buildBrush->sides[ 0 ].contentFlags;
458 // if the plane is not in it canonical order, swap it
460 sidetemp = buildBrush->sides[order];
461 buildBrush->sides[order] = buildBrush->sides[i];
462 buildBrush->sides[i] = sidetemp;
468 // add the edge bevels
470 if ( buildBrush->numsides == 6 ) {
471 return; // pure axial
474 // test the non-axial plane edges
475 for ( i = 6; i < buildBrush->numsides; i++ ) {
476 s = buildBrush->sides + i;
481 for ( j = 0; j < w->numpoints; j++) {
482 k = (j+1)%w->numpoints;
483 VectorSubtract( w->p[j], w->p[k], vec );
484 if ( VectorNormalize( vec, vec ) < 0.5f ) {
488 for ( k = 0; k < 3; k++ ) {
489 if ( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f) ) {
494 continue; // only test non-axial edges
498 //% Sys_Printf( "-------------\n" );
500 // try the six possible slanted axials from this edge
501 for ( axis = 0; axis < 3; axis++ ) {
502 for ( dir = -1; dir <= 1; dir += 2 ) {
506 CrossProduct( vec, vec2, normal );
507 if ( VectorNormalize( normal, normal ) < 0.5f ) {
510 dist = DotProduct( w->p[j], normal );
512 // if all the points on all the sides are
513 // behind this plane, it is a proper edge bevel
514 for ( k = 0; k < buildBrush->numsides; k++ ) {
516 // if this plane has allready been used, skip it
517 if ( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ) ) {
521 w2 = buildBrush->sides[k].winding;
526 for ( l = 0; l < w2->numpoints; l++ ) {
527 d = DotProduct( w2->p[l], normal ) - dist;
529 break; // point in front
535 // if some point was at the front
536 if ( l != w2->numpoints ) {
540 // if no points at the back then the winding is on the bevel plane
541 if ( minBack > -0.1f ) {
542 //% Sys_Printf( "On bevel plane\n" );
547 if ( k != buildBrush->numsides ) {
548 continue; // wasn't part of the outer hull
552 //% Sys_Printf( "n = %f %f %f\n", normal[ 0 ], normal[ 1 ], normal[ 2 ] );
555 if( buildBrush->numsides == MAX_BUILD_SIDES ) {
556 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
558 s2 = &buildBrush->sides[buildBrush->numsides];
559 buildBrush->numsides++;
560 memset( s2, 0, sizeof( *s2 ) );
562 s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[ j ] );
563 s2->contentFlags = buildBrush->sides[0].contentFlags;
576 produces a final brush based on the buildBrush->sides array
577 and links it to the current entity
580 brush_t *FinishBrush( void )
585 /* create windings for sides and bounds for brush */
586 if ( !CreateBrushWindings( buildBrush ) )
589 /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
590 after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
591 if( buildBrush->compileFlags & C_ORIGIN )
596 if( numEntities == 1 )
598 Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n",
599 mapEnt->mapEntityNum, entitySourceBrushes );
603 VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
604 VectorScale (origin, 0.5, origin);
606 sprintf( string, "%i %i %i", (int) origin[ 0 ], (int) origin[ 1 ], (int) origin[ 2 ] );
607 SetKeyValue( &entities[ numEntities - 1 ], "origin", string);
609 VectorCopy( origin, entities[ numEntities - 1 ].origin);
611 /* don't keep this brush */
615 /* determine if the brush is an area portal */
616 if( buildBrush->compileFlags & C_AREAPORTAL )
618 if( numEntities != 1 )
620 Sys_Printf ("Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
625 /* add bevel planes */
629 b = CopyBrush( buildBrush );
631 /* set map entity and brush numbering */
632 b->entityNum = mapEnt->mapEntityNum;
633 b->brushNum = entitySourceBrushes;
638 /* link opaque brushes to head of list, translucent brushes to end */
639 if( b->opaque || mapEnt->lastBrush == NULL )
641 b->next = mapEnt->brushes;
643 if( mapEnt->lastBrush == NULL )
644 mapEnt->lastBrush = b;
649 mapEnt->lastBrush->next = b;
650 mapEnt->lastBrush = b;
653 /* link colorMod volume brushes to the entity directly */
654 if( b->contentShader != NULL &&
655 b->contentShader->colorMod != NULL &&
656 b->contentShader->colorMod->type == CM_VOLUME )
658 b->nextColorModBrush = mapEnt->colorModBrushes;
659 mapEnt->colorModBrushes = b;
662 /* return to sender */
669 TextureAxisFromPlane()
670 determines best orthagonal axis to project a texture onto a wall
671 (must be identical in radiant!)
674 vec3_t baseaxis[18] =
676 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
677 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
678 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
679 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
680 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
681 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
684 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv )
693 for (i=0 ; i<6 ; i++)
695 dot = DotProduct (pln->normal, baseaxis[i*3]);
696 if( dot > best + 0.0001f ) /* ydnar: bug 637 fix, suggested by jmonroe */
703 VectorCopy (baseaxis[bestaxis*3+1], xv);
704 VectorCopy (baseaxis[bestaxis*3+2], yv);
711 creates world-to-texture mapping vecs for crappy quake plane arrangements
714 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] )
718 vec_t ang, sinv, cosv;
723 TextureAxisFromPlane(plane, vecs[0], vecs[1]);
732 { sinv = 0 ; cosv = 1; }
733 else if (rotate == 90)
734 { sinv = 1 ; cosv = 0; }
735 else if (rotate == 180)
736 { sinv = 0 ; cosv = -1; }
737 else if (rotate == 270)
738 { sinv = -1 ; cosv = 0; }
741 ang = rotate / 180 * Q_PI;
760 for (i=0 ; i<2 ; i++) {
761 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
762 nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
767 for (i=0 ; i<2 ; i++)
768 for (j=0 ; j<3 ; j++)
769 mappingVecs[i][j] = vecs[i][j] / scale[i];
771 mappingVecs[0][3] = shift[0];
772 mappingVecs[1][3] = shift[1];
779 parses the sides into buildBrush->sides[], nothing else.
780 no validation, back plane removal, etc.
783 added brush epairs parsing ( ignoring actually )
785 added exclusive brush primitive parsing
787 support for old brush format back in
788 NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
791 static void ParseRawBrush( qboolean onlyLights )
794 vec3_t planePoints[ 3 ];
800 char name[ MAX_QPATH ];
801 char shader[ MAX_QPATH ];
806 buildBrush->numsides = 0;
807 buildBrush->detail = qfalse;
810 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
816 if( !GetToken( qtrue ) )
818 if( !strcmp( token, "}" ) )
821 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
822 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
826 if( strcmp( token, "(" ) )
835 /* test side count */
836 if( buildBrush->numsides >= MAX_BUILD_SIDES )
837 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
840 side = &buildBrush->sides[ buildBrush->numsides ];
841 memset( side, 0, sizeof( *side ) );
842 buildBrush->numsides++;
844 /* read the three point plane definition */
845 Parse1DMatrix( 3, planePoints[ 0 ] );
846 Parse1DMatrix( 3, planePoints[ 1 ] );
847 Parse1DMatrix( 3, planePoints[ 2 ] );
849 /* bp: read the texture matrix */
850 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
851 Parse2DMatrix( 2, 3, (float*) side->texMat );
853 /* read shader name */
855 strcpy( name, token );
858 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
861 shift[ 0 ] = atof( token );
863 shift[ 1 ] = atof( token );
865 rotate = atof( token );
867 scale[ 0 ] = atof( token );
869 scale[ 1 ] = atof( token );
872 /* set default flags and values */
873 sprintf( shader, "textures/%s", name );
875 si = &shaderInfo[ 0 ];
877 si = ShaderInfoForShader( shader );
878 side->shaderInfo = si;
879 side->surfaceFlags = si->surfaceFlags;
880 side->contentFlags = si->contentFlags;
881 side->compileFlags = si->compileFlags;
882 side->value = si->value;
884 /* ydnar: gs mods: bias texture shift */
885 if( si->globalTexture == qfalse )
887 shift[ 0 ] -= (floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth);
888 shift[ 1 ] -= (floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight);
892 historically, there are 3 integer values at the end of a brushside line in a .map file.
893 in quake 3, the only thing that mattered was the first of these three values, which
894 was previously the content flags. and only then did a single bit matter, the detail
895 bit. because every game has its own special flags for specifying detail, the
896 traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
897 by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
898 is stored in compileFlags, as opposed to contentFlags, for multiple-game
902 if( TokenAvailable() )
904 /* get detail bit from map content flags */
906 flags = atoi( token );
907 if( flags & C_DETAIL )
908 side->compileFlags |= C_DETAIL;
912 //% td.flags = atoi( token );
914 //% td.value = atoi( token );
917 /* find the plane number */
918 planenum = MapPlaneFromPoints( planePoints );
919 side->planenum = planenum;
921 /* bp: get the texture mapping for this texturedef / plane combination */
922 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
923 QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
927 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
938 RemoveDuplicateBrushPlanes
939 returns false if the brush has a mirrored set of planes,
940 meaning it encloses no volume.
941 also removes planes without any normal
944 qboolean RemoveDuplicateBrushPlanes( brush_t *b )
951 for ( i = 1 ; i < b->numsides ; i++ ) {
953 // check for a degenerate plane
954 if ( sides[i].planenum == -1) {
955 xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
957 for ( k = i + 1 ; k < b->numsides ; k++ ) {
958 sides[k-1] = sides[k];
965 // check for duplication and mirroring
966 for ( j = 0 ; j < i ; j++ ) {
967 if ( sides[i].planenum == sides[j].planenum ) {
968 xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
969 // remove the second duplicate
970 for ( k = i + 1 ; k < b->numsides ; k++ ) {
971 sides[k-1] = sides[k];
978 if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
979 // mirror plane, brush is invalid
980 xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
992 parses a brush out of a map file and sets it up
995 static void ParseBrush( qboolean onlyLights )
1000 /* parse the brush out of the map */
1001 ParseRawBrush( onlyLights );
1003 /* only go this far? */
1007 /* set some defaults */
1008 buildBrush->portalareas[ 0 ] = -1;
1009 buildBrush->portalareas[ 1 ] = -1;
1010 buildBrush->entityNum = numMapEntities - 1;
1011 buildBrush->brushNum = entitySourceBrushes;
1013 /* if there are mirrored planes, the entire brush is invalid */
1014 if( !RemoveDuplicateBrushPlanes( buildBrush ) )
1017 /* get the content for the entire brush */
1018 SetBrushContents( buildBrush );
1020 /* allow detail brushes to be removed */
1021 if( nodetail && (buildBrush->compileFlags & C_DETAIL) )
1023 //% FreeBrush( buildBrush );
1027 /* allow liquid brushes to be removed */
1028 if( nowater && (buildBrush->compileFlags & C_LIQUID ) )
1030 //% FreeBrush( buildBrush );
1034 /* ydnar: allow hint brushes to be removed */
1035 if( noHint && (buildBrush->compileFlags & C_HINT) )
1037 //% FreeBrush( buildBrush );
1041 /* finish the brush */
1048 MoveBrushesToWorld()
1049 takes all of the brushes from the current entity and
1050 adds them to the world's brush list
1051 (used by func_group)
1054 void MoveBrushesToWorld( entity_t *ent )
1061 for( b = ent->brushes; b != NULL; b = next )
1063 /* get next brush */
1066 /* link opaque brushes to head of list, translucent brushes to end */
1067 if( b->opaque || entities[ 0 ].lastBrush == NULL )
1069 b->next = entities[ 0 ].brushes;
1070 entities[ 0 ].brushes = b;
1071 if( entities[ 0 ].lastBrush == NULL )
1072 entities[ 0 ].lastBrush = b;
1077 entities[ 0 ].lastBrush->next = b;
1078 entities[ 0 ].lastBrush = b;
1081 ent->brushes = NULL;
1083 /* ydnar: move colormod brushes */
1084 if( ent->colorModBrushes != NULL )
1086 for( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush );
1088 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1089 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1091 ent->colorModBrushes = NULL;
1095 if( ent->patches != NULL )
1097 for( pm = ent->patches; pm->next != NULL; pm = pm->next );
1099 pm->next = entities[ 0 ].patches;
1100 entities[ 0 ].patches = ent->patches;
1102 ent->patches = NULL;
1109 AdjustBrushesForOrigin()
1112 void AdjustBrushesForOrigin( entity_t *ent )
1122 /* walk brush list */
1123 for( b = ent->brushes; b != NULL; b = b->next )
1125 /* offset brush planes */
1126 for( i = 0; i < b->numsides; i++)
1128 /* get brush side */
1131 /* offset side plane */
1132 newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin );
1134 /* find a new plane */
1135 s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1138 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1139 CreateBrushWindings( b );
1142 /* walk patch list */
1143 for( p = ent->patches; p != NULL; p = p->next )
1145 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1146 VectorSubtract( p->mesh.verts[ i ].xyz, ent->origin, p->mesh.verts[ i ].xyz );
1153 SetEntityBounds() - ydnar
1154 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1157 void SetEntityBounds( entity_t *e )
1168 /* walk the entity's brushes/patches and determine bounds */
1169 ClearBounds( mins, maxs );
1170 for( b = e->brushes; b; b = b->next )
1172 AddPointToBounds( b->mins, mins, maxs );
1173 AddPointToBounds( b->maxs, mins, maxs );
1175 for( p = e->patches; p; p = p->next )
1177 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1178 AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1181 /* try to find explicit min/max key */
1182 value = ValueForKey( e, "min" );
1183 if( value[ 0 ] != '\0' )
1184 GetVectorForKey( e, "min", mins );
1185 value = ValueForKey( e, "max" );
1186 if( value[ 0 ] != '\0' )
1187 GetVectorForKey( e, "max", maxs );
1189 /* store the bounds */
1190 for( b = e->brushes; b; b = b->next )
1192 VectorCopy( mins, b->eMins );
1193 VectorCopy( maxs, b->eMaxs );
1195 for( p = e->patches; p; p = p->next )
1197 VectorCopy( mins, p->eMins );
1198 VectorCopy( maxs, p->eMaxs );
1205 LoadEntityIndexMap() - ydnar
1206 based on LoadAlphaMap() from terrain.c, a little more generic
1209 void LoadEntityIndexMap( entity_t *e )
1211 int i, size, numLayers, w, h;
1212 const char *value, *indexMapFilename, *shader;
1213 char ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1215 unsigned int *pixels32;
1221 /* this only works with bmodel ents */
1222 if( e->brushes == NULL && e->patches == NULL )
1225 /* determine if there is an index map (support legacy "alphamap" key as well) */
1226 value = ValueForKey( e, "_indexmap" );
1227 if( value[ 0 ] == '\0' )
1228 value = ValueForKey( e, "alphamap" );
1229 if( value[ 0 ] == '\0' )
1231 indexMapFilename = value;
1233 /* get number of layers (support legacy "layers" key as well) */
1234 value = ValueForKey( e, "_layers" );
1235 if( value[ 0 ] == '\0' )
1236 value = ValueForKey( e, "layers" );
1237 if( value[ 0 ] == '\0' )
1239 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1240 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1243 numLayers = atoi( value );
1246 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1247 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1251 /* get base shader name (support legacy "shader" key as well) */
1252 value = ValueForKey( mapEnt, "_shader" );
1253 if( value[ 0 ] == '\0' )
1254 value = ValueForKey( e, "shader" );
1255 if( value[ 0 ] == '\0' )
1257 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1258 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1264 Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n", mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1266 /* get index map file extension */
1267 ExtractFileExtension( indexMapFilename, ext );
1269 /* handle tga image */
1270 if( !Q_stricmp( ext, "tga" ) )
1273 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1275 /* convert to bytes */
1277 pixels = safe_malloc( size );
1278 for( i = 0; i < size; i++ )
1280 pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1281 if( pixels[ i ] >= numLayers )
1282 pixels[ i ] = numLayers - 1;
1285 /* free the 32 bit image */
1291 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1294 //% Sys_Printf( "-------------------------------" );
1296 /* fix up out-of-range values */
1298 for( i = 0; i < size; i++ )
1300 if( pixels[ i ] >= numLayers )
1301 pixels[ i ] = numLayers - 1;
1304 //% if( (i % w) == 0 )
1305 //% Sys_Printf( "\n" );
1306 //% Sys_Printf( "%c", pixels[ i ] + '0' );
1310 //% Sys_Printf( "\n-------------------------------\n" );
1313 /* the index map must be at least 2x2 pixels */
1314 if( w < 2 || h < 2 )
1316 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1317 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1322 /* create a new index map */
1323 im = safe_malloc( sizeof( *im ) );
1324 memset( im, 0, sizeof( *im ) );
1329 im->numLayers = numLayers;
1330 strcpy( im->name, indexMapFilename );
1331 strcpy( im->shader, shader );
1332 im->pixels = pixels;
1334 /* get height offsets */
1335 value = ValueForKey( mapEnt, "_offsets" );
1336 if( value[ 0 ] == '\0' )
1337 value = ValueForKey( e, "offsets" );
1338 if( value[ 0 ] != '\0' )
1340 /* value is a space-seperated set of numbers */
1341 strcpy( offset, value );
1344 /* get each value */
1345 for( i = 0; i < 256 && *search != '\0'; i++ )
1347 space = strstr( search, " " );
1350 im->offsets[ i ] = atof( search );
1357 /* store the index map in every brush/patch in the entity */
1358 for( b = e->brushes; b != NULL; b = b->next )
1360 for( p = e->patches; p != NULL; p = p->next )
1372 parses a single entity out of a map file
1375 static qboolean ParseMapEntity( qboolean onlyLights )
1378 const char *classname, *value;
1379 float lightmapScale;
1380 char shader[ MAX_QPATH ];
1381 shaderInfo_t *celShader = NULL;
1385 int castShadows, recvShadows;
1389 if( !GetToken( qtrue ) )
1392 /* conformance check */
1393 if( strcmp( token, "{" ) )
1395 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1396 "Continuing to process map, but resulting BSP may be invalid.\n",
1397 token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1402 if( numEntities >= MAX_MAP_ENTITIES )
1403 Error( "numEntities == MAX_MAP_ENTITIES" );
1406 entitySourceBrushes = 0;
1407 mapEnt = &entities[ numEntities ];
1409 memset( mapEnt, 0, sizeof( *mapEnt ) );
1411 /* ydnar: true entity numbering */
1412 mapEnt->mapEntityNum = numMapEntities;
1418 /* get initial token */
1419 if( !GetToken( qtrue ) )
1421 Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1422 "Continuing to process map, but resulting BSP may be invalid.\n" );
1426 if( !strcmp( token, "}" ) )
1429 if( !strcmp( token, "{" ) )
1431 /* parse a brush or patch */
1432 if( !GetToken( qtrue ) )
1436 if( !strcmp( token, "patchDef2" ) )
1439 ParsePatch( onlyLights );
1441 else if( !strcmp( token, "terrainDef" ) )
1444 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1446 else if( !strcmp( token, "brushDef" ) )
1448 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1449 Error( "Old brush format not allowed in new brush format map" );
1450 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1452 /* parse brush primitive */
1453 ParseBrush( onlyLights );
1457 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1458 Error( "New brush format not allowed in old brush format map" );
1459 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1461 /* parse old brush format */
1463 ParseBrush( onlyLights );
1465 entitySourceBrushes++;
1469 /* parse a key / value pair */
1472 /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1473 if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1475 ep->next = mapEnt->epairs;
1476 mapEnt->epairs = ep;
1481 /* ydnar: get classname */
1482 classname = ValueForKey( mapEnt, "classname" );
1484 /* ydnar: only lights? */
1485 if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1491 /* ydnar: determine if this is a func_group */
1492 if( !Q_stricmp( "func_group", classname ) )
1497 /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1498 if( funcGroup || mapEnt->mapEntityNum == 0 )
1500 //% Sys_Printf( "World: %d\n", mapEnt->mapEntityNum );
1501 castShadows = WORLDSPAWN_CAST_SHADOWS;
1502 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1505 /* other entities don't cast any shadows, but recv worldspawn shadows */
1508 //% Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1509 castShadows = ENTITY_CAST_SHADOWS;
1510 recvShadows = ENTITY_RECV_SHADOWS;
1513 /* get explicit shadow flags */
1514 GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1516 /* ydnar: get lightmap scaling value for this entity */
1517 if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1518 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) )
1520 /* get lightmap scale from entity */
1521 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1522 if( lightmapScale <= 0.0f )
1523 lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1524 if( lightmapScale > 0.0f )
1525 Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1528 lightmapScale = 0.0f;
1530 /* ydnar: get cel shader :) for this entity */
1531 value = ValueForKey( mapEnt, "_celshader" );
1532 if( value[ 0 ] == '\0' )
1533 value = ValueForKey( &entities[ 0 ], "_celshader" );
1534 if( value[ 0 ] != '\0' )
1536 sprintf( shader, "textures/%s", value );
1537 celShader = ShaderInfoForShader( shader );
1538 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1543 /* attach stuff to everything in the entity */
1544 for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1546 brush->entityNum = mapEnt->mapEntityNum;
1547 brush->castShadows = castShadows;
1548 brush->recvShadows = recvShadows;
1549 brush->lightmapScale = lightmapScale;
1550 brush->celShader = celShader;
1553 for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1555 patch->entityNum = mapEnt->mapEntityNum;
1556 patch->castShadows = castShadows;
1557 patch->recvShadows = recvShadows;
1558 patch->lightmapScale = lightmapScale;
1559 patch->celShader = celShader;
1562 /* ydnar: gs mods: set entity bounds */
1563 SetEntityBounds( mapEnt );
1565 /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1566 LoadEntityIndexMap( mapEnt );
1568 /* get entity origin and adjust brushes */
1569 GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1570 if( mapEnt->origin[ 0 ] || mapEnt->origin[ 1 ] || mapEnt->origin[ 2 ] )
1571 AdjustBrushesForOrigin( mapEnt );
1573 /* group_info entities are just for editor grouping (fixme: leak!) */
1574 if( !Q_stricmp( "group_info", classname ) )
1580 /* group entities are just for editor convenience, toss all brushes into worldspawn */
1583 MoveBrushesToWorld( mapEnt );
1596 loads a map file into a list of entities
1599 void LoadMapFile( char *filename, qboolean onlyLights )
1603 int oldNumEntities, numMapBrushes;
1607 Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1608 Sys_Printf( "Loading %s\n", filename );
1611 file = SafeOpenRead( filename );
1614 /* load the map file */
1615 LoadScriptFile( filename, -1 );
1619 oldNumEntities = numEntities;
1624 numMapDrawSurfs = 0;
1626 g_bBrushPrimit = BPRIMIT_UNDEFINED;
1628 /* allocate a very large temporary brush for building the brushes as they are loaded */
1629 buildBrush = AllocBrush( MAX_BUILD_SIDES );
1631 /* parse the map file */
1632 while( ParseMapEntity( onlyLights ) );
1637 /* emit some statistics */
1638 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1642 /* set map bounds */
1643 ClearBounds( mapMins, mapMaxs );
1644 for( b = entities[ 0 ].brushes; b; b = b->next )
1646 AddPointToBounds( b->mins, mapMins, mapMaxs );
1647 AddPointToBounds( b->maxs, mapMins, mapMaxs );
1650 /* get brush counts */
1651 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1652 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1653 Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1655 /* emit some statistics */
1656 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1657 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1658 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1659 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1660 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1661 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1662 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1663 Sys_Printf( "%9d areaportals\n", c_areaportals);
1664 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1665 mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1666 mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1668 /* write bogus map */
1670 WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );