#define USE_HASHING
#define PLANE_HASHES 8192
-plane_t *planehash[ PLANE_HASHES ];
+int planehash[ PLANE_HASHES ];
int c_boxbevels;
int c_edgebevels;
ydnar: replaced with variable epsilon for djbob
*/
-#define NORMAL_EPSILON 0.00001
-#define DIST_EPSILON 0.01
-
qboolean PlaneEqual( plane_t *p, vec3_t normal, vec_t dist )
{
float ne, de;
de = distanceEpsilon;
/* compare */
- if( fabs( p->dist - dist ) <= de &&
- fabs( p->normal[ 0 ] - normal[ 0 ] ) <= ne &&
- fabs( p->normal[ 1 ] - normal[ 1 ] ) <= ne &&
- fabs( p->normal[ 2 ] - normal[ 2 ] ) <= ne )
+ // We check equality of each component since we're using '<', not '<='
+ // (the epsilons may be zero). We want to use '<' intead of '<=' to be
+ // consistent with the true meaning of "epsilon", and also because other
+ // parts of the code uses this inequality.
+ if ((p->dist == dist || fabs(p->dist - dist) < de) &&
+ (p->normal[0] == normal[0] || fabs(p->normal[0] - normal[0]) < ne) &&
+ (p->normal[1] == normal[1] || fabs(p->normal[1] - normal[1]) < ne) &&
+ (p->normal[2] == normal[2] || fabs(p->normal[2] - normal[2]) < ne))
return qtrue;
/* different */
hash = (PLANE_HASHES - 1) & (int) fabs( p->dist );
p->hash_chain = planehash[hash];
- planehash[hash] = p;
+ planehash[hash] = p - mapplanes + 1;
}
/*
}
// create a new plane
- if (nummapplanes+2 > MAX_MAP_PLANES)
- Error ("MAX_MAP_PLANES");
+ AUTOEXPAND_BY_REALLOC(mapplanes, nummapplanes+1, allocatedmapplanes, 1024);
p = &mapplanes[nummapplanes];
VectorCopy (normal, p->normal);
/*
SnapNormal()
-snaps a near-axial normal vector
+Snaps a near-axial normal vector.
+Returns qtrue if and only if the normal was adjusted.
*/
-void SnapNormal( vec3_t normal )
+qboolean SnapNormal( vec3_t normal )
{
+#if Q3MAP2_EXPERIMENTAL_SNAP_NORMAL_FIX
int i;
+ qboolean adjusted = qfalse;
+
+ // A change from the original SnapNormal() is that we snap each
+ // component that's close to 0. So for example if a normal is
+ // (0.707, 0.707, 0.0000001), it will get snapped to lie perfectly in the
+ // XY plane (its Z component will be set to 0 and its length will be
+ // normalized). The original SnapNormal() didn't snap such vectors - it
+ // only snapped vectors that were near a perfect axis.
+
+ for (i = 0; i < 3; i++)
+ {
+ if (normal[i] != 0.0 && -normalEpsilon < normal[i] && normal[i] < normalEpsilon)
+ {
+ normal[i] = 0.0;
+ adjusted = qtrue;
+ }
+ }
+
+ if (adjusted)
+ {
+ VectorNormalize(normal, normal);
+ return qtrue;
+ }
+ return qfalse;
+#else
+ int i;
+
+ // I would suggest that you uncomment the following code and look at the
+ // results:
+
+ /*
+ Sys_Printf("normalEpsilon is %f\n", normalEpsilon);
+ for (i = 0;; i++)
+ {
+ normal[0] = 1.0;
+ normal[1] = 0.0;
+ normal[2] = i * 0.000001;
+ VectorNormalize(normal, normal);
+ if (1.0 - normal[0] >= normalEpsilon) {
+ Sys_Printf("(%f %f %f)\n", normal[0], normal[1], normal[2]);
+ Error("SnapNormal: test completed");
+ }
+ }
+ */
+
+ // When the normalEpsilon is 0.00001, the loop will break out when normal is
+ // (0.999990 0.000000 0.004469). In other words, this is the vector closest
+ // to axial that will NOT be snapped. Anything closer will be snaped. Now,
+ // 0.004469 is close to 1/225. The length of a circular quarter-arc of radius
+ // 1 is PI/2, or about 1.57. And 0.004469/1.57 is about 0.0028, or about
+ // 1/350. Expressed a different way, 1/350 is also about 0.26/90.
+ // This means is that a normal with an angle that is within 1/4 of a degree
+ // from axial will be "snapped". My belief is that the person who wrote the
+ // code below did not intend it this way. I think the person intended that
+ // the epsilon be measured against the vector components close to 0, not 1.0.
+ // I think the logic should be: if 2 of the normal components are within
+ // epsilon of 0, then the vector can be snapped to be perfectly axial.
+ // We may consider adjusting the epsilon to a larger value when we make this
+ // code fix.
for( i = 0; i < 3; i++ )
{
{
VectorClear( normal );
normal[ i ] = 1;
- break;
+ return qtrue;
}
if( fabs( normal[ i ] - -1 ) < normalEpsilon )
{
VectorClear( normal );
normal[ i ] = -1;
- break;
+ return qtrue;
}
}
+ return qfalse;
+#endif
}
SnapPlane reenabled by namespace because of multiple reports of
q3map2-crashes which were triggered by this patch.
*/
- // div0: ensure the point "center" stays on the plane (actually, this
- // rotates the plane around the point center).
- // if center lies on the plane, it is guaranteed to stay on the plane by
- // this fix.
- vec_t centerDist = DotProduct(normal, center);
SnapNormal( normal );
- *dist += (DotProduct(normal, center) - centerDist);
+
+ // TODO: Rambetter has some serious comments here as well. First off,
+ // in the case where a normal is non-axial, there is nothing special
+ // about integer distances. I would think that snapping a distance might
+ // make sense for axial normals, but I'm not so sure about snapping
+ // non-axial normals. A shift by 0.01 in a plane, multiplied by a clipping
+ // against another plane that is 5 degrees off, and we introduce 0.1 error
+ // easily. A 0.1 error in a vertex is where problems start to happen, such
+ // as disappearing triangles.
+
+ // Second, assuming we have snapped the normal above, let's say that the
+ // plane we just snapped was defined for some points that are actually
+ // quite far away from normal * dist. Well, snapping the normal in this
+ // case means that we've just moved those points by potentially many units!
+ // Therefore, if we are going to snap the normal, we need to know the
+ // points we're snapping for so that the plane snaps with those points in
+ // mind (points remain close to the plane).
+
+ // I would like to know exactly which problems SnapPlane() is trying to
+ // solve so that we can better engineer it (I'm not saying that SnapPlane()
+ // should be removed altogether). Fix all this snapping code at some point!
if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
*dist = Q_rint( *dist );
}
+/*
+SnapPlaneImproved()
+snaps a plane to normal/distance epsilons, improved code
+*/
+void SnapPlaneImproved(vec3_t normal, vec_t *dist, int numPoints, const vec3_t *points)
+{
+ int i;
+ vec3_t center;
+ vec_t distNearestInt;
+
+ if (SnapNormal(normal))
+ {
+ if (numPoints > 0)
+ {
+ // Adjust the dist so that the provided points don't drift away.
+ VectorClear(center);
+ for (i = 0; i < numPoints; i++)
+ {
+ VectorAdd(center, points[i], center);
+ }
+ for (i = 0; i < 3; i++) { center[i] = center[i] / numPoints; }
+ *dist = DotProduct(normal, center);
+ }
+ }
+
+ if (VectorIsOnAxis(normal))
+ {
+ // Only snap distance if the normal is an axis. Otherwise there
+ // is nothing "natural" about snapping the distance to an integer.
+ distNearestInt = Q_rint(*dist);
+ if (-distanceEpsilon < *dist - distNearestInt && *dist - distNearestInt < distanceEpsilon)
+ {
+ *dist = distNearestInt;
+ }
+ }
+}
+
/*
must be within an epsilon distance of the plane
*/
-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?
+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?
#ifdef USE_HASHING
{
int i, j, hash, h;
+ int pidx;
plane_t *p;
vec_t d;
- vec3_t centerofweight;
+ vec3_t normal;
- VectorClear(centerofweight);
- for(i = 0; i < numPoints; ++i)
- VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
-
+ VectorCopy(innormal, normal);
+#if Q3MAP2_EXPERIMENTAL_SNAP_PLANE_FIX
+ SnapPlaneImproved(normal, &dist, numPoints, (const vec3_t *) points);
+#else
+ SnapPlane( normal, &dist );
+#endif
/* hash the plane */
- SnapPlane( normal, &dist, centerofweight );
hash = (PLANE_HASHES - 1) & (int) fabs( dist );
/* search the border bins as well */
for( i = -1; i <= 1; i++ )
{
h = (hash + i) & (PLANE_HASHES - 1);
- for( p = planehash[ h ]; p != NULL; p = p->hash_chain )
+ for( pidx = planehash[ h ] - 1; pidx != -1; pidx = mapplanes[pidx].hash_chain - 1 )
{
+ p = &mapplanes[pidx];
+
/* do standard plane compare */
if( !PlaneEqual( p, normal, dist ) )
continue;
/* ydnar: test supplied points against this plane */
for( j = 0; j < numPoints; j++ )
{
- d = DotProduct( points[ j ], normal ) - dist;
- if( fabs( d ) > distanceEpsilon )
- break;
+ // NOTE: When dist approaches 2^16, the resolution of 32 bit floating
+ // point number is greatly decreased. The distanceEpsilon cannot be
+ // very small when world coordinates extend to 2^16. Making the
+ // dot product here in 64 bit land will not really help the situation
+ // because the error will already be carried in dist.
+ d = DotProduct( points[ j ], p->normal ) - p->dist;
+ d = fabs(d);
+ if (d != 0.0 && d >= distanceEpsilon)
+ break; // Point is too far from plane.
}
/* found a matching plane */
{
int i;
plane_t *p;
+ vec3_t normal;
-
- vec3_t centerofweight;
-
- VectorClear(centerofweight);
- for(i = 0; i < numPoints; ++i)
- VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
-
- SnapPlane( normal, &dist, centerofweight );
+ VectorCopy(innormal, normal);
+#if Q3MAP2_EXPERIMENTAL_SNAP_PLANE_FIX
+ SnapPlaneImproved(normal, &dist, numPoints, (const vec3_t *) points);
+#else
+ SnapPlane( normal, &dist );
+#endif
for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
{
- if( PlaneEqual( p, normal, dist ) )
+ if( !PlaneEqual( p, normal, dist ) )
+ continue;
+
+ /* ydnar: uncomment the following line for old-style plane finding */
+ //% return i;
+
+ /* ydnar: test supplied points against this plane */
+ for( j = 0; j < numPoints; j++ )
+ {
+ d = DotProduct( points[ j ], p->normal ) - p->dist;
+ if( fabs( d ) > distanceEpsilon )
+ break;
+ }
+
+ /* found a matching plane */
+ if( j >= numPoints )
return i;
+ // TODO: Note that the non-USE_HASHING code does not compute epsilons
+ // for the provided points. It should do that. I think this code
+ // is unmaintained because nobody sets USE_HASHING to off.
}
return CreateNewFloatPlane( normal, dist );
int MapPlaneFromPoints( vec3_t *p )
{
+#if Q3MAP2_EXPERIMENTAL_HIGH_PRECISION_MATH_FIXES
+ vec3_accu_t paccu[3];
+ vec3_accu_t t1, t2, normalAccu;
+ vec3_t normal;
+ vec_t dist;
+
+ VectorCopyRegularToAccu(p[0], paccu[0]);
+ VectorCopyRegularToAccu(p[1], paccu[1]);
+ VectorCopyRegularToAccu(p[2], paccu[2]);
+
+ VectorSubtractAccu(paccu[0], paccu[1], t1);
+ VectorSubtractAccu(paccu[2], paccu[1], t2);
+ CrossProductAccu(t1, t2, normalAccu);
+ VectorNormalizeAccu(normalAccu, normalAccu);
+ // TODO: A 32 bit float for the plane distance isn't enough resolution
+ // if the plane is 2^16 units away from the origin (the "epsilon" approaches
+ // 0.01 in that case).
+ dist = (vec_t) DotProductAccu(paccu[0], normalAccu);
+ VectorCopyAccuToRegular(normalAccu, normal);
+
+ return FindFloatPlane(normal, dist, 3, p);
+#else
vec3_t t1, t2, normal;
vec_t dist;
/* store the plane */
return FindFloatPlane( normal, dist, 3, p );
+#endif
}
int contentFlags, compileFlags;
side_t *s;
int i;
- qboolean mixed;
+ //% qboolean mixed;
/* get initial compile flags from first side */
contentFlags = s->contentFlags;
compileFlags = s->compileFlags;
b->contentShader = s->shaderInfo;
- mixed = qfalse;
+ //% mixed = qfalse;
/* get the content/compile flags for every side in the brush */
for( i = 1; i < b->numsides; i++, s++ )
s = &b->sides[ i ];
if( s->shaderInfo == NULL )
continue;
- if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
- mixed = qtrue;
+ //% if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
+ //% mixed = qtrue;
+
+ contentFlags |= s->contentFlags;
+ compileFlags |= s->compileFlags;
}
/* ydnar: getting rid of this stupid warning */
and links it to the current entity
*/
-brush_t *FinishBrush( void )
+static void MergeOrigin(entity_t *ent, vec3_t origin)
+{
+ vec3_t adjustment;
+ char string[128];
+
+ /* we have not parsed the brush completely yet... */
+ GetVectorForKey( ent, "origin", ent->origin );
+
+ VectorMA(origin, -1, ent->originbrush_origin, adjustment);
+ VectorAdd(adjustment, ent->origin, ent->origin);
+ VectorCopy(origin, ent->originbrush_origin);
+
+ sprintf(string, "%f %f %f", ent->origin[0], ent->origin[1], ent->origin[2]);
+ SetKeyValue(ent, "origin", string);
+}
+
+brush_t *FinishBrush( qboolean noCollapseGroups )
{
brush_t *b;
after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
if( buildBrush->compileFlags & C_ORIGIN )
{
- char string[ 32 ];
vec3_t origin;
+ Sys_Printf( "Entity %i, Brush %i: origin brush detected\n",
+ mapEnt->mapEntityNum, entitySourceBrushes );
+
if( numEntities == 1 )
{
Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n",
VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
VectorScale (origin, 0.5, origin);
- sprintf( string, "%i %i %i", (int) origin[ 0 ], (int) origin[ 1 ], (int) origin[ 2 ] );
- SetKeyValue( &entities[ numEntities - 1 ], "origin", string);
-
- VectorCopy( origin, entities[ numEntities - 1 ].origin);
+ MergeOrigin(&entities[ numEntities - 1 ], origin);
/* don't keep this brush */
return NULL;
}
/* add bevel planes */
- AddBrushBevels();
+ if(!noCollapseGroups)
+ AddBrushBevels();
/* keep it */
b = CopyBrush( buildBrush );
int planenum;
shaderInfo_t *si;
vec_t shift[ 2 ];
- vec_t rotate;
+ vec_t rotate = 0;
vec_t scale[ 2 ];
char name[ MAX_QPATH ];
char shader[ MAX_QPATH ];
parses a brush out of a map file and sets it up
*/
-static void ParseBrush( qboolean onlyLights )
+static void ParseBrush( qboolean onlyLights, qboolean noCollapseGroups )
{
- brush_t *b;
-
-
/* parse the brush out of the map */
ParseRawBrush( onlyLights );
}
/* finish the brush */
- b = FinishBrush();
+ FinishBrush(noCollapseGroups);
}
(used by func_group)
*/
+void AdjustBrushesForOrigin( entity_t *ent );
void MoveBrushesToWorld( entity_t *ent )
{
brush_t *b, *next;
parseMesh_t *pm;
+ /* we need to undo the common/origin adjustment, and instead shift them by the entity key origin */
+ VectorScale(ent->origin, -1, ent->originbrush_origin);
+ AdjustBrushesForOrigin(ent);
+ VectorClear(ent->originbrush_origin);
/* move brushes */
for( b = ent->brushes; b != NULL; b = next )
brush_t *b;
parseMesh_t *p;
-
/* walk brush list */
for( b = ent->brushes; b != NULL; b = b->next )
{
s = &b->sides[ i ];
/* offset side plane */
- newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin );
+ newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->originbrush_origin );
/* find a new plane */
s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
for( p = ent->patches; p != NULL; p = p->next )
{
for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
- VectorSubtract( p->mesh.verts[ i ].xyz, ent->origin, p->mesh.verts[ i ].xyz );
+ VectorSubtract( p->mesh.verts[ i ].xyz, ent->originbrush_origin, p->mesh.verts[ i ].xyz );
}
}
parses a single entity out of a map file
*/
-static qboolean ParseMapEntity( qboolean onlyLights )
+static qboolean ParseMapEntity( qboolean onlyLights, qboolean noCollapseGroups )
{
epair_t *ep;
const char *classname, *value;
- float lightmapScale;
+ float lightmapScale, shadeAngle;
+ int lightmapSampleSize;
char shader[ MAX_QPATH ];
shaderInfo_t *celShader = NULL;
brush_t *brush;
}
/* range check */
- if( numEntities >= MAX_MAP_ENTITIES )
- Error( "numEntities == MAX_MAP_ENTITIES" );
+ AUTOEXPAND_BY_REALLOC(entities, numEntities, allocatedEntities, 32);
/* setup */
entitySourceBrushes = 0;
g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
/* parse brush primitive */
- ParseBrush( onlyLights );
+ ParseBrush( onlyLights, noCollapseGroups );
}
else
{
/* parse old brush format */
UnGetToken();
- ParseBrush( onlyLights );
+ ParseBrush( onlyLights, noCollapseGroups );
}
entitySourceBrushes++;
}
/* get explicit shadow flags */
GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
+ /* vortex: added _ls key (short name of lightmapscale) */
/* ydnar: get lightmap scaling value for this entity */
+ lightmapScale = 0.0f;
if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
- strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) )
+ strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) ||
+ strcmp( "", ValueForKey( mapEnt, "_ls" ) ) )
{
/* get lightmap scale from entity */
lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
if( lightmapScale <= 0.0f )
lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
+ if( lightmapScale <= 0.0f )
+ lightmapScale = FloatForKey( mapEnt, "_ls" );
+ if( lightmapScale < 0.0f )
+ lightmapScale = 0.0f;
if( lightmapScale > 0.0f )
Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
}
- else
- lightmapScale = 0.0f;
/* ydnar: get cel shader :) for this entity */
value = ValueForKey( mapEnt, "_celshader" );
value = ValueForKey( &entities[ 0 ], "_celshader" );
if( value[ 0 ] != '\0' )
{
- sprintf( shader, "textures/%s", value );
- celShader = ShaderInfoForShader( shader );
- Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
+ if(strcmp(value, "none"))
+ {
+ sprintf( shader, "textures/%s", value );
+ celShader = ShaderInfoForShader( shader );
+ Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
+ }
+ else
+ {
+ celShader = NULL;
+ }
}
else
- celShader = NULL;
+ celShader = (*globalCelShader ? ShaderInfoForShader(globalCelShader) : NULL);
+
+ /* jal : entity based _shadeangle */
+ shadeAngle = 0.0f;
+ if ( strcmp( "", ValueForKey( mapEnt, "_shadeangle" ) ) )
+ shadeAngle = FloatForKey( mapEnt, "_shadeangle" );
+ /* vortex' aliases */
+ else if ( strcmp( "", ValueForKey( mapEnt, "_smoothnormals" ) ) )
+ shadeAngle = FloatForKey( mapEnt, "_smoothnormals" );
+ else if ( strcmp( "", ValueForKey( mapEnt, "_sn" ) ) )
+ shadeAngle = FloatForKey( mapEnt, "_sn" );
+ else if ( strcmp( "", ValueForKey( mapEnt, "_smooth" ) ) )
+ shadeAngle = FloatForKey( mapEnt, "_smooth" );
+
+ if( shadeAngle < 0.0f )
+ shadeAngle = 0.0f;
+
+ if( shadeAngle > 0.0f )
+ Sys_Printf( "Entity %d (%s) has shading angle of %.4f\n", mapEnt->mapEntityNum, classname, shadeAngle );
+
+ /* jal : entity based _samplesize */
+ lightmapSampleSize = 0;
+ if ( strcmp( "", ValueForKey( mapEnt, "_lightmapsamplesize" ) ) )
+ lightmapSampleSize = IntForKey( mapEnt, "_lightmapsamplesize" );
+ else if ( strcmp( "", ValueForKey( mapEnt, "_samplesize" ) ) )
+ lightmapSampleSize = IntForKey( mapEnt, "_samplesize" );
+
+ if( lightmapSampleSize < 0 )
+ lightmapSampleSize = 0;
+
+ if( lightmapSampleSize > 0 )
+ Sys_Printf( "Entity %d (%s) has lightmap sample size of %d\n", mapEnt->mapEntityNum, classname, lightmapSampleSize );
/* attach stuff to everything in the entity */
for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
brush->entityNum = mapEnt->mapEntityNum;
brush->castShadows = castShadows;
brush->recvShadows = recvShadows;
+ brush->lightmapSampleSize = lightmapSampleSize;
brush->lightmapScale = lightmapScale;
brush->celShader = celShader;
+ brush->shadeAngleDegrees = shadeAngle;
}
for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
patch->entityNum = mapEnt->mapEntityNum;
patch->castShadows = castShadows;
patch->recvShadows = recvShadows;
+ patch->lightmapSampleSize = lightmapSampleSize;
patch->lightmapScale = lightmapScale;
patch->celShader = celShader;
}
/* get entity origin and adjust brushes */
GetVectorForKey( mapEnt, "origin", mapEnt->origin );
- if( mapEnt->origin[ 0 ] || mapEnt->origin[ 1 ] || mapEnt->origin[ 2 ] )
+ if( mapEnt->originbrush_origin[ 0 ] || mapEnt->originbrush_origin[ 1 ] || mapEnt->originbrush_origin[ 2 ] )
AdjustBrushesForOrigin( mapEnt );
/* group_info entities are just for editor grouping (fixme: leak!) */
- if( !Q_stricmp( "group_info", classname ) )
+ if( !noCollapseGroups && !Q_stricmp( "group_info", classname ) )
{
numEntities--;
return qtrue;
}
/* group entities are just for editor convenience, toss all brushes into worldspawn */
- if( funcGroup )
+ if( !noCollapseGroups && funcGroup )
{
MoveBrushesToWorld( mapEnt );
numEntities--;
loads a map file into a list of entities
*/
-void LoadMapFile( char *filename, qboolean onlyLights )
+void LoadMapFile( char *filename, qboolean onlyLights, qboolean noCollapseGroups )
{
FILE *file;
brush_t *b;
- int oldNumEntities, numMapBrushes;
+ int oldNumEntities = 0, numMapBrushes;
/* note it */
buildBrush = AllocBrush( MAX_BUILD_SIDES );
/* parse the map file */
- while( ParseMapEntity( onlyLights ) );
+ while( ParseMapEntity( onlyLights, noCollapseGroups ) );
/* light loading */
if( onlyLights )