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 #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 SnapPlane reenabled by namespace because of multiple reports of
194 q3map2-crashes which were triggered by this patch.
196 SnapNormal( normal );
198 if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
199 *dist = Q_rint( *dist );
206 ydnar: changed to allow a number of test points to be supplied that
207 must be within an epsilon distance of the plane
210 int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
221 SnapPlane( normal, &dist );
222 hash = (PLANE_HASHES - 1) & (int) fabs( dist );
224 /* search the border bins as well */
225 for( i = -1; i <= 1; i++ )
227 h = (hash + i) & (PLANE_HASHES - 1);
228 for( p = planehash[ h ]; p != NULL; p = p->hash_chain )
230 /* do standard plane compare */
231 if( !PlaneEqual( p, normal, dist ) )
234 /* ydnar: uncomment the following line for old-style plane finding */
235 //% return p - mapplanes;
237 /* ydnar: test supplied points against this plane */
238 for( j = 0; j < numPoints; j++ )
240 d = DotProduct( points[ j ], normal ) - dist;
241 if( fabs( d ) > distanceEpsilon )
245 /* found a matching plane */
247 return p - mapplanes;
251 /* none found, so create a new one */
252 return CreateNewFloatPlane( normal, dist );
262 SnapPlane( normal, &dist );
263 for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
265 if( PlaneEqual( p, normal, dist ) )
269 return CreateNewFloatPlane( normal, dist );
278 takes 3 points and finds the plane they lie in
281 int MapPlaneFromPoints( vec3_t *p )
283 vec3_t t1, t2, normal;
287 /* calc plane normal */
288 VectorSubtract( p[ 0 ], p[ 1 ], t1 );
289 VectorSubtract( p[ 2 ], p[ 1 ], t2 );
290 CrossProduct( t1, t2, normal );
291 VectorNormalize( normal, normal );
293 /* calc plane distance */
294 dist = DotProduct( p[ 0 ], normal );
296 /* store the plane */
297 return FindFloatPlane( normal, dist, 3, p );
304 the content flags and compile flags on all sides of a brush should be the same
307 void SetBrushContents( brush_t *b )
309 int contentFlags, compileFlags;
315 /* get initial compile flags from first side */
317 contentFlags = s->contentFlags;
318 compileFlags = s->compileFlags;
319 b->contentShader = s->shaderInfo;
322 /* get the content/compile flags for every side in the brush */
323 for( i = 1; i < b->numsides; i++, s++ )
326 if( s->shaderInfo == NULL )
328 if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
332 /* ydnar: getting rid of this stupid warning */
334 //% Sys_FPrintf( SYS_VRB,"Entity %i, Brush %i: mixed face contentFlags\n", b->entitynum, b->brushnum );
336 /* check for detail & structural */
337 if( (compileFlags & C_DETAIL) && (compileFlags & C_STRUCTURAL) )
339 xml_Select( "Mixed detail and structural (defaulting to structural)", mapEnt->mapEntityNum, entitySourceBrushes, qfalse );
340 compileFlags &= ~C_DETAIL;
343 /* the fulldetail flag will cause detail brushes to be treated like normal brushes */
345 compileFlags &= ~C_DETAIL;
347 /* all translucent brushes that aren't specifically made structural will be detail */
348 if( (compileFlags & C_TRANSLUCENT) && !(compileFlags & C_STRUCTURAL) )
349 compileFlags |= C_DETAIL;
352 if( compileFlags & C_DETAIL )
364 if( compileFlags & C_TRANSLUCENT )
370 if( compileFlags & C_AREAPORTAL )
373 /* set brush flags */
374 b->contentFlags = contentFlags;
375 b->compileFlags = compileFlags;
382 adds any additional planes necessary to allow the brush being
383 built to be expanded against axial bounding boxes
384 ydnar 2003-01-20: added mrelusive fixes
387 void AddBrushBevels( void )
390 int i, j, k, l, order;
400 // add the axial planes
403 for ( axis = 0; axis < 3; axis++ ) {
404 for ( dir = -1; dir <= 1; dir += 2, order++ ) {
405 // see if the plane is allready present
406 for ( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
408 /* ydnar: testing disabling of mre code */
411 if ( mapplanes[s->planenum].normal[axis] >= 0.9999f ) {
416 if ( mapplanes[s->planenum].normal[axis] <= -0.9999f ) {
421 if( (dir > 0 && mapplanes[ s->planenum ].normal[ axis ] == 1.0f ) ||
422 (dir < 0 && mapplanes[ s->planenum ].normal[ axis ] == -1.0f) )
427 if ( i == buildBrush->numsides ) {
429 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
430 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
432 memset( s, 0, sizeof( *s ) );
433 buildBrush->numsides++;
434 VectorClear (normal);
439 /* ydnar: adding bevel plane snapping for fewer bsp planes */
441 dist = floor( buildBrush->maxs[ axis ] / bevelSnap ) * bevelSnap;
443 dist = buildBrush->maxs[ axis ];
447 /* ydnar: adding bevel plane snapping for fewer bsp planes */
449 dist = -ceil( buildBrush->mins[ axis ] / bevelSnap ) * bevelSnap;
451 dist = -buildBrush->mins[ axis ];
454 s->planenum = FindFloatPlane( normal, dist, 0, NULL );
455 s->contentFlags = buildBrush->sides[ 0 ].contentFlags;
460 // if the plane is not in it canonical order, swap it
462 sidetemp = buildBrush->sides[order];
463 buildBrush->sides[order] = buildBrush->sides[i];
464 buildBrush->sides[i] = sidetemp;
470 // add the edge bevels
472 if ( buildBrush->numsides == 6 ) {
473 return; // pure axial
476 // test the non-axial plane edges
477 for ( i = 6; i < buildBrush->numsides; i++ ) {
478 s = buildBrush->sides + i;
483 for ( j = 0; j < w->numpoints; j++) {
484 k = (j+1)%w->numpoints;
485 VectorSubtract( w->p[j], w->p[k], vec );
486 if ( VectorNormalize( vec, vec ) < 0.5f ) {
490 for ( k = 0; k < 3; k++ ) {
491 if ( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f) ) {
496 continue; // only test non-axial edges
500 //% Sys_Printf( "-------------\n" );
502 // try the six possible slanted axials from this edge
503 for ( axis = 0; axis < 3; axis++ ) {
504 for ( dir = -1; dir <= 1; dir += 2 ) {
508 CrossProduct( vec, vec2, normal );
509 if ( VectorNormalize( normal, normal ) < 0.5f ) {
512 dist = DotProduct( w->p[j], normal );
514 // if all the points on all the sides are
515 // behind this plane, it is a proper edge bevel
516 for ( k = 0; k < buildBrush->numsides; k++ ) {
518 // if this plane has allready been used, skip it
519 if ( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ) ) {
523 w2 = buildBrush->sides[k].winding;
528 for ( l = 0; l < w2->numpoints; l++ ) {
529 d = DotProduct( w2->p[l], normal ) - dist;
531 break; // point in front
537 // if some point was at the front
538 if ( l != w2->numpoints ) {
542 // if no points at the back then the winding is on the bevel plane
543 if ( minBack > -0.1f ) {
544 //% Sys_Printf( "On bevel plane\n" );
549 if ( k != buildBrush->numsides ) {
550 continue; // wasn't part of the outer hull
554 //% Sys_Printf( "n = %f %f %f\n", normal[ 0 ], normal[ 1 ], normal[ 2 ] );
557 if( buildBrush->numsides == MAX_BUILD_SIDES ) {
558 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
560 s2 = &buildBrush->sides[buildBrush->numsides];
561 buildBrush->numsides++;
562 memset( s2, 0, sizeof( *s2 ) );
564 s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[ j ] );
565 s2->contentFlags = buildBrush->sides[0].contentFlags;
578 produces a final brush based on the buildBrush->sides array
579 and links it to the current entity
582 brush_t *FinishBrush( void )
587 /* create windings for sides and bounds for brush */
588 if ( !CreateBrushWindings( buildBrush ) )
591 /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
592 after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
593 if( buildBrush->compileFlags & C_ORIGIN )
598 if( numEntities == 1 )
600 Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n",
601 mapEnt->mapEntityNum, entitySourceBrushes );
605 VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
606 VectorScale (origin, 0.5, origin);
608 sprintf( string, "%i %i %i", (int) origin[ 0 ], (int) origin[ 1 ], (int) origin[ 2 ] );
609 SetKeyValue( &entities[ numEntities - 1 ], "origin", string);
611 VectorCopy( origin, entities[ numEntities - 1 ].origin);
613 /* don't keep this brush */
617 /* determine if the brush is an area portal */
618 if( buildBrush->compileFlags & C_AREAPORTAL )
620 if( numEntities != 1 )
622 Sys_Printf ("Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
627 /* add bevel planes */
631 b = CopyBrush( buildBrush );
633 /* set map entity and brush numbering */
634 b->entityNum = mapEnt->mapEntityNum;
635 b->brushNum = entitySourceBrushes;
640 /* link opaque brushes to head of list, translucent brushes to end */
641 if( b->opaque || mapEnt->lastBrush == NULL )
643 b->next = mapEnt->brushes;
645 if( mapEnt->lastBrush == NULL )
646 mapEnt->lastBrush = b;
651 mapEnt->lastBrush->next = b;
652 mapEnt->lastBrush = b;
655 /* link colorMod volume brushes to the entity directly */
656 if( b->contentShader != NULL &&
657 b->contentShader->colorMod != NULL &&
658 b->contentShader->colorMod->type == CM_VOLUME )
660 b->nextColorModBrush = mapEnt->colorModBrushes;
661 mapEnt->colorModBrushes = b;
664 /* return to sender */
671 TextureAxisFromPlane()
672 determines best orthagonal axis to project a texture onto a wall
673 (must be identical in radiant!)
676 vec3_t baseaxis[18] =
678 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
679 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
680 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
681 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
682 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
683 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
686 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv )
695 for (i=0 ; i<6 ; i++)
697 dot = DotProduct (pln->normal, baseaxis[i*3]);
698 if( dot > best + 0.0001f ) /* ydnar: bug 637 fix, suggested by jmonroe */
705 VectorCopy (baseaxis[bestaxis*3+1], xv);
706 VectorCopy (baseaxis[bestaxis*3+2], yv);
713 creates world-to-texture mapping vecs for crappy quake plane arrangements
716 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] )
720 vec_t ang, sinv, cosv;
725 TextureAxisFromPlane(plane, vecs[0], vecs[1]);
734 { sinv = 0 ; cosv = 1; }
735 else if (rotate == 90)
736 { sinv = 1 ; cosv = 0; }
737 else if (rotate == 180)
738 { sinv = 0 ; cosv = -1; }
739 else if (rotate == 270)
740 { sinv = -1 ; cosv = 0; }
743 ang = rotate / 180 * Q_PI;
762 for (i=0 ; i<2 ; i++) {
763 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
764 nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
769 for (i=0 ; i<2 ; i++)
770 for (j=0 ; j<3 ; j++)
771 mappingVecs[i][j] = vecs[i][j] / scale[i];
773 mappingVecs[0][3] = shift[0];
774 mappingVecs[1][3] = shift[1];
781 parses the sides into buildBrush->sides[], nothing else.
782 no validation, back plane removal, etc.
785 added brush epairs parsing ( ignoring actually )
787 added exclusive brush primitive parsing
789 support for old brush format back in
790 NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
793 static void ParseRawBrush( qboolean onlyLights )
796 vec3_t planePoints[ 3 ];
802 char name[ MAX_QPATH ];
803 char shader[ MAX_QPATH ];
808 buildBrush->numsides = 0;
809 buildBrush->detail = qfalse;
812 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
818 if( !GetToken( qtrue ) )
820 if( !strcmp( token, "}" ) )
823 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
824 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
828 if( strcmp( token, "(" ) )
837 /* test side count */
838 if( buildBrush->numsides >= MAX_BUILD_SIDES )
839 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
842 side = &buildBrush->sides[ buildBrush->numsides ];
843 memset( side, 0, sizeof( *side ) );
844 buildBrush->numsides++;
846 /* read the three point plane definition */
847 Parse1DMatrix( 3, planePoints[ 0 ] );
848 Parse1DMatrix( 3, planePoints[ 1 ] );
849 Parse1DMatrix( 3, planePoints[ 2 ] );
851 /* bp: read the texture matrix */
852 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
853 Parse2DMatrix( 2, 3, (float*) side->texMat );
855 /* read shader name */
857 strcpy( name, token );
860 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
863 shift[ 0 ] = atof( token );
865 shift[ 1 ] = atof( token );
867 rotate = atof( token );
869 scale[ 0 ] = atof( token );
871 scale[ 1 ] = atof( token );
874 /* set default flags and values */
875 sprintf( shader, "textures/%s", name );
877 si = &shaderInfo[ 0 ];
879 si = ShaderInfoForShader( shader );
880 side->shaderInfo = si;
881 side->surfaceFlags = si->surfaceFlags;
882 side->contentFlags = si->contentFlags;
883 side->compileFlags = si->compileFlags;
884 side->value = si->value;
886 /* ydnar: gs mods: bias texture shift */
887 if( si->globalTexture == qfalse )
889 shift[ 0 ] -= (floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth);
890 shift[ 1 ] -= (floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight);
894 historically, there are 3 integer values at the end of a brushside line in a .map file.
895 in quake 3, the only thing that mattered was the first of these three values, which
896 was previously the content flags. and only then did a single bit matter, the detail
897 bit. because every game has its own special flags for specifying detail, the
898 traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
899 by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
900 is stored in compileFlags, as opposed to contentFlags, for multiple-game
904 if( TokenAvailable() )
906 /* get detail bit from map content flags */
908 flags = atoi( token );
909 if( flags & C_DETAIL )
910 side->compileFlags |= C_DETAIL;
914 //% td.flags = atoi( token );
916 //% td.value = atoi( token );
919 /* find the plane number */
920 planenum = MapPlaneFromPoints( planePoints );
921 side->planenum = planenum;
923 /* bp: get the texture mapping for this texturedef / plane combination */
924 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
925 QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
929 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
940 RemoveDuplicateBrushPlanes
941 returns false if the brush has a mirrored set of planes,
942 meaning it encloses no volume.
943 also removes planes without any normal
946 qboolean RemoveDuplicateBrushPlanes( brush_t *b )
953 for ( i = 1 ; i < b->numsides ; i++ ) {
955 // check for a degenerate plane
956 if ( sides[i].planenum == -1) {
957 xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
959 for ( k = i + 1 ; k < b->numsides ; k++ ) {
960 sides[k-1] = sides[k];
967 // check for duplication and mirroring
968 for ( j = 0 ; j < i ; j++ ) {
969 if ( sides[i].planenum == sides[j].planenum ) {
970 xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
971 // remove the second duplicate
972 for ( k = i + 1 ; k < b->numsides ; k++ ) {
973 sides[k-1] = sides[k];
980 if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
981 // mirror plane, brush is invalid
982 xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
994 parses a brush out of a map file and sets it up
997 static void ParseBrush( qboolean onlyLights )
1002 /* parse the brush out of the map */
1003 ParseRawBrush( onlyLights );
1005 /* only go this far? */
1009 /* set some defaults */
1010 buildBrush->portalareas[ 0 ] = -1;
1011 buildBrush->portalareas[ 1 ] = -1;
1012 buildBrush->entityNum = numMapEntities - 1;
1013 buildBrush->brushNum = entitySourceBrushes;
1015 /* if there are mirrored planes, the entire brush is invalid */
1016 if( !RemoveDuplicateBrushPlanes( buildBrush ) )
1019 /* get the content for the entire brush */
1020 SetBrushContents( buildBrush );
1022 /* allow detail brushes to be removed */
1023 if( nodetail && (buildBrush->compileFlags & C_DETAIL) )
1025 //% FreeBrush( buildBrush );
1029 /* allow liquid brushes to be removed */
1030 if( nowater && (buildBrush->compileFlags & C_LIQUID ) )
1032 //% FreeBrush( buildBrush );
1036 /* ydnar: allow hint brushes to be removed */
1037 if( noHint && (buildBrush->compileFlags & C_HINT) )
1039 //% FreeBrush( buildBrush );
1043 /* finish the brush */
1050 MoveBrushesToWorld()
1051 takes all of the brushes from the current entity and
1052 adds them to the world's brush list
1053 (used by func_group)
1056 void MoveBrushesToWorld( entity_t *ent )
1063 for( b = ent->brushes; b != NULL; b = next )
1065 /* get next brush */
1068 /* link opaque brushes to head of list, translucent brushes to end */
1069 if( b->opaque || entities[ 0 ].lastBrush == NULL )
1071 b->next = entities[ 0 ].brushes;
1072 entities[ 0 ].brushes = b;
1073 if( entities[ 0 ].lastBrush == NULL )
1074 entities[ 0 ].lastBrush = b;
1079 entities[ 0 ].lastBrush->next = b;
1080 entities[ 0 ].lastBrush = b;
1083 ent->brushes = NULL;
1085 /* ydnar: move colormod brushes */
1086 if( ent->colorModBrushes != NULL )
1088 for( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush );
1090 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1091 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1093 ent->colorModBrushes = NULL;
1097 if( ent->patches != NULL )
1099 for( pm = ent->patches; pm->next != NULL; pm = pm->next );
1101 pm->next = entities[ 0 ].patches;
1102 entities[ 0 ].patches = ent->patches;
1104 ent->patches = NULL;
1111 AdjustBrushesForOrigin()
1114 void AdjustBrushesForOrigin( entity_t *ent )
1124 /* walk brush list */
1125 for( b = ent->brushes; b != NULL; b = b->next )
1127 /* offset brush planes */
1128 for( i = 0; i < b->numsides; i++)
1130 /* get brush side */
1133 /* offset side plane */
1134 newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin );
1136 /* find a new plane */
1137 s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1140 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1141 CreateBrushWindings( b );
1144 /* walk patch list */
1145 for( p = ent->patches; p != NULL; p = p->next )
1147 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1148 VectorSubtract( p->mesh.verts[ i ].xyz, ent->origin, p->mesh.verts[ i ].xyz );
1155 SetEntityBounds() - ydnar
1156 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1159 void SetEntityBounds( entity_t *e )
1170 /* walk the entity's brushes/patches and determine bounds */
1171 ClearBounds( mins, maxs );
1172 for( b = e->brushes; b; b = b->next )
1174 AddPointToBounds( b->mins, mins, maxs );
1175 AddPointToBounds( b->maxs, mins, maxs );
1177 for( p = e->patches; p; p = p->next )
1179 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1180 AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1183 /* try to find explicit min/max key */
1184 value = ValueForKey( e, "min" );
1185 if( value[ 0 ] != '\0' )
1186 GetVectorForKey( e, "min", mins );
1187 value = ValueForKey( e, "max" );
1188 if( value[ 0 ] != '\0' )
1189 GetVectorForKey( e, "max", maxs );
1191 /* store the bounds */
1192 for( b = e->brushes; b; b = b->next )
1194 VectorCopy( mins, b->eMins );
1195 VectorCopy( maxs, b->eMaxs );
1197 for( p = e->patches; p; p = p->next )
1199 VectorCopy( mins, p->eMins );
1200 VectorCopy( maxs, p->eMaxs );
1207 LoadEntityIndexMap() - ydnar
1208 based on LoadAlphaMap() from terrain.c, a little more generic
1211 void LoadEntityIndexMap( entity_t *e )
1213 int i, size, numLayers, w, h;
1214 const char *value, *indexMapFilename, *shader;
1215 char ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1217 unsigned int *pixels32;
1223 /* this only works with bmodel ents */
1224 if( e->brushes == NULL && e->patches == NULL )
1227 /* determine if there is an index map (support legacy "alphamap" key as well) */
1228 value = ValueForKey( e, "_indexmap" );
1229 if( value[ 0 ] == '\0' )
1230 value = ValueForKey( e, "alphamap" );
1231 if( value[ 0 ] == '\0' )
1233 indexMapFilename = value;
1235 /* get number of layers (support legacy "layers" key as well) */
1236 value = ValueForKey( e, "_layers" );
1237 if( value[ 0 ] == '\0' )
1238 value = ValueForKey( e, "layers" );
1239 if( value[ 0 ] == '\0' )
1241 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1242 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1245 numLayers = atoi( value );
1248 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1249 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1253 /* get base shader name (support legacy "shader" key as well) */
1254 value = ValueForKey( mapEnt, "_shader" );
1255 if( value[ 0 ] == '\0' )
1256 value = ValueForKey( e, "shader" );
1257 if( value[ 0 ] == '\0' )
1259 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1260 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1266 Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n", mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1268 /* get index map file extension */
1269 ExtractFileExtension( indexMapFilename, ext );
1271 /* handle tga image */
1272 if( !Q_stricmp( ext, "tga" ) )
1275 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1277 /* convert to bytes */
1279 pixels = safe_malloc( size );
1280 for( i = 0; i < size; i++ )
1282 pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1283 if( pixels[ i ] >= numLayers )
1284 pixels[ i ] = numLayers - 1;
1287 /* free the 32 bit image */
1293 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1296 //% Sys_Printf( "-------------------------------" );
1298 /* fix up out-of-range values */
1300 for( i = 0; i < size; i++ )
1302 if( pixels[ i ] >= numLayers )
1303 pixels[ i ] = numLayers - 1;
1306 //% if( (i % w) == 0 )
1307 //% Sys_Printf( "\n" );
1308 //% Sys_Printf( "%c", pixels[ i ] + '0' );
1312 //% Sys_Printf( "\n-------------------------------\n" );
1315 /* the index map must be at least 2x2 pixels */
1316 if( w < 2 || h < 2 )
1318 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1319 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1324 /* create a new index map */
1325 im = safe_malloc( sizeof( *im ) );
1326 memset( im, 0, sizeof( *im ) );
1331 im->numLayers = numLayers;
1332 strcpy( im->name, indexMapFilename );
1333 strcpy( im->shader, shader );
1334 im->pixels = pixels;
1336 /* get height offsets */
1337 value = ValueForKey( mapEnt, "_offsets" );
1338 if( value[ 0 ] == '\0' )
1339 value = ValueForKey( e, "offsets" );
1340 if( value[ 0 ] != '\0' )
1342 /* value is a space-seperated set of numbers */
1343 strcpy( offset, value );
1346 /* get each value */
1347 for( i = 0; i < 256 && *search != '\0'; i++ )
1349 space = strstr( search, " " );
1352 im->offsets[ i ] = atof( search );
1359 /* store the index map in every brush/patch in the entity */
1360 for( b = e->brushes; b != NULL; b = b->next )
1362 for( p = e->patches; p != NULL; p = p->next )
1374 parses a single entity out of a map file
1377 static qboolean ParseMapEntity( qboolean onlyLights )
1380 const char *classname, *value;
1381 float lightmapScale;
1382 char shader[ MAX_QPATH ];
1383 shaderInfo_t *celShader = NULL;
1387 int castShadows, recvShadows;
1391 if( !GetToken( qtrue ) )
1394 /* conformance check */
1395 if( strcmp( token, "{" ) )
1397 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1398 "Continuing to process map, but resulting BSP may be invalid.\n",
1399 token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1404 if( numEntities >= MAX_MAP_ENTITIES )
1405 Error( "numEntities == MAX_MAP_ENTITIES" );
1408 entitySourceBrushes = 0;
1409 mapEnt = &entities[ numEntities ];
1411 memset( mapEnt, 0, sizeof( *mapEnt ) );
1413 /* ydnar: true entity numbering */
1414 mapEnt->mapEntityNum = numMapEntities;
1420 /* get initial token */
1421 if( !GetToken( qtrue ) )
1423 Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1424 "Continuing to process map, but resulting BSP may be invalid.\n" );
1428 if( !strcmp( token, "}" ) )
1431 if( !strcmp( token, "{" ) )
1433 /* parse a brush or patch */
1434 if( !GetToken( qtrue ) )
1438 if( !strcmp( token, "patchDef2" ) )
1441 ParsePatch( onlyLights );
1443 else if( !strcmp( token, "terrainDef" ) )
1446 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1448 else if( !strcmp( token, "brushDef" ) )
1450 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1451 Error( "Old brush format not allowed in new brush format map" );
1452 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1454 /* parse brush primitive */
1455 ParseBrush( onlyLights );
1459 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1460 Error( "New brush format not allowed in old brush format map" );
1461 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1463 /* parse old brush format */
1465 ParseBrush( onlyLights );
1467 entitySourceBrushes++;
1471 /* parse a key / value pair */
1474 /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1475 if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1477 ep->next = mapEnt->epairs;
1478 mapEnt->epairs = ep;
1483 /* ydnar: get classname */
1484 classname = ValueForKey( mapEnt, "classname" );
1486 /* ydnar: only lights? */
1487 if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1493 /* ydnar: determine if this is a func_group */
1494 if( !Q_stricmp( "func_group", classname ) )
1499 /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1500 if( funcGroup || mapEnt->mapEntityNum == 0 )
1502 //% Sys_Printf( "World: %d\n", mapEnt->mapEntityNum );
1503 castShadows = WORLDSPAWN_CAST_SHADOWS;
1504 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1507 /* other entities don't cast any shadows, but recv worldspawn shadows */
1510 //% Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1511 castShadows = ENTITY_CAST_SHADOWS;
1512 recvShadows = ENTITY_RECV_SHADOWS;
1515 /* get explicit shadow flags */
1516 GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1518 /* ydnar: get lightmap scaling value for this entity */
1519 if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1520 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) )
1522 /* get lightmap scale from entity */
1523 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1524 if( lightmapScale <= 0.0f )
1525 lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1526 if( lightmapScale > 0.0f )
1527 Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1530 lightmapScale = 0.0f;
1532 /* ydnar: get cel shader :) for this entity */
1533 value = ValueForKey( mapEnt, "_celshader" );
1534 if( value[ 0 ] == '\0' )
1535 value = ValueForKey( &entities[ 0 ], "_celshader" );
1536 if( value[ 0 ] != '\0' )
1538 sprintf( shader, "textures/%s", value );
1539 celShader = ShaderInfoForShader( shader );
1540 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1545 /* attach stuff to everything in the entity */
1546 for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1548 brush->entityNum = mapEnt->mapEntityNum;
1549 brush->castShadows = castShadows;
1550 brush->recvShadows = recvShadows;
1551 brush->lightmapScale = lightmapScale;
1552 brush->celShader = celShader;
1555 for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1557 patch->entityNum = mapEnt->mapEntityNum;
1558 patch->castShadows = castShadows;
1559 patch->recvShadows = recvShadows;
1560 patch->lightmapScale = lightmapScale;
1561 patch->celShader = celShader;
1564 /* ydnar: gs mods: set entity bounds */
1565 SetEntityBounds( mapEnt );
1567 /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1568 LoadEntityIndexMap( mapEnt );
1570 /* get entity origin and adjust brushes */
1571 GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1572 if( mapEnt->origin[ 0 ] || mapEnt->origin[ 1 ] || mapEnt->origin[ 2 ] )
1573 AdjustBrushesForOrigin( mapEnt );
1575 /* group_info entities are just for editor grouping (fixme: leak!) */
1576 if( !Q_stricmp( "group_info", classname ) )
1582 /* group entities are just for editor convenience, toss all brushes into worldspawn */
1585 MoveBrushesToWorld( mapEnt );
1598 loads a map file into a list of entities
1601 void LoadMapFile( char *filename, qboolean onlyLights )
1605 int oldNumEntities, numMapBrushes;
1609 Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1610 Sys_Printf( "Loading %s\n", filename );
1613 file = SafeOpenRead( filename );
1616 /* load the map file */
1617 LoadScriptFile( filename, -1 );
1621 oldNumEntities = numEntities;
1626 numMapDrawSurfs = 0;
1628 g_bBrushPrimit = BPRIMIT_UNDEFINED;
1630 /* allocate a very large temporary brush for building the brushes as they are loaded */
1631 buildBrush = AllocBrush( MAX_BUILD_SIDES );
1633 /* parse the map file */
1634 while( ParseMapEntity( onlyLights ) );
1639 /* emit some statistics */
1640 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1644 /* set map bounds */
1645 ClearBounds( mapMins, mapMaxs );
1646 for( b = entities[ 0 ].brushes; b; b = b->next )
1648 AddPointToBounds( b->mins, mapMins, mapMaxs );
1649 AddPointToBounds( b->maxs, mapMins, mapMaxs );
1652 /* get brush counts */
1653 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1654 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1655 Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1657 /* emit some statistics */
1658 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1659 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1660 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1661 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1662 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1663 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1664 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1665 Sys_Printf( "%9d areaportals\n", c_areaportals);
1666 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1667 mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1668 mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1670 /* write bogus map */
1672 WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );