Beispiel #1
0
/*
==================
BrushFromBounds

Creates a new axial brush
==================
*/
bspbrush_t	*BrushFromBounds (vec3_t mins, vec3_t maxs)
{
	bspbrush_t	*b;
	int			i;
	vec3_t		normal;
	vec_t		dist;

	b = AllocBrush (6);
	b->numsides = 6;
	for (i=0 ; i<3 ; i++)
	{
		VectorClear (normal);
		normal[i] = 1;
		dist = maxs[i];
		b->sides[i].planenum = FindFloatPlane (normal, dist);

		normal[i] = -1;
		dist = -mins[i];
		b->sides[3+i].planenum = FindFloatPlane (normal, dist);
	}

	CreateBrushWindings (b);

	return b;
}
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
tmp_node_t *AAS_SubdivideArea_r( tmp_node_t *tmpnode ) {
	int planenum;
	tmp_area_t *frontarea, *backarea;
	tmp_node_t *tmpnode1, *tmpnode2;
	vec3_t normal;
	float dist;

	if ( AAS_FindBestAreaSplitPlane( tmpnode->tmparea, normal, &dist ) ) {
		qprintf( "\r%6d", ++numgravitationalsubdivisions );
		//
		planenum = FindFloatPlane( normal, dist, 0, NULL );
		//split the area
		AAS_SplitArea( tmpnode->tmparea, planenum, &frontarea, &backarea );
		//
		tmpnode->tmparea = NULL;
		tmpnode->planenum = FindFloatPlane( normal, dist, 0, NULL );
		//
		tmpnode1 = AAS_AllocTmpNode();
		tmpnode1->planenum = 0;
		tmpnode1->tmparea = frontarea;
		//
		tmpnode2 = AAS_AllocTmpNode();
		tmpnode2->planenum = 0;
		tmpnode2->tmparea = backarea;
		//subdivide the areas created by splitting recursively
		tmpnode->children[0] = AAS_SubdivideArea_r( tmpnode1 );
		tmpnode->children[1] = AAS_SubdivideArea_r( tmpnode2 );
	} //end if
	return tmpnode;
} //end of the function AAS_SubdivideArea_r
Beispiel #3
0
/*
============
BlockTree

============
*/
node_t	*BlockTree (int xl, int yl, int xh, int yh)
{
	node_t	*node;
	vec3_t	normal;
	float	dist;
	int		mid;

	if (xl == xh && yl == yh)
	{
		node = block_nodes[xl+5][yl+5];
		if (!node)
		{	// return an empty leaf
			node = AllocNode ();
			node->planenum = PLANENUM_LEAF;
			node->contents = 0; //CONTENTS_SOLID;
			return node;
		}
		return node;
	}

	// create a seperator along the largest axis
	node = AllocNode ();

	if (xh - xl > yh - yl)
	{	// split x axis
		mid = xl + (xh-xl)/2 + 1;
		normal[0] = 1;
		normal[1] = 0;
		normal[2] = 0;
		dist = mid*1024;
		node->planenum = FindFloatPlane (normal, dist);
		node->children[0] = BlockTree ( mid, yl, xh, yh);
		node->children[1] = BlockTree ( xl, yl, mid-1, yh);
	}
	else
	{
		mid = yl + (yh-yl)/2 + 1;
		normal[0] = 0;
		normal[1] = 1;
		normal[2] = 0;
		dist = mid*1024;
		node->planenum = FindFloatPlane (normal, dist);
		node->children[0] = BlockTree ( xl, mid, xh, yh);
		node->children[1] = BlockTree ( xl, yl, xh, mid-1);
	}

	return node;
}
Beispiel #4
0
/*
=================
AdjustBrushesForOrigin
=================
*/
void AdjustBrushesForOrigin( entity_t *ent )
{
	int		i;
	side_t		*s;
	vec_t		newdist;
	brush_t		*b;
	parseMesh_t	*p;
	
	for( b = ent->brushes; b != NULL; b = b->next )
	{
		for( i = 0; i < b->numsides; i++)
		{
			s = &b->sides[i];
			
			newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin );
			s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
		}
		
		// rebuild brush windings (just offsetting the winding above should be fine)
		CreateBrushWindings( b );
	}
	
	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 );
	}
}
Beispiel #5
0
static void AdjustEntityForOrigin( uEntity_t *ent ) {
	primitive_t	*prim;
	uBrush_t	*b;
	int			i;
	side_t		*s;

	for ( prim = ent->primitives ; prim ; prim = prim->next ) {
		b = prim->brush;
		if ( !b ) {
			continue;
		}
		for ( i = 0; i < b->numsides; i++ ) {
			idPlane plane;

			s = &b->sides[i];

			plane = dmapGlobals.mapPlanes[s->planenum];
			plane[3] += plane.Normal() * ent->origin;

			s->planenum = FindFloatPlane( plane );

			s->texVec.v[0][3] += DotProduct( ent->origin, s->texVec.v[0] );
			s->texVec.v[1][3] += DotProduct( ent->origin, s->texVec.v[1] );

			// remove any integral shift
			s->texVec.v[0][3] -= floor( s->texVec.v[0][3] );
			s->texVec.v[1][3] -= floor( s->texVec.v[1][3] );
		}
		CreateBrushWindings(b);
	}
}
/*
=================
ParseBrush
=================
*/
static void ParseBrush( const idMapBrush *mapBrush, int primitiveNum ) {
	uBrush_t	*b;
	side_t		*s;
	const idMapBrushSide	*ms;
	int			i;
	bool		fixedDegeneracies = false;
	buildBrush->entitynum = dmapGlobals.num_entities - 1;
	buildBrush->brushnum = entityPrimitive;
	buildBrush->numsides = mapBrush->GetNumSides();
	for( i = 0 ; i < mapBrush->GetNumSides() ; i++ ) {
		s = &buildBrush->sides[i];
		ms = mapBrush->GetSide( i );
		memset( s, 0, sizeof( *s ) );
		s->planenum = FindFloatPlane( ms->GetPlane(), &fixedDegeneracies );
		s->material = declManager->FindMaterial( ms->GetMaterial() );
		ms->GetTextureVectors( s->texVec.v );
		// remove any integral shift, which will help with grouping
		s->texVec.v[0][3] -= floor( s->texVec.v[0][3] );
		s->texVec.v[1][3] -= floor( s->texVec.v[1][3] );
	}
	// if there are mirrored planes, the entire brush is invalid
	if( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
		return;
	}
	// get the content for the entire brush
	SetBrushContents( buildBrush );
	b = FinishBrush();
	if( !b ) {
		return;
	}
	if( fixedDegeneracies && dmapGlobals.verboseentities ) {
		common->Warning( "brush %d has degenerate plane equations", primitiveNum );
	}
}
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_ExpandMapBrush(mapbrush_t *brush, vec3_t mins, vec3_t maxs)
{
	int sn;
	float dist;
	side_t *s;
	plane_t *plane;

	for (sn = 0; sn < brush->numsides; sn++)
	{
		s = brush->original_sides + sn;
		plane = &mapplanes[s->planenum];
		dist = plane->dist;
		if (capsule_collision) {
			dist += CapsuleOriginDistanceFromPlane(plane->normal, mins, maxs);
		}
		else {
			dist += BoxOriginDistanceFromPlane(plane->normal, mins, maxs, 0);
		}
		s->planenum = FindFloatPlane(plane->normal, dist);
		//the side isn't a bevel after expanding
		s->flags &= ~SFL_BEVEL;
		//don't skip the surface
		s->surf &= ~SURF_SKIP;
		//make sure the texinfo is not TEXINFO_NODE
		//when player clip contents brushes are read from the bsp tree
		//they have the texinfo field set to TEXINFO_NODE
		//s->texinfo = 0;
	} //end for
} //end of the function AAS_ExpandMapBrush
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
int AAS_TestSplitPlane(tmp_area_t *tmparea, vec3_t normal, float dist,
							int *facesplits, int *groundsplits, int *epsilonfaces)
{
	int j, side, front, back, planenum;
	float d, d_front, d_back;
	tmp_face_t *face;
	winding_t *w;

	*facesplits = *groundsplits = *epsilonfaces = 0;

	planenum = FindFloatPlane(normal, dist);

	w = AAS_SplitWinding(tmparea, planenum);
	if (!w) return false;
	FreeWinding(w);
	//
	for (face = tmparea->tmpfaces; face; face = face->next[side])
	{
		//side of the face the area is on
		side = face->frontarea != tmparea;

		if ((face->planenum & ~1) == (planenum & ~1))
		{
			Log_Print("AAS_TestSplitPlane: tried face plane as splitter\n");
			return false;
		} //end if
		w = face->winding;
		//reset distance at front and back side of plane
		d_front = d_back = 0;
		//reset front and back flags
		front = back = 0;
		for (j = 0; j < w->numpoints; j++)
		{
			d = DotProduct(w->p[j], normal) - dist;
			if (d > d_front) d_front = d;
			if (d < d_back) d_back = d;

			if (d > 0.4) // PLANESIDE_EPSILON)
				front = 1;
			if (d < -0.4) // PLANESIDE_EPSILON)
				back = 1;
		} //end for
		//check for an epsilon face
		if ( (d_front > FACECLIP_EPSILON && d_front < FACE_EPSILON)
			|| (d_back < -FACECLIP_EPSILON && d_back > -FACE_EPSILON) )
		{
			(*epsilonfaces)++;
		} //end if
		//if the face has points at both sides of the plane
		if (front && back)
		{
			(*facesplits)++;
			if (face->faceflags & FACE_GROUND)
			{
				(*groundsplits)++;
			} //end if
		} //end if
	} //end for
	return true;
} //end of the function AAS_TestSplitPlane
Beispiel #9
0
//===========================================================================
//
// Parameter:			-
// Returns:				-
// Changes Globals:		-
//===========================================================================
void Q3_DPlanes2MapPlanes( void ) {
	int i;

	for ( i = 0; i < q3_numplanes; i++ )
	{
		dplanes2mapplanes[i] = FindFloatPlane( q3_dplanes[i].normal, q3_dplanes[i].dist );
	} //end for
} //end of the function Q3_DPlanes2MapPlanes
Beispiel #10
0
/*
==================
BrushFromBounds

Creates a new axial brush
==================
*/
brush_t	*BrushFromBounds (float minx, float miny, float minz, float maxx, float maxy, float maxz, shaderInfo_t *si)
{
    brush_t	*b;
    vec3_t mins, maxs;
    vec3_t normal;
    vec_t dist;
    int	i;

    b = AllocBrush (6);
    b->entityNum = mapEntityNum;
    b->original = b;
    b->contentShader = si;
    b->compileFlags = si->compileFlags;
    b->contentFlags = si->contentFlags;
    b->opaque = qtrue;
    b->detail = qfalse;
    b->numsides = 6;
    VectorSet(mins, minx, miny, minz);
    VectorSet(maxs, maxx, maxy, maxz);
    for (i=0 ; i<3 ; i++)
    {
        VectorClear (normal);
        normal[i] = 1;
        dist = maxs[i];
        b->sides[i].planenum = FindFloatPlane (normal, dist, 1, (vec3_t*) &maxs );
        b->sides[i].shaderInfo = si;
        b->sides[i].surfaceFlags = si->surfaceFlags;
        b->sides[i].contentFlags = si->contentFlags;
        b->sides[i].compileFlags = si->compileFlags;
        b->sides[i].value = si->value;

        normal[i] = -1;
        dist = -mins[i];
        b->sides[3+i].planenum = FindFloatPlane (normal, dist, 1, (vec3_t*) &mins );
        b->sides[3+i].shaderInfo = si;
        b->sides[3+i].surfaceFlags = si->surfaceFlags;
        b->sides[3+i].contentFlags = si->contentFlags;
        b->sides[3+i].compileFlags = si->compileFlags;
        b->sides[3+i].value = si->value;
    }

    CreateBrushWindings (b);

    return b;
}
Beispiel #11
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void DPlanes2MapPlanes(void)
{
	int i;

	for (i = 0; i < numplanes; i++)
	{
		dplanes2mapplanes[i] = FindFloatPlane(dplanes[i].normal, dplanes[i].dist, 0, NULL);
	} //end for
} //end of the function DPlanes2MapPlanes
Beispiel #12
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
int AAS_TransformPlane(int planenum, vec3_t origin, vec3_t angles)
{
	float newdist, matrix[3][3];
	vec3_t normal;

	//rotate the node plane
	VectorCopy(mapplanes[planenum].normal, normal);
	CreateRotationMatrix(angles, matrix);
	RotatePoint(normal, matrix);
	newdist = mapplanes[planenum].dist + DotProduct(normal, origin);
	return FindFloatPlane(normal, newdist);
} //end of the function AAS_TransformPlane
Beispiel #13
0
/*
=================
MapPlaneFromPoints

takes 3 points and finds the plane they lie in
=================
*/
int MapPlaneFromPoints( vec3_t *p )
{
	vec3_t	t1, t2, normal;
	vec_t	dist;
	
	VectorSubtract( p[0], p[1], t1 );
	VectorSubtract( p[2], p[1], t2 );
	CrossProduct( t1, t2, normal );
	VectorNormalize( normal );
	dist = DotProduct( p[0], normal );
	
	return FindFloatPlane( normal, dist, 3, p );
}
Beispiel #14
0
/*
 * PlaneFromPoints
 */
static int PlaneFromPoints(const vec3_t p0, const vec3_t p1, const vec3_t p2) {
	vec3_t t1, t2, normal;
	vec_t dist;

	VectorSubtract(p0, p1, t1);
	VectorSubtract(p2, p1, t2);
	CrossProduct(t1, t2, normal);
	VectorNormalize(normal);

	dist = DotProduct(p0, normal);

	return FindFloatPlane(normal, dist);
}
Beispiel #15
0
/*
==================
BrushFromBounds

Creates a new axial brush
==================
*/
uBrush_t	*BrushFromBounds( const idBounds &bounds ) {
	uBrush_t	*b;
	int			i;
	idPlane		plane;

	b = AllocBrush (6);
	b->numsides = 6;
	for (i=0 ; i<3 ; i++) {
		plane[0] = plane[1] = plane[2] = 0;
		plane[i] = 1;
		plane[3] = -bounds[1][i];
		b->sides[i].planenum = FindFloatPlane( plane );

		plane[i] = -1;
		plane[3] = bounds[0][i];
		b->sides[3+i].planenum = FindFloatPlane( plane );
	}

	CreateBrushWindings (b);

	return b;
}
Beispiel #16
0
/*
==================
AddMapTriToAreas

Used for curves and inlined models
==================
*/
void AddMapTriToAreas( mapTri_t* tri, uEntity_t* e )
{
	int				area;
	idWinding*		w;
	
	// skip degenerate triangles from pinched curves
	if( MapTriArea( tri ) <= 0 )
	{
		return;
	}
	
	if( dmapGlobals.fullCarve )
	{
		// always fragment into areas
		w = WindingForTri( tri );
		ClipTriIntoTree_r( w, tri, e, e->tree->headnode );
		return;
	}
	
	w = WindingForTri( tri );
	area = CheckWindingInAreas_r( w, e->tree->headnode );
	delete w;
	if( area == -1 )
	{
		return;
	}
	if( area >= 0 )
	{
		mapTri_t*	newTri;
		idPlane		plane;
		int			planeNum;
		textureVectors_t	texVec;
		
		// put in single area
		newTri = CopyMapTri( tri );
		newTri->next = NULL;
		
		PlaneForTri( tri, plane );
		planeNum = FindFloatPlane( plane );
		
		TexVecForTri( &texVec, newTri );
		
		AddTriListToArea( e, newTri, planeNum, area, &texVec );
	}
	else
	{
		// fragment into areas
		w = WindingForTri( tri );
		ClipTriIntoTree_r( w, tri, e, e->tree->headnode );
	}
}
Beispiel #17
0
/*
====================
ClipTriIntoTree_r

This is used for adding curve triangles
The winding will be freed before it returns
====================
*/
void ClipTriIntoTree_r( idWinding* w, mapTri_t* originalTri, uEntity_t* e, node_t* node )
{
	idWinding*		front, *back;
	
	if( !w )
	{
		return;
	}
	
	if( node->planenum != PLANENUM_LEAF )
	{
		//common->Printf( "ClipTriIntoTree_r: splitting triangle with splitplane %i\n", node->nodeNumber );
		
		w->Split( dmapGlobals.mapPlanes[ node->planenum ], ON_EPSILON, &front, &back );
		delete w;
		
		ClipTriIntoTree_r( front, originalTri, e, node->children[0] );
		ClipTriIntoTree_r( back, originalTri, e, node->children[1] );
		
		return;
	}
	
	//common->Printf( "ClipTriIntoTree_r: leaf area = %i, opaque = %i, occupied = %i\n", node->area, node->occupied );
	
	// if opaque leaf, don't add
	if( !node->opaque && node->area >= 0 )
	{
		mapTri_t*	list;
		int			planeNum;
		idPlane		plane;
		textureVectors_t	texVec;
		
		list = WindingToTriList( w, originalTri );
		
		PlaneForTri( originalTri, plane );
		planeNum = FindFloatPlane( plane );
		
		TexVecForTri( &texVec, originalTri );
		
		AddTriListToArea( e, list, planeNum, node->area, &texVec );
	}
	
	delete w;
	return;
}
Beispiel #18
0
int PlaneFromPoints (float *p0, float *p1, float *p2)
{
	vec3_t	t1, t2, normal;
	vec_t	dist;

	last_points[0] = p0;
	last_points[1] = p1;
	last_points[2] = p2;

	VectorSubtract (p0, p1, t1);
	VectorSubtract (p2, p1, t2);
	CrossProduct (t1, t2, normal);
	VectorNormalize (normal, normal);

	dist = DotProduct (p0, normal);

	show_points = 1;
	return FindFloatPlane (normal, dist);
	show_points = 0;
}
Beispiel #19
0
void AAS_CreateCurveBrushes(void)
{
	int i, j, n, planenum, numcurvebrushes = 0;
	q3_dsurface_t *surface;
	q3_drawVert_t *dv_p;
	vec3_t points[MAX_PATCH_VERTS];
	int width, height, c;
	patchCollide_t *pc;
	facet_t *facet;
	mapbrush_t *brush;
	side_t *side;
	entity_t *mapent;
	winding_t *winding;

	qprintf("nummapbrushsides = %d\n", nummapbrushsides);
	mapent = &entities[0];

	for(i = 0; i < q3_numDrawSurfaces; i++)
	{
		surface = &q3_drawSurfaces[i];

		if(!surface->patchWidth)
		{
			continue;
		}

		//if the curve is not solid
		if(!(q3_dshaders[surface->shaderNum].contentFlags & (CONTENTS_SOLID | CONTENTS_PLAYERCLIP)))
		{
			//Log_Print("skipped non-solid curve\n");
			continue;
		} //end if

		//
		width = surface->patchWidth;
		height = surface->patchHeight;
		c = width * height;

		if(c > MAX_PATCH_VERTS)
		{
			Error("ParseMesh: MAX_PATCH_VERTS");
		} //end if

		dv_p = q3_drawVerts + surface->firstVert;

		for(j = 0 ; j < c ; j++, dv_p++)
		{
			points[j][0] = dv_p->xyz[0];
			points[j][1] = dv_p->xyz[1];
			points[j][2] = dv_p->xyz[2];
		} //end for

		// create the internal facet structure
		pc = CM_GeneratePatchCollide(width, height, points);

		//
		for(j = 0; j < pc->numFacets; j++)
		{
			facet = &pc->facets[j];
			//
			brush = &mapbrushes[nummapbrushes];
			brush->original_sides = &brushsides[nummapbrushsides];
			brush->entitynum = 0;
			brush->brushnum = nummapbrushes - mapent->firstbrush;
			//
			brush->numsides = facet->numBorders + 2;
			nummapbrushsides += brush->numsides;
			brush->contents = CONTENTS_SOLID;
			//
			//qprintf("\r%6d curve brushes", nummapbrushsides);//++numcurvebrushes);
			qprintf("\r%6d curve brushes", ++numcurvebrushes);
			//
			planenum = FindFloatPlane(pc->planes[facet->surfacePlane].plane, pc->planes[facet->surfacePlane].plane[3]);
			//
			side = &brush->original_sides[0];
			side->planenum = planenum;
			side->contents = CONTENTS_SOLID;
			side->flags |= SFL_TEXTURED | SFL_VISIBLE | SFL_CURVE;
			side->surf = 0;
			//
			side = &brush->original_sides[1];

			if(create_aas)
			{
				//the plane is expanded later so it's not a problem that
				//these first two opposite sides are coplanar
				side->planenum = planenum ^ 1;
			} //end if
			else
			{
				side->planenum = FindFloatPlane(mapplanes[planenum ^ 1].normal, mapplanes[planenum ^ 1].dist + 1);
				side->flags |= SFL_TEXTURED | SFL_VISIBLE;
			} //end else

			side->contents = CONTENTS_SOLID;
			side->flags |= SFL_CURVE;
			side->surf = 0;
			//
			winding = BaseWindingForPlane(mapplanes[side->planenum].normal, mapplanes[side->planenum].dist);

			for(n = 0; n < facet->numBorders; n++)
			{
				//never use the surface plane as a border
				if(facet->borderPlanes[n] == facet->surfacePlane)
				{
					continue;
				}

				//
				side = &brush->original_sides[2 + n];
				side->planenum = FindFloatPlane(pc->planes[facet->borderPlanes[n]].plane, pc->planes[facet->borderPlanes[n]].plane[3]);

				if(facet->borderInward[n])
				{
					side->planenum ^= 1;
				}

				side->contents = CONTENTS_SOLID;
				side->flags |= SFL_TEXTURED | SFL_CURVE;
				side->surf = 0;

				//chop the winding in place
				if(winding)
				{
					ChopWindingInPlace(&winding, mapplanes[side->planenum ^ 1].normal, mapplanes[side->planenum ^ 1].dist, 0.1);      //CLIP_EPSILON);
				}
			} //end for

			//VectorCopy(pc->bounds[0], brush->mins);
			//VectorCopy(pc->bounds[1], brush->maxs);
			if(!winding)
			{
				Log_Print("WARNING: AAS_CreateCurveBrushes: no winding\n");
				brush->numsides = 0;
				continue;
			} //end if

			brush->original_sides[0].winding = winding;
			WindingBounds(winding, brush->mins, brush->maxs);

			for(n = 0; n < 3; n++)
			{
				//IDBUG: all the indexes into the mins and maxs were zero (not using i)
				if(brush->mins[n] < -MAX_MAP_BOUNDS || brush->maxs[n] > MAX_MAP_BOUNDS)
				{
					Log_Print("entity %i, brush %i: bounds out of range\n", brush->entitynum, brush->brushnum);
					Log_Print("brush->mins[%d] = %f, brush->maxs[%d] = %f\n", n, brush->mins[n], n, brush->maxs[n]);
					brush->numsides = 0; //remove the brush
					break;
				} //end if

				if(brush->mins[n] > MAX_MAP_BOUNDS || brush->maxs[n] < -MAX_MAP_BOUNDS)
				{
					Log_Print("entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum);
					Log_Print("brush->mins[%d] = %f, brush->maxs[%d] = %f\n", n, brush->mins[n], n, brush->maxs[n]);
					brush->numsides = 0; //remove the brush
					break;
				} //end if
			} //end for

			if(create_aas)
			{
				//NOTE: brush bevels now already added
				//AddBrushBevels(brush);
				AAS_CreateMapBrushes(brush, mapent, false);
			} //end if
			else
			{
				// create windings for sides and bounds for brush
				MakeBrushWindings(brush);
				AddBrushBevels(brush);
				nummapbrushes++;
				mapent->numbrushes++;
			} //end else
		} //end for
	} //end for

	//qprintf("\r%6d curve brushes", nummapbrushsides);//++numcurvebrushes);
	qprintf("\r%6d curve brushes\n", numcurvebrushes);
} //end of the function AAS_CreateCurveBrushes
Beispiel #20
0
int SelectSplitPlaneNum( node_t *node, bspface_t *list ) {
	bspface_t	*split;
	bspface_t	*check;
	bspface_t	*bestSplit;
	int			splits, facing, front, back;
	int			side;
	idPlane		*mapPlane;
	int			value, bestValue;
	idPlane		plane;
	int			planenum;
	bool	havePortals;
	float		dist;
	idVec3		halfSize;

	// if it is crossing a 1k block boundary, force a split
	// this prevents epsilon problems from extending an
	// arbitrary distance across the map

	halfSize = ( node->bounds[1] - node->bounds[0] ) * 0.5f;
	for ( int axis = 0; axis < 3; axis++ ) {
		if ( halfSize[axis] > BLOCK_SIZE ) {
			dist = BLOCK_SIZE * ( floor( ( node->bounds[0][axis] + halfSize[axis] ) / BLOCK_SIZE ) + 1.0f );
		} else {
			dist = BLOCK_SIZE * ( floor( node->bounds[0][axis] / BLOCK_SIZE ) + 1.0f );
		}
		if ( dist > node->bounds[0][axis] + 1.0f && dist < node->bounds[1][axis] - 1.0f ) {
			plane[0] = plane[1] = plane[2] = 0.0f;
			plane[axis] = 1.0f;
			plane[3] = -dist;
			planenum = FindFloatPlane( plane );
			return planenum;
		}
	}

	// pick one of the face planes
	// if we have any portal faces at all, only
	// select from them, otherwise select from
	// all faces
	bestValue = -999999;
	bestSplit = list;

	havePortals = false;
	for ( split = list ; split ; split = split->next ) {
		split->checked = false;
		if ( split->portal ) {
			havePortals = true;
		}
	}

	for ( split = list ; split ; split = split->next ) {
		if ( split->checked ) {
			continue;
		}
		if ( havePortals != split->portal ) {
			continue;
		}
		mapPlane = &dmapGlobals.mapPlanes[ split->planenum ];
		splits = 0;
		facing = 0;
		front = 0;
		back = 0;
		for ( check = list ; check ; check = check->next ) {
			if ( check->planenum == split->planenum ) {
				facing++;
				check->checked = true;	// won't need to test this plane again
				continue;
			}
			side = check->w->PlaneSide( *mapPlane );
			if ( side == SIDE_CROSS ) {
				splits++;
			} else if ( side == SIDE_FRONT ) {
				front++;
			} else if ( side == SIDE_BACK ) {
				back++;
			}
		}
		value =  5*facing - 5*splits; // - abs(front-back);
		if ( mapPlane->Type() < PLANETYPE_TRUEAXIAL ) {
			value+=5;		// axial is better
		}

		if ( value > bestValue ) {
			bestValue = value;
			bestSplit = split;
		}
	}

	if ( bestValue == -999999 ) {
		return -1;
	}

	return bestSplit->planenum;
}
Beispiel #21
0
//===========================================================================
// returns a list with brushes created by splitting the given brush with
// planes that go through the face edges and are orthogonal to the face plane
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
bspbrush_t *Q1_SplitBrushWithFace(bspbrush_t *brush, q1_dface_t *face)
{
    int i, edgenum, side, planenum, splits;
    float dist;
    q1_dplane_t plane;
    vec_t *v1, *v2;
    vec3_t normal, edgevec;
    bspbrush_t *front, *back, *brushlist;

    memcpy(&plane, &q1_dplanes[face->planenum], sizeof(q1_dplane_t));
    //check on which side of the plane the face is
    if (face->side)
    {
        VectorNegate(plane.normal, plane.normal);
        plane.dist = -plane.dist;
    } //end if
    splits = 0;
    brushlist = NULL;
    for (i = 0; i < face->numedges; i++)
    {
        //get the first and second vertex of the edge
        edgenum = q1_dsurfedges[face->firstedge + i];
        side = edgenum > 0;
        //if the face plane is flipped
        v1 = q1_dvertexes[q1_dedges[abs(edgenum)].v[side]].point;
        v2 = q1_dvertexes[q1_dedges[abs(edgenum)].v[!side]].point;
        //create a plane through the edge vector, orthogonal to the face plane
        //and with the normal vector pointing out of the face
        VectorSubtract(v1, v2, edgevec);
        CrossProduct(edgevec, plane.normal, normal);
        VectorNormalize(normal);
        dist = DotProduct(normal, v1);
        //
        planenum = FindFloatPlane(normal, dist);
        //split the current brush
        SplitBrush(brush, planenum, &front, &back);
        //if there is a back brush just put it in the list
        if (back)
        {
            //copy the brush contents
            back->side = brush->side;
            //
            back->next = brushlist;
            brushlist = back;
            splits++;
        } //end if
        if (!front)
        {
            Log_Print("Q1_SplitBrushWithFace: no new brush\n");
            FreeBrushList(brushlist);
            return NULL;
        } //end if
        //copy the brush contents
        front->side = brush->side;
        //continue splitting the front brush
        brush = front;
    } //end for
    if (!splits)
    {
        FreeBrush(front);
        return NULL;
    } //end if
    front->next = brushlist;
    brushlist = front;
    return brushlist;
} //end of the function Q1_SplitBrushWithFace
Beispiel #22
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
bspbrush_t *Q1_CreateBrushes_r(bspbrush_t *brush, int nodenum)
{
    int planenum;
    bspbrush_t *front, *back;
    q1_dleaf_t *leaf;

    //if it is a leaf
    if (nodenum < 0)
    {
        leaf = &q1_dleafs[(-nodenum) - 1];
        if (leaf->contents != Q1_CONTENTS_EMPTY)
        {
#ifdef Q1_PRINT
            qprintf("\r%5i", ++q1_numbrushes);
#endif //Q1_PRINT
        } //end if
        switch(leaf->contents)
        {
        case Q1_CONTENTS_EMPTY:
        {
            FreeBrush(brush);
            return NULL;
        } //end case
        case Q1_CONTENTS_SOLID:
#ifdef HLCONTENTS
        case Q1_CONTENTS_CLIP:
#endif HLCONTENTS
        case Q1_CONTENTS_SKY:
#ifdef HLCONTENTS
        case Q1_CONTENTS_TRANSLUCENT:
#endif HLCONTENTS
        {
            brush->side = CONTENTS_SOLID;
            return brush;
        } //end case
        case Q1_CONTENTS_WATER:
        {
            brush->side = CONTENTS_WATER;
            return brush;
        } //end case
        case Q1_CONTENTS_SLIME:
        {
            brush->side = CONTENTS_SLIME;
            return brush;
        } //end case
        case Q1_CONTENTS_LAVA:
        {
            brush->side = CONTENTS_LAVA;
            return brush;
        } //end case
#ifdef HLCONTENTS
        //these contents should not be found in the BSP
        case Q1_CONTENTS_ORIGIN:
        case Q1_CONTENTS_CURRENT_0:
        case Q1_CONTENTS_CURRENT_90:
        case Q1_CONTENTS_CURRENT_180:
        case Q1_CONTENTS_CURRENT_270:
        case Q1_CONTENTS_CURRENT_UP:
        case Q1_CONTENTS_CURRENT_DOWN:
        {
            Error("Q1_CreateBrushes_r: found contents %d in Half-Life BSP", leaf->contents);
            return NULL;
        } //end case
#endif HLCONTENTS
        default:
        {
            Error("Q1_CreateBrushes_r: unknown contents %d in Half-Life BSP", leaf->contents);
            return NULL;
        } //end default
        } //end switch
        return NULL;
    } //end if
    //if the rest of the tree is solid
    /*if (Q1_SolidTree_r(nodenum))
    {
    	brush->side = CONTENTS_SOLID;
    	return brush;
    } //end if*/
    //
    planenum = q1_dnodes[nodenum].planenum;
    planenum = FindFloatPlane(q1_dplanes[planenum].normal, q1_dplanes[planenum].dist);
    //split the brush with the node plane
    Q1_SplitBrush(brush, planenum, nodenum, &front, &back);
    //free the original brush
    FreeBrush(brush);
    //every node must split the brush in two
    if (!front || !back)
    {
        Log_Print("Q1_CreateBrushes_r: WARNING node not splitting brush\n");
        //return NULL;
    } //end if
    //create brushes recursively
    if (front) front = Q1_CreateBrushes_r(front, q1_dnodes[nodenum].children[0]);
    if (back) back = Q1_CreateBrushes_r(back, q1_dnodes[nodenum].children[1]);
    //link the brushes if possible and return them
    if (front)
    {
        for (brush = front; brush->next; brush = brush->next);
        brush->next = back;
        return front;
    } //end if
    else
    {
        return back;
    } //end else
} //end of the function Q1_CreateBrushes_r
//===========================================================================
// find an area with ladder faces and ground faces that are not connected
// split the area with a horizontal plane at the lowest vertex of all
// ladder faces in the area
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
tmp_node_t *AAS_LadderSubdivideArea_r( tmp_node_t *tmpnode ) {
	int side1, i, planenum;
	int foundladderface, foundgroundface;
	float dist;
	tmp_area_t *tmparea, *frontarea, *backarea;
	tmp_face_t *face1;
	tmp_node_t *tmpnode1, *tmpnode2;
	vec3_t lowestpoint, normal = {0, 0, 1};
	plane_t *plane;
	winding_t *w;

	tmparea = tmpnode->tmparea;
	//skip areas with a liquid
	if ( tmparea->contents & ( AREACONTENTS_WATER
							   | AREACONTENTS_LAVA
							   | AREACONTENTS_SLIME ) ) {
		return tmpnode;
	}
	//must be possible to stand in the area
	if ( !( tmparea->presencetype & PRESENCE_NORMAL ) ) {
		return tmpnode;
	}
	//
	foundladderface = false;
	foundgroundface = false;
	lowestpoint[2] = 99999;
	//
	for ( face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1] )
	{
		//side of the face the area is on
		side1 = face1->frontarea != tmparea;
		//if the face is a ladder face
		if ( face1->faceflags & FACE_LADDER ) {
			plane = &mapplanes[face1->planenum];
			//the ladder face plane should be pretty much vertical
			if ( DotProduct( plane->normal, normal ) > -0.1 ) {
				foundladderface = true;
				//find lowest point
				for ( i = 0; i < face1->winding->numpoints; i++ )
				{
					if ( face1->winding->p[i][2] < lowestpoint[2] ) {
						VectorCopy( face1->winding->p[i], lowestpoint );
					} //end if
				} //end for
			} //end if
		} //end if
		else if ( face1->faceflags & FACE_GROUND ) {
			foundgroundface = true;
		} //end else if
	} //end for
	  //
	if ( ( !foundladderface ) || ( !foundgroundface ) ) {
		return tmpnode;
	}
	//
	for ( face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1] )
	{
		//side of the face the area is on
		side1 = face1->frontarea != tmparea;
		//if the face isn't a ground face
		if ( !( face1->faceflags & FACE_GROUND ) ) {
			continue;
		}
		//the ground plane
		plane = &mapplanes[face1->planenum];
		//get the difference between the ground plane and the lowest point
		dist = DotProduct( plane->normal, lowestpoint ) - plane->dist;
		//if the lowest point is very near one of the ground planes
		if ( dist > -1 && dist < 1 ) {
			return tmpnode;
		} //end if
	} //end for
	  //
	dist = DotProduct( normal, lowestpoint );
	planenum = FindFloatPlane( normal, dist, 1, (vec3_t*)&lowestpoint );
	//
	w = AAS_SplitWinding( tmparea, planenum );
	if ( !w ) {
		return tmpnode;
	}
	FreeWinding( w );
	//split the area with a horizontal plane through the lowest point
	qprintf( "\r%6d", ++numladdersubdivisions );
	//
	AAS_SplitArea( tmparea, planenum, &frontarea, &backarea );
	//
	tmpnode->tmparea = NULL;
	tmpnode->planenum = planenum;
	//
	tmpnode1 = AAS_AllocTmpNode();
	tmpnode1->planenum = 0;
	tmpnode1->tmparea = frontarea;
	//
	tmpnode2 = AAS_AllocTmpNode();
	tmpnode2->planenum = 0;
	tmpnode2->tmparea = backarea;
	//subdivide the areas created by splitting recursively
	tmpnode->children[0] = AAS_LadderSubdivideArea_r( tmpnode1 );
	tmpnode->children[1] = AAS_LadderSubdivideArea_r( tmpnode2 );
	//refresh the tree
	AAS_RefreshLadderSubdividedTree_r( tmpaasworld.nodes, tmparea, tmpnode1, tmpnode2, planenum );
	//
	return tmpnode;
} //end of the function AAS_LadderSubdivideArea_r
Beispiel #24
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void Sin_BSPBrushToMapBrush(sin_dbrush_t *bspbrush, entity_t *mapent)
{
	mapbrush_t       *b;
	int              i, k, n;
	side_t           *side, *s2;
	int              planenum;
	sin_dbrushside_t *bspbrushside;
	sin_dplane_t     *bspplane;

	if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
	{
		Error("nummapbrushes >= MAX_MAPFILE_BRUSHES");
	}

	b                 = &mapbrushes[nummapbrushes];
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum      = mapent - entities;
	b->brushnum       = nummapbrushes - mapent->firstbrush;
	b->leafnum        = dbrushleafnums[bspbrush - sin_dbrushes];

	for (n = 0; n < bspbrush->numsides; n++)
	{
		//pointer to the bsp brush side
		bspbrushside = &sin_dbrushsides[bspbrush->firstside + n];

		if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
		{
			Error("MAX_MAPFILE_BRUSHSIDES");
		} //end if
		  //pointer to the map brush side
		side = &brushsides[nummapbrushsides];
		//if the BSP brush side is textured
		if (sin_dbrushsidetextured[bspbrush->firstside + n])
		{
			side->flags |= SFL_TEXTURED;
		}
		else
		{
			side->flags &= ~SFL_TEXTURED;
		}
		//ME: can get side contents and surf directly from BSP file
		side->contents = bspbrush->contents;
		//if the texinfo is TEXINFO_NODE
		if (bspbrushside->texinfo < 0)
		{
			side->surf = 0;
		}
		else
		{
			side->surf = sin_texinfo[bspbrushside->texinfo].flags;
		}

		// translucent objects are automatically classified as detail
//		if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
//			side->contents |= CONTENTS_DETAIL;
		if (side->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP))
		{
			side->contents |= CONTENTS_DETAIL;
		}
		if (fulldetail)
		{
			side->contents &= ~CONTENTS_DETAIL;
		}
		if (!(side->contents & ((LAST_VISIBLE_CONTENTS - 1)
		                        | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP | CONTENTS_MIST)))
		{
			side->contents |= CONTENTS_SOLID;
		}

		// hints and skips are never detail, and have no content
		if (side->surf & (SURF_HINT | SURF_SKIP))
		{
			side->contents = 0;
			side->surf    &= ~CONTENTS_DETAIL;
		}

		//ME: get a plane for this side
		bspplane = &sin_dplanes[bspbrushside->planenum];
		planenum = FindFloatPlane(bspplane->normal, bspplane->dist, 0, NULL);
		//
		// see if the plane has been used already
		//
		//ME: this really shouldn't happen!!!
		//ME: otherwise the bsp file is corrupted??
		//ME: still it seems to happen, maybe Johny Boy's
		//ME: brush bevel adding is crappy ?
		for (k = 0; k < b->numsides; k++)
		{
			s2 = b->original_sides + k;
			if (s2->planenum == planenum)
			{
				Log_Print("Entity %i, Brush %i: duplicate plane\n"
				          , b->entitynum, b->brushnum);
				break;
			}
			if (s2->planenum == (planenum ^ 1))
			{
				Log_Print("Entity %i, Brush %i: mirrored plane\n"
				          , b->entitynum, b->brushnum);
				break;
			}
		}
		if (k != b->numsides)
		{
			continue;       // duplicated

		}
		//
		// keep this side
		//
		//ME: reset pointer to side, why? hell I dunno (pointer is set above already)
		side = b->original_sides + b->numsides;
		//ME: store the plane number
		side->planenum = planenum;
		//ME: texinfo is already stored when bsp is loaded
		//NOTE: check for TEXINFO_NODE, otherwise crash in Sin_BrushContents
		if (bspbrushside->texinfo < 0)
		{
			side->texinfo = 0;
		}
		else
		{
			side->texinfo = bspbrushside->texinfo;
		}

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		// ME: don't need to recalculate because it's already done
		//     (for non-world entities) in the BSP file
//		side_brushtextures[nummapbrushsides] = td;

		nummapbrushsides++;
		b->numsides++;
	} //end for

	// get the content for the entire brush
	b->contents = bspbrush->contents;
	Sin_BrushContents(b);

	if (BrushExists(b))
	{
		c_squattbrushes++;
		b->numsides = 0;
		return;
	} //end if

	//if we're creating AAS
	if (create_aas)
	{
		//create the AAS brushes from this brush, don't add brush bevels
		AAS_CreateMapBrushes(b, mapent, false);
		return;
	} //end if

	// allow detail brushes to be removed
	if (nodetail && (b->contents & CONTENTS_DETAIL))
	{
		b->numsides = 0;
		return;
	} //end if

	// allow water brushes to be removed
	if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)))
	{
		b->numsides = 0;
		return;
	} //end if

	// create windings for sides and bounds for brush
	MakeBrushWindings(b);

	//mark brushes without winding or with a tiny window as bevels
	MarkBrushBevels(b);

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if (b->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP))
	{
		c_clipbrushes++;
		for (i = 0; i < b->numsides; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	} //end for

	//
	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity.  After the entire entity is parsed,
	// the planenums and texinfos will be adjusted for
	// the origin brush
	//
	//ME: not needed because the entities in the BSP file already
	//    have an origin set
//	if (b->contents & CONTENTS_ORIGIN)
//	{
//		char	string[32];
//		vec3_t	origin;
//
//		if (num_entities == 1)
//		{
//			Error ("Entity %i, Brush %i: origin brushes not allowed in world"
//				, b->entitynum, b->brushnum);
//			return;
//		}
//
//		VectorAdd (b->mins, b->maxs, origin);
//		VectorScale (origin, 0.5, origin);
//
//		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
//		SetKeyValue (&entities[b->entitynum], "origin", string);
//
//		VectorCopy (origin, entities[b->entitynum].origin);
//
//		// don't keep this brush
//		b->numsides = 0;
//
//		return;
//	}

	//ME: the bsp brushes already have bevels, so we won't try to
	//    add them again (especially since Johny Boy's bevel adding might
	//    be crappy)
//	AddBrushBevels(b);

	nummapbrushes++;
	mapent->numbrushes++;
} //end of the function Sin_BSPBrushToMapBrush
static void SelectSplitPlaneNum( node_t *node, face_t *list, int *splitPlaneNum, int *compileFlags ){
	face_t      *split;
	face_t      *check;
	face_t      *bestSplit;
	int splits, facing, front, back;
	int side;
	plane_t     *plane;
	int value, bestValue;
	int i;
	vec3_t normal;
	float dist;
	int planenum;
	float sizeBias;

	int frontC,backC,splitsC,facingC;


	/* ydnar: set some defaults */
	*splitPlaneNum = -1; /* leaf */
	*compileFlags = 0;

	/* ydnar 2002-06-24: changed this to split on z-axis as well */
	/* ydnar 2002-09-21: changed blocksize to be a vector, so mappers can specify a 3 element value */

	/* if it is crossing a block boundary, force a split */
	for ( i = 0; i < 3; i++ )
	{
		if ( blockSize[ i ] <= 0 ) {
			continue;
		}
		dist = blockSize[ i ] * ( floor( node->mins[ i ] / blockSize[ i ] ) + 1 );
		if ( node->maxs[ i ] > dist ) {
			VectorClear( normal );
			normal[ i ] = 1;
			planenum = FindFloatPlane( normal, dist, 0, NULL );
			*splitPlaneNum = planenum;
			return;
		}
	}

	/* pick one of the face planes */
	bestValue = -99999;
	bestSplit = list;


	for ( split = list; split; split = split->next )
		split->checked = qfalse;  //we don't add planes that already exist in the bsp. This stops us from checking them repeatedly


	for ( split = list; split; split = split->next )
	{
		if ( split->checked ) {
			continue;
		}


		plane = &mapplanes[ split->planenum ];

		splits = 0;
		facing = 0;
		front = 0;
		back = 0;
		for ( check = list ; check ; check = check->next )
		{
			if ( check->planenum == split->planenum ) {
				facing++;
				check->checked = qtrue; // won't need to test this plane again
				continue;
			}
			side = WindingOnPlaneSide( check->w, plane->normal, plane->dist );
			if ( side == SIDE_CROSS ) {
				splits++;
			}
			else if ( side == SIDE_FRONT ) {
				front++;
			}
			else if ( side == SIDE_BACK ) {
				back++;
			}
		}
		//Bigger is better
		sizeBias = GetSurfaceAreaOfWinding( split->w );


		//Base score = 20000 perfectly balanced
		value = 20000 - ( abs( front - back ) );
		value -= plane->counter; // If we've already used this plane sometime in the past try not to use it again
		value -= facing ;     // if we're going to have alot of other surfs use this plane, we want to get it in quickly.
		value -= splits * 5;    //more splits = bad
		value +=  sizeBias * 10; //We want a huge score bias based on plane size

/*
      //164fps - strange drops in places
      //Base score = 20000 perfectly balanced
      value = 20000-(abs(front-back));
      value -= plane->counter*10;// If we've already used this plane sometime in the past try not to use it again
      value -= facing ;       // if we're going to have alot of other surfs use this plane, we want to get it in quickly.
      value -= splits;        //more splits = bad
        value +=  sizeBias*10; //We want a huge score bias based on plane size
 */

		/*   //166 fps

		     //Base score = 20000 perfectly balanced
		     value = 20000-(abs(front-back));
		     value -= plane->counter;// If we've already used this plane sometime in the past try not to use it again
		     value -= facing ;       // if we're going to have alot of other surfs use this plane, we want to get it in quickly.
		     value -= splits;        //more splits = bad
		       value +=  sizeBias*10; //We want a huge score bias based on plane size
		 */

		/*
		   //150fps
		   sizeBias=GetSurfaceAreaOfWinding(split->w);
		   //Base score = 20000 perfectly balanced
		   value = 20000-(abs(front-back));
		   value -= facing ;       // if we're going to have alot of other surfs use this plane, we want to get it in quickly.
		     value +=  sizeBias*10; //We want a huge score bias based on plane size

		 */


		//if ( plane->type < 3 ) {
		//	value+=5;		// axial is better
		//}
		value += split->priority;       // prioritize hints higher

		if ( value > bestValue ) {
			bestValue = value;
			bestSplit = split;

			frontC = front;
			backC = back;
			splitsC = splits;
			facingC = facing;
		}
	}


	/*
	   for( split = list; split; split = split->next )
	   {
	     if ( split->checked )
	         continue;

	     plane = &mapplanes[ split->planenum ];
	     splits = 0;
	     facing = 0;
	     front = 0;
	     back = 0;
	     for ( check = list ; check ; check = check->next ) {
	         if ( check->planenum == split->planenum ) {
	             facing++;
	             check->checked = qtrue;	// won't need to test this plane again
	             continue;
	         }
	         side = WindingOnPlaneSide( check->w, plane->normal, plane->dist );
	         if ( side == SIDE_CROSS ) {
	             splits++;
	         } else if ( side == SIDE_FRONT ) {
	             front++;
	         } else if ( side == SIDE_BACK ) {
	             back++;
	         }
	     }
	     value =  5*facing - 5*splits; // - abs(front-back);
	     if ( plane->type < 3 ) {
	         value+=5;		// axial is better
	     }
	     value += split->priority;		// prioritize hints higher

	     if ( value > bestValue ) {
	         bestValue = value;
	         bestSplit = split;

	      frontC=front;
	      backC=back;
	      splitsC=splits;
	     }
	   }
	 */

	/* nothing, we have a leaf */
	if ( bestValue == -99999 ) {
		return;
	}

	//Sys_FPrintf (SYS_VRB, "F: %d B:%d S:%d FA:%ds\n",frontC,backC,splitsC,facingC );

	// if (frontC+backC<10)
	{
		//  Sys_FPrintf (SYS_VRB, "Forced Leaf\n");
		//  return; //Test!
	}

	/* set best split data */

	*splitPlaneNum = bestSplit->planenum;
	*compileFlags = bestSplit->compileFlags;

	if ( *splitPlaneNum > -1 ) {
		mapplanes[ *splitPlaneNum ].counter++;
	}

}
Beispiel #26
0
/*
=================
AddBrushBevels

adds any additional planes necessary to allow the brush being
built to be expanded against axial bounding boxes
2003-01-20: added mr.Elusive fixes
=================
*/
void AddBrushBevels( void )
{
	int		axis, dir;
	int		i, j, k, l, order = 0;
	side_t		sidetemp;
	side_t		*s, *s2;
	winding_t		*w, *w2;
	vec3_t		normal;
	float		dist;
	vec3_t		vec, vec2;
	float		d, minBack;

	// add the axial planes
	for( axis = 0; axis < 3; axis++ )
	{
		for( dir = -1; dir <= 1; dir += 2, order++ )
		{
			// see if the plane is allready present
			for( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
			{
				if( mapplanes[s->planenum].normal[axis] == dir )
					break;
			}

			if( i == buildBrush->numsides )
			{
				// add a new side
				if( buildBrush->numsides == MAX_BUILD_SIDES )
					Sys_Break( "Entity %i, Brush %i MAX_BUILD_SIDES\n", buildBrush->entityNum, buildBrush->brushNum );

				Mem_Set( s, 0, sizeof( *s ));
				buildBrush->numsides++;
				VectorClear (normal);
				normal[axis] = dir;

				if( dir == 1 )
				{
					// adding bevel plane snapping for fewer bsp planes
					if( bevelSnap > 0 )
						dist = floor( buildBrush->maxs[axis] / bevelSnap ) * bevelSnap;
					else
						dist = buildBrush->maxs[axis];
				}
				else
				{
					// adding bevel plane snapping for fewer bsp planes
					if( bevelSnap > 0 )
						dist = -ceil( buildBrush->mins[axis] / bevelSnap ) * bevelSnap;
					else
						dist = -buildBrush->mins[axis];
				}

				s->planenum = FindFloatPlane( normal, dist, 0, NULL );
				s->contentFlags = buildBrush->sides[0].contentFlags;
				s->bevel = true;
				c_boxbevels++;
			}

			// if the plane is not in it canonical order, swap it
			if( i != order )
			{
				sidetemp = buildBrush->sides[order];
				buildBrush->sides[order] = buildBrush->sides[i];
				buildBrush->sides[i] = sidetemp;
			}
		}
	}

	// add the edge bevels
	if( buildBrush->numsides == 6 )
		return; // pure axial

	// test the non-axial plane edges
	for( i = 6; i < buildBrush->numsides; i++ )
	{
		s = buildBrush->sides + i;
		w = s->winding;
		if( !w ) continue;

		for( j = 0; j < w->numpoints; j++ )
		{
			k = (j+1)%w->numpoints;
			VectorSubtract( w->p[j], w->p[k], vec );

			if( VectorNormalizeLength( vec ) < 0.5f )
				continue;
			SnapNormal( vec );
			for( k = 0; k < 3; k++ )
			{
				if( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f))
					break;	// axial
			}
			if( k != 3 ) continue; // only test non-axial edges

			// try the six possible slanted axials from this edge
			for( axis = 0; axis < 3; axis++ )
			{
				for( dir = -1; dir <= 1; dir += 2 )
				{
					// construct a plane
					VectorClear( vec2 );
					vec2[axis] = dir;
					CrossProduct( vec, vec2, normal );
					if( VectorNormalizeLength( normal ) < 0.5f )
						continue;
					dist = DotProduct( w->p[j], normal );
					
					// if all the points on all the sides are
					// behind this plane, it is a proper edge bevel
					for( k = 0; k < buildBrush->numsides; k++ )
					{
						// if this plane has allready been used, skip it
						if( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ))
							break;

						w2 = buildBrush->sides[k].winding;
						if( !w2 ) continue;

						minBack = 0.0f;
						for( l = 0; l < w2->numpoints; l++ )
						{
							d = DotProduct( w2->p[l], normal ) - dist;
							if( d > 0.1f ) break; // point in front
							if( d < minBack ) minBack = d;
						}
						// if some point was at the front
						if( l != w2->numpoints )
							break;

						// if no points at the back then the winding is on the bevel plane
						if( minBack > -0.1f )
							break;
					}

					if( k != buildBrush->numsides )
						continue;	// wasn't part of the outer hull
					
					// add this plane
					if( buildBrush->numsides == MAX_BUILD_SIDES )
						Sys_Break( "Entity %i, Brush %i MAX_BUILD_SIDES\n", buildBrush->entityNum, buildBrush->brushNum );

					s2 = &buildBrush->sides[buildBrush->numsides];
					buildBrush->numsides++;
					Mem_Set( s2, 0, sizeof( *s2 ) );

					s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[j] );
					s2->contentFlags = buildBrush->sides[0].contentFlags;
					s2->bevel = true;
					c_edgebevels++;
				}
			}
		}
	}
}
Beispiel #27
0
static void SelectSplitPlaneNum( node_t *node, face_t *list, int *splitPlaneNum, int *compileFlags ){
	face_t *split;
	face_t *check;
	face_t *bestSplit;
	int splits, facing, front, back;
	int side;
	plane_t *plane;
	int value, bestValue;
	int i;
	vec3_t normal;
	float dist;
	int planenum;
	float sizeBias;

	/* ydnar: set some defaults */
	*splitPlaneNum = -1; /* leaf */
	*compileFlags = 0;

	/* ydnar 2002-06-24: changed this to split on z-axis as well */
	/* ydnar 2002-09-21: changed blocksize to be a vector, so mappers can specify a 3 element value */

	/* if it is crossing a block boundary, force a split */
	for ( i = 0; i < 3; i++ )
	{
		if ( blockSize[ i ] <= 0 ) {
			continue;
		}
		dist = blockSize[ i ] * ( floor( node->mins[ i ] / blockSize[ i ] ) + 1 );
		if ( node->maxs[ i ] > dist ) {
			VectorClear( normal );
			normal[ i ] = 1;
			planenum = FindFloatPlane( normal, dist, 0, NULL );
			*splitPlaneNum = planenum;
			return;
		}
	}

	/* pick one of the face planes */
	bestValue = -99999;
	bestSplit = list;


	// div0: this check causes detail/structural mixes
	//for( split = list; split; split = split->next )
	//	split->checked = qfalse;

	for ( split = list; split; split = split->next )
	{
		//if ( split->checked )
		//	continue;

		plane = &mapplanes[ split->planenum ];
		splits = 0;
		facing = 0;
		front = 0;
		back = 0;
		for ( check = list ; check ; check = check->next ) {
			if ( check->planenum == split->planenum ) {
				facing++;
				//check->checked = qtrue;	// won't need to test this plane again
				continue;
			}
			side = WindingOnPlaneSide( check->w, plane->normal, plane->dist );
			if ( side == SIDE_CROSS ) {
				splits++;
			}
			else if ( side == SIDE_FRONT ) {
				front++;
			}
			else if ( side == SIDE_BACK ) {
				back++;
			}
		}

		if ( bspAlternateSplitWeights ) {
			// from 27

			//Bigger is better
			sizeBias = WindingArea( split->w );

			//Base score = 20000 perfectly balanced
			value = 20000 - ( abs( front - back ) );
			value -= plane->counter; // If we've already used this plane sometime in the past try not to use it again
			value -= facing ;       // if we're going to have alot of other surfs use this plane, we want to get it in quickly.
			value -= splits * 5;        //more splits = bad
			value +=  sizeBias * 10; //We want a huge score bias based on plane size
		}
		else
		{
			value =  5 * facing - 5 * splits; // - abs(front-back);
			if ( plane->type < 3 ) {
				value += 5;       // axial is better
			}
		}

		value += split->priority;       // prioritize hints higher

		if ( value > bestValue ) {
			bestValue = value;
			bestSplit = split;
		}
	}

	/* nothing, we have a leaf */
	if ( bestValue == -99999 ) {
		return;
	}

	/* set best split data */
	*splitPlaneNum = bestSplit->planenum;
	*compileFlags = bestSplit->compileFlags;

	if ( *splitPlaneNum > -1 ) {
		mapplanes[ *splitPlaneNum ].counter++;
	}
}
Beispiel #28
0
//===========================================================================
//
// Parameter:               -
// Returns:                 -
// Changes Globals:     -
//===========================================================================
void Q3_BSPBrushToMapBrush(q3_dbrush_t *bspbrush, entity_t *mapent)
{
	mapbrush_t *b;
	int i, k, n;
	side_t *side, *s2;
	int planenum;
	q3_dbrushside_t *bspbrushside;
	q3_dplane_t *bspplane;
	int contentFlags = 0;

	if(nummapbrushes >= MAX_MAPFILE_BRUSHES)
	{
		Error("nummapbrushes >= MAX_MAPFILE_BRUSHES");
	}

	b = &mapbrushes[nummapbrushes];
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum = mapent - entities;
	b->brushnum = nummapbrushes - mapent->firstbrush;
	b->leafnum = dbrushleafnums[bspbrush - q3_dbrushes];

	for(n = 0; n < bspbrush->numSides; n++)
	{
		//pointer to the bsp brush side
		bspbrushside = &q3_dbrushsides[bspbrush->firstSide + n];

		if(nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
		{
			Error("MAX_MAPFILE_BRUSHSIDES");
		} //end if

		//pointer to the map brush side
		side = &brushsides[nummapbrushsides];

		//if the BSP brush side is textured
		if(q3_dbrushsidetextured[bspbrush->firstSide + n])
		{
			side->flags |= SFL_TEXTURED | SFL_VISIBLE;
		}
		else
		{
			side->flags &= ~SFL_TEXTURED;
		}

		//NOTE: all Quake3 sides are assumed textured
		//side->flags |= SFL_TEXTURED|SFL_VISIBLE;
		//
		if(bspbrushside->shaderNum < 0)
		{
			side->contents = 0;
			side->surf = 0;
		} //end if
		else
		{
			side->contents = q3_dshaders[bspbrushside->shaderNum].contentFlags;
			side->surf = q3_dshaders[bspbrushside->shaderNum].surfaceFlags;

			if(strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/hint"))
			{
				//Log_Print("found hint side\n");
				side->surf |= SURF_HINT;
			} //end if

			// Ridah, mark ladder brushes
			if(cfg.rs_allowladders && strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/ladder"))
			{
				//Log_Print("found ladder side\n");
				side->contents |= CONTENTS_LADDER;
				contentFlags |= CONTENTS_LADDER;
			} //end if

			// done.

		} //end else

		//

		if(!(strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/slip")))
		{
			side->flags |= SFL_VISIBLE;
		}
		else if(side->surf & SURF_NODRAW)
		{
			side->flags |= SFL_TEXTURED | SFL_VISIBLE;
		} //end if

		/*
		if (side->contents & (CONTENTS_TRANSLUCENT|CONTENTS_STRUCTURAL))
		{
		  side->flags |= SFL_TEXTURED|SFL_VISIBLE;
		} //end if*/

		// hints and skips are never detail, and have no content
		if(side->surf & (SURF_HINT | SURF_SKIP))
		{
			side->contents = 0;
			//Log_Print("found hint brush side\n");
		}

		/*
		if ((side->surf & SURF_NODRAW) && (side->surf & SURF_NOIMPACT))
		{
		    side->contents = 0;
		    side->surf &= ~CONTENTS_DETAIL;
		    Log_Print("probably found hint brush in a BSP without hints being used\n");
		} //end if*/

		/*
		        // RF, ignore slick brushes (causes ladder issues)
		        if (strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/slick"))
		        {
		            //Log_Print("found hint side\n");
		            b->numsides = 0;
		            b->contents = 0;
		            return; // get out of here
		        } //end if
		*/

		//ME: get a plane for this side
		bspplane = &q3_dplanes[bspbrushside->planeNum];
		planenum = FindFloatPlane(bspplane->normal, bspplane->dist);

		//
		// see if the plane has been used already
		//
		//ME: this really shouldn't happen!!!
		//ME: otherwise the bsp file is corrupted??
		//ME: still it seems to happen, maybe Johny Boy's
		//ME: brush bevel adding is crappy ?
		for(k = 0; k < b->numsides; k++)
		{
			s2 = b->original_sides + k;
//			if (DotProduct (mapplanes[s2->planenum].normal, mapplanes[planenum].normal) > 0.999
//							&& fabs(mapplanes[s2->planenum].dist - mapplanes[planenum].dist) < 0.01 )

			if(s2->planenum == planenum)
			{
				Log_Print("Entity %i, Brush %i: duplicate plane\n"
				          , b->entitynum, b->brushnum);
				break;
			}

			if(s2->planenum == (planenum ^ 1))
			{
				Log_Print("Entity %i, Brush %i: mirrored plane\n"
				          , b->entitynum, b->brushnum);
				break;
			}
		}

		if(k != b->numsides)
		{
			continue;       // duplicated

		}

		//
		// keep this side
		//
		//ME: reset pointer to side, why? hell I dunno (pointer is set above already)
		side = b->original_sides + b->numsides;
		//ME: store the plane number
		side->planenum = planenum;
		//ME: texinfo is already stored when bsp is loaded
		//NOTE: check for TEXINFO_NODE, otherwise crash in Q3_BrushContents
		//if (bspbrushside->texinfo < 0) side->texinfo = 0;
		//else side->texinfo = bspbrushside->texinfo;

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		// ME: don't need to recalculate because it's already done
		//     (for non-world entities) in the BSP file
//		side_brushtextures[nummapbrushsides] = td;

		nummapbrushsides++;
		b->numsides++;
	} //end for

	// get the content for the entire brush
	//Quake3 bsp brushes don't have a contents
	b->contents = q3_dshaders[bspbrush->shaderNum].contentFlags | contentFlags;
	// Ridah, Wolf has ladders (if we call Q3_BrushContents(), we'll get the solid area bug
	b->contents &= ~(/*CONTENTS_LADDER|*/ CONTENTS_FOG | CONTENTS_STRUCTURAL);

	//b->contents = Q3_BrushContents(b);
	//
	// Ridah, CONTENTS_MOSTERCLIP should prevent AAS from being created, but not clip players/AI in the game
	if(b->contents & CONTENTS_MONSTERCLIP)
	{
		b->contents |= CONTENTS_PLAYERCLIP;
	}

	// func_explosive's not solid
	if(!strcmp("func_explosive", ValueForKey(&entities[b->entitynum], "classname")) ||
	        !strcmp("func_invisible_user", ValueForKey(&entities[b->entitynum], "classname")) ||
	        !strcmp("script_mover", ValueForKey(&entities[b->entitynum], "classname")) ||
	        !strcmp("func_static", ValueForKey(&entities[b->entitynum], "classname")))
	{
		Log_Print("Ignoring %s brush..\n", ValueForKey(&entities[b->entitynum], "classname"));
		b->numsides = 0;
		b->contents = 0;
		return;
	}

	if(BrushExists(b))
	{
		c_squattbrushes++;
		b->numsides = 0;
		return;
	} //end if

	//if we're creating AAS
	if(create_aas)
	{
		//create the AAS brushes from this brush, don't add brush bevels
		AAS_CreateMapBrushes(b, mapent, false);
		return;
	} //end if

	// allow detail brushes to be removed
	if(nodetail && (b->contents & CONTENTS_DETAIL))
	{
		b->numsides = 0;
		return;
	} //end if

	// allow water brushes to be removed
	if(nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)))
	{
		b->numsides = 0;
		return;
	} //end if


	// create windings for sides and bounds for brush
	MakeBrushWindings(b);

	//mark brushes without winding or with a tiny window as bevels
	MarkBrushBevels(b);

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if(b->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP))
	{
		c_clipbrushes++;

		for(i = 0; i < b->numsides; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	} //end for

	//
	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity.  After the entire entity is parsed,
	// the planenums and texinfos will be adjusted for
	// the origin brush
	//
	//ME: not needed because the entities in the BSP file already
	//    have an origin set
//	if (b->contents & CONTENTS_ORIGIN)
//	{
//		char    string[32];
//		vec3_t  origin;
//
//		if (num_entities == 1)
//		{
//			Error ("Entity %i, Brush %i: origin brushes not allowed in world"
//				, b->entitynum, b->brushnum);
//			return;
//		}
//
//		VectorAdd (b->mins, b->maxs, origin);
//		VectorScale (origin, 0.5, origin);
//
//		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
//		SetKeyValue (&entities[b->entitynum], "origin", string);
//
//		VectorCopy (origin, entities[b->entitynum].origin);
//
//		// don't keep this brush
//		b->numsides = 0;
//
//		return;
//	}

	//ME: the bsp brushes already have bevels, so we won't try to
	//    add them again (especially since Johny Boy's bevel adding might
	//    be crappy)
//	AddBrushBevels(b);

	nummapbrushes++;
	mapent->numbrushes++;
} //end of the function Q3_BSPBrushToMapBrush
Beispiel #29
0
/*
================
ParseMapEntity
================
*/
qboolean	ParseMapEntity (void)
{
	entity_t	*mapent;
	epair_t		*e;
	side_t		*s;
	int			i, j;
	int			startbrush, startsides;
	vec_t		newdist;
	mapbrush_t	*b;

	if (!GetToken (true))
		return false;

	if (strcmp (token, "{") )
		Error ("ParseEntity: { not found");
	
	if (num_entities == MAX_MAP_ENTITIES)
		Error ("num_entities == MAX_MAP_ENTITIES");

	startbrush = nummapbrushes;
	startsides = nummapbrushsides;

	mapent = &entities[num_entities];
	num_entities++;
	memset (mapent, 0, sizeof(*mapent));
	mapent->firstbrush = nummapbrushes;
	mapent->numbrushes = 0;
//	mapent->portalareas[0] = -1;
//	mapent->portalareas[1] = -1;

	do
	{
		if (!GetToken (true))
			Error ("ParseEntity: EOF without closing brace");
		if (!strcmp (token, "}") )
			break;
		if (!strcmp (token, "{") )
			ParseBrush (mapent);
		else
		{
			e = ParseEpair ();
			e->next = mapent->epairs;
			mapent->epairs = e;
		}
	} while (1);

	GetVectorForKey (mapent, "origin", mapent->origin);

	//
	// if there was an origin brush, offset all of the planes and texinfo
	//
	if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
	{
		for (i=0 ; i<mapent->numbrushes ; i++)
		{
			b = &mapbrushes[mapent->firstbrush + i];
			for (j=0 ; j<b->numsides ; j++)
			{
				s = &b->original_sides[j];
				newdist = mapplanes[s->planenum].dist -
					DotProduct (mapplanes[s->planenum].normal, mapent->origin);
				s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
				s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
					&side_brushtextures[s-brushsides], mapent->origin);
			}
			MakeBrushWindings (b);
		}
	}

	// group entities are just for editor convenience
	// toss all brushes into the world entity
	if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
	{
		MoveBrushesToWorld (mapent);
		mapent->numbrushes = 0;
		return true;
	}

	// areaportal entities move their brushes, but don't eliminate
	// the entity
	if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
	{
		char	str[128];

		if (mapent->numbrushes != 1)
			Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1);

		b = &mapbrushes[nummapbrushes-1];
		b->contents = CONTENTS_AREAPORTAL;
		c_areaportals++;
		mapent->areaportalnum = c_areaportals;
		// set the portal number as "style"
		sprintf (str, "%i", c_areaportals);
		SetKeyValue (mapent, "style", str);
		MoveBrushesToWorld (mapent);
		return true;
	}

	return true;
}
Beispiel #30
0
/*
=================
AddBrushBevels

Adds any additional planes necessary to allow the brush to be expanded
against axial bounding boxes
=================
*/
void AddBrushBevels (mapbrush_t *b)
{
	int		axis, dir;
	int		i, j, k, l, order;
	side_t	sidetemp;
	brush_texture_t	tdtemp;
	side_t	*s, *s2;
	vec3_t	normal;
	float	dist;
	winding_t	*w, *w2;
	vec3_t	vec, vec2;
	float	d;

	//
	// add the axial planes
	//
	order = 0;
	for (axis=0 ; axis <3 ; axis++)
	{
		for (dir=-1 ; dir <= 1 ; dir+=2, order++)
		{
			// see if the plane is allready present
			for (i=0, s=b->original_sides ; i<b->numsides ; i++,s++)
			{
				if (mapplanes[s->planenum].normal[axis] == dir)
					break;
			}

			if (i == b->numsides)
			{	// add a new side
				if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
					Error ("MAX_MAP_BRUSHSIDES");
				nummapbrushsides++;
				b->numsides++;
				VectorClear (normal);
				normal[axis] = dir;
				if (dir == 1)
					dist = b->maxs[axis];
				else
					dist = -b->mins[axis];
				s->planenum = FindFloatPlane (normal, dist);
				s->texinfo = b->original_sides[0].texinfo;
				s->contents = b->original_sides[0].contents;
				s->bevel = true;
				c_boxbevels++;
			}

			// if the plane is not in it canonical order, swap it
			if (i != order)
			{
				sidetemp = b->original_sides[order];
				b->original_sides[order] = b->original_sides[i];
				b->original_sides[i] = sidetemp;

				j = b->original_sides - brushsides;
				tdtemp = side_brushtextures[j+order];
				side_brushtextures[j+order] = side_brushtextures[j+i];
				side_brushtextures[j+i] = tdtemp;
			}
		}
	}

	//
	// add the edge bevels
	//
	if (b->numsides == 6)
		return;		// pure axial

	// test the non-axial plane edges
	for (i=6 ; i<b->numsides ; i++)
	{
		s = b->original_sides + i;
		w = s->winding;
		if (!w)
			continue;
		for (j=0 ; j<w->numpoints ; j++)
		{
			k = (j+1)%w->numpoints;
			VectorSubtract (w->p[j], w->p[k], vec);
			if (VectorNormalize (vec, vec) < 0.5)
				continue;
			SnapVector (vec);
			for (k=0 ; k<3 ; k++)
				if ( vec[k] == -1 || vec[k] == 1)
					break;	// axial
			if (k != 3)
				continue;	// only test non-axial edges

			// try the six possible slanted axials from this edge
			for (axis=0 ; axis <3 ; axis++)
			{
				for (dir=-1 ; dir <= 1 ; dir+=2)
				{
					// construct a plane
					VectorClear (vec2);
					vec2[axis] = dir;
					CrossProduct (vec, vec2, normal);
					if (VectorNormalize (normal, normal) < 0.5)
						continue;
					dist = DotProduct (w->p[j], normal);

					// if all the points on all the sides are
					// behind this plane, it is a proper edge bevel
					for (k=0 ; k<b->numsides ; k++)
					{
						// if this plane has allready been used, skip it
						if (PlaneEqual (&mapplanes[b->original_sides[k].planenum]
							, normal, dist) )
							break;

						w2 = b->original_sides[k].winding;
						if (!w2)
							continue;
						for (l=0 ; l<w2->numpoints ; l++)
						{
							d = DotProduct (w2->p[l], normal) - dist;
							if (d > 0.1)
								break;	// point in front
						}
						if (l != w2->numpoints)
							break;
					}

					if (k != b->numsides)
						continue;	// wasn't part of the outer hull
					// add this plane
					if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
						Error ("MAX_MAP_BRUSHSIDES");
					nummapbrushsides++;
					s2 = &b->original_sides[b->numsides];
					s2->planenum = FindFloatPlane (normal, dist);
					s2->texinfo = b->original_sides[0].texinfo;
					s2->contents = b->original_sides[0].contents;
					s2->bevel = true;
					c_edgebevels++;
					b->numsides++;
				}
			}
		}
	}
}