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 qboolean PlaneEqual( plane_t *p, vec3_t normal, vec_t dist ){
66 /* get local copies */
71 // We check equality of each component since we're using '<', not '<='
72 // (the epsilons may be zero). We want to use '<' instead of '<=' to be
73 // consistent with the true meaning of "epsilon", and also because other
74 // parts of the code uses this inequality.
75 if ( ( p->dist == dist || fabs( p->dist - dist ) < de ) &&
76 ( p->normal[0] == normal[0] || fabs( p->normal[0] - normal[0] ) < ne ) &&
77 ( p->normal[1] == normal[1] || fabs( p->normal[1] - normal[1] ) < ne ) &&
78 ( p->normal[2] == normal[2] || fabs( p->normal[2] - normal[2] ) < ne ) ) {
92 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 ){
110 if ( VectorLength( normal ) < 0.5 ) {
111 Sys_Printf( "FloatPlane: bad normal\n" );
115 // create a new plane
116 AUTOEXPAND_BY_REALLOC( mapplanes, nummapplanes + 1, allocatedmapplanes, 1024 );
118 p = &mapplanes[nummapplanes];
119 VectorCopy( normal, p->normal );
121 p->type = ( p + 1 )->type = PlaneTypeForNormal( p->normal );
123 VectorSubtract( vec3_origin, normal, ( p + 1 )->normal );
124 ( p + 1 )->dist = -dist;
128 // allways put axial planes facing positive first
130 if ( p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0 ) {
137 AddPlaneToHash( p + 1 );
138 return nummapplanes - 1;
143 AddPlaneToHash( p + 1 );
144 return nummapplanes - 2;
151 Snaps a near-axial normal vector.
152 Returns qtrue if and only if the normal was adjusted.
155 qboolean SnapNormal( vec3_t normal ){
156 #if Q3MAP2_EXPERIMENTAL_SNAP_NORMAL_FIX
158 qboolean adjusted = qfalse;
160 // A change from the original SnapNormal() is that we snap each
161 // component that's close to 0. So for example if a normal is
162 // (0.707, 0.707, 0.0000001), it will get snapped to lie perfectly in the
163 // XY plane (its Z component will be set to 0 and its length will be
164 // normalized). The original SnapNormal() didn't snap such vectors - it
165 // only snapped vectors that were near a perfect axis.
167 //adjusting vectors, that were near a perfect axis, with bigger epsilon
168 //they cause precision errors
171 if ( ( normal[0] != 0.0 || normal[1] != 0.0 ) && fabs(normal[0]) < 0.00025 && fabs(normal[1]) < 0.00025){
172 normal[0] = normal[1] = 0.0;
175 else if ( ( normal[0] != 0.0 || normal[2] != 0.0 ) && fabs(normal[0]) < 0.00025 && fabs(normal[2]) < 0.00025){
176 normal[0] = normal[2] = 0.0;
179 else if ( ( normal[2] != 0.0 || normal[1] != 0.0 ) && fabs(normal[2]) < 0.00025 && fabs(normal[1]) < 0.00025){
180 normal[2] = normal[1] = 0.0;
186 for ( i=0; i<30; i++ )
188 double x, y, z, length;
190 y=(double) ( 0.00001 * i );
193 Sys_Printf("(%6.18f %6.18f %6.18f)inNormal\n", x,y,z );
195 length = sqrt( ( x * x ) + ( y * y ) + ( z * z ) );
196 Sys_Printf("(%6.18f)length\n", length);
197 x = (vec_t) ( x / length );
198 y = (vec_t) ( y / length );
199 z = (vec_t) ( z / length );
200 Sys_Printf("(%6.18f %6.18f %6.18f)outNormal\n\n", x,y,z );
202 Error("vectorNormalize test completed");
205 for ( i = 0; i < 3; i++ )
207 if ( normal[i] != 0.0 && -normalEpsilon < normal[i] && normal[i] < normalEpsilon ) {
214 VectorNormalize( normal, normal );
221 // I would suggest that you uncomment the following code and look at the
225 Sys_Printf("normalEpsilon is %f\n", normalEpsilon);
230 normal[2] = i * 0.000001;
231 VectorNormalize(normal, normal);
232 if (1.0 - normal[0] >= normalEpsilon) {
233 Sys_Printf("(%f %f %f)\n", normal[0], normal[1], normal[2]);
234 Error("SnapNormal: test completed");
239 // When the normalEpsilon is 0.00001, the loop will break out when normal is
240 // (0.999990 0.000000 0.004469). In other words, this is the vector closest
241 // to axial that will NOT be snapped. Anything closer will be snaped. Now,
242 // 0.004469 is close to 1/225. The length of a circular quarter-arc of radius
243 // 1 is PI/2, or about 1.57. And 0.004469/1.57 is about 0.0028, or about
244 // 1/350. Expressed a different way, 1/350 is also about 0.26/90.
245 // This means is that a normal with an angle that is within 1/4 of a degree
246 // from axial will be "snapped". My belief is that the person who wrote the
247 // code below did not intend it this way. I think the person intended that
248 // the epsilon be measured against the vector components close to 0, not 1.0.
249 // I think the logic should be: if 2 of the normal components are within
250 // epsilon of 0, then the vector can be snapped to be perfectly axial.
251 // We may consider adjusting the epsilon to a larger value when we make this
254 for ( i = 0; i < 3; i++ )
256 if ( fabs( normal[ i ] - 1 ) < normalEpsilon ) {
257 VectorClear( normal );
261 if ( fabs( normal[ i ] - -1 ) < normalEpsilon ) {
262 VectorClear( normal );
275 snaps a plane to normal/distance epsilons
278 void SnapPlane( vec3_t normal, vec_t *dist ){
279 // SnapPlane disabled by LordHavoc because it often messes up collision
280 // brushes made from triangles of embedded models, and it has little effect
281 // on anything else (axial planes are usually derived from snapped points)
283 SnapPlane reenabled by namespace because of multiple reports of
284 q3map2-crashes which were triggered by this patch.
286 SnapNormal( normal );
288 // TODO: Rambetter has some serious comments here as well. First off,
289 // in the case where a normal is non-axial, there is nothing special
290 // about integer distances. I would think that snapping a distance might
291 // make sense for axial normals, but I'm not so sure about snapping
292 // non-axial normals. A shift by 0.01 in a plane, multiplied by a clipping
293 // against another plane that is 5 degrees off, and we introduce 0.1 error
294 // easily. A 0.1 error in a vertex is where problems start to happen, such
295 // as disappearing triangles.
297 // Second, assuming we have snapped the normal above, let's say that the
298 // plane we just snapped was defined for some points that are actually
299 // quite far away from normal * dist. Well, snapping the normal in this
300 // case means that we've just moved those points by potentially many units!
301 // Therefore, if we are going to snap the normal, we need to know the
302 // points we're snapping for so that the plane snaps with those points in
303 // mind (points remain close to the plane).
305 // I would like to know exactly which problems SnapPlane() is trying to
306 // solve so that we can better engineer it (I'm not saying that SnapPlane()
307 // should be removed altogether). Fix all this snapping code at some point!
309 if ( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon ) {
310 *dist = Q_rint( *dist );
316 snaps a plane to normal/distance epsilons, improved code
318 void SnapPlaneImproved( vec3_t normal, vec_t *dist, int numPoints, const vec3_t *points ){
321 vec_t distNearestInt;
323 if ( SnapNormal( normal ) ) {
324 if ( numPoints > 0 ) {
325 // Adjust the dist so that the provided points don't drift away.
326 VectorClear( center );
327 for ( i = 0; i < numPoints; i++ )
329 VectorAdd( center, points[i], center );
331 for ( i = 0; i < 3; i++ ) { center[i] = center[i] / numPoints; }
332 *dist = DotProduct( normal, center );
336 if ( VectorIsOnAxis( normal ) ) {
337 // Only snap distance if the normal is an axis. Otherwise there
338 // is nothing "natural" about snapping the distance to an integer.
339 distNearestInt = Q_rint( *dist );
340 if ( -distanceEpsilon < *dist - distNearestInt && *dist - distNearestInt < distanceEpsilon ) {
341 *dist = distNearestInt;
350 ydnar: changed to allow a number of test points to be supplied that
351 must be within an epsilon distance of the plane
354 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?
365 VectorCopy( innormal, normal );
366 #if Q3MAP2_EXPERIMENTAL_SNAP_PLANE_FIX
367 SnapPlaneImproved( normal, &dist, numPoints, (const vec3_t *) points );
369 SnapPlane( normal, &dist );
372 hash = ( PLANE_HASHES - 1 ) & (int) fabs( dist );
374 /* search the border bins as well */
375 for ( i = -1; i <= 1; i++ )
377 h = ( hash + i ) & ( PLANE_HASHES - 1 );
378 for ( pidx = planehash[ h ] - 1; pidx != -1; pidx = mapplanes[pidx].hash_chain - 1 )
380 p = &mapplanes[pidx];
382 /* do standard plane compare */
383 if ( !PlaneEqual( p, normal, dist ) ) {
387 /* ydnar: uncomment the following line for old-style plane finding */
388 //% return p - mapplanes;
390 /* ydnar: test supplied points against this plane */
391 for ( j = 0; j < numPoints; j++ )
393 // NOTE: When dist approaches 2^16, the resolution of 32 bit floating
394 // point number is greatly decreased. The distanceEpsilon cannot be
395 // very small when world coordinates extend to 2^16. Making the
396 // dot product here in 64 bit land will not really help the situation
397 // because the error will already be carried in dist.
398 d = DotProduct( points[ j ], p->normal ) - p->dist;
400 if ( d != 0.0 && d >= distanceEpsilon ) {
401 break; // Point is too far from plane.
405 /* found a matching plane */
406 if ( j >= numPoints ) {
407 return p - mapplanes;
412 /* none found, so create a new one */
413 return CreateNewFloatPlane( normal, dist );
423 VectorCopy( innormal, normal );
424 #if Q3MAP2_EXPERIMENTAL_SNAP_PLANE_FIX
425 SnapPlaneImproved( normal, &dist, numPoints, (const vec3_t *) points );
427 SnapPlane( normal, &dist );
429 for ( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
431 if ( !PlaneEqual( p, normal, dist ) ) {
435 /* ydnar: uncomment the following line for old-style plane finding */
438 /* ydnar: test supplied points against this plane */
439 for ( j = 0; j < numPoints; j++ )
441 d = DotProduct( points[ j ], p->normal ) - p->dist;
442 if ( fabs( d ) > distanceEpsilon ) {
447 /* found a matching plane */
448 if ( j >= numPoints ) {
451 // TODO: Note that the non-USE_HASHING code does not compute epsilons
452 // for the provided points. It should do that. I think this code
453 // is unmaintained because nobody sets USE_HASHING to off.
456 return CreateNewFloatPlane( normal, dist );
465 takes 3 points and finds the plane they lie in
468 int MapPlaneFromPoints( vec3_t *p ){
469 #if Q3MAP2_EXPERIMENTAL_HIGH_PRECISION_MATH_FIXES
470 vec3_accu_t paccu[3];
471 vec3_accu_t t1, t2, normalAccu;
475 VectorCopyRegularToAccu( p[0], paccu[0] );
476 VectorCopyRegularToAccu( p[1], paccu[1] );
477 VectorCopyRegularToAccu( p[2], paccu[2] );
479 VectorSubtractAccu( paccu[0], paccu[1], t1 );
480 VectorSubtractAccu( paccu[2], paccu[1], t2 );
481 CrossProductAccu( t1, t2, normalAccu );
482 VectorNormalizeAccu( normalAccu, normalAccu );
483 // TODO: A 32 bit float for the plane distance isn't enough resolution
484 // if the plane is 2^16 units away from the origin (the "epsilon" approaches
485 // 0.01 in that case).
486 dist = (vec_t) DotProductAccu( paccu[0], normalAccu );
487 VectorCopyAccuToRegular( normalAccu, normal );
489 return FindFloatPlane( normal, dist, 3, p );
491 vec3_t t1, t2, normal;
495 /* calc plane normal */
496 VectorSubtract( p[ 0 ], p[ 1 ], t1 );
497 VectorSubtract( p[ 2 ], p[ 1 ], t2 );
498 CrossProduct( t1, t2, normal );
499 VectorNormalize( normal, normal );
501 /* calc plane distance */
502 dist = DotProduct( p[ 0 ], normal );
504 /* store the plane */
505 return FindFloatPlane( normal, dist, 3, p );
513 the content flags and compile flags on all sides of a brush should be the same
516 void SetBrushContents( brush_t *b ){
517 int contentFlags, compileFlags;
523 /* get initial compile flags from first side */
525 contentFlags = s->contentFlags;
526 compileFlags = s->compileFlags;
527 b->contentShader = s->shaderInfo;
530 /* get the content/compile flags for every side in the brush */
531 for ( i = 1; i < b->numsides; i++, s++ )
534 if ( s->shaderInfo == NULL ) {
537 //% if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
540 contentFlags |= s->contentFlags;
541 compileFlags |= s->compileFlags;
544 /* ydnar: getting rid of this stupid warning */
546 //% Sys_FPrintf( SYS_VRB,"Entity %i, Brush %i: mixed face contentFlags\n", b->entitynum, b->brushnum );
548 /* check for detail & structural */
549 if ( ( compileFlags & C_DETAIL ) && ( compileFlags & C_STRUCTURAL ) ) {
550 xml_Select( "Mixed detail and structural (defaulting to structural)", mapEnt->mapEntityNum, entitySourceBrushes, qfalse );
551 compileFlags &= ~C_DETAIL;
554 /* the fulldetail flag will cause detail brushes to be treated like normal brushes */
556 compileFlags &= ~C_DETAIL;
559 /* all translucent brushes that aren't specifically made structural will be detail */
560 if ( ( compileFlags & C_TRANSLUCENT ) && !( compileFlags & C_STRUCTURAL ) ) {
561 compileFlags |= C_DETAIL;
565 if ( compileFlags & C_DETAIL ) {
576 if ( compileFlags & C_TRANSLUCENT ) {
584 if ( compileFlags & C_AREAPORTAL ) {
588 /* set brush flags */
589 b->contentFlags = contentFlags;
590 b->compileFlags = compileFlags;
597 adds any additional planes necessary to allow the brush being
598 built to be expanded against axial bounding boxes
599 ydnar 2003-01-20: added mrelusive fixes
602 void AddBrushBevels( void ){
604 int i, j, k, l, order;
614 // add the axial planes
617 for ( axis = 0; axis < 3; axis++ ) {
618 for ( dir = -1; dir <= 1; dir += 2, order++ ) {
619 // see if the plane is allready present
620 for ( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
622 /* ydnar: testing disabling of mre code */
625 if ( mapplanes[s->planenum].normal[axis] >= 0.9999f ) {
630 if ( mapplanes[s->planenum].normal[axis] <= -0.9999f ) {
635 if ( ( dir > 0 && mapplanes[ s->planenum ].normal[ axis ] == 1.0f ) ||
636 ( dir < 0 && mapplanes[ s->planenum ].normal[ axis ] == -1.0f ) ) {
642 if ( i == buildBrush->numsides ) {
644 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
645 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
647 memset( s, 0, sizeof( *s ) );
648 buildBrush->numsides++;
649 VectorClear( normal );
653 /* ydnar: adding bevel plane snapping for fewer bsp planes */
654 if ( bevelSnap > 0 ) {
655 dist = floor( buildBrush->maxs[ axis ] / bevelSnap ) * bevelSnap;
658 dist = buildBrush->maxs[ axis ];
663 /* ydnar: adding bevel plane snapping for fewer bsp planes */
664 if ( bevelSnap > 0 ) {
665 dist = -ceil( buildBrush->mins[ axis ] / bevelSnap ) * bevelSnap;
668 dist = -buildBrush->mins[ axis ];
672 s->planenum = FindFloatPlane( normal, dist, 0, NULL );
673 s->contentFlags = buildBrush->sides[ 0 ].contentFlags;
678 // if the plane is not in it canonical order, swap it
680 sidetemp = buildBrush->sides[order];
681 buildBrush->sides[order] = buildBrush->sides[i];
682 buildBrush->sides[i] = sidetemp;
688 // add the edge bevels
690 if ( buildBrush->numsides == 6 ) {
691 return; // pure axial
694 // test the non-axial plane edges
695 for ( i = 6; i < buildBrush->numsides; i++ ) {
696 s = buildBrush->sides + i;
701 for ( j = 0; j < w->numpoints; j++ ) {
702 k = ( j + 1 ) % w->numpoints;
703 VectorSubtract( w->p[j], w->p[k], vec );
704 if ( VectorNormalize( vec, vec ) < 0.5f ) {
708 for ( k = 0; k < 3; k++ ) {
709 if ( vec[k] == -1.0f || vec[k] == 1.0f || ( vec[k] == 0.0f && vec[( k + 1 ) % 3] == 0.0f ) ) {
714 continue; // only test non-axial edges
718 //% Sys_Printf( "-------------\n" );
720 // try the six possible slanted axials from this edge
721 for ( axis = 0; axis < 3; axis++ ) {
722 for ( dir = -1; dir <= 1; dir += 2 ) {
726 CrossProduct( vec, vec2, normal );
727 if ( VectorNormalize( normal, normal ) < 0.5f ) {
730 dist = DotProduct( w->p[j], normal );
732 // if all the points on all the sides are
733 // behind this plane, it is a proper edge bevel
734 for ( k = 0; k < buildBrush->numsides; k++ ) {
736 // if this plane has allready been used, skip it
737 if ( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ) ) {
741 w2 = buildBrush->sides[k].winding;
746 for ( l = 0; l < w2->numpoints; l++ ) {
747 d = DotProduct( w2->p[l], normal ) - dist;
749 break; // point in front
755 // if some point was at the front
756 if ( l != w2->numpoints ) {
760 // if no points at the back then the winding is on the bevel plane
761 if ( minBack > -0.1f ) {
762 //% Sys_Printf( "On bevel plane\n" );
767 if ( k != buildBrush->numsides ) {
768 continue; // wasn't part of the outer hull
772 //% Sys_Printf( "n = %f %f %f\n", normal[ 0 ], normal[ 1 ], normal[ 2 ] );
775 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
776 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
778 s2 = &buildBrush->sides[buildBrush->numsides];
779 buildBrush->numsides++;
780 memset( s2, 0, sizeof( *s2 ) );
782 s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[ j ] );
783 s2->contentFlags = buildBrush->sides[0].contentFlags;
796 produces a final brush based on the buildBrush->sides array
797 and links it to the current entity
800 static void MergeOrigin( entity_t *ent, vec3_t origin ){
804 /* we have not parsed the brush completely yet... */
805 GetVectorForKey( ent, "origin", ent->origin );
807 VectorMA( origin, -1, ent->originbrush_origin, adjustment );
808 VectorAdd( adjustment, ent->origin, ent->origin );
809 VectorCopy( origin, ent->originbrush_origin );
811 sprintf( string, "%f %f %f", ent->origin[0], ent->origin[1], ent->origin[2] );
812 SetKeyValue( ent, "origin", string );
815 brush_t *FinishBrush( qboolean noCollapseGroups ){
819 /* create windings for sides and bounds for brush */
820 if ( !CreateBrushWindings( buildBrush ) ) {
824 /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity.
825 after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
826 if ( buildBrush->compileFlags & C_ORIGIN ) {
829 Sys_Printf( "Entity %i, Brush %i: origin brush detected\n",
830 mapEnt->mapEntityNum, entitySourceBrushes );
832 if ( numEntities == 1 ) {
833 Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n",
834 mapEnt->mapEntityNum, entitySourceBrushes );
838 VectorAdd( buildBrush->mins, buildBrush->maxs, origin );
839 VectorScale( origin, 0.5, origin );
841 MergeOrigin( &entities[ numEntities - 1 ], origin );
843 /* don't keep this brush */
847 /* determine if the brush is an area portal */
848 if ( buildBrush->compileFlags & C_AREAPORTAL ) {
849 if ( numEntities != 1 ) {
850 Sys_Printf( "Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes );
855 /* add bevel planes */
856 if ( !noCollapseGroups ) {
861 b = CopyBrush( buildBrush );
863 /* set map entity and brush numbering */
864 b->entityNum = mapEnt->mapEntityNum;
865 b->brushNum = entitySourceBrushes;
870 /* link opaque brushes to head of list, translucent brushes to end */
871 if ( b->opaque || mapEnt->lastBrush == NULL ) {
872 b->next = mapEnt->brushes;
874 if ( mapEnt->lastBrush == NULL ) {
875 mapEnt->lastBrush = b;
881 mapEnt->lastBrush->next = b;
882 mapEnt->lastBrush = b;
885 /* link colorMod volume brushes to the entity directly */
886 if ( b->contentShader != NULL &&
887 b->contentShader->colorMod != NULL &&
888 b->contentShader->colorMod->type == CM_VOLUME ) {
889 b->nextColorModBrush = mapEnt->colorModBrushes;
890 mapEnt->colorModBrushes = b;
893 /* return to sender */
900 TextureAxisFromPlane()
901 determines best orthagonal axis to project a texture onto a wall
902 (must be identical in radiant!)
905 vec3_t baseaxis[18] =
907 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
908 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
909 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
910 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
911 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
912 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
915 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv ){
923 for ( i = 0 ; i < 6 ; i++ )
925 dot = DotProduct( pln->normal, baseaxis[i * 3] );
926 if ( dot > best + 0.0001f ) { /* ydnar: bug 637 fix, suggested by jmonroe */
932 VectorCopy( baseaxis[bestaxis * 3 + 1], xv );
933 VectorCopy( baseaxis[bestaxis * 3 + 2], yv );
940 creates world-to-texture mapping vecs for crappy quake plane arrangements
943 void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] ){
946 vec_t ang, sinv, cosv;
951 TextureAxisFromPlane( plane, vecs[0], vecs[1] );
964 else if ( rotate == 90 ) {
967 else if ( rotate == 180 ) {
968 sinv = 0 ; cosv = -1;
970 else if ( rotate == 270 ) {
971 sinv = -1 ; cosv = 0;
975 ang = rotate / 180 * Q_PI;
983 else if ( vecs[0][1] ) {
993 else if ( vecs[1][1] ) {
1000 for ( i = 0 ; i < 2 ; i++ ) {
1001 ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
1002 nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
1007 for ( i = 0 ; i < 2 ; i++ )
1008 for ( j = 0 ; j < 3 ; j++ )
1009 mappingVecs[i][j] = vecs[i][j] / scale[i];
1011 mappingVecs[0][3] = shift[0];
1012 mappingVecs[1][3] = shift[1];
1019 parses the sides into buildBrush->sides[], nothing else.
1020 no validation, back plane removal, etc.
1023 added brush epairs parsing ( ignoring actually )
1025 added exclusive brush primitive parsing
1027 support for old brush format back in
1028 NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes
1031 static void ParseRawBrush( qboolean onlyLights ){
1033 vec3_t planePoints[ 3 ];
1039 char name[ MAX_QPATH ];
1040 char shader[ MAX_QPATH ];
1045 buildBrush->numsides = 0;
1046 buildBrush->detail = qfalse;
1049 if ( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) {
1056 if ( !GetToken( qtrue ) ) {
1059 if ( !strcmp( token, "}" ) ) {
1063 /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */
1064 if ( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) {
1067 if ( strcmp( token, "(" ) ) {
1078 /* test side count */
1079 if ( buildBrush->numsides >= MAX_BUILD_SIDES ) {
1080 xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue );
1084 side = &buildBrush->sides[ buildBrush->numsides ];
1085 memset( side, 0, sizeof( *side ) );
1086 buildBrush->numsides++;
1088 /* read the three point plane definition */
1089 Parse1DMatrix( 3, planePoints[ 0 ] );
1090 Parse1DMatrix( 3, planePoints[ 1 ] );
1091 Parse1DMatrix( 3, planePoints[ 2 ] );
1093 /* bp: read the texture matrix */
1094 if ( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) {
1095 Parse2DMatrix( 2, 3, (float*) side->texMat );
1098 /* read shader name */
1100 strcpy( name, token );
1103 if ( g_bBrushPrimit == BPRIMIT_OLDBRUSHES ) {
1105 shift[ 0 ] = atof( token );
1107 shift[ 1 ] = atof( token );
1109 rotate = atof( token );
1111 scale[ 0 ] = atof( token );
1113 scale[ 1 ] = atof( token );
1116 /* set default flags and values */
1117 sprintf( shader, "textures/%s", name );
1119 si = &shaderInfo[ 0 ];
1122 si = ShaderInfoForShader( shader );
1124 side->shaderInfo = si;
1125 side->surfaceFlags = si->surfaceFlags;
1126 side->contentFlags = si->contentFlags;
1127 side->compileFlags = si->compileFlags;
1128 side->value = si->value;
1130 /* ydnar: gs mods: bias texture shift */
1131 if ( si->globalTexture == qfalse ) {
1132 shift[ 0 ] -= ( floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth );
1133 shift[ 1 ] -= ( floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight );
1137 historically, there are 3 integer values at the end of a brushside line in a .map file.
1138 in quake 3, the only thing that mattered was the first of these three values, which
1139 was previously the content flags. and only then did a single bit matter, the detail
1140 bit. because every game has its own special flags for specifying detail, the
1141 traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0
1142 by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
1143 is stored in compileFlags, as opposed to contentFlags, for multiple-game
1147 if ( TokenAvailable() ) {
1148 /* get detail bit from map content flags */
1150 flags = atoi( token );
1151 if ( flags & C_DETAIL ) {
1152 side->compileFlags |= C_DETAIL;
1157 //% td.flags = atoi( token );
1159 //% td.value = atoi( token );
1162 /* find the plane number */
1163 planenum = MapPlaneFromPoints( planePoints );
1164 side->planenum = planenum;
1166 /* bp: get the texture mapping for this texturedef / plane combination */
1167 if ( g_bBrushPrimit == BPRIMIT_OLDBRUSHES ) {
1168 QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs );
1173 if ( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) {
1183 RemoveDuplicateBrushPlanes
1184 returns false if the brush has a mirrored set of planes,
1185 meaning it encloses no volume.
1186 also removes planes without any normal
1189 qboolean RemoveDuplicateBrushPlanes( brush_t *b ){
1195 for ( i = 1 ; i < b->numsides ; i++ ) {
1197 // check for a degenerate plane
1198 if ( sides[i].planenum == -1 ) {
1199 xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse );
1201 for ( k = i + 1 ; k < b->numsides ; k++ ) {
1202 sides[k - 1] = sides[k];
1209 // check for duplication and mirroring
1210 for ( j = 0 ; j < i ; j++ ) {
1211 if ( sides[i].planenum == sides[j].planenum ) {
1212 xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse );
1213 // remove the second duplicate
1214 for ( k = i + 1 ; k < b->numsides ; k++ ) {
1215 sides[k - 1] = sides[k];
1222 if ( sides[i].planenum == ( sides[j].planenum ^ 1 ) ) {
1223 // mirror plane, brush is invalid
1224 xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse );
1236 parses a brush out of a map file and sets it up
1239 static void ParseBrush( qboolean onlyLights, qboolean noCollapseGroups ){
1240 /* parse the brush out of the map */
1241 ParseRawBrush( onlyLights );
1243 /* only go this far? */
1248 /* set some defaults */
1249 buildBrush->portalareas[ 0 ] = -1;
1250 buildBrush->portalareas[ 1 ] = -1;
1251 buildBrush->entityNum = numMapEntities - 1;
1252 buildBrush->brushNum = entitySourceBrushes;
1254 /* if there are mirrored planes, the entire brush is invalid */
1255 if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
1259 /* get the content for the entire brush */
1260 SetBrushContents( buildBrush );
1262 /* allow detail brushes to be removed */
1263 if ( nodetail && ( buildBrush->compileFlags & C_DETAIL ) ) {
1264 //% FreeBrush( buildBrush );
1268 /* allow liquid brushes to be removed */
1269 if ( nowater && ( buildBrush->compileFlags & C_LIQUID ) ) {
1270 //% FreeBrush( buildBrush );
1274 /* ydnar: allow hint brushes to be removed */
1275 if ( noHint && ( buildBrush->compileFlags & C_HINT ) ) {
1276 //% FreeBrush( buildBrush );
1280 /* finish the brush */
1281 FinishBrush( noCollapseGroups );
1287 MoveBrushesToWorld()
1288 takes all of the brushes from the current entity and
1289 adds them to the world's brush list
1290 (used by func_group)
1293 void AdjustBrushesForOrigin( entity_t *ent );
1294 void MoveBrushesToWorld( entity_t *ent ){
1298 /* we need to undo the common/origin adjustment, and instead shift them by the entity key origin */
1299 VectorScale( ent->origin, -1, ent->originbrush_origin );
1300 AdjustBrushesForOrigin( ent );
1301 VectorClear( ent->originbrush_origin );
1304 for ( b = ent->brushes; b != NULL; b = next )
1306 /* get next brush */
1309 /* link opaque brushes to head of list, translucent brushes to end */
1310 if ( b->opaque || entities[ 0 ].lastBrush == NULL ) {
1311 b->next = entities[ 0 ].brushes;
1312 entities[ 0 ].brushes = b;
1313 if ( entities[ 0 ].lastBrush == NULL ) {
1314 entities[ 0 ].lastBrush = b;
1320 entities[ 0 ].lastBrush->next = b;
1321 entities[ 0 ].lastBrush = b;
1324 ent->brushes = NULL;
1326 /* ydnar: move colormod brushes */
1327 if ( ent->colorModBrushes != NULL ) {
1328 for ( b = ent->colorModBrushes; b->nextColorModBrush != NULL; b = b->nextColorModBrush ) ;
1330 b->nextColorModBrush = entities[ 0 ].colorModBrushes;
1331 entities[ 0 ].colorModBrushes = ent->colorModBrushes;
1333 ent->colorModBrushes = NULL;
1337 if ( ent->patches != NULL ) {
1338 for ( pm = ent->patches; pm->next != NULL; pm = pm->next ) ;
1340 pm->next = entities[ 0 ].patches;
1341 entities[ 0 ].patches = ent->patches;
1343 ent->patches = NULL;
1350 AdjustBrushesForOrigin()
1353 void AdjustBrushesForOrigin( entity_t *ent ){
1361 /* walk brush list */
1362 for ( b = ent->brushes; b != NULL; b = b->next )
1364 /* offset brush planes */
1365 for ( i = 0; i < b->numsides; i++ )
1367 /* get brush side */
1370 /* offset side plane */
1371 newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->originbrush_origin );
1373 /* find a new plane */
1374 s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
1377 /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */
1378 CreateBrushWindings( b );
1381 /* walk patch list */
1382 for ( p = ent->patches; p != NULL; p = p->next )
1384 for ( i = 0; i < ( p->mesh.width * p->mesh.height ); i++ )
1385 VectorSubtract( p->mesh.verts[ i ].xyz, ent->originbrush_origin, p->mesh.verts[ i ].xyz );
1392 SetEntityBounds() - ydnar
1393 finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders)
1396 void SetEntityBounds( entity_t *e ){
1406 /* walk the entity's brushes/patches and determine bounds */
1407 ClearBounds( mins, maxs );
1408 for ( b = e->brushes; b; b = b->next )
1410 AddPointToBounds( b->mins, mins, maxs );
1411 AddPointToBounds( b->maxs, mins, maxs );
1413 for ( p = e->patches; p; p = p->next )
1415 for ( i = 0; i < ( p->mesh.width * p->mesh.height ); i++ )
1416 AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs );
1419 /* try to find explicit min/max key */
1420 value = ValueForKey( e, "min" );
1421 if ( value[ 0 ] != '\0' ) {
1422 GetVectorForKey( e, "min", mins );
1424 value = ValueForKey( e, "max" );
1425 if ( value[ 0 ] != '\0' ) {
1426 GetVectorForKey( e, "max", maxs );
1429 /* store the bounds */
1430 for ( b = e->brushes; b; b = b->next )
1432 VectorCopy( mins, b->eMins );
1433 VectorCopy( maxs, b->eMaxs );
1435 for ( p = e->patches; p; p = p->next )
1437 VectorCopy( mins, p->eMins );
1438 VectorCopy( maxs, p->eMaxs );
1445 LoadEntityIndexMap() - ydnar
1446 based on LoadAlphaMap() from terrain.c, a little more generic
1449 void LoadEntityIndexMap( entity_t *e ){
1450 int i, size, numLayers, w, h;
1451 const char *value, *indexMapFilename, *shader;
1452 char ext[ MAX_QPATH ], offset[ 4096 ], *search, *space;
1454 unsigned int *pixels32;
1460 /* this only works with bmodel ents */
1461 if ( e->brushes == NULL && e->patches == NULL ) {
1465 /* determine if there is an index map (support legacy "alphamap" key as well) */
1466 value = ValueForKey( e, "_indexmap" );
1467 if ( value[ 0 ] == '\0' ) {
1468 value = ValueForKey( e, "alphamap" );
1470 if ( value[ 0 ] == '\0' ) {
1473 indexMapFilename = value;
1475 /* get number of layers (support legacy "layers" key as well) */
1476 value = ValueForKey( e, "_layers" );
1477 if ( value[ 0 ] == '\0' ) {
1478 value = ValueForKey( e, "layers" );
1480 if ( value[ 0 ] == '\0' ) {
1481 Sys_FPrintf( SYS_WRN, "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename );
1482 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1485 numLayers = atoi( value );
1486 if ( numLayers < 1 ) {
1487 Sys_FPrintf( SYS_WRN, "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers );
1488 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1492 /* get base shader name (support legacy "shader" key as well) */
1493 value = ValueForKey( mapEnt, "_shader" );
1494 if ( value[ 0 ] == '\0' ) {
1495 value = ValueForKey( e, "shader" );
1497 if ( value[ 0 ] == '\0' ) {
1498 Sys_FPrintf( SYS_WRN, "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename );
1499 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1505 Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n", mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename );
1507 /* get index map file extension */
1508 ExtractFileExtension( indexMapFilename, ext );
1510 /* handle tga image */
1511 if ( !Q_stricmp( ext, "tga" ) ) {
1513 Load32BitImage( indexMapFilename, &pixels32, &w, &h );
1515 /* convert to bytes */
1517 pixels = safe_malloc( size );
1518 for ( i = 0; i < size; i++ )
1520 pixels[ i ] = ( ( pixels32[ i ] & 0xFF ) * numLayers ) / 256;
1521 if ( pixels[ i ] >= numLayers ) {
1522 pixels[ i ] = numLayers - 1;
1526 /* free the 32 bit image */
1532 Load256Image( indexMapFilename, &pixels, NULL, &w, &h );
1535 //% Sys_Printf( "-------------------------------" );
1537 /* fix up out-of-range values */
1539 for ( i = 0; i < size; i++ )
1541 if ( pixels[ i ] >= numLayers ) {
1542 pixels[ i ] = numLayers - 1;
1546 //% if( (i % w) == 0 )
1547 //% Sys_Printf( "\n" );
1548 //% Sys_Printf( "%c", pixels[ i ] + '0' );
1552 //% Sys_Printf( "\n-------------------------------\n" );
1555 /* the index map must be at least 2x2 pixels */
1556 if ( w < 2 || h < 2 ) {
1557 Sys_FPrintf( SYS_WRN, "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename );
1558 Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" );
1563 /* create a new index map */
1564 im = safe_malloc( sizeof( *im ) );
1565 memset( im, 0, sizeof( *im ) );
1570 im->numLayers = numLayers;
1571 strcpy( im->name, indexMapFilename );
1572 strcpy( im->shader, shader );
1573 im->pixels = pixels;
1575 /* get height offsets */
1576 value = ValueForKey( mapEnt, "_offsets" );
1577 if ( value[ 0 ] == '\0' ) {
1578 value = ValueForKey( e, "offsets" );
1580 if ( value[ 0 ] != '\0' ) {
1581 /* value is a space-seperated set of numbers */
1582 strcpy( offset, value );
1585 /* get each value */
1586 for ( i = 0; i < 256 && *search != '\0'; i++ )
1588 space = strstr( search, " " );
1589 if ( space != NULL ) {
1592 im->offsets[ i ] = atof( search );
1593 if ( space == NULL ) {
1600 /* store the index map in every brush/patch in the entity */
1601 for ( b = e->brushes; b != NULL; b = b->next )
1603 for ( p = e->patches; p != NULL; p = p->next )
1615 parses a single entity out of a map file
1618 static qboolean ParseMapEntity( qboolean onlyLights, qboolean noCollapseGroups ){
1620 const char *classname, *value;
1621 float lightmapScale, shadeAngle;
1622 int lightmapSampleSize;
1623 char shader[ MAX_QPATH ];
1624 shaderInfo_t *celShader = NULL;
1628 int castShadows, recvShadows;
1632 if ( !GetToken( qtrue ) ) {
1636 /* conformance check */
1637 if ( strcmp( token, "{" ) ) {
1638 Sys_FPrintf( SYS_WRN, "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n"
1639 "Continuing to process map, but resulting BSP may be invalid.\n",
1640 token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] );
1645 AUTOEXPAND_BY_REALLOC( entities, numEntities, allocatedEntities, 32 );
1648 entitySourceBrushes = 0;
1649 mapEnt = &entities[ numEntities ];
1651 memset( mapEnt, 0, sizeof( *mapEnt ) );
1653 /* ydnar: true entity numbering */
1654 mapEnt->mapEntityNum = numMapEntities;
1660 /* get initial token */
1661 if ( !GetToken( qtrue ) ) {
1662 Sys_FPrintf( SYS_WRN, "WARNING: ParseEntity: EOF without closing brace\n"
1663 "Continuing to process map, but resulting BSP may be invalid.\n" );
1667 if ( !strcmp( token, "}" ) ) {
1671 if ( !strcmp( token, "{" ) ) {
1672 /* parse a brush or patch */
1673 if ( !GetToken( qtrue ) ) {
1678 if ( !strcmp( token, "patchDef2" ) ) {
1680 ParsePatch( onlyLights );
1682 else if ( !strcmp( token, "terrainDef" ) ) {
1684 Sys_FPrintf( SYS_WRN, "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */
1686 else if ( !strcmp( token, "brushDef" ) ) {
1687 if ( g_bBrushPrimit == BPRIMIT_OLDBRUSHES ) {
1688 Error( "Old brush format not allowed in new brush format map" );
1690 g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
1692 /* parse brush primitive */
1693 ParseBrush( onlyLights, noCollapseGroups );
1697 if ( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) {
1698 Error( "New brush format not allowed in old brush format map" );
1700 g_bBrushPrimit = BPRIMIT_OLDBRUSHES;
1702 /* parse old brush format */
1704 ParseBrush( onlyLights, noCollapseGroups );
1706 entitySourceBrushes++;
1710 /* parse a key / value pair */
1713 /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */
1714 if ( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' ) {
1715 ep->next = mapEnt->epairs;
1716 mapEnt->epairs = ep;
1721 /* ydnar: get classname */
1722 classname = ValueForKey( mapEnt, "classname" );
1724 /* ydnar: only lights? */
1725 if ( onlyLights && Q_strncasecmp( classname, "light", 5 ) ) {
1730 /* ydnar: determine if this is a func_group */
1731 if ( !Q_stricmp( "func_group", classname ) ) {
1738 /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1739 if ( funcGroup || mapEnt->mapEntityNum == 0 ) {
1740 //% Sys_Printf( "World: %d\n", mapEnt->mapEntityNum );
1741 castShadows = WORLDSPAWN_CAST_SHADOWS;
1742 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1745 /* other entities don't cast any shadows, but recv worldspawn shadows */
1748 //% Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum );
1749 castShadows = ENTITY_CAST_SHADOWS;
1750 recvShadows = ENTITY_RECV_SHADOWS;
1753 /* get explicit shadow flags */
1754 GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
1756 /* vortex: added _ls key (short name of lightmapscale) */
1757 /* ydnar: get lightmap scaling value for this entity */
1758 lightmapScale = 0.0f;
1759 if ( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
1760 strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) ||
1761 strcmp( "", ValueForKey( mapEnt, "_ls" ) ) ) {
1762 /* get lightmap scale from entity */
1763 lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
1764 if ( lightmapScale <= 0.0f ) {
1765 lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
1767 if ( lightmapScale <= 0.0f ) {
1768 lightmapScale = FloatForKey( mapEnt, "_ls" );
1770 if ( lightmapScale < 0.0f ) {
1771 lightmapScale = 0.0f;
1773 if ( lightmapScale > 0.0f ) {
1774 Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
1778 /* ydnar: get cel shader :) for this entity */
1779 value = ValueForKey( mapEnt, "_celshader" );
1780 if ( value[ 0 ] == '\0' ) {
1781 value = ValueForKey( &entities[ 0 ], "_celshader" );
1783 if ( value[ 0 ] != '\0' ) {
1784 if ( strcmp( value, "none" ) ) {
1785 sprintf( shader, "textures/%s", value );
1786 celShader = ShaderInfoForShader( shader );
1787 Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
1795 celShader = ( *globalCelShader ? ShaderInfoForShader( globalCelShader ) : NULL );
1798 /* jal : entity based _shadeangle */
1800 if ( strcmp( "", ValueForKey( mapEnt, "_shadeangle" ) ) ) {
1801 shadeAngle = FloatForKey( mapEnt, "_shadeangle" );
1803 /* vortex' aliases */
1804 else if ( strcmp( "", ValueForKey( mapEnt, "_smoothnormals" ) ) ) {
1805 shadeAngle = FloatForKey( mapEnt, "_smoothnormals" );
1807 else if ( strcmp( "", ValueForKey( mapEnt, "_sn" ) ) ) {
1808 shadeAngle = FloatForKey( mapEnt, "_sn" );
1810 else if ( strcmp( "", ValueForKey( mapEnt, "_sa" ) ) ) {
1811 shadeAngle = FloatForKey( mapEnt, "_sa" );
1813 else if ( strcmp( "", ValueForKey( mapEnt, "_smooth" ) ) ) {
1814 shadeAngle = FloatForKey( mapEnt, "_smooth" );
1817 if ( shadeAngle < 0.0f ) {
1821 if ( shadeAngle > 0.0f ) {
1822 Sys_Printf( "Entity %d (%s) has shading angle of %.4f\n", mapEnt->mapEntityNum, classname, shadeAngle );
1825 /* jal : entity based _samplesize */
1826 lightmapSampleSize = 0;
1827 if ( strcmp( "", ValueForKey( mapEnt, "_lightmapsamplesize" ) ) ) {
1828 lightmapSampleSize = IntForKey( mapEnt, "_lightmapsamplesize" );
1830 else if ( strcmp( "", ValueForKey( mapEnt, "_samplesize" ) ) ) {
1831 lightmapSampleSize = IntForKey( mapEnt, "_samplesize" );
1833 else if ( strcmp( "", ValueForKey( mapEnt, "_ss" ) ) ) {
1834 lightmapSampleSize = IntForKey( mapEnt, "_ss" );
1837 if ( lightmapSampleSize < 0 ) {
1838 lightmapSampleSize = 0;
1841 if ( lightmapSampleSize > 0 ) {
1842 Sys_Printf( "Entity %d (%s) has lightmap sample size of %d\n", mapEnt->mapEntityNum, classname, lightmapSampleSize );
1845 /* attach stuff to everything in the entity */
1846 for ( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
1848 brush->entityNum = mapEnt->mapEntityNum;
1849 brush->castShadows = castShadows;
1850 brush->recvShadows = recvShadows;
1851 brush->lightmapSampleSize = lightmapSampleSize;
1852 brush->lightmapScale = lightmapScale;
1853 brush->celShader = celShader;
1854 brush->shadeAngleDegrees = shadeAngle;
1857 for ( patch = mapEnt->patches; patch != NULL; patch = patch->next )
1859 patch->entityNum = mapEnt->mapEntityNum;
1860 patch->castShadows = castShadows;
1861 patch->recvShadows = recvShadows;
1862 patch->lightmapSampleSize = lightmapSampleSize;
1863 patch->lightmapScale = lightmapScale;
1864 patch->celShader = celShader;
1867 /* ydnar: gs mods: set entity bounds */
1868 SetEntityBounds( mapEnt );
1870 /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */
1871 LoadEntityIndexMap( mapEnt );
1873 /* get entity origin and adjust brushes */
1874 GetVectorForKey( mapEnt, "origin", mapEnt->origin );
1875 if ( mapEnt->originbrush_origin[ 0 ] || mapEnt->originbrush_origin[ 1 ] || mapEnt->originbrush_origin[ 2 ] ) {
1876 AdjustBrushesForOrigin( mapEnt );
1879 /* group_info entities are just for editor grouping (fixme: leak!) */
1880 if ( !noCollapseGroups && !Q_stricmp( "group_info", classname ) ) {
1885 /* group entities are just for editor convenience, toss all brushes into worldspawn */
1886 if ( !noCollapseGroups && funcGroup ) {
1887 MoveBrushesToWorld( mapEnt );
1900 loads a map file into a list of entities
1903 void LoadMapFile( char *filename, qboolean onlyLights, qboolean noCollapseGroups ){
1906 int oldNumEntities = 0, numMapBrushes;
1910 Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" );
1911 Sys_Printf( "Loading %s\n", filename );
1914 file = SafeOpenRead( filename );
1917 /* load the map file */
1918 LoadScriptFile( filename, -1 );
1922 oldNumEntities = numEntities;
1929 numMapDrawSurfs = 0;
1931 g_bBrushPrimit = BPRIMIT_UNDEFINED;
1933 /* allocate a very large temporary brush for building the brushes as they are loaded */
1934 buildBrush = AllocBrush( MAX_BUILD_SIDES );
1936 /* parse the map file */
1937 while ( ParseMapEntity( onlyLights, noCollapseGroups ) ) ;
1941 /* emit some statistics */
1942 Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities );
1946 /* set map bounds */
1947 ClearBounds( mapMins, mapMaxs );
1948 for ( b = entities[ 0 ].brushes; b; b = b->next )
1950 AddPointToBounds( b->mins, mapMins, mapMaxs );
1951 AddPointToBounds( b->maxs, mapMins, mapMaxs );
1954 /* get brush counts */
1955 numMapBrushes = CountBrushList( entities[ 0 ].brushes );
1956 if ( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 ) {
1957 Sys_FPrintf( SYS_WRN, "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" );
1960 /* emit some statistics */
1961 Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes );
1962 Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail );
1963 Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches );
1964 Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels );
1965 Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels );
1966 Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
1967 Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes );
1968 Sys_Printf( "%9d areaportals\n", c_areaportals );
1969 Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n",
1970 mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ],
1971 mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ] );
1973 /* write bogus map */
1975 WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes );