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, vec3_t center )
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 // div0: ensure the point "center" stays on the plane (actually, this
197 // rotates the plane around the point center).
198 // if center lies on the plane, it is guaranteed to stay on the plane by
200 vec_t centerDist = DotProduct(normal, center);
201 SnapNormal( normal );
202 *dist += (DotProduct(normal, center) - centerDist);
204 if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
205 *dist = Q_rint( *dist );
212 ydnar: changed to allow a number of test points to be supplied that
213 must be within an epsilon distance of the plane
216 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( p = planehash[ h ]; p != NULL; p = p->hash_chain )
240 /* do standard plane compare */
241 if( !PlaneEqual( p, normal, dist ) )
244 /* ydnar: uncomment the following line for old-style plane finding */
245 //% return p - mapplanes;
247 /* ydnar: test supplied points against this plane */
248 for( j = 0; j < numPoints; j++ )
250 d = DotProduct( points[ j ], normal ) - dist;
251 if( fabs( d ) > distanceEpsilon )
255 /* found a matching plane */
257 return p - mapplanes;
261 /* none found, so create a new one */
262 return CreateNewFloatPlane( normal, dist );
272 vec3_t centerofweight;
274 VectorClear(centerofweight);
275 for(i = 0; i < numPoints; ++i)
276 VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
278 SnapPlane( normal, &dist, centerofweight );
279 for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
281 if( PlaneEqual( p, normal, dist ) )
285 return CreateNewFloatPlane( normal, dist );
294 takes 3 points and finds the plane they lie in
297 int MapPlaneFromPoints( vec3_t *p )
299 vec3_t t1, t2, normal;
303 /* calc plane normal */
304 VectorSubtract( p[ 0 ], p[ 1 ], t1 );
305 VectorSubtract( p[ 2 ], p[ 1 ], t2 );
306 CrossProduct( t1, t2, normal );
307 VectorNormalize( normal, normal );
309 /* calc plane distance */
310 dist = DotProduct( p[ 0 ], normal );
312 /* store the plane */
313 return FindFloatPlane( normal, dist, 3, p );
320 the content flags and compile flags on all sides of a brush should be the same
323 void SetBrushContents( brush_t *b )
325 int contentFlags, compileFlags;
331 /* get initial compile flags from first side */
333 contentFlags = s->contentFlags;
334 compileFlags = s->compileFlags;
335 b->contentShader = s->shaderInfo;
338 /* get the content/compile flags for every side in the brush */
339 for( i = 1; i < b->numsides; i++, s++ )
342 if( s->shaderInfo == NULL )
344 if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
348 /* ydnar: getting rid of this stupid warning */
350 //% Sys_FPrintf( SYS_VRB,"Entity %i, Brush %i: mixed face contentFlags\n", b->entitynum, b->brushnum );
352 /* check for detail & structural */
353 if( (compileFlags & C_DETAIL) && (compileFlags & C_STRUCTURAL) )
355 xml_Select( "Mixed detail and structural (defaulting to structural)", mapEnt->mapEntityNum, entitySourceBrushes, qfalse );
356 compileFlags &= ~C_DETAIL;
359 /* the fulldetail flag will cause detail brushes to be treated like normal brushes */
361 compileFlags &= ~C_DETAIL;
363 /* all translucent brushes that aren't specifically made structural will be detail */
364 if( (compileFlags & C_TRANSLUCENT) && !(compileFlags & C_STRUCTURAL) )
365 compileFlags |= C_DETAIL;
368 if( compileFlags & C_DETAIL )
380 if( compileFlags & C_TRANSLUCENT )
386 if( compileFlags & C_AREAPORTAL )
389 /* set brush flags */
390 b->contentFlags = contentFlags;
391 b->compileFlags = compileFlags;
398 adds any additional planes necessary to allow the brush being
399 built to be expanded against axial bounding boxes
400 ydnar 2003-01-20: added mrelusive fixes
403 void AddBrushBevels( void )
406 int i, j, k, l, order;
416 // add the axial planes
419 for ( axis = 0; axis < 3; axis++ ) {
420 for ( dir = -1; dir <= 1; dir += 2, order++ ) {
421 // see if the plane is allready present
422 for ( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
424 /* ydnar: testing disabling of mre code */
427 if ( mapplanes[s->planenum].normal[axis] >= 0.9999f ) {
432 if ( mapplanes[s->planenum].normal[axis] <= -0.9999f ) {
437 if( (dir > 0 && mapplanes[ s->planenum ].normal[ axis ] == 1.0f ) ||
438 (dir < 0 && mapplanes[ s->planenum ].normal[ axis ] == -1.0f) )
443 if ( i == buildBrush->numsides ) {
445 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
446 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
448 memset( s, 0, sizeof( *s ) );
449 buildBrush->numsides++;
450 VectorClear (normal);
455 /* ydnar: adding bevel plane snapping for fewer bsp planes */
457 dist = floor( buildBrush->maxs[ axis ] / bevelSnap ) * bevelSnap;
459 dist = buildBrush->maxs[ axis ];
463 /* ydnar: adding bevel plane snapping for fewer bsp planes */
465 dist = -ceil( buildBrush->mins[ axis ] / bevelSnap ) * bevelSnap;
467 dist = -buildBrush->mins[ axis ];
470 s->planenum = FindFloatPlane( normal, dist, 0, NULL );
471 s->contentFlags = buildBrush->sides[ 0 ].contentFlags;
476 // if the plane is not in it canonical order, swap it
478 sidetemp = buildBrush->sides[order];
479 buildBrush->sides[order] = buildBrush->sides[i];
480 buildBrush->sides[i] = sidetemp;
486 // add the edge bevels
488 if ( buildBrush->numsides == 6 ) {
489 return; // pure axial
492 // test the non-axial plane edges
493 for ( i = 6; i < buildBrush->numsides; i++ ) {
494 s = buildBrush->sides + i;
499 for ( j = 0; j < w->numpoints; j++) {
500 k = (j+1)%w->numpoints;
501 VectorSubtract( w->p[j], w->p[k], vec );
502 if ( VectorNormalize( vec, vec ) < 0.5f ) {
506 for ( k = 0; k < 3; k++ ) {
507 if ( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f) ) {
512 continue; // only test non-axial edges
516 //% Sys_Printf( "-------------\n" );
518 // try the six possible slanted axials from this edge
519 for ( axis = 0; axis < 3; axis++ ) {
520 for ( dir = -1; dir <= 1; dir += 2 ) {
524 CrossProduct( vec, vec2, normal );
525 if ( VectorNormalize( normal, normal ) < 0.5f ) {
528 dist = DotProduct( w->p[j], normal );
530 // if all the points on all the sides are
531 // behind this plane, it is a proper edge bevel
532 for ( k = 0; k < buildBrush->numsides; k++ ) {
534 // if this plane has allready been used, skip it
535 if ( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ) ) {
539 w2 = buildBrush->sides[k].winding;
544 for ( l = 0; l < w2->numpoints; l++ ) {
545 d = DotProduct( w2->p[l], normal ) - dist;
547 break; // point in front
553 // if some point was at the front
554 if ( l != w2->numpoints ) {
558 // if no points at the back then the winding is on the bevel plane
559 if ( minBack > -0.1f ) {
560 //% Sys_Printf( "On bevel plane\n" );
565 if ( k != buildBrush->numsides ) {
566 continue; // wasn't part of the outer hull
570 //% Sys_Printf( "n = %f %f %f\n", normal[ 0 ], normal[ 1 ], normal[ 2 ] );
573 if( buildBrush->numsides == MAX_BUILD_SIDES ) {
574 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
576 s2 = &buildBrush->sides[buildBrush->numsides];
577 buildBrush->numsides++;
578 memset( s2, 0, sizeof( *s2 ) );
580 s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[ j ] );
581 s2->contentFlags = buildBrush->sides[0].contentFlags;
594 produces a final brush based on the buildBrush->sides array
595 and links it to the current entity
598 static void MergeOrigin(entity_t *ent, vec3_t origin)
602 /* we have not parsed the brush completely yet... */
603 GetVectorForKey( ent, "origin", ent->origin );
605 VectorMA(origin, -1, ent->originbrush_origin, adjustment);
606 VectorAdd(adjustment, ent->origin, ent->origin);
607 VectorCopy(origin, ent->originbrush_origin);
610 sprintf(string, "%f %f %f", ent->origin[0], ent->origin[1], ent->origin[2]);
611 SetKeyValue(ent, "origin", string);
614 brush_t *FinishBrush( void )
619 /* create windings for sides and bounds for brush */
620 if ( !CreateBrushWindings( buildBrush ) )
623 /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
624 after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
625 if( buildBrush->compileFlags & C_ORIGIN )
630 Sys_Printf( "Entity %i, Brush %i: origin brush detected\n",
631 mapEnt->mapEntityNum, entitySourceBrushes );
633 if( numEntities == 1 )
635 Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n",
636 mapEnt->mapEntityNum, entitySourceBrushes );
640 VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
641 VectorScale (origin, 0.5, origin);
643 MergeOrigin(&entities[ numEntities - 1 ], origin);
645 /* don't keep this brush */
649 /* determine if the brush is an area portal */
650 if( buildBrush->compileFlags & C_AREAPORTAL )
652 if( numEntities != 1 )
654 Sys_Printf ("Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
659 /* add bevel planes */
663 b = CopyBrush( buildBrush );
665 /* set map entity and brush numbering */
666 b->entityNum = mapEnt->mapEntityNum;
667 b->brushNum = entitySourceBrushes;
672 /* link opaque brushes to head of list, translucent brushes to end */
673 if( b->opaque || mapEnt->lastBrush == NULL )
675 b->next = mapEnt->brushes;
677 if( mapEnt->lastBrush == NULL )
678 mapEnt->lastBrush = b;
683 mapEnt->lastBrush->next = b;
684 mapEnt->lastBrush = b;
687 /* link colorMod volume brushes to the entity directly */
688 if( b->contentShader != NULL &&
689 b->contentShader->colorMod != NULL &&
690 b->contentShader->colorMod->type == CM_VOLUME )
692 b->nextColorModBrush = mapEnt->colorModBrushes;
693 mapEnt->colorModBrushes = b;
696 /* return to sender */
703 TextureAxisFromPlane()
704 determines best orthagonal axis to project a texture onto a wall
705 (must be identical in radiant!)
708 vec3_t baseaxis[18] =
710 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
711 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
712 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
713 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
714 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
715 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
718 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv )
727 for (i=0 ; i<6 ; i++)
729 dot = DotProduct (pln->normal, baseaxis[i*3]);
730 if( dot > best + 0.0001f ) /* ydnar: bug 637 fix, suggested by jmonroe */
737 VectorCopy (baseaxis[bestaxis*3+1], xv);
738 VectorCopy (baseaxis[bestaxis*3+2], yv);
745 creates world-to-texture mapping vecs for crappy quake plane arrangements
748 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] )
752 vec_t ang, sinv, cosv;
757 TextureAxisFromPlane(plane, vecs[0], vecs[1]);
766 { sinv = 0 ; cosv = 1; }
767 else if (rotate == 90)
768 { sinv = 1 ; cosv = 0; }
769 else if (rotate == 180)
770 { sinv = 0 ; cosv = -1; }
771 else if (rotate == 270)
772 { sinv = -1 ; cosv = 0; }
775 ang = rotate / 180 * Q_PI;
794 for (i=0 ; i<2 ; i++) {
795 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
796 nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
801 for (i=0 ; i<2 ; i++)
802 for (j=0 ; j<3 ; j++)
803 mappingVecs[i][j] = vecs[i][j] / scale[i];
805 mappingVecs[0][3] = shift[0];
806 mappingVecs[1][3] = shift[1];
813 parses the sides into buildBrush->sides[], nothing else.
814 no validation, back plane removal, etc.
817 added brush epairs parsing ( ignoring actually )
819 added exclusive brush primitive parsing
821 support for old brush format back in
822 NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
825 static void ParseRawBrush( qboolean onlyLights )
828 vec3_t planePoints[ 3 ];
834 char name[ MAX_QPATH ];
835 char shader[ MAX_QPATH ];
840 buildBrush->numsides = 0;
841 buildBrush->detail = qfalse;
844 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
850 if( !GetToken( qtrue ) )
852 if( !strcmp( token, "}" ) )
855 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
856 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
860 if( strcmp( token, "(" ) )
869 /* test side count */
870 if( buildBrush->numsides >= MAX_BUILD_SIDES )
871 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
874 side = &buildBrush->sides[ buildBrush->numsides ];
875 memset( side, 0, sizeof( *side ) );
876 buildBrush->numsides++;
878 /* read the three point plane definition */
879 Parse1DMatrix( 3, planePoints[ 0 ] );
880 Parse1DMatrix( 3, planePoints[ 1 ] );
881 Parse1DMatrix( 3, planePoints[ 2 ] );
883 /* bp: read the texture matrix */
884 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
885 Parse2DMatrix( 2, 3, (float*) side->texMat );
887 /* read shader name */
889 strcpy( name, token );
892 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
895 shift[ 0 ] = atof( token );
897 shift[ 1 ] = atof( token );
899 rotate = atof( token );
901 scale[ 0 ] = atof( token );
903 scale[ 1 ] = atof( token );
906 /* set default flags and values */
907 sprintf( shader, "textures/%s", name );
909 si = &shaderInfo[ 0 ];
911 si = ShaderInfoForShader( shader );
912 side->shaderInfo = si;
913 side->surfaceFlags = si->surfaceFlags;
914 side->contentFlags = si->contentFlags;
915 side->compileFlags = si->compileFlags;
916 side->value = si->value;
918 /* ydnar: gs mods: bias texture shift */
919 if( si->globalTexture == qfalse )
921 shift[ 0 ] -= (floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth);
922 shift[ 1 ] -= (floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight);
926 historically, there are 3 integer values at the end of a brushside line in a .map file.
927 in quake 3, the only thing that mattered was the first of these three values, which
928 was previously the content flags. and only then did a single bit matter, the detail
929 bit. because every game has its own special flags for specifying detail, the
930 traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
931 by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
932 is stored in compileFlags, as opposed to contentFlags, for multiple-game
936 if( TokenAvailable() )
938 /* get detail bit from map content flags */
940 flags = atoi( token );
941 if( flags & C_DETAIL )
942 side->compileFlags |= C_DETAIL;
946 //% td.flags = atoi( token );
948 //% td.value = atoi( token );
951 /* find the plane number */
952 planenum = MapPlaneFromPoints( planePoints );
953 side->planenum = planenum;
955 /* bp: get the texture mapping for this texturedef / plane combination */
956 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
957 QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
961 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
972 RemoveDuplicateBrushPlanes
973 returns false if the brush has a mirrored set of planes,
974 meaning it encloses no volume.
975 also removes planes without any normal
978 qboolean RemoveDuplicateBrushPlanes( brush_t *b )
985 for ( i = 1 ; i < b->numsides ; i++ ) {
987 // check for a degenerate plane
988 if ( sides[i].planenum == -1) {
989 xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
991 for ( k = i + 1 ; k < b->numsides ; k++ ) {
992 sides[k-1] = sides[k];
999 // check for duplication and mirroring
1000 for ( j = 0 ; j < i ; j++ ) {
1001 if ( sides[i].planenum == sides[j].planenum ) {
1002 xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
1003 // remove the second duplicate
1004 for ( k = i + 1 ; k < b->numsides ; k++ ) {
1005 sides[k-1] = sides[k];
1012 if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
1013 // mirror plane, brush is invalid
1014 xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
1026 parses a brush out of a map file and sets it up
1029 static void ParseBrush( qboolean onlyLights )
1034 /* parse the brush out of the map */
1035 ParseRawBrush( onlyLights );
1037 /* only go this far? */
1041 /* set some defaults */
1042 buildBrush->portalareas[ 0 ] = -1;
1043 buildBrush->portalareas[ 1 ] = -1;
1044 buildBrush->entityNum = numMapEntities - 1;
1045 buildBrush->brushNum = entitySourceBrushes;
1047 /* if there are mirrored planes, the entire brush is invalid */
1048 if( !RemoveDuplicateBrushPlanes( buildBrush ) )
1051 /* get the content for the entire brush */
1052 SetBrushContents( buildBrush );
1054 /* allow detail brushes to be removed */
1055 if( nodetail && (buildBrush->compileFlags & C_DETAIL) )
1057 //% FreeBrush( buildBrush );
1061 /* allow liquid brushes to be removed */
1062 if( nowater && (buildBrush->compileFlags & C_LIQUID ) )
1064 //% FreeBrush( buildBrush );
1068 /* ydnar: allow hint brushes to be removed */
1069 if( noHint && (buildBrush->compileFlags & C_HINT) )
1071 //% FreeBrush( buildBrush );
1075 /* finish the brush */
1082 MoveBrushesToWorld()
1083 takes all of the brushes from the current entity and
1084 adds them to the world's brush list
1085 (used by func_group)
1088 void AdjustBrushesForOrigin( entity_t *ent );
1089 void MoveBrushesToWorld( entity_t *ent )
1094 /* we need to undo the common/origin adjustment, and instead shift them by the entity key origin */
1095 VectorScale(ent->origin, -1, ent->originbrush_origin);
1096 AdjustBrushesForOrigin(ent);
1097 VectorClear(ent->originbrush_origin);
1100 for( b = ent->brushes; b != NULL; b = next )
1102 /* get next brush */
1105 /* link opaque brushes to head of list, translucent brushes to end */
1106 if( b->opaque || entities[ 0 ].lastBrush == NULL )
1108 b->next = entities[ 0 ].brushes;
1109 entities[ 0 ].brushes = b;
1110 if( entities[ 0 ].lastBrush == NULL )
1111 entities[ 0 ].lastBrush = b;
1116 entities[ 0 ].lastBrush->next = b;
1117 entities[ 0 ].lastBrush = b;
1120 ent->brushes = NULL;
1122 /* ydnar: move colormod brushes */
1123 if( ent->colorModBrushes != NULL )
1125 for( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush );
1127 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1128 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1130 ent->colorModBrushes = NULL;
1134 if( ent->patches != NULL )
1136 for( pm = ent->patches; pm->next != NULL; pm = pm->next );
1138 pm->next = entities[ 0 ].patches;
1139 entities[ 0 ].patches = ent->patches;
1141 ent->patches = NULL;
1148 AdjustBrushesForOrigin()
1151 void AdjustBrushesForOrigin( entity_t *ent )
1160 /* walk brush list */
1161 for( b = ent->brushes; b != NULL; b = b->next )
1163 /* offset brush planes */
1164 for( i = 0; i < b->numsides; i++)
1166 /* get brush side */
1169 /* offset side plane */
1170 newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->originbrush_origin );
1172 /* find a new plane */
1173 s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1176 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1177 CreateBrushWindings( b );
1180 /* walk patch list */
1181 for( p = ent->patches; p != NULL; p = p->next )
1183 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1184 VectorSubtract( p->mesh.verts[ i ].xyz, ent->originbrush_origin, p->mesh.verts[ i ].xyz );
1191 SetEntityBounds() - ydnar
1192 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1195 void SetEntityBounds( entity_t *e )
1206 /* walk the entity's brushes/patches and determine bounds */
1207 ClearBounds( mins, maxs );
1208 for( b = e->brushes; b; b = b->next )
1210 AddPointToBounds( b->mins, mins, maxs );
1211 AddPointToBounds( b->maxs, mins, maxs );
1213 for( p = e->patches; p; p = p->next )
1215 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1216 AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1219 /* try to find explicit min/max key */
1220 value = ValueForKey( e, "min" );
1221 if( value[ 0 ] != '\0' )
1222 GetVectorForKey( e, "min", mins );
1223 value = ValueForKey( e, "max" );
1224 if( value[ 0 ] != '\0' )
1225 GetVectorForKey( e, "max", maxs );
1227 /* store the bounds */
1228 for( b = e->brushes; b; b = b->next )
1230 VectorCopy( mins, b->eMins );
1231 VectorCopy( maxs, b->eMaxs );
1233 for( p = e->patches; p; p = p->next )
1235 VectorCopy( mins, p->eMins );
1236 VectorCopy( maxs, p->eMaxs );
1243 LoadEntityIndexMap() - ydnar
1244 based on LoadAlphaMap() from terrain.c, a little more generic
1247 void LoadEntityIndexMap( entity_t *e )
1249 int i, size, numLayers, w, h;
1250 const char *value, *indexMapFilename, *shader;
1251 char ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1253 unsigned int *pixels32;
1259 /* this only works with bmodel ents */
1260 if( e->brushes == NULL && e->patches == NULL )
1263 /* determine if there is an index map (support legacy "alphamap" key as well) */
1264 value = ValueForKey( e, "_indexmap" );
1265 if( value[ 0 ] == '\0' )
1266 value = ValueForKey( e, "alphamap" );
1267 if( value[ 0 ] == '\0' )
1269 indexMapFilename = value;
1271 /* get number of layers (support legacy "layers" key as well) */
1272 value = ValueForKey( e, "_layers" );
1273 if( value[ 0 ] == '\0' )
1274 value = ValueForKey( e, "layers" );
1275 if( value[ 0 ] == '\0' )
1277 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1278 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1281 numLayers = atoi( value );
1284 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1285 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1289 /* get base shader name (support legacy "shader" key as well) */
1290 value = ValueForKey( mapEnt, "_shader" );
1291 if( value[ 0 ] == '\0' )
1292 value = ValueForKey( e, "shader" );
1293 if( value[ 0 ] == '\0' )
1295 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1296 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1302 Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n", mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1304 /* get index map file extension */
1305 ExtractFileExtension( indexMapFilename, ext );
1307 /* handle tga image */
1308 if( !Q_stricmp( ext, "tga" ) )
1311 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1313 /* convert to bytes */
1315 pixels = safe_malloc( size );
1316 for( i = 0; i < size; i++ )
1318 pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1319 if( pixels[ i ] >= numLayers )
1320 pixels[ i ] = numLayers - 1;
1323 /* free the 32 bit image */
1329 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1332 //% Sys_Printf( "-------------------------------" );
1334 /* fix up out-of-range values */
1336 for( i = 0; i < size; i++ )
1338 if( pixels[ i ] >= numLayers )
1339 pixels[ i ] = numLayers - 1;
1342 //% if( (i % w) == 0 )
1343 //% Sys_Printf( "\n" );
1344 //% Sys_Printf( "%c", pixels[ i ] + '0' );
1348 //% Sys_Printf( "\n-------------------------------\n" );
1351 /* the index map must be at least 2x2 pixels */
1352 if( w < 2 || h < 2 )
1354 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1355 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1360 /* create a new index map */
1361 im = safe_malloc( sizeof( *im ) );
1362 memset( im, 0, sizeof( *im ) );
1367 im->numLayers = numLayers;
1368 strcpy( im->name, indexMapFilename );
1369 strcpy( im->shader, shader );
1370 im->pixels = pixels;
1372 /* get height offsets */
1373 value = ValueForKey( mapEnt, "_offsets" );
1374 if( value[ 0 ] == '\0' )
1375 value = ValueForKey( e, "offsets" );
1376 if( value[ 0 ] != '\0' )
1378 /* value is a space-seperated set of numbers */
1379 strcpy( offset, value );
1382 /* get each value */
1383 for( i = 0; i < 256 && *search != '\0'; i++ )
1385 space = strstr( search, " " );
1388 im->offsets[ i ] = atof( search );
1395 /* store the index map in every brush/patch in the entity */
1396 for( b = e->brushes; b != NULL; b = b->next )
1398 for( p = e->patches; p != NULL; p = p->next )
1410 parses a single entity out of a map file
1413 static qboolean ParseMapEntity( qboolean onlyLights )
1416 const char *classname, *value;
1417 float lightmapScale;
1418 char shader[ MAX_QPATH ];
1419 shaderInfo_t *celShader = NULL;
1423 int castShadows, recvShadows;
1427 if( !GetToken( qtrue ) )
1430 /* conformance check */
1431 if( strcmp( token, "{" ) )
1433 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1434 "Continuing to process map, but resulting BSP may be invalid.\n",
1435 token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1440 if( numEntities >= MAX_MAP_ENTITIES )
1441 Error( "numEntities == MAX_MAP_ENTITIES" );
1444 entitySourceBrushes = 0;
1445 mapEnt = &entities[ numEntities ];
1447 memset( mapEnt, 0, sizeof( *mapEnt ) );
1449 /* ydnar: true entity numbering */
1450 mapEnt->mapEntityNum = numMapEntities;
1456 /* get initial token */
1457 if( !GetToken( qtrue ) )
1459 Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1460 "Continuing to process map, but resulting BSP may be invalid.\n" );
1464 if( !strcmp( token, "}" ) )
1467 if( !strcmp( token, "{" ) )
1469 /* parse a brush or patch */
1470 if( !GetToken( qtrue ) )
1474 if( !strcmp( token, "patchDef2" ) )
1477 ParsePatch( onlyLights );
1479 else if( !strcmp( token, "terrainDef" ) )
1482 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1484 else if( !strcmp( token, "brushDef" ) )
1486 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1487 Error( "Old brush format not allowed in new brush format map" );
1488 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1490 /* parse brush primitive */
1491 ParseBrush( onlyLights );
1495 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1496 Error( "New brush format not allowed in old brush format map" );
1497 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1499 /* parse old brush format */
1501 ParseBrush( onlyLights );
1503 entitySourceBrushes++;
1507 /* parse a key / value pair */
1510 /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1511 if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1513 ep->next = mapEnt->epairs;
1514 mapEnt->epairs = ep;
1519 /* ydnar: get classname */
1520 classname = ValueForKey( mapEnt, "classname" );
1522 /* ydnar: only lights? */
1523 if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1529 /* ydnar: determine if this is a func_group */
1530 if( !Q_stricmp( "func_group", classname ) )
1535 /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1536 if( funcGroup || mapEnt->mapEntityNum == 0 )
1538 //% Sys_Printf( "World: %d\n", mapEnt->mapEntityNum );
1539 castShadows = WORLDSPAWN_CAST_SHADOWS;
1540 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1543 /* other entities don't cast any shadows, but recv worldspawn shadows */
1546 //% Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1547 castShadows = ENTITY_CAST_SHADOWS;
1548 recvShadows = ENTITY_RECV_SHADOWS;
1551 /* get explicit shadow flags */
1552 GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1554 /* ydnar: get lightmap scaling value for this entity */
1555 if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1556 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) )
1558 /* get lightmap scale from entity */
1559 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1560 if( lightmapScale <= 0.0f )
1561 lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1562 if( lightmapScale > 0.0f )
1563 Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1566 lightmapScale = 0.0f;
1568 /* ydnar: get cel shader :) for this entity */
1569 value = ValueForKey( mapEnt, "_celshader" );
1570 if( value[ 0 ] == '\0' )
1571 value = ValueForKey( &entities[ 0 ], "_celshader" );
1572 if( value[ 0 ] != '\0' )
1574 sprintf( shader, "textures/%s", value );
1575 celShader = ShaderInfoForShader( shader );
1576 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1581 /* attach stuff to everything in the entity */
1582 for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1584 brush->entityNum = mapEnt->mapEntityNum;
1585 brush->castShadows = castShadows;
1586 brush->recvShadows = recvShadows;
1587 brush->lightmapScale = lightmapScale;
1588 brush->celShader = celShader;
1591 for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1593 patch->entityNum = mapEnt->mapEntityNum;
1594 patch->castShadows = castShadows;
1595 patch->recvShadows = recvShadows;
1596 patch->lightmapScale = lightmapScale;
1597 patch->celShader = celShader;
1600 /* ydnar: gs mods: set entity bounds */
1601 SetEntityBounds( mapEnt );
1603 /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1604 LoadEntityIndexMap( mapEnt );
1606 /* get entity origin and adjust brushes */
1607 GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1608 if( mapEnt->originbrush_origin[ 0 ] || mapEnt->originbrush_origin[ 1 ] || mapEnt->originbrush_origin[ 2 ] )
1609 AdjustBrushesForOrigin( mapEnt );
1611 /* group_info entities are just for editor grouping (fixme: leak!) */
1612 if( !Q_stricmp( "group_info", classname ) )
1618 /* group entities are just for editor convenience, toss all brushes into worldspawn */
1621 MoveBrushesToWorld( mapEnt );
1634 loads a map file into a list of entities
1637 void LoadMapFile( char *filename, qboolean onlyLights )
1641 int oldNumEntities, numMapBrushes;
1645 Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1646 Sys_Printf( "Loading %s\n", filename );
1649 file = SafeOpenRead( filename );
1652 /* load the map file */
1653 LoadScriptFile( filename, -1 );
1657 oldNumEntities = numEntities;
1662 numMapDrawSurfs = 0;
1664 g_bBrushPrimit = BPRIMIT_UNDEFINED;
1666 /* allocate a very large temporary brush for building the brushes as they are loaded */
1667 buildBrush = AllocBrush( MAX_BUILD_SIDES );
1669 /* parse the map file */
1670 while( ParseMapEntity( onlyLights ) );
1675 /* emit some statistics */
1676 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1680 /* set map bounds */
1681 ClearBounds( mapMins, mapMaxs );
1682 for( b = entities[ 0 ].brushes; b; b = b->next )
1684 AddPointToBounds( b->mins, mapMins, mapMaxs );
1685 AddPointToBounds( b->maxs, mapMins, mapMaxs );
1688 /* get brush counts */
1689 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1690 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1691 Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1693 /* emit some statistics */
1694 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1695 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1696 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1697 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1698 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1699 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1700 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1701 Sys_Printf( "%9d areaportals\n", c_areaportals);
1702 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1703 mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1704 mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1706 /* write bogus map */
1708 WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );