Esempio n. 1
0
/**
 * @brief The faces vertexes have been added to the superverts[] array,
 * and there may be more there than can be held in a face (MAXEDGES).
 *
 * If less, the faces vertexnums[] will be filled in, otherwise
 * face will reference a tree of split[] faces until all of the
 * vertexnums can be added.
 *
 * @note superverts[base] will become face->vertexnums[0], and the others
 * will be circularly filled in.
 */
static void FaceFromSuperverts (node_t* node, face_t* f, int base)
{
	int i, remaining;

	remaining = numsuperverts;
	/* must split into two faces, because of vertex overload */
	while (remaining > MAXEDGES) {
		c_faceoverflows++;

		face_t* newf = f->split[0] = NewFaceFromFace(f);
		newf->next = node->faces;
		node->faces = newf;

		newf->numpoints = MAXEDGES;
		for (i = 0; i < MAXEDGES; i++)
			newf->vertexnums[i] = superverts[(i + base) % numsuperverts];

		f->split[1] = NewFaceFromFace(f);
		f = f->split[1];
		f->next = node->faces;
		node->faces = f;

		remaining -= (MAXEDGES - 2);
		base = (base + MAXEDGES - 1) % numsuperverts;
	}

	/* copy the vertexes back to the face */
	f->numpoints = remaining;
	for (i = 0; i < remaining; i++)
		f->vertexnums[i] = superverts[(i + base) % numsuperverts];
}
Esempio n. 2
0
/**
 * @brief Chop up faces that are larger than we want in the surface cache
 */
static void SubdivideFace (node_t* node, face_t* f)
{
	if (f->merged)
		return;

	/* special (non-surface cached) faces don't need subdivision */
	const dBspTexinfo_t* tex = &curTile->texinfo[f->texinfo];
	if (tex->surfaceFlags & SURF_WARP)
		return;

	for (int axis = 0; axis < 2; axis++) {
		while (1) {
			const winding_t* w = f->w;
			winding_t* frontw, *backw;
			float mins = 999999;
			float maxs = -999999;
			vec3_t temp;
			vec_t v;

			VectorCopy(tex->vecs[axis], temp);
			for (int i = 0; i < w->numpoints; i++) {
				v = DotProduct(w->p[i], temp);
				if (v < mins)
					mins = v;
				if (v > maxs)
					maxs = v;
			}

			/* no bsp subdivide for this winding? */
			if (maxs - mins <= config.subdivideSize)
				break;

			/* split it */
			c_subdivide++;

			v = VectorNormalize(temp);

			vec_t dist = (mins + config.subdivideSize - 16) / v;

			ClipWindingEpsilon(w, temp, dist, ON_EPSILON, &frontw, &backw);
			if (!frontw || !backw)
				Sys_Error("SubdivideFace: didn't split the polygon (texture: '%s')",
					tex->texture);

			f->split[0] = NewFaceFromFace(f);
			f->split[0]->w = frontw;
			f->split[0]->next = node->faces;
			node->faces = f->split[0];

			f->split[1] = NewFaceFromFace(f);
			f->split[1]->w = backw;
			f->split[1]->next = node->faces;
			node->faces = f->split[1];

			SubdivideFace(node, f->split[0]);
			SubdivideFace(node, f->split[1]);
			return;
		}
	}
}
Esempio n. 3
0
//-----------------------------------------------------------------------------
// Purpose: Copies a face and its winding
// Input  : *pFace - 
// Output : face_t
//-----------------------------------------------------------------------------
face_t *CopyFace( face_t *pFace )
{
	face_t *f = NewFaceFromFace( pFace );
	f->w = CopyWinding( pFace->w );

	return f;
}
Esempio n. 4
0
/**
 * @brief If two polygons share a common edge and the edges that meet at the
 * common points are both inside the other polygons, merge them
 *
 * @return nullptr if the faces couldn't be merged, or the new face.
 * @note The originals will NOT be freed.
 */
static face_t* TryMerge (face_t* f1, face_t* f2, const vec3_t planenormal)
{
	face_t* newf;
	winding_t* nw;

	if (!f1->w || !f2->w)
		return nullptr;
	if (f1->texinfo != f2->texinfo)
		return nullptr;
	if (f1->planenum != f2->planenum)	/* on front and back sides */
		return nullptr;
	if (f1->contentFlags != f2->contentFlags)
		return nullptr;

	nw = TryMergeWinding(f1->w, f2->w, planenormal);
	if (!nw)
		return nullptr;

	c_merge++;
	newf = NewFaceFromFace(f1);
	newf->w = nw;

	f1->merged = newf;
	f2->merged = newf;

	return newf;
}
Esempio n. 5
0
/*
==================
SaveOutside

Saves all of the faces in the outside list to the bsp plane list
==================
*/
static void
SaveOutside(bool mirror)
{
    face_t *f, *next, *newf;
    int i;
    int planenum;

    for (f = outside; f; f = next) {
	next = f->next;
	csgfaces++;
	planenum = f->planenum;

	if (mirror) {
	    newf = NewFaceFromFace(f);

	    newf->w.numpoints = f->w.numpoints;
	    newf->planeside = f->planeside ^ 1;	// reverse side
	    newf->contents[0] = f->contents[1];
	    newf->contents[1] = f->contents[0];

	    for (i = 0; i < f->w.numpoints; i++)	// add points backwards
		VectorCopy(f->w.points[f->w.numpoints - 1 - i], newf->w.points[i]);

	    validfaces[planenum] =
		MergeFaceToList(newf, validfaces[planenum]);
	}

	validfaces[planenum] = MergeFaceToList(f, validfaces[planenum]);
	validfaces[planenum] = FreeMergeListScraps(validfaces[planenum]);
    }
}
Esempio n. 6
0
/*	Saves all of the faces in the outside list to the bsp plane list
*/
static void SaveOutside( tree_t *tree, bool mirror )
{
	int		planenum;
	face_t	*f, *next, *newf;

	for( f = outside; f; f = next ) 
	{
		next = f->next;
		numcsgfaces++;
		planenum = f->planenum;

		if( mirror ) 
		{
			newf = NewFaceFromFace( f );
			newf->planeside = f->planeside ^ 1;	// reverse side
			newf->contents[0] = f->contents[1];
			newf->contents[1] = f->contents[0];
			newf->winding = ReverseWinding( f->winding );
			tree->validfaces[planenum] = MergeFaceToList_r( newf, tree->validfaces[planenum] );
		}

		tree->validfaces[planenum] = MergeFaceToList_r( f, tree->validfaces[planenum]);
		tree->validfaces[planenum] = FreeMergeListScraps( tree->validfaces[planenum] );
	}
}
Esempio n. 7
0
bface_t	*CopyFace (bface_t *f)
{
	bface_t	*n;

	n = NewFaceFromFace (f);
	n->w = CopyWinding (f->w);
	VectorCopy (f->mins, n->mins);
	VectorCopy (f->maxs, n->maxs);
	return n;
}
Esempio n. 8
0
/*
=============
TryMerge

If two polygons share a common edge and the edges that meet at the
common points are both inside the other polygons, merge them

Returns NULL if the faces couldn't be merged, or the new face.
The originals will NOT be freed.
=============
*/
static face_t *
TryMerge(face_t *f1, face_t *f2)
{
    vec_t *p1, *p2, *p3, *p4, *back;
    face_t *newf;
    int i, j, k, l;
    vec3_t normal, delta, planenormal;
    vec_t dot;
    plane_t *plane;
    bool keep1, keep2;

    if (f1->w.numpoints == -1 ||
	f2->w.numpoints == -1 ||
	f1->planeside != f2->planeside ||
	f1->texturenum != f2->texturenum ||
	f1->contents[0] != f2->contents[0] ||
	f1->contents[1] != f2->contents[1])
	return NULL;

    // find a common edge
    p1 = p2 = NULL;		// stop compiler warning
    j = 0;			//

    for (i = 0; i < f1->w.numpoints; i++) {
	p1 = f1->w.points[i];
	p2 = f1->w.points[(i + 1) % f1->w.numpoints];
	for (j = 0; j < f2->w.numpoints; j++) {
	    p3 = f2->w.points[j];
	    p4 = f2->w.points[(j + 1) % f2->w.numpoints];
	    for (k = 0; k < 3; k++) {
		if (fabs(p1[k] - p4[k]) > EQUAL_EPSILON ||
		    fabs(p2[k] - p3[k]) > EQUAL_EPSILON)
		    break;
	    }
	    if (k == 3)
		break;
	}
	if (j < f2->w.numpoints)
	    break;
    }

    if (i == f1->w.numpoints)
	return NULL;		// no matching edges

    // check slope of connected lines
    // if the slopes are colinear, the point can be removed
    plane = &pPlanes[f1->planenum];
    VectorCopy(plane->normal, planenormal);
    if (f1->planeside)
	VectorSubtract(vec3_origin, planenormal, planenormal);

    back = f1->w.points[(i + f1->w.numpoints - 1) % f1->w.numpoints];
    VectorSubtract(p1, back, delta);
    CrossProduct(planenormal, delta, normal);
    VectorNormalize(normal);

    back = f2->w.points[(j + 2) % f2->w.numpoints];
    VectorSubtract(back, p1, delta);
    dot = DotProduct(delta, normal);
    if (dot > CONTINUOUS_EPSILON)
	return NULL;		// not a convex polygon
    keep1 = dot < -CONTINUOUS_EPSILON;

    back = f1->w.points[(i + 2) % f1->w.numpoints];
    VectorSubtract(back, p2, delta);
    CrossProduct(planenormal, delta, normal);
    VectorNormalize(normal);

    back = f2->w.points[(j + f2->w.numpoints - 1) % f2->w.numpoints];
    VectorSubtract(back, p2, delta);
    dot = DotProduct(delta, normal);
    if (dot > CONTINUOUS_EPSILON)
	return NULL;		// not a convex polygon
    keep2 = dot < -CONTINUOUS_EPSILON;

    // build the new polygon
    if (f1->w.numpoints + f2->w.numpoints > MAXEDGES) {
	Message(msgWarning, warnTooManyMergePoints);
	return NULL;
    }

    newf = NewFaceFromFace(f1);

    // copy first polygon
    if (keep2)
	k = (i + 1) % f1->w.numpoints;
    else
	k = (i + 2) % f1->w.numpoints;
    for (; k != i; k = (k + 1) % f1->w.numpoints) {
	VectorCopy(f1->w.points[k], newf->w.points[newf->w.numpoints]);
	newf->w.numpoints++;
    }

    // copy second polygon
    if (keep1)
	l = (j + 1) % f2->w.numpoints;
    else
	l = (j + 2) % f2->w.numpoints;
    for (; l != j; l = (l + 1) % f2->w.numpoints) {
	VectorCopy(f2->w.points[l], newf->w.points[newf->w.numpoints]);
	newf->w.numpoints++;
    }

    UpdateFaceSphere(newf);

    return newf;
}
Esempio n. 9
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. 10
0
bface_t *ClipFace (brush_t *b, bface_t *f, bface_t **outside,
				 int splitplane, qboolean precedence)
{
	bface_t		*front;
	winding_t	*fw, *bw;
	vec_t		d;
	plane_t		*split;
	int			i, count[3];

	// handle exact plane matches special

	if (f->planenum == (splitplane^1) )
	{	// opposite side, so put on inside list
		return f;
	}

	if ( f->planenum == splitplane )
	{
		// coplanar
		if (precedence)
		{	// this fragment will go to the inside, because
			// the earlier one was clipped to the outside
			return f;
		}
		f->next = *outside;
		*outside = f;
		return NULL;
	}

	split = &mapplanes[splitplane];
#if 0
	count[0] = count[1] = count[2] = 0;
	for (i=0 ; i<f->w->numpoints ; i++)
	{
		d = DotProduct (f->w->p[i], split->normal) - split->dist;
		if (d < -SPLIT_EPSILON)
			count[1]++;
		else if (d > SPLIT_EPSILON)
			count[0]++;
		else
			count[2]++;
	}

	if (!count[0])
	{
		fw = NULL;
		bw = f->w;
	}
	else if (!count[1])
	{
		fw = f->w;
		bw = NULL;
	}
	else
#endif
		ClipWindingNoCopy (f->w, split->normal, split->dist, &fw, &bw);

	if (!fw)
		return f;

	if (!bw)
	{
		f->next = *outside;
		*outside = f;
		return NULL;
	}

	FreeWinding (f->w);

	front = NewFaceFromFace (f);
	front->w = fw;
	WindingBounds (fw, front->mins, front->maxs);
	front->next = *outside;
	*outside = front;

	f->w = bw;
	WindingBounds (bw, f->mins, f->maxs);

	return f;
}
Esempio n. 11
0
static void     SplitFaceForTjunc(face_t* f, face_t* original)
{
    int             i;
    face_t*         newface;
    face_t*         chain;
    vec3_t          dir, test;
    vec_t           v;
    int             firstcorner, lastcorner;

#ifdef _DEBUG
    static int      counter = 0;

    Log("SplitFaceForTjunc %d\n", counter++);
#endif

    chain = NULL;
    do
    {
        hlassume(f->original == NULL, assume_ValidPointer);     // "SplitFaceForTjunc: f->original"

        if (f->numpoints <= MAXPOINTS)
        {                                                  // the face is now small enough without more cutting
            // so copy it back to the original
            *original = *f;
            original->original = chain;
            original->next = newlist;
            newlist = original;
            return;
        }

        tjuncfaces++;

restart:
        // find the last corner 
        VectorSubtract(f->pts[f->numpoints - 1], f->pts[0], dir);
        VectorNormalize(dir);
        for (lastcorner = f->numpoints - 1; lastcorner > 0; lastcorner--)
        {
            VectorSubtract(f->pts[lastcorner - 1], f->pts[lastcorner], test);
            VectorNormalize(test);
            v = DotProduct(test, dir);
            if (v < 1.0 - ON_EPSILON || v > 1.0 + ON_EPSILON)
            {
                break;
            }
        }

        // find the first corner        
        VectorSubtract(f->pts[1], f->pts[0], dir);
        VectorNormalize(dir);
        for (firstcorner = 1; firstcorner < f->numpoints - 1; firstcorner++)
        {
            VectorSubtract(f->pts[firstcorner + 1], f->pts[firstcorner], test);
            VectorNormalize(test);
            v = DotProduct(test, dir);
            if (v < 1.0 - ON_EPSILON || v > 1.0 + ON_EPSILON)
            {
                break;
            }
        }

        if (firstcorner + 2 >= MAXPOINTS)
        {
            // rotate the point winding
            VectorCopy(f->pts[0], test);
            for (i = 1; i < f->numpoints; i++)
            {
                VectorCopy(f->pts[i], f->pts[i - 1]);
            }
            VectorCopy(test, f->pts[f->numpoints - 1]);
            goto restart;
        }

        // cut off as big a piece as possible, less than MAXPOINTS, and not
        // past lastcorner

        newface = NewFaceFromFace(f);

        hlassume(f->original == NULL, assume_ValidPointer);     // "SplitFaceForTjunc: f->original"

        newface->original = chain;
        chain = newface;
        newface->next = newlist;
        newlist = newface;
        if (f->numpoints - firstcorner <= MAXPOINTS)
        {
            newface->numpoints = firstcorner + 2;
        }
        else if (lastcorner + 2 < MAXPOINTS && f->numpoints - lastcorner <= MAXPOINTS)
        {
            newface->numpoints = lastcorner + 2;
        }
        else
        {
            newface->numpoints = MAXPOINTS;
        }

        for (i = 0; i < newface->numpoints; i++)
        {
            VectorCopy(f->pts[i], newface->pts[i]);
        }

        for (i = newface->numpoints - 1; i < f->numpoints; i++)
        {
            VectorCopy(f->pts[i], f->pts[i - (newface->numpoints - 2)]);
        }
        f->numpoints -= (newface->numpoints - 2);
    }
    while (1);

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

    if (in->w.numpoints < 0)
	Message(msgError, errFreedFace);

    /* Fast test */
    dot = DotProduct(in->origin, split->normal) - split->dist;
    if (dot > in->radius) {
	counts[SIDE_FRONT] = 1;
	counts[SIDE_BACK] = 0;
    } else if (dot < -in->radius) {
	counts[SIDE_FRONT] = 0;
	counts[SIDE_BACK] = 1;
    } else {
	CalcSides(&in->w, split, sides, dists, counts);
    }

    // Plane doesn't split this face after all
    if (!counts[SIDE_FRONT]) {
	*front = NULL;
	*back = in;
	return;
    }
    if (!counts[SIDE_BACK]) {
	*front = in;
	*back = NULL;
	return;
    }

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

    // distribute the points and generate splits
    for (i = 0; i < in->w.numpoints; i++) {
	// Note: Possible for numpoints on newf or new2 to exceed MAXEDGES if
	// in->w.numpoints == MAXEDGES and it is a really devious split.

	p1 = in->w.points[i];

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

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

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

	// generate a split point
	p2 = in->w.points[(i + 1) % in->w.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->w.points[newf->w.numpoints]);
	newf->w.numpoints++;
	VectorCopy(mid, new2->w.points[new2->w.numpoints]);
	new2->w.numpoints++;
    }

    if (newf->w.numpoints > MAXEDGES || new2->w.numpoints > MAXEDGES)
	Message(msgError, errLowSplitPointCount);

    // free the original face now that it is represented by the fragments
    FreeMem(in, FACE, 1);
}
Esempio n. 13
0
/*
=============
TryMerge

If two polygons share a common edge and the edges that meet at the
common points are both inside the other polygons, merge them

Returns NULL if the faces couldn't be merged, or the new face.
The originals will NOT be freed.
=============
*/
face_t *TryMerge (face_t *f1, face_t *f2)
{
  vec_t		*p1 = NULL, *p2 = NULL, *p3, *p4, *back;
  face_t		*newf;
  int			i, j, k, l;
  vec3_t		normal, delta, planenormal;
  vec_t		dot;
  plane_t		*plane;
  qboolean		keep1, keep2;
	
  if (f1->numpoints == -1 || f2->numpoints == -1 ||
      f1->planeside != f2->planeside ||
      f1->texturenum != f2->texturenum ||
      f1->contents[0] != f2->contents[0] ||
      f1->contents[1] != f2->contents[1])
    return NULL;
		
  //
  // find a common edge
  //	
  for (i=0, j = 0 ; i<f1->numpoints ; i++)
    {
      p1 = f1->pts[i];
      p2 = f1->pts[(i+1)%f1->numpoints];
      for (j=0 ; j<f2->numpoints ; j++)
	{
	  p3 = f2->pts[j];
	  p4 = f2->pts[(j+1)%f2->numpoints];
	  for (k=0 ; k<3 ; k++)
	    {
	      if (fabs(p1[k] - p4[k]) > EQUAL_EPSILON ||
		  fabs(p2[k] - p3[k]) > EQUAL_EPSILON)
		break;
	    }
	  if (k==3)
	    break;
	}
      if (j < f2->numpoints)
	break;
    }
	
  if (i == f1->numpoints)
    return NULL;			// no matching edges

  //
  // check slope of connected lines
  // if the slopes are colinear, the point can be removed
  //
  plane = &planes[f1->planenum];
  VectorCopy (plane->normal, planenormal);
  if (f1->planeside)
    VectorNegate (planenormal, planenormal);
		
  back = f1->pts[(i+f1->numpoints-1)%f1->numpoints];
  VectorSubtract (p1, back, delta);
  CrossProduct (planenormal, delta, normal);
  VectorNormalize (normal);
	
  back = f2->pts[(j+2)%f2->numpoints];
  VectorSubtract (back, p1, delta);
  dot = DotProduct (delta, normal);
  if (dot > CONTINUOUS_EPSILON)
    return NULL;			// not a convex polygon
  keep1 = dot < -CONTINUOUS_EPSILON;
	
  back = f1->pts[(i+2)%f1->numpoints];
  VectorSubtract (back, p2, delta);
  CrossProduct (planenormal, delta, normal);
  VectorNormalize (normal);

  back = f2->pts[(j+f2->numpoints-1)%f2->numpoints];
  VectorSubtract (back, p2, delta);
  dot = DotProduct (delta, normal);
  if (dot > CONTINUOUS_EPSILON)
    return NULL;			// not a convex polygon
  keep2 = dot < -CONTINUOUS_EPSILON;

  //
  // build the new polygon
  //
  if (f1->numpoints + f2->numpoints > MAXEDGES)
    {
      //		Error ("TryMerge: too many edges!");
      return NULL;
    }

  newf = NewFaceFromFace (f1);
	
  // copy first polygon
  for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
    {
      if (k==(i+1)%f1->numpoints && !keep2)
	continue;
		
      VectorCopy (f1->pts[k], newf->pts[newf->numpoints]);
      newf->numpoints++;
    }
	
  // copy second polygon
  for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
    {
      if (l==(j+1)%f2->numpoints && !keep1)
	continue;
      VectorCopy (f2->pts[l], newf->pts[newf->numpoints]);
      newf->numpoints++;
    }

  return newf;
}
Esempio n. 14
0
void FaceFromSuperface (face_t *original)
{
	int			i, numpts;
	face_t		*newf, *chain;
	vec3_t		dir, test;
	vec_t		v;
	int			firstcorner, lastcorner;

	chain = NULL;
	do
	{
		if( superface->numpoints < 3 ) {
			c_degenerateFaces++;
			return;
		}

		if (superface->numpoints <= MAX_VERTS_ON_FACE)
		{	// the face is now small enough without more cutting
			// so copy it back to the original
			*original = superface->original;
			original->winding = CopyWindingExt( superface->numpoints, superface->points );
			original->original = chain;
			original->next = newlist;
			newlist = original;
			return;
		}

		c_tjuncfaces++;

restart:
	// find the last corner
		VectorSubtract (superface->points[superface->numpoints-1], superface->points[0], dir);
		VectorNormalize (dir);
		for (lastcorner=superface->numpoints-1 ; lastcorner > 0 ; lastcorner--)
		{
			VectorSubtract (superface->points[lastcorner-1], superface->points[lastcorner], test);
			VectorNormalize (test);
			v = DotProduct (test, dir);
			if (v < 0.9999 || v > 1.00001)
			{
				break;
			}
		}

	// find the first corner
		VectorSubtract (superface->points[1], superface->points[0], dir);
		VectorNormalize (dir);
		for (firstcorner=1 ; firstcorner < superface->numpoints-1 ; firstcorner++)
		{
			VectorSubtract (superface->points[firstcorner+1], superface->points[firstcorner], test);
			VectorNormalize (test);
			v = DotProduct (test, dir);
			if (v < 0.9999 || v > 1.00001)
				break;
		}

		if (firstcorner+2 >= MAX_VERTS_ON_FACE)
		{
			c_rotated++;
		// rotate the point winding
			VectorCopy (superface->points[0], test);
			for (i=1 ; i<superface->numpoints ; i++)
				VectorCopy (superface->points[i], superface->points[i-1]);
			VectorCopy (test, superface->points[superface->numpoints-1]);
			goto restart;
		}


	// cut off as big a piece as possible, less than MAXPOINTS, and not
	// past lastcorner
		newf = NewFaceFromFace (&superface->original);
		newf->original = chain;
		chain = newf;
		newf->next = newlist;
		newlist = newf;

		if (superface->numpoints - firstcorner <= MAX_VERTS_ON_FACE)
			numpts = firstcorner + 2;
		else if (lastcorner+2 < MAX_VERTS_ON_FACE && superface->numpoints - lastcorner <= MAX_VERTS_ON_FACE)
			numpts = lastcorner + 2;
		else
			numpts = MAX_VERTS_ON_FACE;

		if( numpts < 3 ) {
			c_degenerateFaces++;
			return;
		}
		newf->winding = CopyWindingExt( numpts, superface->points );

		for (i=newf->winding->numpoints-1 ; i<superface->numpoints ; i++)
			VectorCopy (superface->points[i], superface->points[i-(newf->winding->numpoints-2)]);
		superface->numpoints -= (newf->winding->numpoints-2);
	} while (1);
}
Esempio n. 15
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. 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
static void
SplitFaceForTjunc(face_t *f, face_t *original)
{
    int i;
    face_t *newf, *chain;
    vec3_t dir, test;
    vec_t v;
    int firstcorner, lastcorner;

    chain = NULL;
    do {
	if (f->w.numpoints <= MAXPOINTS) {	// the face is now small enough without more cutting
	    // so copy it back to the original
	    *original = *f;
	    original->original = chain;
	    original->next = newlist;
	    newlist = original;
	    return;
	}

	tjuncfaces++;

      restart:
	// find the last corner
	VectorSubtract(f->w.points[f->w.numpoints - 1], f->w.points[0], dir);
	VectorNormalize(dir);
	for (lastcorner = f->w.numpoints - 1; lastcorner > 0; lastcorner--) {
	    VectorSubtract(f->w.points[lastcorner - 1], f->w.points[lastcorner], test);
	    VectorNormalize(test);
	    v = DotProduct(test, dir);
	    if (v < 1 - ANGLEEPSILON || v > 1 + ANGLEEPSILON) {
		break;
	    }
	}

	// find the first corner
	VectorSubtract(f->w.points[1], f->w.points[0], dir);
	VectorNormalize(dir);
	for (firstcorner = 1; firstcorner < f->w.numpoints - 1; firstcorner++) {
	    VectorSubtract(f->w.points[firstcorner + 1], f->w.points[firstcorner],
			   test);
	    VectorNormalize(test);
	    v = DotProduct(test, dir);
	    if (v < 1 - ANGLEEPSILON || v > 1 + ANGLEEPSILON) {
		break;
	    }
	}

	if (firstcorner + 2 >= MAXPOINTS) {
	    // rotate the point winding
	    VectorCopy(f->w.points[0], test);
	    for (i = 1; i < f->w.numpoints; i++) {
		VectorCopy(f->w.points[i], f->w.points[i - 1]);
	    }
	    VectorCopy(test, f->w.points[f->w.numpoints - 1]);
	    goto restart;
	}

	// cut off as big a piece as possible, less than MAXPOINTS, and not
	// past lastcorner

	newf = NewFaceFromFace(f);
	if (f->original)
	    Error(errOriginalExists);

	newf->original = chain;
	chain = newf;
	newf->next = newlist;
	newlist = newf;
	if (f->w.numpoints - firstcorner <= MAXPOINTS)
	    newf->w.numpoints = firstcorner + 2;
	else if (lastcorner + 2 < MAXPOINTS &&
		 f->w.numpoints - lastcorner <= MAXPOINTS)
	    newf->w.numpoints = lastcorner + 2;
	else
	    newf->w.numpoints = MAXPOINTS;

	for (i = 0; i < newf->w.numpoints; i++) {
	    VectorCopy(f->w.points[i], newf->w.points[i]);
	}


	for (i = newf->w.numpoints - 1; i < f->w.numpoints; i++) {
	    VectorCopy(f->w.points[i], f->w.points[i - (newf->w.numpoints - 2)]);
	}
	f->w.numpoints -= (newf->w.numpoints - 2);
    } while (1);

}