/*
=================
idRenderModelDecal::AddDepthFadedWinding
=================
*/
void idRenderModelDecal::AddDepthFadedWinding( const idWinding &w, const idMaterial *decalMaterial, const idPlane fadePlanes[2], float fadeDepth, int startTime ) {
	idFixedWinding front, back;
	front = w;
	if( front.Split( &back, fadePlanes[0], 0.1f ) == SIDE_CROSS ) {
		AddWinding( back, decalMaterial, fadePlanes, fadeDepth, startTime );
	}
	if( front.Split( &back, fadePlanes[1], 0.1f ) == SIDE_CROSS ) {
		AddWinding( back, decalMaterial, fadePlanes, fadeDepth, startTime );
	}
	AddWinding( front, decalMaterial, fadePlanes, fadeDepth, startTime );
}
Beispiel #2
0
static int RemoveDegenerateFaces( TESStesselator *tess, TESSmesh *mesh )
/*
* Delete any degenerate faces with only two edges.  WalkDirtyRegions()
* will catch almost all of these, but it won't catch degenerate faces
* produced by splice operations on already-processed edges.
* The two places this can happen are in FinishLeftRegions(), when
* we splice in a "temporary" edge produced by ConnectRightVertex(),
* and in CheckForLeftSplice(), where we splice already-processed
* edges to ensure that our dictionary invariants are not violated
* by numerical errors.
*
* In both these cases it is *very* dangerous to delete the offending
* edge at the time, since one of the routines further up the stack
* will sometimes be keeping a pointer to that edge.
*/
{
	TESSface *f, *fNext;
	TESShalfEdge *e;

	/*LINTED*/
	for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
		fNext = f->next;
		e = f->anEdge;
		assert( e->Lnext != e );

		if( e->Lnext->Lnext == e ) {
			/* A face with only two edges */
			AddWinding( e->Onext, e );
			if ( !tessMeshDelete( tess->mesh, e ) ) return 0;
		}
	}
	return 1;
}
Beispiel #3
0
static void WalkDirtyRegions( TESStesselator *tess, ActiveRegion *regUp )
/*
* When the upper or lower edge of any region changes, the region is
* marked "dirty".  This routine walks through all the dirty regions
* and makes sure that the dictionary invariants are satisfied
* (see the comments at the beginning of this file).  Of course
* new dirty regions can be created as we make changes to restore
* the invariants.
*/
{
	ActiveRegion *regLo = RegionBelow(regUp);
	TESShalfEdge *eUp, *eLo;

	for( ;; ) {
		/* Find the lowest dirty region (we walk from the bottom up). */
		while( regLo->dirty ) {
			regUp = regLo;
			regLo = RegionBelow(regLo);
		}
		if( ! regUp->dirty ) {
			regLo = regUp;
			regUp = RegionAbove( regUp );
			if( regUp == NULL || ! regUp->dirty ) {
				/* We've walked all the dirty regions */
				return;
			}
		}
		regUp->dirty = FALSE;
		eUp = regUp->eUp;
		eLo = regLo->eUp;

		if( eUp->Dst != eLo->Dst ) {
			/* Check that the edge ordering is obeyed at the Dst vertices. */
			if( CheckForLeftSplice( tess, regUp )) {

				/* If the upper or lower edge was marked fixUpperEdge, then
				* we no longer need it (since these edges are needed only for
				* vertices which otherwise have no right-going edges).
				*/
				if( regLo->fixUpperEdge ) {
					DeleteRegion( tess, regLo );
					if ( !tessMeshDelete( tess->mesh, eLo ) ) longjmp(tess->env,1);
					regLo = RegionBelow( regUp );
					eLo = regLo->eUp;
				} else if( regUp->fixUpperEdge ) {
					DeleteRegion( tess, regUp );
					if ( !tessMeshDelete( tess->mesh, eUp ) ) longjmp(tess->env,1);
					regUp = RegionAbove( regLo );
					eUp = regUp->eUp;
				}
			}
		}
		if( eUp->Org != eLo->Org ) {
			if(    eUp->Dst != eLo->Dst
				&& ! regUp->fixUpperEdge && ! regLo->fixUpperEdge
				&& (eUp->Dst == tess->event || eLo->Dst == tess->event) )
			{
				/* When all else fails in CheckForIntersect(), it uses tess->event
				* as the intersection location.  To make this possible, it requires
				* that tess->event lie between the upper and lower edges, and also
				* that neither of these is marked fixUpperEdge (since in the worst
				* case it might splice one of these edges into tess->event, and
				* violate the invariant that fixable edges are the only right-going
				* edge from their associated vertex).
				*/
				if( CheckForIntersect( tess, regUp )) {
					/* WalkDirtyRegions() was called recursively; we're done */
					return;
				}
			} else {
				/* Even though we can't use CheckForIntersect(), the Org vertices
				* may violate the dictionary edge ordering.  Check and correct this.
				*/
				(void) CheckForRightSplice( tess, regUp );
			}
		}
		if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) {
			/* A degenerate loop consisting of only two edges -- delete it. */
			AddWinding( eLo, eUp );
			DeleteRegion( tess, regUp );
			if ( !tessMeshDelete( tess->mesh, eUp ) ) longjmp(tess->env,1);
			regUp = RegionAbove( regLo );
		}
	}
}
Beispiel #4
0
static void AddRightEdges( TESStesselator *tess, ActiveRegion *regUp,
						  TESShalfEdge *eFirst, TESShalfEdge *eLast, TESShalfEdge *eTopLeft,
						  int cleanUp )
