Beispiel #1
0
/*
============
idAASLocal::EdgeSplitPoint

  calculates split point of the edge with the plane
  returns true if the split point is between the edge vertices
============
*/
bool idAASLocal::EdgeSplitPoint( idVec3 &split, int edgeNum, const idPlane &plane ) const {
	const aasEdge_t *edge;
	idVec3 v1, v2;
	float d1, d2;
	edge = &file->GetEdge( edgeNum );
	v1 = file->GetVertex( edge->vertexNum[0] );
	v2 = file->GetVertex( edge->vertexNum[1] );
	d1 = v1 * plane.Normal() - plane.Dist();
	d2 = v2 * plane.Normal() - plane.Dist();
	//if ( (d1 < CM_CLIP_EPSILON && d2 < CM_CLIP_EPSILON) || (d1 > -CM_CLIP_EPSILON && d2 > -CM_CLIP_EPSILON) ) {
	if( FLOATSIGNBITSET( d1 ) == FLOATSIGNBITSET( d2 ) ) {
		return false;
	}
	split = v1 + ( d1 / ( d1 - d2 ) ) * ( v2 - v1 );
	return true;
}
Beispiel #2
0
/*
============
idBrush::Split
============
*/
int idBrush::Split( const idPlane& plane, int planeNum, idBrush** front, idBrush** back ) const
{
	int res, i, j;
	idBrushSide* side, *frontSide, *backSide;
	float dist, maxBack, maxFront, *maxBackWinding, *maxFrontWinding;
	idWinding* w, *mid;
	
	assert( windingsValid );
	
	if( front )
	{
		*front = NULL;
	}
	if( back )
	{
		*back = NULL;
	}
	
	res = bounds.PlaneSide( plane, -BRUSH_EPSILON );
	if( res == PLANESIDE_FRONT )
	{
		if( front )
		{
			*front = Copy();
		}
		return res;
	}
	if( res == PLANESIDE_BACK )
	{
		if( back )
		{
			*back = Copy();
		}
		return res;
	}
	
	maxBackWinding = ( float* ) _alloca16( sides.Num() * sizeof( float ) );
	maxFrontWinding = ( float* ) _alloca16( sides.Num() * sizeof( float ) );
	
	maxFront = maxBack = 0.0f;
	for( i = 0; i < sides.Num(); i++ )
	{
		side = sides[i];
		
		w = side->winding;
		
		if( !w )
		{
			continue;
		}
		
		maxBackWinding[i] = 10.0f;
		maxFrontWinding[i] = -10.0f;
		
		for( j = 0; j < w->GetNumPoints(); j++ )
		{
		
			dist = plane.Distance( ( *w )[j].ToVec3() );
			if( dist > maxFrontWinding[i] )
			{
				maxFrontWinding[i] = dist;
			}
			if( dist < maxBackWinding[i] )
			{
				maxBackWinding[i] = dist;
			}
		}
		
		if( maxFrontWinding[i] > maxFront )
		{
			maxFront = maxFrontWinding[i];
		}
		if( maxBackWinding[i] < maxBack )
		{
			maxBack = maxBackWinding[i];
		}
	}
	
	if( maxFront < BRUSH_EPSILON )
	{
		if( back )
		{
			*back = Copy();
		}
		return PLANESIDE_BACK;
	}
	
	if( maxBack > -BRUSH_EPSILON )
	{
		if( front )
		{
			*front = Copy();
		}
		return PLANESIDE_FRONT;
	}
	
	mid = new idWinding( plane.Normal(), plane.Dist() );
	
	for( i = 0; i < sides.Num() && mid; i++ )
	{
		mid = mid->Clip( -sides[i]->plane, BRUSH_EPSILON, false );
	}
	
	if( mid )
	{
		if( mid->IsTiny() )
		{
			delete mid;
			mid = NULL;
		}
		else if( mid->IsHuge() )
		{
			// if the winding is huge then the brush is unbounded
			common->Warning( "brush %d on entity %d is unbounded"
							 "( %1.2f %1.2f %1.2f )-( %1.2f %1.2f %1.2f )-( %1.2f %1.2f %1.2f )", primitiveNum, entityNum,
							 bounds[0][0], bounds[0][1], bounds[0][2], bounds[1][0], bounds[1][1], bounds[1][2],
							 bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1], bounds[1][2] - bounds[0][2] );
			delete mid;
			mid = NULL;
		}
	}
	
	if( !mid )
	{
		if( maxFront > - maxBack )
		{
			if( front )
			{
				*front = Copy();
			}
			return PLANESIDE_FRONT;
		}
		else
		{
			if( back )
			{
				*back = Copy();
			}
			return PLANESIDE_BACK;
		}
	}
	
	if( !front && !back )
	{
		delete mid;
		return PLANESIDE_CROSS;
	}
	
	*front = new idBrush();
	( *front )->SetContents( contents );
	( *front )->SetEntityNum( entityNum );
	( *front )->SetPrimitiveNum( primitiveNum );
	*back = new idBrush();
	( *back )->SetContents( contents );
	( *back )->SetEntityNum( entityNum );
	( *back )->SetPrimitiveNum( primitiveNum );
	
	for( i = 0; i < sides.Num(); i++ )
	{
		side = sides[i];
		
		if( !side->winding )
		{
			continue;
		}
		
		// if completely at the front
		if( maxBackWinding[i] >= BRUSH_EPSILON )
		{
			( *front )->sides.Append( side->Copy() );
		}
		// if completely at the back
		else if( maxFrontWinding[i] <= -BRUSH_EPSILON )
		{
			( *back )->sides.Append( side->Copy() );
		}
		else
		{
			// split the side
			side->Split( plane, &frontSide, &backSide );
			if( frontSide )
			{
				( *front )->sides.Append( frontSide );
			}
			else if( maxFrontWinding[i] > -BRUSH_EPSILON )
			{
				// favor an overconstrained brush
				side = side->Copy();
				side->winding = side->winding->Clip( idPlane( plane.Normal(), ( plane.Dist() - ( BRUSH_EPSILON + 0.02f ) ) ), 0.01f, true );
				assert( side->winding );
				( *front )->sides.Append( side );
			}
			if( backSide )
			{
				( *back )->sides.Append( backSide );
			}
			else if( maxBackWinding[i] < BRUSH_EPSILON )
			{
				// favor an overconstrained brush
				side = side->Copy();
				side->winding = side->winding->Clip( idPlane( -plane.Normal(), -( plane.Dist() + ( BRUSH_EPSILON + 0.02f ) ) ), 0.01f, true );
				assert( side->winding );
				( *back )->sides.Append( side );
			}
		}
	}
	
	side = new idBrushSide( -plane, planeNum ^ 1 );
	side->winding = mid->Reverse();
	side->flags |= SFL_SPLIT;
	( *front )->sides.Append( side );
	( *front )->windingsValid = true;
	( *front )->BoundBrush( this );
	
	side = new idBrushSide( plane, planeNum );
	side->winding = mid;
	side->flags |= SFL_SPLIT;
	( *back )->sides.Append( side );
	( *back )->windingsValid = true;
	( *back )->BoundBrush( this );
	
	return PLANESIDE_CROSS;
}
Beispiel #3
0
/*
============
idBrushBSPNode::Split
============
*/
bool idBrushBSPNode::Split( const idPlane &splitPlane, int splitPlaneNum ) {
	int s, i;
	idWinding *mid;
	idBrushBSPPortal *p, *midPortal, *newPortals[2];
	idBrushBSPNode *newNodes[2];

	mid = new idWinding( splitPlane.Normal(), splitPlane.Dist() );

	for ( p = portals; p && mid; p = p->next[s] ) {
		s = (p->nodes[1] == this);
		if ( s ) {
			mid = mid->Clip( -p->plane, 0.1f, false );
		}
		else {
			mid = mid->Clip( p->plane, 0.1f, false );
		}
	}

	if ( !mid ) {
		return false;
	}

	// allocate two new nodes
	for ( i = 0; i < 2; i++ ) {
		newNodes[i] = new idBrushBSPNode();
		newNodes[i]->flags = flags;
		newNodes[i]->contents = contents;
		newNodes[i]->parent = this;
	}

	// split all portals of the node
	for ( p = portals; p; p = portals ) {
		s = (p->nodes[1] == this);
		p->Split( splitPlane, &newPortals[0], &newPortals[1] );
		for ( i = 0; i < 2; i++ ) {
			if ( newPortals[i] ) {
				if ( s ) {
					newPortals[i]->AddToNodes( p->nodes[0], newNodes[i] );
				}
				else {
					newPortals[i]->AddToNodes( newNodes[i], p->nodes[1] );
				}
			}
		}
		p->RemoveFromNode( p->nodes[0] );
		p->RemoveFromNode( p->nodes[1] );
		delete p;
	}

	// add seperating portal
	midPortal = new idBrushBSPPortal();
	midPortal->plane = splitPlane;
	midPortal->planeNum = splitPlaneNum;
	midPortal->winding = mid;
	midPortal->AddToNodes( newNodes[0], newNodes[1] );

	// set new child nodes
	children[0] = newNodes[0];
	children[1] = newNodes[1];
	plane = splitPlane;

	return true;
}
Beispiel #4
0
/*
============
idAASLocal::FloorEdgeSplitPoint

  calculates either the closest or furthest point on the floor of the area which also lies on the pathPlane
  the point has to be on the front side of the frontPlane to be valid
============
*/
bool idAASLocal::FloorEdgeSplitPoint( idVec3 &bestSplit, int areaNum, const idPlane &pathPlane, const idPlane &frontPlane, bool closest ) const {
	int i, j, faceNum, edgeNum;
	const aasArea_t *area;
	const aasFace_t *face;
	idVec3 split;
	float dist, bestDist;
	const aasEdge_t *edge;
	idVec3 v1, v2;
	float d1, d2;

	area = &file->GetArea( areaNum );
	if ( closest ) {
		bestDist = maxWalkPathDistance;

		for ( i = area->numFaces-1; i >= 0; i-- ) {
			faceNum = file->GetFaceIndex( area->firstFace + i );
			face = &file->GetFace( abs(faceNum) );

			if ( !(face->flags & FACE_FLOOR ) ) {
				continue;
			}

			for ( j = face->numEdges-1; j >= 0; j-- ) {
				edgeNum = file->GetEdgeIndex( face->firstEdge + j );

				edge = &file->GetEdge( abs( edgeNum ) );
				v1 = file->GetVertex( edge->vertexNum[0] );
				v2 = file->GetVertex( edge->vertexNum[1] );
				d1 = v1 * pathPlane.Normal() - pathPlane.Dist();
				d2 = v2 * pathPlane.Normal() - pathPlane.Dist();

				//if ( (d1 < CM_CLIP_EPSILON && d2 < CM_CLIP_EPSILON) || (d1 > -CM_CLIP_EPSILON && d2 > -CM_CLIP_EPSILON) ) {
				if ( FLOATSIGNBITSET( d1 ) == FLOATSIGNBITSET( d2 ) ) {
					continue;
				}

				split = v1 + (d1 / (d1 - d2)) * (v2 - v1);
				dist = frontPlane.Distance( split );
				if ( dist >= -0.1f && dist < bestDist ) {
					bestDist = dist;
					bestSplit = split;
				}
			}
		}

		return ( bestDist < maxWalkPathDistance );

	} else {
		bestDist = -0.1f;

		for ( i = area->numFaces-1; i >= 0; i-- ) {
			faceNum = file->GetFaceIndex( area->firstFace + i );
			face = &file->GetFace( abs(faceNum) );

			if ( !(face->flags & FACE_FLOOR ) ) {
				continue;
			}

			for ( j = face->numEdges-1; j >= 0; j-- ) {
				edgeNum = file->GetEdgeIndex( face->firstEdge + j );

				edge = &file->GetEdge( abs( edgeNum ) );
				v1 = file->GetVertex( edge->vertexNum[0] );
				v2 = file->GetVertex( edge->vertexNum[1] );
				d1 = v1 * pathPlane.Normal() - pathPlane.Dist();
				d2 = v2 * pathPlane.Normal() - pathPlane.Dist();

				//if ( (d1 < CM_CLIP_EPSILON && d2 < CM_CLIP_EPSILON) || (d1 > -CM_CLIP_EPSILON && d2 > -CM_CLIP_EPSILON) ) {
				if ( FLOATSIGNBITSET( d1 ) == FLOATSIGNBITSET( d2 ) ) {
					continue;
				}

				split = v1 + (d1 / (d1 - d2)) * (v2 - v1);
				dist = frontPlane.Distance( split );
				if ( dist > bestDist ) {
					bestDist = dist;
					bestSplit = split;
				}
			}
		}

		return ( bestDist > -0.1f );
	}
}