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 )
349 contentFlags |= s->contentFlags;
350 compileFlags |= s->compileFlags;
353 /* ydnar: getting rid of this stupid warning */
355 //% Sys_FPrintf( SYS_VRB,"Entity %i, Brush %i: mixed face contentFlags\n", b->entitynum, b->brushnum );
357 /* check for detail & structural */
358 if( (compileFlags & C_DETAIL) && (compileFlags & C_STRUCTURAL) )
360 xml_Select( "Mixed detail and structural (defaulting to structural)", mapEnt->mapEntityNum, entitySourceBrushes, qfalse );
361 compileFlags &= ~C_DETAIL;
364 /* the fulldetail flag will cause detail brushes to be treated like normal brushes */
366 compileFlags &= ~C_DETAIL;
368 /* all translucent brushes that aren't specifically made structural will be detail */
369 if( (compileFlags & C_TRANSLUCENT) && !(compileFlags & C_STRUCTURAL) )
370 compileFlags |= C_DETAIL;
373 if( compileFlags & C_DETAIL )
385 if( compileFlags & C_TRANSLUCENT )
391 if( compileFlags & C_AREAPORTAL )
394 /* set brush flags */
395 b->contentFlags = contentFlags;
396 b->compileFlags = compileFlags;
403 adds any additional planes necessary to allow the brush being
404 built to be expanded against axial bounding boxes
405 ydnar 2003-01-20: added mrelusive fixes
408 void AddBrushBevels( void )
411 int i, j, k, l, order;
421 // add the axial planes
424 for ( axis = 0; axis < 3; axis++ ) {
425 for ( dir = -1; dir <= 1; dir += 2, order++ ) {
426 // see if the plane is allready present
427 for ( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
429 /* ydnar: testing disabling of mre code */
432 if ( mapplanes[s->planenum].normal[axis] >= 0.9999f ) {
437 if ( mapplanes[s->planenum].normal[axis] <= -0.9999f ) {
442 if( (dir > 0 && mapplanes[ s->planenum ].normal[ axis ] == 1.0f ) ||
443 (dir < 0 && mapplanes[ s->planenum ].normal[ axis ] == -1.0f) )
448 if ( i == buildBrush->numsides ) {
450 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
451 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
453 memset( s, 0, sizeof( *s ) );
454 buildBrush->numsides++;
455 VectorClear (normal);
460 /* ydnar: adding bevel plane snapping for fewer bsp planes */
462 dist = floor( buildBrush->maxs[ axis ] / bevelSnap ) * bevelSnap;
464 dist = buildBrush->maxs[ axis ];
468 /* ydnar: adding bevel plane snapping for fewer bsp planes */
470 dist = -ceil( buildBrush->mins[ axis ] / bevelSnap ) * bevelSnap;
472 dist = -buildBrush->mins[ axis ];
475 s->planenum = FindFloatPlane( normal, dist, 0, NULL );
476 s->contentFlags = buildBrush->sides[ 0 ].contentFlags;
481 // if the plane is not in it canonical order, swap it
483 sidetemp = buildBrush->sides[order];
484 buildBrush->sides[order] = buildBrush->sides[i];
485 buildBrush->sides[i] = sidetemp;
491 // add the edge bevels
493 if ( buildBrush->numsides == 6 ) {
494 return; // pure axial
497 // test the non-axial plane edges
498 for ( i = 6; i < buildBrush->numsides; i++ ) {
499 s = buildBrush->sides + i;
504 for ( j = 0; j < w->numpoints; j++) {
505 k = (j+1)%w->numpoints;
506 VectorSubtract( w->p[j], w->p[k], vec );
507 if ( VectorNormalize( vec, vec ) < 0.5f ) {
511 for ( k = 0; k < 3; k++ ) {
512 if ( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f) ) {
517 continue; // only test non-axial edges
521 //% Sys_Printf( "-------------\n" );
523 // try the six possible slanted axials from this edge
524 for ( axis = 0; axis < 3; axis++ ) {
525 for ( dir = -1; dir <= 1; dir += 2 ) {
529 CrossProduct( vec, vec2, normal );
530 if ( VectorNormalize( normal, normal ) < 0.5f ) {
533 dist = DotProduct( w->p[j], normal );
535 // if all the points on all the sides are
536 // behind this plane, it is a proper edge bevel
537 for ( k = 0; k < buildBrush->numsides; k++ ) {
539 // if this plane has allready been used, skip it
540 if ( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ) ) {
544 w2 = buildBrush->sides[k].winding;
549 for ( l = 0; l < w2->numpoints; l++ ) {
550 d = DotProduct( w2->p[l], normal ) - dist;
552 break; // point in front
558 // if some point was at the front
559 if ( l != w2->numpoints ) {
563 // if no points at the back then the winding is on the bevel plane
564 if ( minBack > -0.1f ) {
565 //% Sys_Printf( "On bevel plane\n" );
570 if ( k != buildBrush->numsides ) {
571 continue; // wasn't part of the outer hull
575 //% Sys_Printf( "n = %f %f %f\n", normal[ 0 ], normal[ 1 ], normal[ 2 ] );
578 if( buildBrush->numsides == MAX_BUILD_SIDES ) {
579 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
581 s2 = &buildBrush->sides[buildBrush->numsides];
582 buildBrush->numsides++;
583 memset( s2, 0, sizeof( *s2 ) );
585 s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[ j ] );
586 s2->contentFlags = buildBrush->sides[0].contentFlags;
599 produces a final brush based on the buildBrush->sides array
600 and links it to the current entity
603 static void MergeOrigin(entity_t *ent, vec3_t origin)
608 /* we have not parsed the brush completely yet... */
609 GetVectorForKey( ent, "origin", ent->origin );
611 VectorMA(origin, -1, ent->originbrush_origin, adjustment);
612 VectorAdd(adjustment, ent->origin, ent->origin);
613 VectorCopy(origin, ent->originbrush_origin);
615 sprintf(string, "%f %f %f", ent->origin[0], ent->origin[1], ent->origin[2]);
616 SetKeyValue(ent, "origin", string);
619 brush_t *FinishBrush( void )
624 /* create windings for sides and bounds for brush */
625 if ( !CreateBrushWindings( buildBrush ) )
628 /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
629 after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
630 if( buildBrush->compileFlags & C_ORIGIN )
634 Sys_Printf( "Entity %i, Brush %i: origin brush detected\n",
635 mapEnt->mapEntityNum, entitySourceBrushes );
637 if( numEntities == 1 )
639 Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n",
640 mapEnt->mapEntityNum, entitySourceBrushes );
644 VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
645 VectorScale (origin, 0.5, origin);
647 MergeOrigin(&entities[ numEntities - 1 ], origin);
649 /* don't keep this brush */
653 /* determine if the brush is an area portal */
654 if( buildBrush->compileFlags & C_AREAPORTAL )
656 if( numEntities != 1 )
658 Sys_Printf ("Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
663 /* add bevel planes */
667 b = CopyBrush( buildBrush );
669 /* set map entity and brush numbering */
670 b->entityNum = mapEnt->mapEntityNum;
671 b->brushNum = entitySourceBrushes;
676 /* link opaque brushes to head of list, translucent brushes to end */
677 if( b->opaque || mapEnt->lastBrush == NULL )
679 b->next = mapEnt->brushes;
681 if( mapEnt->lastBrush == NULL )
682 mapEnt->lastBrush = b;
687 mapEnt->lastBrush->next = b;
688 mapEnt->lastBrush = b;
691 /* link colorMod volume brushes to the entity directly */
692 if( b->contentShader != NULL &&
693 b->contentShader->colorMod != NULL &&
694 b->contentShader->colorMod->type == CM_VOLUME )
696 b->nextColorModBrush = mapEnt->colorModBrushes;
697 mapEnt->colorModBrushes = b;
700 /* return to sender */
707 TextureAxisFromPlane()
708 determines best orthagonal axis to project a texture onto a wall
709 (must be identical in radiant!)
712 vec3_t baseaxis[18] =
714 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
715 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
716 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
717 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
718 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
719 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
722 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv )
731 for (i=0 ; i<6 ; i++)
733 dot = DotProduct (pln->normal, baseaxis[i*3]);
734 if( dot > best + 0.0001f ) /* ydnar: bug 637 fix, suggested by jmonroe */
741 VectorCopy (baseaxis[bestaxis*3+1], xv);
742 VectorCopy (baseaxis[bestaxis*3+2], yv);
749 creates world-to-texture mapping vecs for crappy quake plane arrangements
752 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] )
756 vec_t ang, sinv, cosv;
761 TextureAxisFromPlane(plane, vecs[0], vecs[1]);
770 { sinv = 0 ; cosv = 1; }
771 else if (rotate == 90)
772 { sinv = 1 ; cosv = 0; }
773 else if (rotate == 180)
774 { sinv = 0 ; cosv = -1; }
775 else if (rotate == 270)
776 { sinv = -1 ; cosv = 0; }
779 ang = rotate / 180 * Q_PI;
798 for (i=0 ; i<2 ; i++) {
799 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
800 nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
805 for (i=0 ; i<2 ; i++)
806 for (j=0 ; j<3 ; j++)
807 mappingVecs[i][j] = vecs[i][j] / scale[i];
809 mappingVecs[0][3] = shift[0];
810 mappingVecs[1][3] = shift[1];
817 parses the sides into buildBrush->sides[], nothing else.
818 no validation, back plane removal, etc.
821 added brush epairs parsing ( ignoring actually )
823 added exclusive brush primitive parsing
825 support for old brush format back in
826 NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
829 static void ParseRawBrush( qboolean onlyLights )
832 vec3_t planePoints[ 3 ];
838 char name[ MAX_QPATH ];
839 char shader[ MAX_QPATH ];
844 buildBrush->numsides = 0;
845 buildBrush->detail = qfalse;
848 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
854 if( !GetToken( qtrue ) )
856 if( !strcmp( token, "}" ) )
859 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
860 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
864 if( strcmp( token, "(" ) )
873 /* test side count */
874 if( buildBrush->numsides >= MAX_BUILD_SIDES )
875 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
878 side = &buildBrush->sides[ buildBrush->numsides ];
879 memset( side, 0, sizeof( *side ) );
880 buildBrush->numsides++;
882 /* read the three point plane definition */
883 Parse1DMatrix( 3, planePoints[ 0 ] );
884 Parse1DMatrix( 3, planePoints[ 1 ] );
885 Parse1DMatrix( 3, planePoints[ 2 ] );
887 /* bp: read the texture matrix */
888 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
889 Parse2DMatrix( 2, 3, (float*) side->texMat );
891 /* read shader name */
893 strcpy( name, token );
896 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
899 shift[ 0 ] = atof( token );
901 shift[ 1 ] = atof( token );
903 rotate = atof( token );
905 scale[ 0 ] = atof( token );
907 scale[ 1 ] = atof( token );
910 /* set default flags and values */
911 sprintf( shader, "textures/%s", name );
913 si = &shaderInfo[ 0 ];
915 si = ShaderInfoForShader( shader );
916 side->shaderInfo = si;
917 side->surfaceFlags = si->surfaceFlags;
918 side->contentFlags = si->contentFlags;
919 side->compileFlags = si->compileFlags;
920 side->value = si->value;
922 /* ydnar: gs mods: bias texture shift */
923 if( si->globalTexture == qfalse )
925 shift[ 0 ] -= (floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth);
926 shift[ 1 ] -= (floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight);
930 historically, there are 3 integer values at the end of a brushside line in a .map file.
931 in quake 3, the only thing that mattered was the first of these three values, which
932 was previously the content flags. and only then did a single bit matter, the detail
933 bit. because every game has its own special flags for specifying detail, the
934 traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
935 by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
936 is stored in compileFlags, as opposed to contentFlags, for multiple-game
940 if( TokenAvailable() )
942 /* get detail bit from map content flags */
944 flags = atoi( token );
945 if( flags & C_DETAIL )
946 side->compileFlags |= C_DETAIL;
950 //% td.flags = atoi( token );
952 //% td.value = atoi( token );
955 /* find the plane number */
956 planenum = MapPlaneFromPoints( planePoints );
957 side->planenum = planenum;
959 /* bp: get the texture mapping for this texturedef / plane combination */
960 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
961 QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
965 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
976 RemoveDuplicateBrushPlanes
977 returns false if the brush has a mirrored set of planes,
978 meaning it encloses no volume.
979 also removes planes without any normal
982 qboolean RemoveDuplicateBrushPlanes( brush_t *b )
989 for ( i = 1 ; i < b->numsides ; i++ ) {
991 // check for a degenerate plane
992 if ( sides[i].planenum == -1) {
993 xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
995 for ( k = i + 1 ; k < b->numsides ; k++ ) {
996 sides[k-1] = sides[k];
1003 // check for duplication and mirroring
1004 for ( j = 0 ; j < i ; j++ ) {
1005 if ( sides[i].planenum == sides[j].planenum ) {
1006 xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
1007 // remove the second duplicate
1008 for ( k = i + 1 ; k < b->numsides ; k++ ) {
1009 sides[k-1] = sides[k];
1016 if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
1017 // mirror plane, brush is invalid
1018 xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
1030 parses a brush out of a map file and sets it up
1033 static void ParseBrush( qboolean onlyLights )
1038 /* parse the brush out of the map */
1039 ParseRawBrush( onlyLights );
1041 /* only go this far? */
1045 /* set some defaults */
1046 buildBrush->portalareas[ 0 ] = -1;
1047 buildBrush->portalareas[ 1 ] = -1;
1048 buildBrush->entityNum = numMapEntities - 1;
1049 buildBrush->brushNum = entitySourceBrushes;
1051 /* if there are mirrored planes, the entire brush is invalid */
1052 if( !RemoveDuplicateBrushPlanes( buildBrush ) )
1055 /* get the content for the entire brush */
1056 SetBrushContents( buildBrush );
1058 /* allow detail brushes to be removed */
1059 if( nodetail && (buildBrush->compileFlags & C_DETAIL) )
1061 //% FreeBrush( buildBrush );
1065 /* allow liquid brushes to be removed */
1066 if( nowater && (buildBrush->compileFlags & C_LIQUID ) )
1068 //% FreeBrush( buildBrush );
1072 /* ydnar: allow hint brushes to be removed */
1073 if( noHint && (buildBrush->compileFlags & C_HINT) )
1075 //% FreeBrush( buildBrush );
1079 /* finish the brush */
1086 MoveBrushesToWorld()
1087 takes all of the brushes from the current entity and
1088 adds them to the world's brush list
1089 (used by func_group)
1092 void AdjustBrushesForOrigin( entity_t *ent );
1093 void MoveBrushesToWorld( entity_t *ent )
1098 /* we need to undo the common/origin adjustment, and instead shift them by the entity key origin */
1099 VectorScale(ent->origin, -1, ent->originbrush_origin);
1100 AdjustBrushesForOrigin(ent);
1101 VectorClear(ent->originbrush_origin);
1104 for( b = ent->brushes; b != NULL; b = next )
1106 /* get next brush */
1109 /* link opaque brushes to head of list, translucent brushes to end */
1110 if( b->opaque || entities[ 0 ].lastBrush == NULL )
1112 b->next = entities[ 0 ].brushes;
1113 entities[ 0 ].brushes = b;
1114 if( entities[ 0 ].lastBrush == NULL )
1115 entities[ 0 ].lastBrush = b;
1120 entities[ 0 ].lastBrush->next = b;
1121 entities[ 0 ].lastBrush = b;
1124 ent->brushes = NULL;
1126 /* ydnar: move colormod brushes */
1127 if( ent->colorModBrushes != NULL )
1129 for( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush );
1131 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1132 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1134 ent->colorModBrushes = NULL;
1138 if( ent->patches != NULL )
1140 for( pm = ent->patches; pm->next != NULL; pm = pm->next );
1142 pm->next = entities[ 0 ].patches;
1143 entities[ 0 ].patches = ent->patches;
1145 ent->patches = NULL;
1152 AdjustBrushesForOrigin()
1155 void AdjustBrushesForOrigin( entity_t *ent )
1164 /* walk brush list */
1165 for( b = ent->brushes; b != NULL; b = b->next )
1167 /* offset brush planes */
1168 for( i = 0; i < b->numsides; i++)
1170 /* get brush side */
1173 /* offset side plane */
1174 newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->originbrush_origin );
1176 /* find a new plane */
1177 s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1180 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1181 CreateBrushWindings( b );
1184 /* walk patch list */
1185 for( p = ent->patches; p != NULL; p = p->next )
1187 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1188 VectorSubtract( p->mesh.verts[ i ].xyz, ent->originbrush_origin, p->mesh.verts[ i ].xyz );
1195 SetEntityBounds() - ydnar
1196 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1199 void SetEntityBounds( entity_t *e )
1210 /* walk the entity's brushes/patches and determine bounds */
1211 ClearBounds( mins, maxs );
1212 for( b = e->brushes; b; b = b->next )
1214 AddPointToBounds( b->mins, mins, maxs );
1215 AddPointToBounds( b->maxs, mins, maxs );
1217 for( p = e->patches; p; p = p->next )
1219 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1220 AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1223 /* try to find explicit min/max key */
1224 value = ValueForKey( e, "min" );
1225 if( value[ 0 ] != '\0' )
1226 GetVectorForKey( e, "min", mins );
1227 value = ValueForKey( e, "max" );
1228 if( value[ 0 ] != '\0' )
1229 GetVectorForKey( e, "max", maxs );
1231 /* store the bounds */
1232 for( b = e->brushes; b; b = b->next )
1234 VectorCopy( mins, b->eMins );
1235 VectorCopy( maxs, b->eMaxs );
1237 for( p = e->patches; p; p = p->next )
1239 VectorCopy( mins, p->eMins );
1240 VectorCopy( maxs, p->eMaxs );
1247 LoadEntityIndexMap() - ydnar
1248 based on LoadAlphaMap() from terrain.c, a little more generic
1251 void LoadEntityIndexMap( entity_t *e )
1253 int i, size, numLayers, w, h;
1254 const char *value, *indexMapFilename, *shader;
1255 char ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1257 unsigned int *pixels32;
1263 /* this only works with bmodel ents */
1264 if( e->brushes == NULL && e->patches == NULL )
1267 /* determine if there is an index map (support legacy "alphamap" key as well) */
1268 value = ValueForKey( e, "_indexmap" );
1269 if( value[ 0 ] == '\0' )
1270 value = ValueForKey( e, "alphamap" );
1271 if( value[ 0 ] == '\0' )
1273 indexMapFilename = value;
1275 /* get number of layers (support legacy "layers" key as well) */
1276 value = ValueForKey( e, "_layers" );
1277 if( value[ 0 ] == '\0' )
1278 value = ValueForKey( e, "layers" );
1279 if( value[ 0 ] == '\0' )
1281 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1282 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1285 numLayers = atoi( value );
1288 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1289 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1293 /* get base shader name (support legacy "shader" key as well) */
1294 value = ValueForKey( mapEnt, "_shader" );
1295 if( value[ 0 ] == '\0' )
1296 value = ValueForKey( e, "shader" );
1297 if( value[ 0 ] == '\0' )
1299 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1300 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1306 Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n", mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1308 /* get index map file extension */
1309 ExtractFileExtension( indexMapFilename, ext );
1311 /* handle tga image */
1312 if( !Q_stricmp( ext, "tga" ) )
1315 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1317 /* convert to bytes */
1319 pixels = safe_malloc( size );
1320 for( i = 0; i < size; i++ )
1322 pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1323 if( pixels[ i ] >= numLayers )
1324 pixels[ i ] = numLayers - 1;
1327 /* free the 32 bit image */
1333 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1336 //% Sys_Printf( "-------------------------------" );
1338 /* fix up out-of-range values */
1340 for( i = 0; i < size; i++ )
1342 if( pixels[ i ] >= numLayers )
1343 pixels[ i ] = numLayers - 1;
1346 //% if( (i % w) == 0 )
1347 //% Sys_Printf( "\n" );
1348 //% Sys_Printf( "%c", pixels[ i ] + '0' );
1352 //% Sys_Printf( "\n-------------------------------\n" );
1355 /* the index map must be at least 2x2 pixels */
1356 if( w < 2 || h < 2 )
1358 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1359 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1364 /* create a new index map */
1365 im = safe_malloc( sizeof( *im ) );
1366 memset( im, 0, sizeof( *im ) );
1371 im->numLayers = numLayers;
1372 strcpy( im->name, indexMapFilename );
1373 strcpy( im->shader, shader );
1374 im->pixels = pixels;
1376 /* get height offsets */
1377 value = ValueForKey( mapEnt, "_offsets" );
1378 if( value[ 0 ] == '\0' )
1379 value = ValueForKey( e, "offsets" );
1380 if( value[ 0 ] != '\0' )
1382 /* value is a space-seperated set of numbers */
1383 strcpy( offset, value );
1386 /* get each value */
1387 for( i = 0; i < 256 && *search != '\0'; i++ )
1389 space = strstr( search, " " );
1392 im->offsets[ i ] = atof( search );
1399 /* store the index map in every brush/patch in the entity */
1400 for( b = e->brushes; b != NULL; b = b->next )
1402 for( p = e->patches; p != NULL; p = p->next )
1414 parses a single entity out of a map file
1417 static qboolean ParseMapEntity( qboolean onlyLights )
1420 const char *classname, *value;
1421 float lightmapScale, shadeAngle;
1422 int lightmapSampleSize;
1423 char shader[ MAX_QPATH ];
1424 shaderInfo_t *celShader = NULL;
1428 int castShadows, recvShadows;
1432 if( !GetToken( qtrue ) )
1435 /* conformance check */
1436 if( strcmp( token, "{" ) )
1438 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1439 "Continuing to process map, but resulting BSP may be invalid.\n",
1440 token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1445 if( numEntities >= MAX_MAP_ENTITIES )
1446 Error( "numEntities == MAX_MAP_ENTITIES" );
1449 entitySourceBrushes = 0;
1450 mapEnt = &entities[ numEntities ];
1452 memset( mapEnt, 0, sizeof( *mapEnt ) );
1454 /* ydnar: true entity numbering */
1455 mapEnt->mapEntityNum = numMapEntities;
1461 /* get initial token */
1462 if( !GetToken( qtrue ) )
1464 Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1465 "Continuing to process map, but resulting BSP may be invalid.\n" );
1469 if( !strcmp( token, "}" ) )
1472 if( !strcmp( token, "{" ) )
1474 /* parse a brush or patch */
1475 if( !GetToken( qtrue ) )
1479 if( !strcmp( token, "patchDef2" ) )
1482 ParsePatch( onlyLights );
1484 else if( !strcmp( token, "terrainDef" ) )
1487 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1489 else if( !strcmp( token, "brushDef" ) )
1491 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1492 Error( "Old brush format not allowed in new brush format map" );
1493 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1495 /* parse brush primitive */
1496 ParseBrush( onlyLights );
1500 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1501 Error( "New brush format not allowed in old brush format map" );
1502 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1504 /* parse old brush format */
1506 ParseBrush( onlyLights );
1508 entitySourceBrushes++;
1512 /* parse a key / value pair */
1515 /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1516 if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1518 ep->next = mapEnt->epairs;
1519 mapEnt->epairs = ep;
1524 /* ydnar: get classname */
1525 classname = ValueForKey( mapEnt, "classname" );
1527 /* ydnar: only lights? */
1528 if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1534 /* ydnar: determine if this is a func_group */
1535 if( !Q_stricmp( "func_group", classname ) )
1540 /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1541 if( funcGroup || mapEnt->mapEntityNum == 0 )
1543 //% Sys_Printf( "World: %d\n", mapEnt->mapEntityNum );
1544 castShadows = WORLDSPAWN_CAST_SHADOWS;
1545 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1548 /* other entities don't cast any shadows, but recv worldspawn shadows */
1551 //% Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1552 castShadows = ENTITY_CAST_SHADOWS;
1553 recvShadows = ENTITY_RECV_SHADOWS;
1556 /* get explicit shadow flags */
1557 GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1559 /* vortex: added _ls key (short name of lightmapscale) */
1560 /* ydnar: get lightmap scaling value for this entity */
1561 lightmapScale = 0.0f;
1562 if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1563 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) ||
1564 strcmp( "", ValueForKey( mapEnt, "_ls" ) ) )
1566 /* get lightmap scale from entity */
1567 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1568 if( lightmapScale <= 0.0f )
1569 lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1570 if( lightmapScale <= 0.0f )
1571 lightmapScale = FloatForKey( mapEnt, "_ls" );
1572 if( lightmapScale < 0.0f )
1573 lightmapScale = 0.0f;
1574 if( lightmapScale > 0.0f )
1575 Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1578 /* ydnar: get cel shader :) for this entity */
1579 value = ValueForKey( mapEnt, "_celshader" );
1580 if( value[ 0 ] == '\0' )
1581 value = ValueForKey( &entities[ 0 ], "_celshader" );
1582 if( value[ 0 ] != '\0' )
1584 sprintf( shader, "textures/%s", value );
1585 celShader = ShaderInfoForShader( shader );
1586 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1589 celShader = *globalCelShader ? ShaderInfoForShader(globalCelShader) : NULL;
1591 /* jal : entity based _shadeangle */
1593 if ( strcmp( "", ValueForKey( mapEnt, "_shadeangle" ) ) )
1594 shadeAngle = FloatForKey( mapEnt, "_shadeangle" );
1595 /* vortex' aliases */
1596 else if ( strcmp( "", ValueForKey( mapEnt, "_smoothnormals" ) ) )
1597 shadeAngle = FloatForKey( mapEnt, "_smoothnormals" );
1598 else if ( strcmp( "", ValueForKey( mapEnt, "_sn" ) ) )
1599 shadeAngle = FloatForKey( mapEnt, "_sn" );
1600 else if ( strcmp( "", ValueForKey( mapEnt, "_smooth" ) ) )
1601 shadeAngle = FloatForKey( mapEnt, "_smooth" );
1603 if( shadeAngle < 0.0f )
1606 if( shadeAngle > 0.0f )
1607 Sys_Printf( "Entity %d (%s) has shading angle of %.4f\n", mapEnt->mapEntityNum, classname, shadeAngle );
1609 /* jal : entity based _samplesize */
1610 lightmapSampleSize = 0;
1611 if ( strcmp( "", ValueForKey( mapEnt, "_lightmapsamplesize" ) ) )
1612 lightmapSampleSize = IntForKey( mapEnt, "_lightmapsamplesize" );
1613 else if ( strcmp( "", ValueForKey( mapEnt, "_samplesize" ) ) )
1614 lightmapSampleSize = IntForKey( mapEnt, "_samplesize" );
1616 if( lightmapSampleSize < 0 )
1617 lightmapSampleSize = 0;
1619 if( lightmapSampleSize > 0 )
1620 Sys_Printf( "Entity %d (%s) has lightmap sample size of %d\n", mapEnt->mapEntityNum, classname, lightmapSampleSize );
1622 /* attach stuff to everything in the entity */
1623 for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1625 brush->entityNum = mapEnt->mapEntityNum;
1626 brush->castShadows = castShadows;
1627 brush->recvShadows = recvShadows;
1628 brush->lightmapSampleSize = lightmapSampleSize;
1629 brush->lightmapScale = lightmapScale;
1630 brush->celShader = celShader;
1631 brush->shadeAngleDegrees = shadeAngle;
1634 for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1636 patch->entityNum = mapEnt->mapEntityNum;
1637 patch->castShadows = castShadows;
1638 patch->recvShadows = recvShadows;
1639 patch->lightmapSampleSize = lightmapSampleSize;
1640 patch->lightmapScale = lightmapScale;
1641 patch->celShader = celShader;
1644 /* ydnar: gs mods: set entity bounds */
1645 SetEntityBounds( mapEnt );
1647 /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1648 LoadEntityIndexMap( mapEnt );
1650 /* get entity origin and adjust brushes */
1651 GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1652 if( mapEnt->originbrush_origin[ 0 ] || mapEnt->originbrush_origin[ 1 ] || mapEnt->originbrush_origin[ 2 ] )
1653 AdjustBrushesForOrigin( mapEnt );
1655 /* group_info entities are just for editor grouping (fixme: leak!) */
1656 if( !Q_stricmp( "group_info", classname ) )
1662 /* group entities are just for editor convenience, toss all brushes into worldspawn */
1665 MoveBrushesToWorld( mapEnt );
1678 loads a map file into a list of entities
1681 void LoadMapFile( char *filename, qboolean onlyLights )
1685 int oldNumEntities, numMapBrushes;
1689 Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1690 Sys_Printf( "Loading %s\n", filename );
1693 file = SafeOpenRead( filename );
1696 /* load the map file */
1697 LoadScriptFile( filename, -1 );
1701 oldNumEntities = numEntities;
1706 numMapDrawSurfs = 0;
1708 g_bBrushPrimit = BPRIMIT_UNDEFINED;
1710 /* allocate a very large temporary brush for building the brushes as they are loaded */
1711 buildBrush = AllocBrush( MAX_BUILD_SIDES );
1713 /* parse the map file */
1714 while( ParseMapEntity( onlyLights ) );
1719 /* emit some statistics */
1720 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1724 /* set map bounds */
1725 ClearBounds( mapMins, mapMaxs );
1726 for( b = entities[ 0 ].brushes; b; b = b->next )
1728 AddPointToBounds( b->mins, mapMins, mapMaxs );
1729 AddPointToBounds( b->maxs, mapMins, mapMaxs );
1732 /* get brush counts */
1733 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1734 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1735 Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1737 /* emit some statistics */
1738 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1739 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1740 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1741 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1742 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1743 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1744 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1745 Sys_Printf( "%9d areaportals\n", c_areaportals);
1746 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1747 mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1748 mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1750 /* write bogus map */
1752 WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );