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 innormal, vec_t dist, int numPoints, vec3_t *points ) // NOTE: this has a side effect on the normal. Good or bad?
224 vec3_t centerofweight;
227 VectorClear(centerofweight);
228 for(i = 0; i < numPoints; ++i)
229 VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
232 VectorCopy(innormal, normal);
233 SnapPlane( normal, &dist, centerofweight );
234 hash = (PLANE_HASHES - 1) & (int) fabs( dist );
236 /* search the border bins as well */
237 for( i = -1; i <= 1; i++ )
239 h = (hash + i) & (PLANE_HASHES - 1);
240 for( pidx = planehash[ h ] - 1; pidx != -1; pidx = mapplanes[pidx].hash_chain - 1 )
242 p = &mapplanes[pidx];
244 /* do standard plane compare */
245 if( !PlaneEqual( p, normal, dist ) )
248 /* ydnar: uncomment the following line for old-style plane finding */
249 //% return p - mapplanes;
251 /* ydnar: test supplied points against this plane */
252 for( j = 0; j < numPoints; j++ )
254 d = DotProduct( points[ j ], p->normal ) - p->dist;
255 if( fabs( d ) > distanceEpsilon )
259 /* found a matching plane */
261 return p - mapplanes;
265 /* none found, so create a new one */
266 return CreateNewFloatPlane( normal, dist );
277 vec3_t centerofweight;
279 VectorClear(centerofweight);
280 for(i = 0; i < numPoints; ++i)
281 VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
283 VectorCopy(innormal, normal);
284 SnapPlane( normal, &dist, centerofweight );
285 for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
287 if( PlaneEqual( p, normal, dist ) )
291 return CreateNewFloatPlane( normal, dist );
300 takes 3 points and finds the plane they lie in
303 int MapPlaneFromPoints( vec3_t *p )
305 vec3_t t1, t2, normal;
309 /* calc plane normal */
310 VectorSubtract( p[ 0 ], p[ 1 ], t1 );
311 VectorSubtract( p[ 2 ], p[ 1 ], t2 );
312 CrossProduct( t1, t2, normal );
313 VectorNormalize( normal, normal );
315 /* calc plane distance */
316 dist = DotProduct( p[ 0 ], normal );
318 /* store the plane */
319 return FindFloatPlane( normal, dist, 3, p );
326 the content flags and compile flags on all sides of a brush should be the same
329 void SetBrushContents( brush_t *b )
331 int contentFlags, compileFlags;
337 /* get initial compile flags from first side */
339 contentFlags = s->contentFlags;
340 compileFlags = s->compileFlags;
341 b->contentShader = s->shaderInfo;
344 /* get the content/compile flags for every side in the brush */
345 for( i = 1; i < b->numsides; i++, s++ )
348 if( s->shaderInfo == NULL )
350 if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
353 contentFlags |= s->contentFlags;
354 compileFlags |= s->compileFlags;
357 /* ydnar: getting rid of this stupid warning */
359 //% Sys_FPrintf( SYS_VRB,"Entity %i, Brush %i: mixed face contentFlags\n", b->entitynum, b->brushnum );
361 /* check for detail & structural */
362 if( (compileFlags & C_DETAIL) && (compileFlags & C_STRUCTURAL) )
364 xml_Select( "Mixed detail and structural (defaulting to structural)", mapEnt->mapEntityNum, entitySourceBrushes, qfalse );
365 compileFlags &= ~C_DETAIL;
368 /* the fulldetail flag will cause detail brushes to be treated like normal brushes */
370 compileFlags &= ~C_DETAIL;
372 /* all translucent brushes that aren't specifically made structural will be detail */
373 if( (compileFlags & C_TRANSLUCENT) && !(compileFlags & C_STRUCTURAL) )
374 compileFlags |= C_DETAIL;
377 if( compileFlags & C_DETAIL )
389 if( compileFlags & C_TRANSLUCENT )
395 if( compileFlags & C_AREAPORTAL )
398 /* set brush flags */
399 b->contentFlags = contentFlags;
400 b->compileFlags = compileFlags;
407 adds any additional planes necessary to allow the brush being
408 built to be expanded against axial bounding boxes
409 ydnar 2003-01-20: added mrelusive fixes
412 void AddBrushBevels( void )
415 int i, j, k, l, order;
425 // add the axial planes
428 for ( axis = 0; axis < 3; axis++ ) {
429 for ( dir = -1; dir <= 1; dir += 2, order++ ) {
430 // see if the plane is allready present
431 for ( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
433 /* ydnar: testing disabling of mre code */
436 if ( mapplanes[s->planenum].normal[axis] >= 0.9999f ) {
441 if ( mapplanes[s->planenum].normal[axis] <= -0.9999f ) {
446 if( (dir > 0 && mapplanes[ s->planenum ].normal[ axis ] == 1.0f ) ||
447 (dir < 0 && mapplanes[ s->planenum ].normal[ axis ] == -1.0f) )
452 if ( i == buildBrush->numsides ) {
454 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
455 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
457 memset( s, 0, sizeof( *s ) );
458 buildBrush->numsides++;
459 VectorClear (normal);
464 /* ydnar: adding bevel plane snapping for fewer bsp planes */
466 dist = floor( buildBrush->maxs[ axis ] / bevelSnap ) * bevelSnap;
468 dist = buildBrush->maxs[ axis ];
472 /* ydnar: adding bevel plane snapping for fewer bsp planes */
474 dist = -ceil( buildBrush->mins[ axis ] / bevelSnap ) * bevelSnap;
476 dist = -buildBrush->mins[ axis ];
479 s->planenum = FindFloatPlane( normal, dist, 0, NULL );
480 s->contentFlags = buildBrush->sides[ 0 ].contentFlags;
485 // if the plane is not in it canonical order, swap it
487 sidetemp = buildBrush->sides[order];
488 buildBrush->sides[order] = buildBrush->sides[i];
489 buildBrush->sides[i] = sidetemp;
495 // add the edge bevels
497 if ( buildBrush->numsides == 6 ) {
498 return; // pure axial
501 // test the non-axial plane edges
502 for ( i = 6; i < buildBrush->numsides; i++ ) {
503 s = buildBrush->sides + i;
508 for ( j = 0; j < w->numpoints; j++) {
509 k = (j+1)%w->numpoints;
510 VectorSubtract( w->p[j], w->p[k], vec );
511 if ( VectorNormalize( vec, vec ) < 0.5f ) {
515 for ( k = 0; k < 3; k++ ) {
516 if ( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f) ) {
521 continue; // only test non-axial edges
525 //% Sys_Printf( "-------------\n" );
527 // try the six possible slanted axials from this edge
528 for ( axis = 0; axis < 3; axis++ ) {
529 for ( dir = -1; dir <= 1; dir += 2 ) {
533 CrossProduct( vec, vec2, normal );
534 if ( VectorNormalize( normal, normal ) < 0.5f ) {
537 dist = DotProduct( w->p[j], normal );
539 // if all the points on all the sides are
540 // behind this plane, it is a proper edge bevel
541 for ( k = 0; k < buildBrush->numsides; k++ ) {
543 // if this plane has allready been used, skip it
544 if ( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ) ) {
548 w2 = buildBrush->sides[k].winding;
553 for ( l = 0; l < w2->numpoints; l++ ) {
554 d = DotProduct( w2->p[l], normal ) - dist;
556 break; // point in front
562 // if some point was at the front
563 if ( l != w2->numpoints ) {
567 // if no points at the back then the winding is on the bevel plane
568 if ( minBack > -0.1f ) {
569 //% Sys_Printf( "On bevel plane\n" );
574 if ( k != buildBrush->numsides ) {
575 continue; // wasn't part of the outer hull
579 //% Sys_Printf( "n = %f %f %f\n", normal[ 0 ], normal[ 1 ], normal[ 2 ] );
582 if( buildBrush->numsides == MAX_BUILD_SIDES ) {
583 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue);
585 s2 = &buildBrush->sides[buildBrush->numsides];
586 buildBrush->numsides++;
587 memset( s2, 0, sizeof( *s2 ) );
589 s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[ j ] );
590 s2->contentFlags = buildBrush->sides[0].contentFlags;
603 produces a final brush based on the buildBrush->sides array
604 and links it to the current entity
607 static void MergeOrigin(entity_t *ent, vec3_t origin)
612 /* we have not parsed the brush completely yet... */
613 GetVectorForKey( ent, "origin", ent->origin );
615 VectorMA(origin, -1, ent->originbrush_origin, adjustment);
616 VectorAdd(adjustment, ent->origin, ent->origin);
617 VectorCopy(origin, ent->originbrush_origin);
619 sprintf(string, "%f %f %f", ent->origin[0], ent->origin[1], ent->origin[2]);
620 SetKeyValue(ent, "origin", string);
623 brush_t *FinishBrush( qboolean noCollapseGroups )
628 /* create windings for sides and bounds for brush */
629 if ( !CreateBrushWindings( buildBrush ) )
632 /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
633 after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
634 if( buildBrush->compileFlags & C_ORIGIN )
638 Sys_Printf( "Entity %i, Brush %i: origin brush detected\n",
639 mapEnt->mapEntityNum, entitySourceBrushes );
641 if( numEntities == 1 )
643 Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n",
644 mapEnt->mapEntityNum, entitySourceBrushes );
648 VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
649 VectorScale (origin, 0.5, origin);
651 MergeOrigin(&entities[ numEntities - 1 ], origin);
653 /* don't keep this brush */
657 /* determine if the brush is an area portal */
658 if( buildBrush->compileFlags & C_AREAPORTAL )
660 if( numEntities != 1 )
662 Sys_Printf ("Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
667 /* add bevel planes */
668 if(!noCollapseGroups)
672 b = CopyBrush( buildBrush );
674 /* set map entity and brush numbering */
675 b->entityNum = mapEnt->mapEntityNum;
676 b->brushNum = entitySourceBrushes;
681 /* link opaque brushes to head of list, translucent brushes to end */
682 if( b->opaque || mapEnt->lastBrush == NULL )
684 b->next = mapEnt->brushes;
686 if( mapEnt->lastBrush == NULL )
687 mapEnt->lastBrush = b;
692 mapEnt->lastBrush->next = b;
693 mapEnt->lastBrush = b;
696 /* link colorMod volume brushes to the entity directly */
697 if( b->contentShader != NULL &&
698 b->contentShader->colorMod != NULL &&
699 b->contentShader->colorMod->type == CM_VOLUME )
701 b->nextColorModBrush = mapEnt->colorModBrushes;
702 mapEnt->colorModBrushes = b;
705 /* return to sender */
712 TextureAxisFromPlane()
713 determines best orthagonal axis to project a texture onto a wall
714 (must be identical in radiant!)
717 vec3_t baseaxis[18] =
719 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
720 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
721 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
722 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
723 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
724 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
727 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv )
736 for (i=0 ; i<6 ; i++)
738 dot = DotProduct (pln->normal, baseaxis[i*3]);
739 if( dot > best + 0.0001f ) /* ydnar: bug 637 fix, suggested by jmonroe */
746 VectorCopy (baseaxis[bestaxis*3+1], xv);
747 VectorCopy (baseaxis[bestaxis*3+2], yv);
754 creates world-to-texture mapping vecs for crappy quake plane arrangements
757 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] )
761 vec_t ang, sinv, cosv;
766 TextureAxisFromPlane(plane, vecs[0], vecs[1]);
775 { sinv = 0 ; cosv = 1; }
776 else if (rotate == 90)
777 { sinv = 1 ; cosv = 0; }
778 else if (rotate == 180)
779 { sinv = 0 ; cosv = -1; }
780 else if (rotate == 270)
781 { sinv = -1 ; cosv = 0; }
784 ang = rotate / 180 * Q_PI;
803 for (i=0 ; i<2 ; i++) {
804 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
805 nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
810 for (i=0 ; i<2 ; i++)
811 for (j=0 ; j<3 ; j++)
812 mappingVecs[i][j] = vecs[i][j] / scale[i];
814 mappingVecs[0][3] = shift[0];
815 mappingVecs[1][3] = shift[1];
822 parses the sides into buildBrush->sides[], nothing else.
823 no validation, back plane removal, etc.
826 added brush epairs parsing ( ignoring actually )
828 added exclusive brush primitive parsing
830 support for old brush format back in
831 NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
834 static void ParseRawBrush( qboolean onlyLights )
837 vec3_t planePoints[ 3 ];
843 char name[ MAX_QPATH ];
844 char shader[ MAX_QPATH ];
849 buildBrush->numsides = 0;
850 buildBrush->detail = qfalse;
853 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
859 if( !GetToken( qtrue ) )
861 if( !strcmp( token, "}" ) )
864 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
865 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
869 if( strcmp( token, "(" ) )
878 /* test side count */
879 if( buildBrush->numsides >= MAX_BUILD_SIDES )
880 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
883 side = &buildBrush->sides[ buildBrush->numsides ];
884 memset( side, 0, sizeof( *side ) );
885 buildBrush->numsides++;
887 /* read the three point plane definition */
888 Parse1DMatrix( 3, planePoints[ 0 ] );
889 Parse1DMatrix( 3, planePoints[ 1 ] );
890 Parse1DMatrix( 3, planePoints[ 2 ] );
892 /* bp: read the texture matrix */
893 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
894 Parse2DMatrix( 2, 3, (float*) side->texMat );
896 /* read shader name */
898 strcpy( name, token );
901 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
904 shift[ 0 ] = atof( token );
906 shift[ 1 ] = atof( token );
908 rotate = atof( token );
910 scale[ 0 ] = atof( token );
912 scale[ 1 ] = atof( token );
915 /* set default flags and values */
916 sprintf( shader, "textures/%s", name );
918 si = &shaderInfo[ 0 ];
920 si = ShaderInfoForShader( shader );
921 side->shaderInfo = si;
922 side->surfaceFlags = si->surfaceFlags;
923 side->contentFlags = si->contentFlags;
924 side->compileFlags = si->compileFlags;
925 side->value = si->value;
927 /* ydnar: gs mods: bias texture shift */
928 if( si->globalTexture == qfalse )
930 shift[ 0 ] -= (floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth);
931 shift[ 1 ] -= (floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight);
935 historically, there are 3 integer values at the end of a brushside line in a .map file.
936 in quake 3, the only thing that mattered was the first of these three values, which
937 was previously the content flags. and only then did a single bit matter, the detail
938 bit. because every game has its own special flags for specifying detail, the
939 traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
940 by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
941 is stored in compileFlags, as opposed to contentFlags, for multiple-game
945 if( TokenAvailable() )
947 /* get detail bit from map content flags */
949 flags = atoi( token );
950 if( flags & C_DETAIL )
951 side->compileFlags |= C_DETAIL;
955 //% td.flags = atoi( token );
957 //% td.value = atoi( token );
960 /* find the plane number */
961 planenum = MapPlaneFromPoints( planePoints );
962 side->planenum = planenum;
964 /* bp: get the texture mapping for this texturedef / plane combination */
965 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
966 QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
970 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
981 RemoveDuplicateBrushPlanes
982 returns false if the brush has a mirrored set of planes,
983 meaning it encloses no volume.
984 also removes planes without any normal
987 qboolean RemoveDuplicateBrushPlanes( brush_t *b )
994 for ( i = 1 ; i < b->numsides ; i++ ) {
996 // check for a degenerate plane
997 if ( sides[i].planenum == -1) {
998 xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
1000 for ( k = i + 1 ; k < b->numsides ; k++ ) {
1001 sides[k-1] = sides[k];
1008 // check for duplication and mirroring
1009 for ( j = 0 ; j < i ; j++ ) {
1010 if ( sides[i].planenum == sides[j].planenum ) {
1011 xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
1012 // remove the second duplicate
1013 for ( k = i + 1 ; k < b->numsides ; k++ ) {
1014 sides[k-1] = sides[k];
1021 if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
1022 // mirror plane, brush is invalid
1023 xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
1035 parses a brush out of a map file and sets it up
1038 static void ParseBrush( qboolean onlyLights, qboolean noCollapseGroups )
1043 /* parse the brush out of the map */
1044 ParseRawBrush( onlyLights );
1046 /* only go this far? */
1050 /* set some defaults */
1051 buildBrush->portalareas[ 0 ] = -1;
1052 buildBrush->portalareas[ 1 ] = -1;
1053 buildBrush->entityNum = numMapEntities - 1;
1054 buildBrush->brushNum = entitySourceBrushes;
1056 /* if there are mirrored planes, the entire brush is invalid */
1057 if( !RemoveDuplicateBrushPlanes( buildBrush ) )
1060 /* get the content for the entire brush */
1061 SetBrushContents( buildBrush );
1063 /* allow detail brushes to be removed */
1064 if( nodetail && (buildBrush->compileFlags & C_DETAIL) )
1066 //% FreeBrush( buildBrush );
1070 /* allow liquid brushes to be removed */
1071 if( nowater && (buildBrush->compileFlags & C_LIQUID ) )
1073 //% FreeBrush( buildBrush );
1077 /* ydnar: allow hint brushes to be removed */
1078 if( noHint && (buildBrush->compileFlags & C_HINT) )
1080 //% FreeBrush( buildBrush );
1084 /* finish the brush */
1085 b = FinishBrush(noCollapseGroups);
1091 MoveBrushesToWorld()
1092 takes all of the brushes from the current entity and
1093 adds them to the world's brush list
1094 (used by func_group)
1097 void AdjustBrushesForOrigin( entity_t *ent );
1098 void MoveBrushesToWorld( entity_t *ent )
1103 /* we need to undo the common/origin adjustment, and instead shift them by the entity key origin */
1104 VectorScale(ent->origin, -1, ent->originbrush_origin);
1105 AdjustBrushesForOrigin(ent);
1106 VectorClear(ent->originbrush_origin);
1109 for( b = ent->brushes; b != NULL; b = next )
1111 /* get next brush */
1114 /* link opaque brushes to head of list, translucent brushes to end */
1115 if( b->opaque || entities[ 0 ].lastBrush == NULL )
1117 b->next = entities[ 0 ].brushes;
1118 entities[ 0 ].brushes = b;
1119 if( entities[ 0 ].lastBrush == NULL )
1120 entities[ 0 ].lastBrush = b;
1125 entities[ 0 ].lastBrush->next = b;
1126 entities[ 0 ].lastBrush = b;
1129 ent->brushes = NULL;
1131 /* ydnar: move colormod brushes */
1132 if( ent->colorModBrushes != NULL )
1134 for( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush );
1136 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1137 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1139 ent->colorModBrushes = NULL;
1143 if( ent->patches != NULL )
1145 for( pm = ent->patches; pm->next != NULL; pm = pm->next );
1147 pm->next = entities[ 0 ].patches;
1148 entities[ 0 ].patches = ent->patches;
1150 ent->patches = NULL;
1157 AdjustBrushesForOrigin()
1160 void AdjustBrushesForOrigin( entity_t *ent )
1169 /* walk brush list */
1170 for( b = ent->brushes; b != NULL; b = b->next )
1172 /* offset brush planes */
1173 for( i = 0; i < b->numsides; i++)
1175 /* get brush side */
1178 /* offset side plane */
1179 newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->originbrush_origin );
1181 /* find a new plane */
1182 s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1185 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1186 CreateBrushWindings( b );
1189 /* walk patch list */
1190 for( p = ent->patches; p != NULL; p = p->next )
1192 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1193 VectorSubtract( p->mesh.verts[ i ].xyz, ent->originbrush_origin, p->mesh.verts[ i ].xyz );
1200 SetEntityBounds() - ydnar
1201 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1204 void SetEntityBounds( entity_t *e )
1215 /* walk the entity's brushes/patches and determine bounds */
1216 ClearBounds( mins, maxs );
1217 for( b = e->brushes; b; b = b->next )
1219 AddPointToBounds( b->mins, mins, maxs );
1220 AddPointToBounds( b->maxs, mins, maxs );
1222 for( p = e->patches; p; p = p->next )
1224 for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
1225 AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1228 /* try to find explicit min/max key */
1229 value = ValueForKey( e, "min" );
1230 if( value[ 0 ] != '\0' )
1231 GetVectorForKey( e, "min", mins );
1232 value = ValueForKey( e, "max" );
1233 if( value[ 0 ] != '\0' )
1234 GetVectorForKey( e, "max", maxs );
1236 /* store the bounds */
1237 for( b = e->brushes; b; b = b->next )
1239 VectorCopy( mins, b->eMins );
1240 VectorCopy( maxs, b->eMaxs );
1242 for( p = e->patches; p; p = p->next )
1244 VectorCopy( mins, p->eMins );
1245 VectorCopy( maxs, p->eMaxs );
1252 LoadEntityIndexMap() - ydnar
1253 based on LoadAlphaMap() from terrain.c, a little more generic
1256 void LoadEntityIndexMap( entity_t *e )
1258 int i, size, numLayers, w, h;
1259 const char *value, *indexMapFilename, *shader;
1260 char ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1262 unsigned int *pixels32;
1268 /* this only works with bmodel ents */
1269 if( e->brushes == NULL && e->patches == NULL )
1272 /* determine if there is an index map (support legacy "alphamap" key as well) */
1273 value = ValueForKey( e, "_indexmap" );
1274 if( value[ 0 ] == '\0' )
1275 value = ValueForKey( e, "alphamap" );
1276 if( value[ 0 ] == '\0' )
1278 indexMapFilename = value;
1280 /* get number of layers (support legacy "layers" key as well) */
1281 value = ValueForKey( e, "_layers" );
1282 if( value[ 0 ] == '\0' )
1283 value = ValueForKey( e, "layers" );
1284 if( value[ 0 ] == '\0' )
1286 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1287 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1290 numLayers = atoi( value );
1293 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1294 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1298 /* get base shader name (support legacy "shader" key as well) */
1299 value = ValueForKey( mapEnt, "_shader" );
1300 if( value[ 0 ] == '\0' )
1301 value = ValueForKey( e, "shader" );
1302 if( value[ 0 ] == '\0' )
1304 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1305 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1311 Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n", mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1313 /* get index map file extension */
1314 ExtractFileExtension( indexMapFilename, ext );
1316 /* handle tga image */
1317 if( !Q_stricmp( ext, "tga" ) )
1320 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1322 /* convert to bytes */
1324 pixels = safe_malloc( size );
1325 for( i = 0; i < size; i++ )
1327 pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256;
1328 if( pixels[ i ] >= numLayers )
1329 pixels[ i ] = numLayers - 1;
1332 /* free the 32 bit image */
1338 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1341 //% Sys_Printf( "-------------------------------" );
1343 /* fix up out-of-range values */
1345 for( i = 0; i < size; i++ )
1347 if( pixels[ i ] >= numLayers )
1348 pixels[ i ] = numLayers - 1;
1351 //% if( (i % w) == 0 )
1352 //% Sys_Printf( "\n" );
1353 //% Sys_Printf( "%c", pixels[ i ] + '0' );
1357 //% Sys_Printf( "\n-------------------------------\n" );
1360 /* the index map must be at least 2x2 pixels */
1361 if( w < 2 || h < 2 )
1363 Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1364 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1369 /* create a new index map */
1370 im = safe_malloc( sizeof( *im ) );
1371 memset( im, 0, sizeof( *im ) );
1376 im->numLayers = numLayers;
1377 strcpy( im->name, indexMapFilename );
1378 strcpy( im->shader, shader );
1379 im->pixels = pixels;
1381 /* get height offsets */
1382 value = ValueForKey( mapEnt, "_offsets" );
1383 if( value[ 0 ] == '\0' )
1384 value = ValueForKey( e, "offsets" );
1385 if( value[ 0 ] != '\0' )
1387 /* value is a space-seperated set of numbers */
1388 strcpy( offset, value );
1391 /* get each value */
1392 for( i = 0; i < 256 && *search != '\0'; i++ )
1394 space = strstr( search, " " );
1397 im->offsets[ i ] = atof( search );
1404 /* store the index map in every brush/patch in the entity */
1405 for( b = e->brushes; b != NULL; b = b->next )
1407 for( p = e->patches; p != NULL; p = p->next )
1419 parses a single entity out of a map file
1422 static qboolean ParseMapEntity( qboolean onlyLights, qboolean noCollapseGroups )
1425 const char *classname, *value;
1426 float lightmapScale, shadeAngle;
1427 int lightmapSampleSize;
1428 char shader[ MAX_QPATH ];
1429 shaderInfo_t *celShader = NULL;
1433 int castShadows, recvShadows;
1437 if( !GetToken( qtrue ) )
1440 /* conformance check */
1441 if( strcmp( token, "{" ) )
1443 Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1444 "Continuing to process map, but resulting BSP may be invalid.\n",
1445 token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1450 if( numEntities >= MAX_MAP_ENTITIES )
1451 Error( "numEntities == MAX_MAP_ENTITIES" );
1454 entitySourceBrushes = 0;
1455 mapEnt = &entities[ numEntities ];
1457 memset( mapEnt, 0, sizeof( *mapEnt ) );
1459 /* ydnar: true entity numbering */
1460 mapEnt->mapEntityNum = numMapEntities;
1466 /* get initial token */
1467 if( !GetToken( qtrue ) )
1469 Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n"
1470 "Continuing to process map, but resulting BSP may be invalid.\n" );
1474 if( !strcmp( token, "}" ) )
1477 if( !strcmp( token, "{" ) )
1479 /* parse a brush or patch */
1480 if( !GetToken( qtrue ) )
1484 if( !strcmp( token, "patchDef2" ) )
1487 ParsePatch( onlyLights );
1489 else if( !strcmp( token, "terrainDef" ) )
1492 Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1494 else if( !strcmp( token, "brushDef" ) )
1496 if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
1497 Error( "Old brush format not allowed in new brush format map" );
1498 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1500 /* parse brush primitive */
1501 ParseBrush( onlyLights, noCollapseGroups );
1505 if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES )
1506 Error( "New brush format not allowed in old brush format map" );
1507 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1509 /* parse old brush format */
1511 ParseBrush( onlyLights, noCollapseGroups );
1513 entitySourceBrushes++;
1517 /* parse a key / value pair */
1520 /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1521 if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' )
1523 ep->next = mapEnt->epairs;
1524 mapEnt->epairs = ep;
1529 /* ydnar: get classname */
1530 classname = ValueForKey( mapEnt, "classname" );
1532 /* ydnar: only lights? */
1533 if( onlyLights && Q_strncasecmp( classname, "light", 5 ) )
1539 /* ydnar: determine if this is a func_group */
1540 if( !Q_stricmp( "func_group", classname ) )
1545 /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1546 if( funcGroup || mapEnt->mapEntityNum == 0 )
1548 //% Sys_Printf( "World: %d\n", mapEnt->mapEntityNum );
1549 castShadows = WORLDSPAWN_CAST_SHADOWS;
1550 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1553 /* other entities don't cast any shadows, but recv worldspawn shadows */
1556 //% Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1557 castShadows = ENTITY_CAST_SHADOWS;
1558 recvShadows = ENTITY_RECV_SHADOWS;
1561 /* get explicit shadow flags */
1562 GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1564 /* vortex: added _ls key (short name of lightmapscale) */
1565 /* ydnar: get lightmap scaling value for this entity */
1566 lightmapScale = 0.0f;
1567 if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1568 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) ||
1569 strcmp( "", ValueForKey( mapEnt, "_ls" ) ) )
1571 /* get lightmap scale from entity */
1572 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1573 if( lightmapScale <= 0.0f )
1574 lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1575 if( lightmapScale <= 0.0f )
1576 lightmapScale = FloatForKey( mapEnt, "_ls" );
1577 if( lightmapScale < 0.0f )
1578 lightmapScale = 0.0f;
1579 if( lightmapScale > 0.0f )
1580 Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1583 /* ydnar: get cel shader :) for this entity */
1584 value = ValueForKey( mapEnt, "_celshader" );
1585 if( value[ 0 ] == '\0' )
1586 value = ValueForKey( &entities[ 0 ], "_celshader" );
1587 if( value[ 0 ] != '\0' )
1589 if(strcmp(value, "none"))
1591 sprintf( shader, "textures/%s", value );
1592 celShader = ShaderInfoForShader( shader );
1593 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1601 celShader = (*globalCelShader ? ShaderInfoForShader(globalCelShader) : NULL);
1603 /* jal : entity based _shadeangle */
1605 if ( strcmp( "", ValueForKey( mapEnt, "_shadeangle" ) ) )
1606 shadeAngle = FloatForKey( mapEnt, "_shadeangle" );
1607 /* vortex' aliases */
1608 else if ( strcmp( "", ValueForKey( mapEnt, "_smoothnormals" ) ) )
1609 shadeAngle = FloatForKey( mapEnt, "_smoothnormals" );
1610 else if ( strcmp( "", ValueForKey( mapEnt, "_sn" ) ) )
1611 shadeAngle = FloatForKey( mapEnt, "_sn" );
1612 else if ( strcmp( "", ValueForKey( mapEnt, "_smooth" ) ) )
1613 shadeAngle = FloatForKey( mapEnt, "_smooth" );
1615 if( shadeAngle < 0.0f )
1618 if( shadeAngle > 0.0f )
1619 Sys_Printf( "Entity %d (%s) has shading angle of %.4f\n", mapEnt->mapEntityNum, classname, shadeAngle );
1621 /* jal : entity based _samplesize */
1622 lightmapSampleSize = 0;
1623 if ( strcmp( "", ValueForKey( mapEnt, "_lightmapsamplesize" ) ) )
1624 lightmapSampleSize = IntForKey( mapEnt, "_lightmapsamplesize" );
1625 else if ( strcmp( "", ValueForKey( mapEnt, "_samplesize" ) ) )
1626 lightmapSampleSize = IntForKey( mapEnt, "_samplesize" );
1628 if( lightmapSampleSize < 0 )
1629 lightmapSampleSize = 0;
1631 if( lightmapSampleSize > 0 )
1632 Sys_Printf( "Entity %d (%s) has lightmap sample size of %d\n", mapEnt->mapEntityNum, classname, lightmapSampleSize );
1634 /* attach stuff to everything in the entity */
1635 for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1637 brush->entityNum = mapEnt->mapEntityNum;
1638 brush->castShadows = castShadows;
1639 brush->recvShadows = recvShadows;
1640 brush->lightmapSampleSize = lightmapSampleSize;
1641 brush->lightmapScale = lightmapScale;
1642 brush->celShader = celShader;
1643 brush->shadeAngleDegrees = shadeAngle;
1646 for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1648 patch->entityNum = mapEnt->mapEntityNum;
1649 patch->castShadows = castShadows;
1650 patch->recvShadows = recvShadows;
1651 patch->lightmapSampleSize = lightmapSampleSize;
1652 patch->lightmapScale = lightmapScale;
1653 patch->celShader = celShader;
1656 /* ydnar: gs mods: set entity bounds */
1657 SetEntityBounds( mapEnt );
1659 /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1660 LoadEntityIndexMap( mapEnt );
1662 /* get entity origin and adjust brushes */
1663 GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1664 if( mapEnt->originbrush_origin[ 0 ] || mapEnt->originbrush_origin[ 1 ] || mapEnt->originbrush_origin[ 2 ] )
1665 AdjustBrushesForOrigin( mapEnt );
1667 /* group_info entities are just for editor grouping (fixme: leak!) */
1668 if( !noCollapseGroups && !Q_stricmp( "group_info", classname ) )
1674 /* group entities are just for editor convenience, toss all brushes into worldspawn */
1675 if( !noCollapseGroups && funcGroup )
1677 MoveBrushesToWorld( mapEnt );
1690 loads a map file into a list of entities
1693 void LoadMapFile( char *filename, qboolean onlyLights, qboolean noCollapseGroups )
1697 int oldNumEntities = 0, numMapBrushes;
1701 Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1702 Sys_Printf( "Loading %s\n", filename );
1705 file = SafeOpenRead( filename );
1708 /* load the map file */
1709 LoadScriptFile( filename, -1 );
1713 oldNumEntities = numEntities;
1718 numMapDrawSurfs = 0;
1720 g_bBrushPrimit = BPRIMIT_UNDEFINED;
1722 /* allocate a very large temporary brush for building the brushes as they are loaded */
1723 buildBrush = AllocBrush( MAX_BUILD_SIDES );
1725 /* parse the map file */
1726 while( ParseMapEntity( onlyLights, noCollapseGroups ) );
1731 /* emit some statistics */
1732 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1736 /* set map bounds */
1737 ClearBounds( mapMins, mapMaxs );
1738 for( b = entities[ 0 ].brushes; b; b = b->next )
1740 AddPointToBounds( b->mins, mapMins, mapMaxs );
1741 AddPointToBounds( b->maxs, mapMins, mapMaxs );
1744 /* get brush counts */
1745 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1746 if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 )
1747 Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1749 /* emit some statistics */
1750 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1751 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1752 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches);
1753 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels);
1754 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels);
1755 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1756 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes);
1757 Sys_Printf( "%9d areaportals\n", c_areaportals);
1758 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1759 mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1760 mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]);
1762 /* write bogus map */
1764 WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );