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 int 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];
99 planehash[hash] = p - mapplanes + 1;
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 AUTOEXPAND_BY_REALLOC(mapplanes, nummapplanes+1, allocatedmapplanes, 1024);
120 p = &mapplanes[nummapplanes];
121 VectorCopy (normal, p->normal);
123 p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
125 VectorSubtract (vec3_origin, normal, (p+1)->normal);
130 // allways put axial planes facing positive first
133 if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
141 AddPlaneToHash (p+1);
142 return nummapplanes - 1;
147 AddPlaneToHash (p+1);
148 return nummapplanes - 2;
155 snaps a near-axial normal vector
158 void SnapNormal( vec3_t normal )
162 for( i = 0; i < 3; i++ )
164 if( fabs( normal[ i ] - 1 ) < normalEpsilon )
166 VectorClear( normal );
170 if( fabs( normal[ i ] - -1 ) < normalEpsilon )
172 VectorClear( normal );
183 snaps a plane to normal/distance epsilons
186 void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
188 // SnapPlane disabled by LordHavoc because it often messes up collision
189 // brushes made from triangles of embedded models, and it has little effect
190 // on anything else (axial planes are usually derived from snapped points)
192 SnapPlane reenabled by namespace because of multiple reports of
193 q3map2-crashes which were triggered by this patch.
195 // div0: ensure the point "center" stays on the plane (actually, this
196 // rotates the plane around the point center).
197 // if center lies on the plane, it is guaranteed to stay on the plane by
199 vec_t centerDist = DotProduct(normal, center);
200 SnapNormal( normal );
201 *dist += (DotProduct(normal, center) - centerDist);
203 if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
204 *dist = Q_rint( *dist );
211 ydnar: changed to allow a number of test points to be supplied that
212 must be within an epsilon distance of the plane
215 int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) // NOTE: this has a side effect on the normal. Good or bad?
224 vec3_t centerofweight;
226 VectorClear(centerofweight);
227 for(i = 0; i < numPoints; ++i)
228 VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
231 SnapPlane( normal, &dist, centerofweight );
232 hash = (PLANE_HASHES - 1) & (int) fabs( dist );
234 /* search the border bins as well */
235 for( i = -1; i <= 1; i++ )
237 h = (hash + i) & (PLANE_HASHES - 1);
238 for( pidx = planehash[ h ] - 1; pidx != -1; pidx = mapplanes[pidx].hash_chain - 1 )
240 p = &mapplanes[pidx];
242 /* do standard plane compare */
243 if( !PlaneEqual( p, normal, dist ) )
246 /* ydnar: uncomment the following line for old-style plane finding */
247 //% return p - mapplanes;
249 /* ydnar: test supplied points against this plane */
250 for( j = 0; j < numPoints; j++ )
252 d = DotProduct( points[ j ], normal ) - dist;
253 if( fabs( d ) > distanceEpsilon )
257 /* found a matching plane */
259 return p - mapplanes;
263 /* none found, so create a new one */
264 return CreateNewFloatPlane( normal, dist );
274 vec3_t centerofweight;
276 VectorClear(centerofweight);
277 for(i = 0; i < numPoints; ++i)
278 VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
280 SnapPlane( normal, &dist, centerofweight );
281 for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
283 if( PlaneEqual( p, normal, dist ) )
287 return CreateNewFloatPlane( normal, dist );
296 takes 3 points and finds the plane they lie in
299 int MapPlaneFromPoints( vec3_t *p )
301 vec3_t t1, t2, normal;
305 /* calc plane normal */
306 VectorSubtract( p[ 0 ], p[ 1 ], t1 );
307 VectorSubtract( p[ 2 ], p[ 1 ], t2 );
308 CrossProduct( t1, t2, normal );
309 VectorNormalize( normal, normal );
311 /* calc plane distance */
312 dist = DotProduct( p[ 0 ], normal );
314 /* store the plane */
315 return FindFloatPlane( normal, dist, 3, p );
322 the content flags and compile flags on all sides of a brush should be the same
325 void SetBrushContents( brush_t *b )
327 int contentFlags, compileFlags;
333 /* get initial compile flags from first side */
335 contentFlags = s->contentFlags;
336 compileFlags = s->compileFlags;
337 b->contentShader = s->shaderInfo;
340 /* get the content/compile flags for every side in the brush */
341 for( i = 1; i < b->numsides; i++, s++ )
344 if( s->shaderInfo == NULL )
346 if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
350 /* ydnar: getting rid of this stupid warning */
352 //% Sys_FPrintf( SYS_VRB,"Entity %i, Brush %i: mixed face contentFlags\n", b->entitynum, b->brushnum );
354 /* check for detail & structural */
355 if( (compileFlags & C_DETAIL) && (compileFlags & C_STRUCTURAL) )
357 xml_Select( "Mixed detail and structural (defaulting to structural)", mapEnt->mapEntityNum, entitySourceBrushes, qfalse );
358 compileFlags &= ~C_DETAIL;
361 /* the fulldetail flag will cause detail brushes to be treated like normal brushes */
363 compileFlags &= ~C_DETAIL;
365 /* all translucent brushes that aren't specifically made structural will be detail */
366 if( (compileFlags & C_TRANSLUCENT) && !(compileFlags & C_STRUCTURAL) )
367 compileFlags |= C_DETAIL;
370 if( compileFlags & C_DETAIL )
382 if( compileFlags & C_TRANSLUCENT )
388 if( compileFlags & C_AREAPORTAL )
391 /* set brush flags */
392 b->contentFlags = contentFlags;
393 b->compileFlags = compileFlags;
400 adds any additional planes necessary to allow the brush being
401 built to be expanded against axial bounding boxes
402 ydnar 2003-01-20: added mrelusive fixes
405 void AddBrushBevels( void )
408 int i, j, k, l, order;
418 // add the axial planes
421 for ( axis = 0; axis < 3; axis++ ) {
422 for ( dir = -1; dir <= 1; dir += 2, order++ ) {
423 // see if the plane is allready present
424 for ( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
426 /* ydnar: testing disabling of mre code */
429 if ( mapplanes[s->planenum].normal[axis] >= 0.9999f ) {
434 if ( mapplanes[s->planenum].normal[axis] <= -0.9999f ) {
439 if( (dir > 0 && mapplanes[ s->planenum ].normal[ axis ] == 1.0f ) ||
440 (dir < 0 && mapplanes[ s->planenum ].normal[ axis ] == -1.0f) )
445 if ( i == buildBrush->numsides ) {
447 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
448 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
450 memset( s, 0, sizeof( *s ) );
451 buildBrush->numsides++;
452 VectorClear (normal);
457 /* ydnar: adding bevel plane snapping for fewer bsp planes */
459 dist = floor( buildBrush->maxs[ axis ] / bevelSnap ) * bevelSnap;
461 dist = buildBrush->maxs[ axis ];
465 /* ydnar: adding bevel plane snapping for fewer bsp planes */
467 dist = -ceil( buildBrush->mins[ axis ] / bevelSnap ) * bevelSnap;
469 dist = -buildBrush->mins[ axis ];
472 s->planenum = FindFloatPlane( normal, dist, 0, NULL );
473 s->contentFlags = buildBrush->sides[ 0 ].contentFlags;
478 // if the plane is not in it canonical order, swap it
480 sidetemp = buildBrush->sides[order];
481 buildBrush->sides[order] = buildBrush->sides[i];
482 buildBrush->sides[i] = sidetemp;
488 // add the edge bevels
490 if ( buildBrush->numsides == 6 ) {
491 return; // pure axial
494 // test the non-axial plane edges
495 for ( i = 6; i < buildBrush->numsides; i++ ) {
496 s = buildBrush->sides + i;
501 for ( j = 0; j < w->numpoints; j++) {
502 k = (j+1)%w->numpoints;
503 VectorSubtract( w->p[j], w->p[k], vec );
504 if ( VectorNormalize( vec, vec ) < 0.5f ) {
508 for ( k = 0; k < 3; k++ ) {
509 if ( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f) ) {
514 continue; // only test non-axial edges
518 //% Sys_Printf( "-------------\n" );
520 // try the six possible slanted axials from this edge
521 for ( axis = 0; axis < 3; axis++ ) {
522 for ( dir = -1; dir <= 1; dir += 2 ) {
526 CrossProduct( vec, vec2, normal );
527 if ( VectorNormalize( normal, normal ) < 0.5f ) {
530 dist = DotProduct( w->p[j], normal );
532 // if all the points on all the sides are
533 // behind this plane, it is a proper edge bevel
534 for ( k = 0; k < buildBrush->numsides; k++ ) {
536 // if this plane has allready been used, skip it
537 if ( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ) ) {
541 w2 = buildBrush->sides[k].winding;
546 for ( l = 0; l < w2->numpoints; l++ ) {
547 d = DotProduct( w2->p[l], normal ) - dist;
549 break; // point in front
555 // if some point was at the front
556 if ( l != w2->numpoints ) {
560 // if no points at the back then the winding is on the bevel plane
561 if ( minBack > -0.1f ) {
562 //% Sys_Printf( "On bevel plane\n" );
567 if ( k != buildBrush->numsides ) {
568 continue; // wasn't part of the outer hull
572 //% Sys_Printf( "n = %f %f %f\n", normal[ 0 ], normal[ 1 ], normal[ 2 ] );
575 if( buildBrush->numsides == MAX_BUILD_SIDES ) {
576 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
578 s2 = &buildBrush->sides[buildBrush->numsides];
579 buildBrush->numsides++;
580 memset( s2, 0, sizeof( *s2 ) );
582 s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[ j ] );
583 s2->contentFlags = buildBrush->sides[0].contentFlags;
596 produces a final brush based on the buildBrush->sides array
597 and links it to the current entity
600 static void MergeOrigin(entity_t *ent, vec3_t origin)
604 /* we have not parsed the brush completely yet... */
605 GetVectorForKey( ent, "origin", ent->origin );
607 VectorMA(origin, -1, ent->originbrush_origin, adjustment);
608 VectorAdd(adjustment, ent->origin, ent->origin);
609 VectorCopy(origin, ent->originbrush_origin);
612 sprintf(string, "%f %f %f", ent->origin[0], ent->origin[1], ent->origin[2]);
613 SetKeyValue(ent, "origin", string);
616 brush_t *FinishBrush( void )
621 /* create windings for sides and bounds for brush */
622 if ( !CreateBrushWindings( buildBrush ) )
625 /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
626 after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
627 if( buildBrush->compileFlags & C_ORIGIN )
632 Sys_Printf( "Entity %i, Brush %i: origin brush detected\n",
633 mapEnt->mapEntityNum, entitySourceBrushes );
635 if( numEntities == 1 )
637 Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n",
638 mapEnt->mapEntityNum, entitySourceBrushes );
642 VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
643 VectorScale (origin, 0.5, origin);
645 MergeOrigin(&entities[ numEntities - 1 ], origin);
647 /* don't keep this brush */
651 /* determine if the brush is an area portal */
652 if( buildBrush->compileFlags & C_AREAPORTAL )
654 if( numEntities != 1 )
656 Sys_Printf ("Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
661 /* add bevel planes */
665 b = CopyBrush( buildBrush );
667 /* set map entity and brush numbering */
668 b->entityNum = mapEnt->mapEntityNum;
669 b->brushNum = entitySourceBrushes;
674 /* link opaque brushes to head of list, translucent brushes to end */
675 if( b->opaque || mapEnt->lastBrush == NULL )
677 b->next = mapEnt->brushes;
679 if( mapEnt->lastBrush == NULL )
680 mapEnt->lastBrush = b;
685 mapEnt->lastBrush->next = b;
686 mapEnt->lastBrush = b;
689 /* link colorMod volume brushes to the entity directly */
690 if( b->contentShader != NULL &&
691 b->contentShader->colorMod != NULL &&
692 b->contentShader->colorMod->type == CM_VOLUME )
694 b->nextColorModBrush = mapEnt->colorModBrushes;
695 mapEnt->colorModBrushes = b;
698 /* return to sender */
705 TextureAxisFromPlane()
706 determines best orthagonal axis to project a texture onto a wall
707 (must be identical in radiant!)
710 vec3_t baseaxis[18] =
712 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
713 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
714 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
715 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
716 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
717 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
720 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv )
729 for (i=0 ; i<6 ; i++)
731 dot = DotProduct (pln->normal, baseaxis[i*3]);
732 if( dot > best + 0.0001f ) /* ydnar: bug 637 fix, suggested by jmonroe */
739 VectorCopy (baseaxis[bestaxis*3+1], xv);
740 VectorCopy (baseaxis[bestaxis*3+2], yv);
747 creates world-to-texture mapping vecs for crappy quake plane arrangements
750 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] )
754 vec_t ang, sinv, cosv;
759 TextureAxisFromPlane(plane, vecs[0], vecs[1]);
768 { sinv = 0 ; cosv = 1; }
769 else if (rotate == 90)
770 { sinv = 1 ; cosv = 0; }
771 else if (rotate == 180)
772 { sinv = 0 ; cosv = -1; }
773 else if (rotate == 270)
774 { sinv = -1 ; cosv = 0; }
777 ang = rotate / 180 * Q_PI;
796 for (i=0 ; i<2 ; i++) {
797 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
798 nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
803 for (i=0 ; i<2 ; i++)
804 for (j=0 ; j<3 ; j++)
805 mappingVecs[i][j] = vecs[i][j] / scale[i];
807 mappingVecs[0][3] = shift[0];
808 mappingVecs[1][3] = shift[1];
815 parses the sides into buildBrush->sides[], nothing else.
816 no validation, back plane removal, etc.
819 added brush epairs parsing ( ignoring actually )
821 added exclusive brush primitive parsing
823 support for old brush format back in
824 NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
827 static void ParseRawBrush( qboolean onlyLights )
830 vec3_t planePoints[ 3 ];
836 char name[ MAX_QPATH ];
837 char shader[ MAX_QPATH ];
842 buildBrush->numsides = 0;
843 buildBrush->detail = qfalse;
846 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
852 if( !GetToken( qtrue ) )
854 if( !strcmp( token, "}" ) )
857 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
858 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
862 if( strcmp( token, "(" ) )
871 /* test side count */
872 if( buildBrush->numsides >= MAX_BUILD_SIDES )
873 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
876 side = &buildBrush->sides[ buildBrush->numsides ];
877 memset( side, 0, sizeof( *side ) );
878 buildBrush->numsides++;
880 /* read the three point plane definition */
881 Parse1DMatrix( 3, planePoints[ 0 ] );
882 Parse1DMatrix( 3, planePoints[ 1 ] );
883 Parse1DMatrix( 3, planePoints[ 2 ] );
885 /* bp: read the texture matrix */
886 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
887 Parse2DMatrix( 2, 3, (float*) side->texMat );
889 /* read shader name */
891 strcpy( name, token );
894 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
897 shift[ 0 ] = atof( token );
899 shift[ 1 ] = atof( token );
901 rotate = atof( token );
903 scale[ 0 ] = atof( token );
905 scale[ 1 ] = atof( token );
908 /* set default flags and values */
909 sprintf( shader, "textures/%s", name );
911 si = &shaderInfo[ 0 ];
913 si = ShaderInfoForShader( shader );
914 side->shaderInfo = si;
915 side->surfaceFlags = si->surfaceFlags;
916 side->contentFlags = si->contentFlags;
917 side->compileFlags = si->compileFlags;
918 side->value = si->value;
920 /* ydnar: gs mods: bias texture shift */
921 if( si->globalTexture == qfalse )
923 shift[ 0 ] -= (floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth);
924 shift[ 1 ] -= (floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight);
928 historically, there are 3 integer values at the end of a brushside line in a .map file.
929 in quake 3, the only thing that mattered was the first of these three values, which
930 was previously the content flags. and only then did a single bit matter, the detail
931 bit. because every game has its own special flags for specifying detail, the
932 traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
933 by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
934 is stored in compileFlags, as opposed to contentFlags, for multiple-game
938 if( TokenAvailable() )
940 /* get detail bit from map content flags */
942 flags = atoi( token );
943 if( flags & C_DETAIL )
944 side->compileFlags |= C_DETAIL;
948 //% td.flags = atoi( token );
950 //% td.value = atoi( token );
953 /* find the plane number */
954 planenum = MapPlaneFromPoints( planePoints );
955 side->planenum = planenum;
957 /* bp: get the texture mapping for this texturedef / plane combination */
958 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
959 QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
963 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
974 RemoveDuplicateBrushPlanes
975 returns false if the brush has a mirrored set of planes,
976 meaning it encloses no volume.
977 also removes planes without any normal
980 qboolean RemoveDuplicateBrushPlanes( brush_t *b )
987 for ( i = 1 ; i < b->numsides ; i++ ) {
989 // check for a degenerate plane
990 if ( sides[i].planenum == -1) {
991 xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
993 for ( k = i + 1 ; k < b->numsides ; k++ ) {
994 sides[k-1] = sides[k];
1001 // check for duplication and mirroring
1002 for ( j = 0 ; j < i ; j++ ) {
1003 if ( sides[i].planenum == sides[j].planenum ) {
1004 xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
1005 // remove the second duplicate
1006 for ( k = i + 1 ; k < b->numsides ; k++ ) {
1007 sides[k-1] = sides[k];
1014 if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
1015 // mirror plane, brush is invalid
1016 xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
1028 parses a brush out of a map file and sets it up
1031 static void ParseBrush( qboolean onlyLights )
1036 /* parse the brush out of the map */
1037 ParseRawBrush( onlyLights );
1039 /* only go this far? */
1043 /* set some defaults */
1044 buildBrush->portalareas[ 0 ] = -1;
1045 buildBrush->portalareas[ 1 ] = -1;
1046 buildBrush->entityNum = numMapEntities - 1;
1047 buildBrush->brushNum = entitySourceBrushes;
1049 /* if there are mirrored planes, the entire brush is invalid */
1050 if( !RemoveDuplicateBrushPlanes( buildBrush ) )
1053 /* get the content for the entire brush */
1054 SetBrushContents( buildBrush );
1056 /* allow detail brushes to be removed */
1057 if( nodetail && (buildBrush->compileFlags & C_DETAIL) )
1059 //% FreeBrush( buildBrush );
1063 /* allow liquid brushes to be removed */
1064 if( nowater && (buildBrush->compileFlags & C_LIQUID ) )
1066 //% FreeBrush( buildBrush );
1070 /* ydnar: allow hint brushes to be removed */
1071 if( noHint && (buildBrush->compileFlags & C_HINT) )
1073 //% FreeBrush( buildBrush );
1077 /* finish the brush */
1084 MoveBrushesToWorld()
1085 takes all of the brushes from the current entity and
1086 adds them to the world's brush list
1087 (used by func_group)
1090 void AdjustBrushesForOrigin( entity_t *ent );
1091 void MoveBrushesToWorld( entity_t *ent )
1096 /* we need to undo the common/origin adjustment, and instead shift them by the entity key origin */
1097 VectorScale(ent->origin, -1, ent->originbrush_origin);
1098 AdjustBrushesForOrigin(ent);
1099 VectorClear(ent->originbrush_origin);
1102 for( b = ent->brushes; b != NULL; b = next )
1104 /* get next brush */
1107 /* link opaque brushes to head of list, translucent brushes to end */
1108 if( b->opaque || entities[ 0 ].lastBrush == NULL )
1110 b->next = entities[ 0 ].brushes;
1111 entities[ 0 ].brushes = b;
1112 if( entities[ 0 ].lastBrush == NULL )
1113 entities[ 0 ].lastBrush = b;
1118 entities[ 0 ].lastBrush->next = b;
1119 entities[ 0 ].lastBrush = b;
1122 ent->brushes = NULL;
1124 /* ydnar: move colormod brushes */
1125 if( ent->colorModBrushes != NULL )
1127 for( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush );
1129 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1130 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1132 ent->colorModBrushes = NULL;
1136 if( ent->patches != NULL )
1138 for( pm = ent->patches; pm->next != NULL; pm = pm->next );
1140 pm->next = entities[ 0 ].patches;
1141 entities[ 0 ].patches = ent->patches;
1143 ent->patches = NULL;
1150 AdjustBrushesForOrigin()
1153 void AdjustBrushesForOrigin( entity_t *ent )
1162 /* walk brush list */
1163 for( b = ent->brushes; b != NULL; b = b->next )
1165 /* offset brush planes */
1166 for( i = 0; i < b->numsides; i++)
1168 /* get brush side */
1171 /* offset side plane */
1172 newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->originbrush_origin );
1174 /* find a new plane */
1175 s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1178 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1179 CreateBrushWindings( b );
1182 /* walk patch list */
1183 for( p = ent->patches; p != NULL; p = p->next )
1185 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1186 VectorSubtract( p->mesh.verts[ i ].xyz, ent->originbrush_origin, p->mesh.verts[ i ].xyz );
1193 SetEntityBounds() - ydnar
1194 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1197 void SetEntityBounds( entity_t *e )
1208 /* walk the entity's brushes/patches and determine bounds */
1209 ClearBounds( mins, maxs );
1210 for( b = e->brushes; b; b = b->next )
1212 AddPointToBounds( b->mins, mins, maxs );
1213 AddPointToBounds( b->maxs, mins, maxs );
1215 for( p = e->patches; p; p = p->next )
1217 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1218 AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1221 /* try to find explicit min/max key */
1222 value = ValueForKey( e, "min" );
1223 if( value[ 0 ] != '\0' )
1224 GetVectorForKey( e, "min", mins );
1225 value = ValueForKey( e, "max" );
1226 if( value[ 0 ] != '\0' )
1227 GetVectorForKey( e, "max", maxs );
1229 /* store the bounds */
1230 for( b = e->brushes; b; b = b->next )
1232 VectorCopy( mins, b->eMins );
1233 VectorCopy( maxs, b->eMaxs );
1235 for( p = e->patches; p; p = p->next )
1237 VectorCopy( mins, p->eMins );
1238 VectorCopy( maxs, p->eMaxs );
1245 LoadEntityIndexMap() - ydnar
1246 based on LoadAlphaMap() from terrain.c, a little more generic
1249 void LoadEntityIndexMap( entity_t *e )
1251 int i, size, numLayers, w, h;
1252 const char *value, *indexMapFilename, *shader;
1253 char ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1255 unsigned int *pixels32;
1261 /* this only works with bmodel ents */
1262 if( e->brushes == NULL && e->patches == NULL )
1265 /* determine if there is an index map (support legacy "alphamap" key as well) */
1266 value = ValueForKey( e, "_indexmap" );
1267 if( value[ 0 ] == '\0' )
1268 value = ValueForKey( e, "alphamap" );
1269 if( value[ 0 ] == '\0' )
1271 indexMapFilename = value;
1273 /* get number of layers (support legacy "layers" key as well) */
1274 value = ValueForKey( e, "_layers" );
1275 if( value[ 0 ] == '\0' )
1276 value = ValueForKey( e, "layers" );
1277 if( value[ 0 ] == '\0' )
1279 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1280 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1283 numLayers = atoi( value );
1286 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1287 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1291 /* get base shader name (support legacy "shader" key as well) */
1292 value = ValueForKey( mapEnt, "_shader" );
1293 if( value[ 0 ] == '\0' )
1294 value = ValueForKey( e, "shader" );
1295 if( value[ 0 ] == '\0' )
1297 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1298 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1304 Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n", mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1306 /* get index map file extension */
1307 ExtractFileExtension( indexMapFilename, ext );
1309 /* handle tga image */
1310 if( !Q_stricmp( ext, "tga" ) )
1313 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1315 /* convert to bytes */
1317 pixels = safe_malloc( size );
1318 for( i = 0; i < size; i++ )
1320 pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1321 if( pixels[ i ] >= numLayers )
1322 pixels[ i ] = numLayers - 1;
1325 /* free the 32 bit image */
1331 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1334 //% Sys_Printf( "-------------------------------" );
1336 /* fix up out-of-range values */
1338 for( i = 0; i < size; i++ )
1340 if( pixels[ i ] >= numLayers )
1341 pixels[ i ] = numLayers - 1;
1344 //% if( (i % w) == 0 )
1345 //% Sys_Printf( "\n" );
1346 //% Sys_Printf( "%c", pixels[ i ] + '0' );
1350 //% Sys_Printf( "\n-------------------------------\n" );
1353 /* the index map must be at least 2x2 pixels */
1354 if( w < 2 || h < 2 )
1356 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1357 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1362 /* create a new index map */
1363 im = safe_malloc( sizeof( *im ) );
1364 memset( im, 0, sizeof( *im ) );
1369 im->numLayers = numLayers;
1370 strcpy( im->name, indexMapFilename );
1371 strcpy( im->shader, shader );
1372 im->pixels = pixels;
1374 /* get height offsets */
1375 value = ValueForKey( mapEnt, "_offsets" );
1376 if( value[ 0 ] == '\0' )
1377 value = ValueForKey( e, "offsets" );
1378 if( value[ 0 ] != '\0' )
1380 /* value is a space-seperated set of numbers */
1381 strcpy( offset, value );
1384 /* get each value */
1385 for( i = 0; i < 256 && *search != '\0'; i++ )
1387 space = strstr( search, " " );
1390 im->offsets[ i ] = atof( search );
1397 /* store the index map in every brush/patch in the entity */
1398 for( b = e->brushes; b != NULL; b = b->next )
1400 for( p = e->patches; p != NULL; p = p->next )
1412 parses a single entity out of a map file
1415 static qboolean ParseMapEntity( qboolean onlyLights )
1418 const char *classname, *value;
1419 float lightmapScale;
1420 char shader[ MAX_QPATH ];
1421 shaderInfo_t *celShader = NULL;
1425 int castShadows, recvShadows;
1429 if( !GetToken( qtrue ) )
1432 /* conformance check */
1433 if( strcmp( token, "{" ) )
1435 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1436 "Continuing to process map, but resulting BSP may be invalid.\n",
1437 token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1442 if( numEntities >= MAX_MAP_ENTITIES )
1443 Error( "numEntities == MAX_MAP_ENTITIES" );
1446 entitySourceBrushes = 0;
1447 mapEnt = &entities[ numEntities ];
1449 memset( mapEnt, 0, sizeof( *mapEnt ) );
1451 /* ydnar: true entity numbering */
1452 mapEnt->mapEntityNum = numMapEntities;
1458 /* get initial token */
1459 if( !GetToken( qtrue ) )
1461 Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1462 "Continuing to process map, but resulting BSP may be invalid.\n" );
1466 if( !strcmp( token, "}" ) )
1469 if( !strcmp( token, "{" ) )
1471 /* parse a brush or patch */
1472 if( !GetToken( qtrue ) )
1476 if( !strcmp( token, "patchDef2" ) )
1479 ParsePatch( onlyLights );
1481 else if( !strcmp( token, "terrainDef" ) )
1484 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1486 else if( !strcmp( token, "brushDef" ) )
1488 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1489 Error( "Old brush format not allowed in new brush format map" );
1490 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1492 /* parse brush primitive */
1493 ParseBrush( onlyLights );
1497 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1498 Error( "New brush format not allowed in old brush format map" );
1499 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1501 /* parse old brush format */
1503 ParseBrush( onlyLights );
1505 entitySourceBrushes++;
1509 /* parse a key / value pair */
1512 /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1513 if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1515 ep->next = mapEnt->epairs;
1516 mapEnt->epairs = ep;
1521 /* ydnar: get classname */
1522 classname = ValueForKey( mapEnt, "classname" );
1524 /* ydnar: only lights? */
1525 if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1531 /* ydnar: determine if this is a func_group */
1532 if( !Q_stricmp( "func_group", classname ) )
1537 /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1538 if( funcGroup || mapEnt->mapEntityNum == 0 )
1540 //% Sys_Printf( "World: %d\n", mapEnt->mapEntityNum );
1541 castShadows = WORLDSPAWN_CAST_SHADOWS;
1542 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1545 /* other entities don't cast any shadows, but recv worldspawn shadows */
1548 //% Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1549 castShadows = ENTITY_CAST_SHADOWS;
1550 recvShadows = ENTITY_RECV_SHADOWS;
1553 /* get explicit shadow flags */
1554 GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1556 /* ydnar: get lightmap scaling value for this entity */
1557 if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1558 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) )
1560 /* get lightmap scale from entity */
1561 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1562 if( lightmapScale <= 0.0f )
1563 lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1564 if( lightmapScale > 0.0f )
1565 Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1568 lightmapScale = 0.0f;
1570 /* ydnar: get cel shader :) for this entity */
1571 value = ValueForKey( mapEnt, "_celshader" );
1572 if( value[ 0 ] == '\0' )
1573 value = ValueForKey( &entities[ 0 ], "_celshader" );
1574 if( value[ 0 ] != '\0' )
1576 sprintf( shader, "textures/%s", value );
1577 celShader = ShaderInfoForShader( shader );
1578 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1581 celShader = *globalCelShader ? ShaderInfoForShader(globalCelShader) : NULL;
1583 /* attach stuff to everything in the entity */
1584 for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1586 brush->entityNum = mapEnt->mapEntityNum;
1587 brush->castShadows = castShadows;
1588 brush->recvShadows = recvShadows;
1589 brush->lightmapScale = lightmapScale;
1590 brush->celShader = celShader;
1593 for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1595 patch->entityNum = mapEnt->mapEntityNum;
1596 patch->castShadows = castShadows;
1597 patch->recvShadows = recvShadows;
1598 patch->lightmapScale = lightmapScale;
1599 patch->celShader = celShader;
1602 /* ydnar: gs mods: set entity bounds */
1603 SetEntityBounds( mapEnt );
1605 /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1606 LoadEntityIndexMap( mapEnt );
1608 /* get entity origin and adjust brushes */
1609 GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1610 if( mapEnt->originbrush_origin[ 0 ] || mapEnt->originbrush_origin[ 1 ] || mapEnt->originbrush_origin[ 2 ] )
1611 AdjustBrushesForOrigin( mapEnt );
1613 /* group_info entities are just for editor grouping (fixme: leak!) */
1614 if( !Q_stricmp( "group_info", classname ) )
1620 /* group entities are just for editor convenience, toss all brushes into worldspawn */
1623 MoveBrushesToWorld( mapEnt );
1636 loads a map file into a list of entities
1639 void LoadMapFile( char *filename, qboolean onlyLights )
1643 int oldNumEntities, numMapBrushes;
1647 Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1648 Sys_Printf( "Loading %s\n", filename );
1651 file = SafeOpenRead( filename );
1654 /* load the map file */
1655 LoadScriptFile( filename, -1 );
1659 oldNumEntities = numEntities;
1664 numMapDrawSurfs = 0;
1666 g_bBrushPrimit = BPRIMIT_UNDEFINED;
1668 /* allocate a very large temporary brush for building the brushes as they are loaded */
1669 buildBrush = AllocBrush( MAX_BUILD_SIDES );
1671 /* parse the map file */
1672 while( ParseMapEntity( onlyLights ) );
1677 /* emit some statistics */
1678 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1682 /* set map bounds */
1683 ClearBounds( mapMins, mapMaxs );
1684 for( b = entities[ 0 ].brushes; b; b = b->next )
1686 AddPointToBounds( b->mins, mapMins, mapMaxs );
1687 AddPointToBounds( b->maxs, mapMins, mapMaxs );
1690 /* get brush counts */
1691 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1692 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1693 Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1695 /* emit some statistics */
1696 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1697 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1698 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1699 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1700 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1701 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1702 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1703 Sys_Printf( "%9d areaportals\n", c_areaportals);
1704 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1705 mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1706 mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1708 /* write bogus map */
1710 WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );