Esempio n. 1
0
int TexelDelta( face_t *f, dplane_t *plane )
{
	int	 current, delta;


	current = delta = 0;
	// Does the plane split the face?
	if ( FaceSide (f, plane) == SIDE_ON )
	{
		face_t *front, *back;
		
		// Compute the change in texture cache from splitting the face
		current = TexelSize( f );

		// Speculatively split the face
		SplitFaceTmp(f, plane, &front, &back);
		if (!front || !back)	// Didn't actually split the face
			delta = 0;
		else
		{
			delta = 0;//TexelSize( front ) + TexelSize( back ) - current;		// Change in texel size
			FreeFace( front );												// Free new faces
			FreeFace( back );
		}
	}
	
	return delta;
}
Esempio n. 2
0
static void FreeTree_r (node_t *node)
{
	face_t *f, *nextf;

	/* free children */
	if (node->planenum != PLANENUM_LEAF) {
		FreeTree_r(node->children[0]);
		FreeTree_r(node->children[1]);
	}

	/* free bspbrushes */
	FreeBrushList(node->brushlist);

	/* free faces */
	for (f = node->faces; f; f = nextf) {
		nextf = f->next;
		FreeFace(f);
	}

	/* free the node */
	if (node->volume)
		FreeBrush(node->volume);

	if (threadstate.numthreads == 1)
		c_nodes--;
	Mem_Free(node);
}
Esempio n. 3
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;
}
Esempio n. 4
0
face_t *MergeFaceToList (face_t *face, face_t *list)
{	
  face_t	*newf, *f;
	
  for (f=list ; f ; f=f->next)
    {
      //CheckColinear (f);		
      if (mergedebug)
	{
	  Draw_ClearWindow ();
	  Draw_DrawFace (face);
	  Draw_DrawFace (f);
	  Draw_SetBlack ();
	}
      newf = TryMerge (face, f);
      if (!newf)
	continue;
      FreeFace (face);
      f->numpoints = -1;		// merged out
      return MergeFaceToList (newf, list);
    }
	
  // didn't merge, so add at start
  face->next = list;
  return face;
}
Esempio n. 5
0
/*
   =============
   FreeTree_r
   =============
 */
void FreeTree_r( node_t *node ){
	face_t      *f, *nextf;

	// free children
	if ( node->planenum != PLANENUM_LEAF ) {
		FreeTree_r( node->children[0] );
		FreeTree_r( node->children[1] );
	}

	// free bspbrushes
	FreeBrushList( node->brushlist );

	// free faces
	for ( f = node->faces ; f ; f = nextf )
	{
		nextf = f->next;
		FreeFace( f );
	}

	// free the node
	if ( node->volume ) {
		FreeBrush( node->volume );
	}

	if ( numthreads == 1 ) {
		c_nodes--;
	}
	free( node );
}
Esempio n. 6
0
/*
==================
SaveOutside

The faces remaining on the outside list are final
polygons.  Write them to the output file.

Passable contents (water, lava, etc) will generate
a mirrored copy of the face to be seen from the inside.
==================
*/
void SaveOutside (brush_t *b, int hull, bface_t *outside, int mirrorcontents)
{
	bface_t	*f , *next, *f2;
	int		i;
	int		planenum;
	vec3_t	temp;

	for (f=outside ; f ; f=next)
	{
		next = f->next;

		if (WindingArea (f->w) < 1.0)
		{
			c_tiny++;
			qprintf ("Entity %i, Brush %i: tiny fragment\n"
				, b->entitynum, b->brushnum);
			continue;
		}

		// count unique faces
		if (!hull)
		{
			for (f2=b->hulls[hull].faces ; f2 ; f2=f2->next)
			{
				if (f2->planenum == f->planenum)
				{
					if (!f2->used)
					{
						f2->used = true;
						c_outfaces++;
					}
					break;
				}
			}
		}

		WriteFace (hull, f);

//		if (mirrorcontents != CONTENTS_SOLID)
		{
			f->planenum ^= 1;
			f->plane = &mapplanes[f->planenum];
			f->contents = mirrorcontents;

			// swap point orders
			for (i=0 ; i<f->w->numpoints/2 ; i++)	// add points backwards
			{
				VectorCopy (f->w->p[i], temp);
				VectorCopy (f->w->p[f->w->numpoints-1-i]
					, f->w->p[i]);
				VectorCopy (temp, f->w->p[f->w->numpoints-1-i]);
			}
			WriteFace (hull, f);
		}

		FreeFace (f);
	}
}
Esempio n. 7
0
File: brush.c Progetto: kellyrm/Q1
/*
=================
FreeBrushFaces
=================
*/
void FreeBrushFaces(face_t *pFaceList)
{
	face_t *pFace, *pNext;

	for (pFace = pFaceList; pFace; pFace = pNext)
	{
		pNext = pFace->next;
		FreeFace(pFace);
	}
}
Esempio n. 8
0
//-----------------------------------------------------------------------------
// Purpose: Free the list of faces stored at the leaves
//-----------------------------------------------------------------------------
void FreeLeafFaces( face_t *pLeafFaceList )
{
    int count = 0;
    face_t *f, *next;

    f = pLeafFaceList;

    while ( f )
    {
        next = f->next;
        FreeFace( f );
        f = next;
        count++;
    }
}
Esempio n. 9
0
File: csg4.c Progetto: dommul/super8
/*
==================
FreeInside

Free all the faces that got clipped out
==================
*/
static void FreeInside( int contents )
{
	face_t	*f, *next;

	for( f = inside; f; f = next ) {
		next = f->next;

		if( contents == CONTENTS_SOLID ) {
			FreeFace (f);
			continue;
		}

		f->contents[0] = contents;
		f->next = outside;
		outside = f;
	}
}
Esempio n. 10
0
/*
=============
FreeLeafSurfs
=============
*/
void FreeLeafSurfs (node_t *leaf)
{
	surface_t *surf, *snext;
	face_t		*f, *fnext;

	for (surf = leaf->surfaces ; surf ; surf=snext)
	{
		snext = surf->next;
		for (f=surf->faces ; f ; f=fnext)
		{
			fnext = f->next;
			FreeFace (f);
		}
		FreeSurface (surf);
	}

	leaf->surfaces = NULL;
}
Esempio n. 11
0
File: merge.c Progetto: kellyrm/Q1
/*
===============
MergeFaceToList
===============
*/
face_t *MergeFaceToList (face_t *face, face_t *list)
{
	face_t	*newf, *f;

	for (f=list ; f ; f=f->next)
	{
		newf = TryMerge (face, f);
		if (!newf)
			continue;
		FreeFace (face);
		ResizeFace (f, 0);
		f->numpoints = -1;		// merged out
		return MergeFaceToList (newf, list);
	}

// didn't merge, so add at start
	face->next = list;
	return face;
}
Esempio n. 12
0
/*
===============
FreeMergeListScraps
===============
*/
face_t *FreeMergeListScraps (face_t *merged)
{
  face_t	*head, *next;
	
  head = NULL;
  for ( ; merged ; merged = next)
    {
      next = merged->next;
      if (merged->numpoints == -1)
	FreeFace (merged);
      else
	{
	  merged->next = head;
	  head = merged;
	}
    }

  return head;
}
Esempio n. 13
0
/*
===========
FreeDrawNodes_r
===========
*/
void FreeDrawNodes_r (node_t *node)
{
	int		i;
	face_t	*f, *next;

	for (i=0 ; i<2 ; i++)
		if (node->children[i]->planenum != -1)
			FreeDrawNodes_r (node->children[i]);

	//
	// free the faces on the node
	//
	for (f=node->faces ; f ; f=next)
	{
		next = f->next;
		FreeFace (f);
	}

	free (node);
}
Esempio n. 14
0
/*
=============================================================================

GatherNodeFaces

Frees the current node tree and returns a new chain of the surfaces that
have inside faces.
=============================================================================
*/
static void GatherNodeFaces_r (node_t *node)
{
	face_t	*f, *next;

	if (node->planenum != PLANENUM_LEAF)
	{
//
// decision node
//
		for (f = node->faces ; f ; f = next)
		{
			next = f->next;
			if (!f->numpoints)
			{	// face was removed outside
				FreeFace (f);
			}
			else
			{
				f->next = validfaces[f->planenum];
				validfaces[f->planenum] = f;
			}
		}

		GatherNodeFaces_r (node->children[0]);
		GatherNodeFaces_r (node->children[1]);

		free (node);
	}
	else
	{
//
// leaf node
//
		free (node);
	}
}
Esempio n. 15
0
/*
==================
LinkConvexFaces

Determines the contents of the leaf and creates the final list of
original faces that have some fragment inside this leaf
==================
*/
void LinkConvexFaces (surface_t *planelist, node_t *leafnode)
{
	face_t		*f, *next;
	surface_t	*surf, *pnext;
	int			i, count;

	leafnode->faces = NULL;
	leafnode->contents = 0;
	leafnode->planenum = -1;

	count = 0;
	for ( surf = planelist ; surf ; surf = surf->next)
	{
		for (f = surf->faces ; f ; f=f->next)
		{
			count++;
			if (!leafnode->contents)
				leafnode->contents = f->contents[0];
			else if (leafnode->contents != f->contents[0])
				Error ("LinkConvexFaces: Mixed face contents in leafnode");
		}
	}

	if (!leafnode->contents)
		leafnode->contents = CONTENTS_SOLID;

	switch (leafnode->contents)
	{
		case CONTENTS_EMPTY:
			c_empty++;
			break;
		case CONTENTS_SOLID:
			c_solid++;
			break;
		case CONTENTS_WATER:
		case CONTENTS_SLIME:
		case CONTENTS_LAVA:
		case CONTENTS_SKY:
			c_water++;
			break;
		default:
			Error ("LinkConvexFaces: bad contents number");
	}

	//
	// write the list of faces, and free the originals
	//
	leaffaces += count;
	leafnode->markfaces = malloc(sizeof(face_t *)*(count+1));
	i = 0;
	for ( surf = planelist ; surf ; surf = pnext)
	{
		pnext = surf->next;
		for (f = surf->faces ; f ; f=next)
		{
			next = f->next;
			leafnode->markfaces[i] = f->original;
			i++;
			FreeFace (f);
		}
		FreeSurface (surf);
	}
	leafnode->markfaces[i] = NULL;	// sentinal
}
Esempio n. 16
0
//-----------------------------------------------------------------------------
// Purpose: Recursively filter a face into the tree leaving references to the
//			original face in any visible leaves that a clipped fragment falls
//			into.
// Input  : *node - current head of tree
//			*face - clipped face fragment
//			*original - unclipped original face
// Output : Returns true if any references were left
//-----------------------------------------------------------------------------
bool MergeFace_r( node_t *node, face_t *face, face_t *original )
{
	bool referenced = false;

	if ( node->planenum == PLANENUM_LEAF )
	{
		if ( node->contents & CONTENTS_SOLID )
		{
			FreeFace( face );
			return false;
		}

		leafface_t *plist = new leafface_t;
		plist->pFace = original;
		plist->pNext = node->leaffacelist;
		node->leaffacelist = plist;

		referenced = true;
	}
	else
	{
		// UNDONE: Don't copy the faces each time unless it's necessary!?!?!
		plane_t *plane = &g_MainMap->mapplanes[node->planenum];
		winding_t *frontwinding, *backwinding, *onwinding;

		Vector offset;
		WindingCenter( face->w, offset );

		// UNDONE: Export epsilon from original face clipping code
		ClassifyWindingEpsilon_Offset(face->w, plane->normal, plane->dist, 0.001, &frontwinding, &backwinding, &onwinding, -offset);

		if ( onwinding )
		{
			// face is in the split plane, go down the appropriate side according to the facing direction
			assert( frontwinding == NULL );
			assert( backwinding == NULL );

			if ( DotProduct( g_MainMap->mapplanes[face->planenum].normal, g_MainMap->mapplanes[node->planenum].normal ) > 0 )
			{
				frontwinding = onwinding;
			}
			else
			{
				backwinding = onwinding;
			}
		}

		if ( frontwinding )
		{
			face_t *tmp = NewFaceFromFace( face );
			tmp->w = frontwinding;
			referenced = MergeFace_r( node->children[0], tmp, original );
		}
		if ( backwinding )
		{
			face_t *tmp = NewFaceFromFace( face );
			tmp->w = backwinding;
			bool test = MergeFace_r( node->children[1], tmp, original );
			referenced = referenced || test;
		}
	}
	FreeFace( face );

	return referenced;
}
Esempio n. 17
0
// Compute a list of faces that are visible on the detail brush sides
face_t *ComputeVisibleBrushSides( bspbrush_t *list )
{
	face_t *pTotalFaces = NULL;
	CUtlVector<bspbrush_t *> cutBrushes;

	// Go through the whole brush list
	for ( bspbrush_t *pbrush = list; pbrush; pbrush = pbrush->next )
	{
		face_t *pFaces = NULL;
		mapbrush_t *mb = pbrush->original;

		if ( !(mb->contents & ALL_VISIBLE_CONTENTS) )
			continue;

		// Make a face for each brush side, then clip it by the other
		// details to see if any fragments are visible
		for ( int i = 0; i < pbrush->numsides; i++ )
		{
			winding_t *winding = pbrush->sides[i].winding;
			if ( !winding )
				continue;
			
			if (! (pbrush->sides[i].contents & ALL_VISIBLE_CONTENTS) )
				continue;

			side_t *side = FindOriginalSide( mb, pbrush->sides + i );
			face_t *f = MakeBrushFace( side, winding );

			// link to head of face list
			f->next = pFaces;
			pFaces = f;
		}

		// Make a list of brushes that can cut the face list for this brush
		cutBrushes.RemoveAll();
		if ( GetListOfCutBrushes( cutBrushes, pbrush, list ) )
		{
			// now cut each face to find visible fragments
			for ( face_t *f = pFaces; f; f = f->next )
			{
				// this will be a new list of faces that this face cuts into
				face_t *pClip = NULL;
				ClipFaceToBrushList( f, cutBrushes, &pClip );
				if ( pClip )
				{
					int outCount = CountFaceList(pClip);
					// it cut into more faces (or it was completely cut away)
					if ( outCount <= 1 )
					{
						// was removed or cut down, mark as split
						f->split[0] = f;
						// insert face fragments at head of list (UNDONE: reverses order, do we care?)
						while ( pClip )
						{
							face_t *next = pClip->next;
							pClip->next = pFaces;
							pFaces = pClip;
							pClip = next;
						}
					}
					else
					{
						// it cut into more than one visible fragment
						// Don't fragment details
						// UNDONE: Build 2d convex hull of this list and swap face winding 
						// with that polygon?  That would fix the remaining issues.
						FreeFaceList( pClip );
						pClip = NULL;
					}
				}
			}
		}
	
		// move visible fragments to global face list
		while ( pFaces )
		{
			face_t *next = pFaces->next;
			if ( pFaces->split[0] )
			{
				FreeFace( pFaces );
			}
			else
			{
				pFaces->next = pTotalFaces;
				pTotalFaces = pFaces;
			}
			pFaces = next;
		}
	}

	return pTotalFaces;
}
Esempio n. 18
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;
}
Esempio n. 19
0
/*
==================
ClearOutFaces_r

Removes unused nodes
==================
*/
node_t *ClearOutFaces_r (node_t *node)
{
    face_t		*f, *fnext;
    face_t		**fp;
    portal_t	*p;

    // mark the node and all it's faces, so they
    // can be removed if no children use them

    node->valid = 0;	// will be set if any children touch it
    for (f=node->faces ; f ; f=f->next)
        f->outputnumber = -1;

    // go down the children
    if (node->planenum != -1)
    {
        //
        // decision node
        //
        node->children[0] = ClearOutFaces_r (node->children[0]);
        node->children[1] = ClearOutFaces_r (node->children[1]);

        // free any faces not in open child leafs
        f=node->faces;
        node->faces = NULL;

        for ( ; f ; f=fnext)
        {
            fnext = f->next;
            if (f->outputnumber == -1)
            {   // never referenced, so free it
                c_free_faces++;
                FreeFace (f);
            }
            else
            {
                c_keep_faces++;
                f->next = node->faces;
                node->faces = f;
            }
        }

        if (!node->valid)
        {
            // this node does not touch any interior leafs

            // if both children are solid, just make this node solid
            if (node->children[0]->contents == CONTENTS_SOLID
                    && node->children[1]->contents == CONTENTS_SOLID)
            {
                node->contents = CONTENTS_SOLID;
                node->planenum = -1;
                return node;
            }

            // if one child is solid, shortcut down the other side
            if (node->children[0]->contents == CONTENTS_SOLID)
                return node->children[1];
            if (node->children[1]->contents == CONTENTS_SOLID)
                return node->children[0];

            c_falsenodes++;
        }
        return node;
    }

    //
    // leaf node
    //
    if (node->contents != CONTENTS_SOLID)
    {
        // this node is still inside

        // mark all the nodes used as portals
        for (p = node->portals ; p ; )
        {
            if (p->onnode)
                p->onnode->valid = 1;
            if (p->nodes[0] == node)		// only write out from first leaf
                p = p->next[0];
            else
                p = p->next[1];
        }

        // mark all of the faces to be drawn
        for (fp = node->markfaces ; *fp ; fp++)
            (*fp)->outputnumber = 0;

        return node;
    }

    // this was a filled in node, so free the markfaces
    if (node->planenum != -1)
        free (node->markfaces);

    return node;
}
Esempio n. 20
0
/*
===========
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);
	}
}
Esempio n. 21
0
/*
==================
SplitFace

==================
*/
void SplitFace (face_t *in, plane_t *split, face_t **front, face_t **back)
{
	double	dists[MAXEDGES+1];
	int		sides[MAXEDGES+1];
	int		counts[3];
	double	dot;
	int		i, j;
	face_t	*newf, *new2;
	double	*p1, *p2;
	vec3_t	mid;

	if (in->numpoints < 0)
		Error ("%s: freed face", __thisfunc__);
	counts[0] = counts[1] = counts[2] = 0;

// determine sides for each point
	for (i = 0 ; i < in->numpoints ; i++)
	{
		dot = DotProduct (in->pts[i], split->normal);
		dot -= split->dist;
		dists[i] = dot;
		if (dot > ON_EPSILON)
			sides[i] = SIDE_FRONT;
		else if (dot < -ON_EPSILON)
			sides[i] = SIDE_BACK;
		else
			sides[i] = SIDE_ON;
		counts[sides[i]]++;
	}
	sides[i] = sides[0];
	dists[i] = dists[0];

	if (!counts[0])
	{
		*front = NULL;
		*back = in;
		return;
	}
	if (!counts[1])
	{
		*front = in;
		*back = NULL;
		return;
	}

	*back = newf = NewFaceFromFace (in);
	*front = new2 = NewFaceFromFace (in);

// distribute the points and generate splits

	for (i = 0 ; i < in->numpoints ; i++)
	{
		if (newf->numpoints > MAXEDGES || new2->numpoints > MAXEDGES)
			Error ("%s: numpoints > MAXEDGES", __thisfunc__);

		p1 = in->pts[i];

		if (sides[i] == SIDE_ON)
		{
			VectorCopy (p1, newf->pts[newf->numpoints]);
			newf->numpoints++;
			VectorCopy (p1, new2->pts[new2->numpoints]);
			new2->numpoints++;
			continue;
		}

		if (sides[i] == SIDE_FRONT)
		{
			VectorCopy (p1, new2->pts[new2->numpoints]);
			new2->numpoints++;
		}
		else
		{
			VectorCopy (p1, newf->pts[newf->numpoints]);
			newf->numpoints++;
		}

		if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
			continue;

	// generate a split point
		p2 = in->pts[(i+1)%in->numpoints];

		dot = dists[i] / (dists[i]-dists[i+1]);
		for (j = 0 ; j < 3 ; j++)
		{	// avoid round off error when possible
			if (split->normal[j] == 1)
				mid[j] = split->dist;
			else if (split->normal[j] == -1)
				mid[j] = -split->dist;
			else
				mid[j] = p1[j] + dot*(p2[j]-p1[j]);
		}

		VectorCopy (mid, newf->pts[newf->numpoints]);
		newf->numpoints++;
		VectorCopy (mid, new2->pts[new2->numpoints]);
		new2->numpoints++;
	}

	if (newf->numpoints > MAXEDGES || new2->numpoints > MAXEDGES)
		Error ("%s: numpoints > MAXEDGES", __thisfunc__);

#if 0
	CheckFace (newf);
	CheckFace (new2);
#endif

// free the original face now that is is represented by the fragments
	FreeFace (in);
}
Esempio n. 22
0
/*
=================
CreateBrushFaces
=================
*/
void CreateBrushFaces (void)
{
	int				i,j, k;
	vec_t			r;
	face_t			*f, *next;
	winding_t		*w;
	plane_t			clipplane, faceplane;
	mface_t			*mf;
	vec3_t			offset, point;

	offset[0] = offset[1] = offset[2] = 0;
	ClearBounds( brush_mins, brush_maxs );

	brush_faces = NULL;

	if (!strncmp(ValueForKey(CurrentEntity, "classname"), "rotate_", 7))
	{
		entity_t	*FoundEntity;
		char 		*searchstring;
		char		text[20];

		searchstring = ValueForKey (CurrentEntity, "target");
		FoundEntity = FindTargetEntity(searchstring);
		if (FoundEntity)
			GetVectorForKey(FoundEntity, "origin", offset);

		sprintf(text, "%g %g %g", offset[0], offset[1], offset[2]);
		SetKeyValue(CurrentEntity, "origin", text);
	}

	GetVectorForKey(CurrentEntity, "origin", offset);
	//printf("%i brushfaces at offset %f %f %f\n", numbrushfaces, offset[0], offset[1], offset[2]);

	for (i = 0;i < numbrushfaces;i++)
	{
		mf = &faces[i];

		//printf("plane %f %f %f %f\n", mf->plane.normal[0], mf->plane.normal[1], mf->plane.normal[2], mf->plane.dist);
		faceplane = mf->plane;
		w = BaseWindingForPlane (&faceplane);

		//VectorNegate( faceplane.normal, point );
		for (j = 0;j < numbrushfaces && w;j++)
		{
			clipplane = faces[j].plane;
			if( j == i/* || VectorCompare( clipplane.normal, point )*/ )
				continue;

			// flip the plane, because we want to keep the back side
			VectorNegate(clipplane.normal, clipplane.normal);
			clipplane.dist *= -1;

			w = ClipWindingEpsilon (w, &clipplane, ON_EPSILON, true);
		}

		if (!w)
		{
			//printf("----- skipped plane -----\n");
			continue;	// overcontrained plane
		}

		// this face is a keeper
		f = AllocFace ();
		f->winding = w;

		for (j = 0;j < w->numpoints;j++)
		{
			for (k = 0;k < 3;k++)
			{
				point[k] = w->points[j][k] - offset[k];
				r = Q_rint( point[k] );
				if ( fabs( point[k] - r ) < ZERO_EPSILON)
					w->points[j][k] = r;
				else
					w->points[j][k] = point[k];

				// check for incomplete brushes
				if( w->points[j][k] >= BOGUS_RANGE || w->points[j][k] <= -BOGUS_RANGE )
					break;
			}

			// remove this brush
			if (k < 3)
			{
				FreeFace (f);
				for (f = brush_faces; f; f = next)
				{
					next = f->next;
					FreeFace (f);
				}
				brush_faces = NULL;
				//printf("----- skipped brush -----\n");
				return;
			}

			AddPointToBounds( w->points[j], brush_mins, brush_maxs );
		}

		CheckWinding( w );

		faceplane.dist -= DotProduct(faceplane.normal, offset);
		f->texturenum = mf->texinfo;
		f->planenum = FindPlane (&faceplane, &f->planeside);
		f->next = brush_faces;
		brush_faces = f;
	}

	// Rotatable objects have to have a bounding box big enough
	// to account for all its rotations.
	if (DotProduct(offset, offset))
	{
		vec_t delta;

		delta = RadiusFromBounds( brush_mins, brush_maxs );

		for (k = 0;k < 3;k++)
		{
			brush_mins[k] = -delta;
			brush_maxs[k] = delta;
		}
	}

	//printf("%i : %f %f %f : %f %f %f\n", numbrushfaces, brush_mins[0], brush_mins[1], brush_mins[2], brush_maxs[0], brush_maxs[1], brush_maxs[2]);
}