示例#1
0
//-----------------------------------------------------------------------------
// Purpose: Loop through each face and filter it into the tree
// Input  : *out - 
//			*pFaces - 
//-----------------------------------------------------------------------------
face_t *FilterFacesIntoTree( tree_t *out, face_t *pFaces )
{
	face_t *pLeafFaceList = NULL;
	for ( face_t *f = pFaces; f; f = f->next )
	{
		if( f->merged || f->split[0] || f->split[1] )
			continue;

		face_t *tmp = CopyFace( f );
		face_t *original = CopyFace( f );

		if ( MergeFace_r( out->headnode, tmp, original ) )
		{
			// clear out portal (comes from a different tree)
			original->portal = NULL;
			original->next = pLeafFaceList;
			pLeafFaceList = original;
		}
		else
		{
			FreeFace( original );
		}
	}

	return pLeafFaceList;
}
示例#2
0
face_t* MakePlaneList(face_t* top, face_t* bottom)
{
	face_t*		fList;
	face_t*		curFace;
	face_t*		newTop;
	face_t*		newBot;
	int			i;
	int			j;
	int			k;
	vec3_t		t1, t2, t3;
	
	fList = NULL;
	newTop = Face_Alloc();
	CopyFace(top, newTop);
	newBot = Face_Alloc();
	CopyFace(bottom, newBot);
	WrapFaces(newTop, newBot);
	for (i = 0; i<newTop->face_winding->numpoints; i++)
	{
		if (i == (newTop->face_winding->numpoints - 1))
		{
			j = 0;
		}
		else
		{
			j = i + 1;
		}
		
		curFace = Face_Alloc();
		VectorCopy(newTop->face_winding->points[j],curFace->planepts[0]);
		VectorCopy(newTop->face_winding->points[i],curFace->planepts[1]);
		VectorCopy(newBot->face_winding->points[i],curFace->planepts[2]);
	
		for (k=0 ; k<3 ; k++)
		{
			t1[k] = curFace->planepts[0][k] - curFace->planepts[1][k];
			t2[k] = curFace->planepts[2][k] - curFace->planepts[1][k];
			t3[k] = curFace->planepts[1][k];
		}
		
		CrossProduct(t1,t2, curFace->plane.normal);
		if (VectorCompare (curFace->plane.normal, vec3_origin))
		{
			printf ("WARNING: brush plane with no normal\n");
		
		}
		VectorNormalize (curFace->plane.normal);
		curFace->plane.dist = DotProduct (t3, curFace->plane.normal);
	
		curFace->next = fList;
		fList = curFace;
  	}	// for loop
	return fList;
}
示例#3
0
// Clips f to a list of potential cutting brushes
// If f clips into new faces, returns the list of new faces in pOutputList
static void ClipFaceToBrushList( face_t *f, const CUtlVector<bspbrush_t *> &cutBrushes, face_t **pOutputList )
{
	*pOutputList = NULL;

	if ( f->split[0] )
		return;

	face_t *pClipList = CopyFace( f );
	pClipList->next = NULL;
	bool clipped = false;
	for ( int i = 0; i < cutBrushes.Count(); i++ )
	{
		bspbrush_t *cut = cutBrushes[i];
		for ( face_t *pCutFace = pClipList; pCutFace; pCutFace = pCutFace->next )
		{
			face_t *pClip = NULL;
			// already split, no need to clip
			if ( pCutFace->split[0] )
				continue;

			if ( ClipFaceToBrush( pCutFace, cut, &pClip ) )
			{
				clipped = true;
				// mark face bad, the brush clipped it away
				pCutFace->split[0] = pCutFace;
			}
			else if ( pClip )
			{
				clipped = true;
				// mark this face as split
				pCutFace->split[0] = pCutFace;

				// insert face fragments at head of list (UNDONE: reverses order, do we care?)
				while ( pClip )
				{
					face_t *next = pClip->next;
					pClip->next = pClipList;
					pClipList = pClip;
					pClip = next;
				}
			}
		}
	}
	if ( clipped )
	{
		*pOutputList = pClipList;
	}
	else
	{
		// didn't do any clipping, go ahead and free the copy of the face here.
		FreeFaceList( pClipList );
	}
}
示例#4
0
文件: qcsg.c 项目: 6779660/halflife
/*
==================
CopyFacesToOutside

Make a copy of all the faces of the brush, so they
can be chewed up by other brushes.

All of the faces start on the outside list.
As other brushes take bites out of the faces, the
fragments are moved to the inside list, so they
can be freed when they are determined to be
completely enclosed in solid.
==================
*/
bface_t *CopyFacesToOutside (brushhull_t *bh)
{
	bface_t		*f, *newf;
	bface_t		*outside;

	outside = NULL;
	
	for (f=bh->faces ; f ; f=f->next)
	{
		brushfaces++;

		newf = CopyFace (f);
		WindingBounds (newf->w, newf->mins, newf->maxs);
		newf->next = outside;
		outside = newf;
	}

	return outside;
}
示例#5
0
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pFace - input face to test
//			*pbrush - brush to clip face against
//			**pOutputList - list of faces clipped from pFace
// Output : Returns true if the brush completely clips the face
//-----------------------------------------------------------------------------
// NOTE: This assumes the brushes have already been chopped so that no solid space
// is enclosed by more than one brush!!
bool ClipFaceToBrush( face_t *pFace, bspbrush_t *pbrush, face_t **pOutputList )
{
	int planenum = pFace->planenum & (~1);
	int foundSide = -1;

	CUtlVector<int> sortedSides;

	int i;
	for ( i = 0; i < pbrush->numsides && foundSide < 0; i++ )
	{
		int bplane = pbrush->sides[i].planenum & (~1);
		if ( bplane == planenum )
			foundSide = i;
	}

	Vector offset = -0.5f * (pbrush->maxs + pbrush->mins);
	face_t *currentface = CopyFace( pFace );

	if ( foundSide >= 0 )
	{
		sortedSides.RemoveAll();
		for ( i = 0; i < pbrush->numsides; i++ )
		{
			// don't clip to bevels
			if ( pbrush->sides[i].bevel )
				continue;

			if ( g_MainMap->mapplanes[pbrush->sides[i].planenum].type <= PLANE_Z )
			{
				sortedSides.AddToHead( i );
			}
			else
			{
				sortedSides.AddToTail( i );
			}
		}

		for ( i = 0; i < sortedSides.Size(); i++ )
		{
			int index = sortedSides[i];
			if ( index == foundSide )
				continue;
			
			plane_t *plane = &g_MainMap->mapplanes[pbrush->sides[index].planenum];
			winding_t *frontwinding, *backwinding;
			ClipWindingEpsilon_Offset(currentface->w, plane->normal, plane->dist, 0.001, &frontwinding, &backwinding, offset);
			
			// only clip if some part of this face is on the back side of all brush sides
			if ( !backwinding || WindingIsTiny(backwinding))
			{
				FreeFaceList( *pOutputList );
				*pOutputList = NULL;
				break;
			}
			if ( frontwinding && !WindingIsTiny(frontwinding) )
			{
				// add this fragment to the return list
				// make a face for the fragment
				face_t *f = NewFaceFromFace( pFace );
				f->w = frontwinding;
				
				// link the fragment in
				f->next = *pOutputList;
				*pOutputList = f;
			}

			// update the current winding to be the part behind each plane
			FreeWinding( currentface->w );
			currentface->w = backwinding;
		}

		// free the bit that is left in solid or not clipped (if we broke out early)
		FreeFace( currentface );

		// if we made it all the way through and didn't produce any fragments then the whole face was clipped away
		if ( !*pOutputList && i == sortedSides.Size() )
		{
			return true;
		}
	}
	return false;
}
示例#6
0
// Returns false if union of brushes is obviously zero
static void     AddPlaneToUnion(brushhull_t* hull, const int planenum)
{
    bool            need_new_face = false;

    bface_t*        new_face_list;

    bface_t*        face;
    bface_t*        next;

    plane_t*        split;
    Winding*        front;
    Winding*        back;

    new_face_list = NULL;

    next = NULL;

    hlassert(hull);

    if (!hull->faces)
    {
        return;
    }
    hlassert(hull->faces->w);

    for (face = hull->faces; face; face = next)
    {
        hlassert(face->w);
        next = face->next;

        // Duplicate plane, ignore
        if (face->planenum == planenum)
        {
            AddFaceToList(&new_face_list, CopyFace(face));
            continue;
        }

        split = &g_mapplanes[planenum];
        face->w->Clip(split->normal, split->dist, &front, &back);

        if (front)
        {
            delete front;
            need_new_face = true;

            if (back)
            {                                              // Intersected the face
                delete face->w;
                face->w = back;
                AddFaceToList(&new_face_list, CopyFace(face));
            }
        }
        else
        {
            // Completely missed it, back is identical to face->w so it is destroyed
            if (back)
            {
                delete back;
                AddFaceToList(&new_face_list, CopyFace(face));
            }
        }
        hlassert(face->w);
    }

    FreeFaceList(hull->faces);
    hull->faces = new_face_list;

    if (need_new_face && (NumberOfHullFaces(hull) > 2))
    {
        Winding*        new_winding = NewWindingFromPlane(hull, planenum);

        if (new_winding)
        {
            bface_t*        new_face = (bface_t*)Alloc(sizeof(bface_t));

            new_face->planenum = planenum;
            new_face->w = new_winding;

            new_face->next = hull->faces;
            hull->faces = new_face;
        }
    }
}
示例#7
0
void WrapFaces( face_t* top, face_t* bottom)
{
	face_t*	tempFace;
	int		i;	
	float	maxX;
	float	maxY;
	int pointFlag;

	tempFace = Face_Alloc();
	//wrap the top face points the other way
	CopyFace(top, tempFace);
	for ( i = 0; i<top->face_winding->numpoints; i++)
	{
		VectorCopy(top->face_winding->points[top->face_winding->numpoints-1-i],tempFace->face_winding->points[i]);
	}
	CopyFace(tempFace,top);
	// top and bottom are now wrapped with normals pointing upward
	// now grab the point in top with most positive x (and y if there are more than one)
	maxX = top->face_winding->points[0][0];
	maxY = top->face_winding->points[0][1];
	pointFlag = 0;

	for ( i = 1; i<top->face_winding->numpoints; i++)
	{
		if ( maxX > top->face_winding->points[i][0] )
		{
			continue;
		}
		else
		{
			if ( maxX == top->face_winding->points[i][0] )
			{
				if (top->face_winding->points[i][1] > maxY)
				{
					maxY = top->face_winding->points[i][1];
					pointFlag = i;
				}
			}
			else
			{
				maxX = top->face_winding->points[i][0];
				maxY = top->face_winding->points[i][1];
				pointFlag = i;
			}
		}
	}
//  now, starting at the point[pointflag] in top, write the sequence starting at [0] in tempFace
	for ( i = 0; i<top->face_winding->numpoints; i++)
	{
		if (pointFlag == top->face_winding->numpoints)
		{
			pointFlag = 0;
		}
		VectorCopy(top->face_winding->points[pointFlag], tempFace->face_winding->points[i]);
		pointFlag++;
	}
	CopyFace(tempFace,top);
//repeat with bottom
	CopyFace(bottom, tempFace);
	maxX = bottom->face_winding->points[0][0];
	maxY = bottom->face_winding->points[0][1];
	pointFlag = 0;

	for ( i = 1; i<bottom->face_winding->numpoints; i++)
	{
		if ( maxX > bottom->face_winding->points[i][0] )
		{
			continue;
		}
		else
		{
			if ( maxX == bottom->face_winding->points[i][0] )
			{
				if (bottom->face_winding->points[i][1] > maxY)
				{
					maxY = bottom->face_winding->points[i][1];
					pointFlag = i;
				}
			}
			else
			{
				maxX = bottom->face_winding->points[i][0];
				maxY = bottom->face_winding->points[i][1];
				pointFlag = i;
			}
		}
	}
//  now, starting at the point[pointflag] in bottom, write the sequence starting at [0] in tempFace
	for ( i = 0; i<bottom->face_winding->numpoints; i++)
	{
		if (pointFlag == bottom->face_winding->numpoints)
		{
			pointFlag = 0;
		}
		VectorCopy(bottom->face_winding->points[pointFlag], tempFace->face_winding->points[i]);
		pointFlag++;
	}
	CopyFace(tempFace,bottom);
	Face_Free(tempFace);
	return;
}
示例#8
0
文件: qcsg.c 项目: 6779660/halflife
/*
===========
CSGBrush
===========
*/
void CSGBrush (int brushnum)
{
	int			hull;
	brush_t		*b1, *b2;
	brushhull_t	*bh1, *bh2;
	int			bn;
	qboolean	overwrite;
	int			i;
	bface_t		*f, *f2, *next, *fcopy;
	bface_t		*outside, *oldoutside;
	entity_t	*e;
	vec_t		area;

	SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL);

	b1 = &mapbrushes[brushnum];

	e = &entities[b1->entitynum];

	for (hull = 0 ; hull<NUM_HULLS ; hull++)
	{
		bh1 = &b1->hulls[hull];

		// set outside to a copy of the brush's faces
		outside = CopyFacesToOutside (bh1);
		overwrite = false;

		for (bn=0 ; bn<e->numbrushes ; bn++)
		{
			// see if b2 needs to clip a chunk out of b1

			if (bn==brushnum)
			{
				overwrite = true;	// later brushes now overwrite
				continue;
			}

			b2 = &mapbrushes[e->firstbrush + bn];
			bh2 = &b2->hulls[hull];

			if (!bh2->faces)
				continue;		// brush isn't in this hull

			// check brush bounding box first
			for (i=0 ; i<3 ; i++)
				if (bh1->mins[i] > bh2->maxs[i] 
				|| bh1->maxs[i] < bh2->mins[i])
					break;
			if (i<3)
				continue;

			// divide faces by the planes of the b2 to find which
			// fragments are inside
		
			f = outside;
			outside = NULL;
			for ( ; f ; f=next)
			{
				next = f->next;

				// check face bounding box first
				for (i=0 ; i<3 ; i++)
					if (bh2->mins[i] > f->maxs[i] 
					|| bh2->maxs[i] < f->mins[i])
						break;
				if (i<3)
				{	// this face doesn't intersect brush2's bbox
					f->next = outside;
					outside = f;
					continue;
				}

				oldoutside = outside;
				fcopy = CopyFace (f);	// save to avoid fake splits

				// throw pieces on the front sides of the planes
				// into the outside list, return the remains on the inside
				for (f2=bh2->faces ; f2 && f ; f2=f2->next)
					f = ClipFace (b1, f, &outside, f2->planenum, overwrite);

				area = f ? WindingArea (f->w) : 0;
				if (f && area < 1.0)
				{
					qprintf ("Entity %i, Brush %i: tiny penetration\n"
						, b1->entitynum, b1->brushnum);
					c_tiny_clip++;
					FreeFace (f);
					f = NULL;
				}
				if (f)
				{
					// there is one convex fragment of the original
					// face left inside brush2
					FreeFace (fcopy);

					if (b1->contents > b2->contents)
					{	// inside a water brush
						f->contents = b2->contents;
						f->next = outside;
						outside = f;
					}
					else	// inside a solid brush
						FreeFace (f);	// throw it away
				}
				else
				{	// the entire thing was on the outside, even
					// though the bounding boxes intersected,
					// which will never happen with axial planes

					// free the fragments chopped to the outside
					while (outside != oldoutside)
					{
						f2 = outside->next;
						FreeFace (outside);
						outside = f2;
					}

					// revert to the original face to avoid
					// unneeded false cuts
					fcopy->next = outside;
					outside = fcopy;
				}
			}

		}

		// all of the faces left in outside are real surface faces
		SaveOutside (b1, hull, outside, b1->contents);
	}
}