/*
* Purpose: insert right-going edges into the edge dictionary, and update
* winding numbers and mesh connectivity appropriately.  All right-going
* edges share a common origin vOrg.  Edges are inserted CCW starting at
* eFirst; the last edge inserted is eLast->Oprev.  If vOrg has any
* left-going edges already processed, then eTopLeft must be the edge
* such that an imaginary upward vertical segment from vOrg would be
* contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft
* should be NULL.
*/
{
	ActiveRegion *reg, *regPrev;
	TESShalfEdge *e, *ePrev;
	int firstTime = TRUE;

	/* Insert the new right-going edges in the dictionary */
	e = eFirst;
	do {
		assert( VertLeq( e->Org, e->Dst ));
		AddRegionBelow( tess, regUp, e->Sym );
		e = e->Onext;
	} while ( e != eLast );

	/* Walk *all* right-going edges from e->Org, in the dictionary order,
	* updating the winding numbers of each region, and re-linking the mesh
	* edges to match the dictionary ordering (if necessary).
	*/
	if( eTopLeft == NULL ) {
		eTopLeft = RegionBelow( regUp )->eUp->Rprev;
	}
	regPrev = regUp;
	ePrev = eTopLeft;
	for( ;; ) {
		reg = RegionBelow( regPrev );
		e = reg->eUp->Sym;
		if( e->Org != ePrev->Org ) break;

		if( e->Onext != ePrev ) {
			/* Unlink e from its current position, and relink below ePrev */
			if ( !tessMeshSplice( tess->mesh, e->Oprev, e ) ) longjmp(tess->env,1);
			if ( !tessMeshSplice( tess->mesh, ePrev->Oprev, e ) ) longjmp(tess->env,1);
		}
		/* Compute the winding number and "inside" flag for the new regions */
		reg->windingNumber = regPrev->windingNumber - e->winding;
		reg->inside = IsWindingInside( tess, reg->windingNumber );

		/* Check for two outgoing edges with same slope -- process these
		* before any intersection tests (see example in tessComputeInterior).
		*/
		regPrev->dirty = TRUE;
		if( ! firstTime && CheckForRightSplice( tess, regPrev )) {
			AddWinding( e, ePrev );
			DeleteRegion( tess, regPrev );
			if ( !tessMeshDelete( tess->mesh, ePrev ) ) longjmp(tess->env,1);
		}
		firstTime = FALSE;
		regPrev = reg;
		ePrev = e;
	}
	regPrev->dirty = TRUE;
	assert( regPrev->windingNumber - e->winding == reg->windingNumber );

	if( cleanUp ) {
		/* Check for intersections between newly adjacent edges. */
		WalkDirtyRegions( tess, regPrev );
	}
}