Пример #1
0
/*
==================
FixTriangleAgainstHash

Potentially splits a triangle into a list of triangles based on tjunctions
==================
*/
static mapTri_t	*FixTriangleAgainstHash(const mapTri_t *tri)
{
	mapTri_t		*fixed;
	mapTri_t		*a;
	mapTri_t		*test, *next;
	int				blocks[2][3];
	int				i, j, k;
	hashVert_t		*hv;

	// if this triangle is degenerate after point snapping,
	// do nothing (this shouldn't happen, because they should
	// be removed as they are hashed)
	if (tri->hashVert[0] == tri->hashVert[1]
	    || tri->hashVert[0] == tri->hashVert[2]
	    || tri->hashVert[1] == tri->hashVert[2]) {
		return NULL;
	}

	fixed = CopyMapTri(tri);
	fixed->next = NULL;

	HashBlocksForTri(tri, blocks);

	for (i = blocks[0][0] ; i <= blocks[1][0] ; i++) {
		for (j = blocks[0][1] ; j <= blocks[1][1] ; j++) {
			for (k = blocks[0][2] ; k <= blocks[1][2] ; k++) {
				for (hv = hashVerts[i][j][k] ; hv ; hv = hv->next) {
					// fix all triangles in the list against this point
					test = fixed;
					fixed = NULL;

					for (; test ; test = next) {
						next = test->next;
						a = FixTriangleAgainstHashVert(test, hv);

						if (a) {
							// cut into two triangles
							a->next->next = fixed;
							fixed = a;
							FreeTri(test);
						} else {
							test->next = fixed;
							fixed = test;
						}
					}
				}
			}
		}
	}

	return fixed;
}
Пример #2
0
/*
==================
AddMapTriToAreas

Used for curves and inlined models
==================
*/
void AddMapTriToAreas( mapTri_t* tri, uEntity_t* e )
{
	int				area;
	idWinding*		w;
	
	// skip degenerate triangles from pinched curves
	if( MapTriArea( tri ) <= 0 )
	{
		return;
	}
	
	if( dmapGlobals.fullCarve )
	{
		// always fragment into areas
		w = WindingForTri( tri );
		ClipTriIntoTree_r( w, tri, e, e->tree->headnode );
		return;
	}
	
	w = WindingForTri( tri );
	area = CheckWindingInAreas_r( w, e->tree->headnode );
	delete w;
	if( area == -1 )
	{
		return;
	}
	if( area >= 0 )
	{
		mapTri_t*	newTri;
		idPlane		plane;
		int			planeNum;
		textureVectors_t	texVec;
		
		// put in single area
		newTri = CopyMapTri( tri );
		newTri->next = NULL;
		
		PlaneForTri( tri, plane );
		planeNum = FindFloatPlane( plane );
		
		TexVecForTri( &texVec, newTri );
		
		AddTriListToArea( e, newTri, planeNum, area, &texVec );
	}
	else
	{
		// fragment into areas
		w = WindingForTri( tri );
		ClipTriIntoTree_r( w, tri, e, e->tree->headnode );
	}
}
Пример #3
0
/*
===============
CopyTriList
===============
*/
mapTri_t	*CopyTriList( const mapTri_t *a ) {
    mapTri_t	*testList;
    const mapTri_t	*tri;

    testList = NULL;
    for ( tri = a ; tri ; tri = tri->next ) {
        mapTri_t	*copy;

        copy = CopyMapTri( tri );
        copy ->next = testList;
        testList = copy;
    }

    return testList;
}
Пример #4
0
/*
===============
RemoveBadTris

Return a new list with any zero or negative area triangles removed
===============
*/
mapTri_t	*RemoveBadTris( const mapTri_t *list ) {
    mapTri_t	*newList;
    mapTri_t	*copy;
    const mapTri_t	*tri;

    newList = NULL;

    for ( tri = list ; tri ; tri = tri->next ) {
        if ( MapTriArea( tri ) > 0 ) {
            copy = CopyMapTri( tri );
            copy->next = newList;
            newList = copy;
        }
    }

    return newList;
}
Пример #5
0
// RB begin
int FilterMeshesIntoTree_r( idWinding* w, mapTri_t* originalTri, node_t* node )
{
	idWinding*		front, *back;
	int				c;
	
	if( !w )
	{
		return 0;
	}
	
	if( node->planenum == PLANENUM_LEAF )
	{
		// add it to the leaf list
		if( originalTri->material->GetContentFlags() & CONTENTS_AREAPORTAL )
		{
			mapTri_t* list = CopyMapTri( originalTri );
			list->next = NULL;
			
			node->areaPortalTris = MergeTriLists( node->areaPortalTris, list );
		}
		
		const MapPolygonMesh* mapMesh = originalTri->originalMapMesh;
		
		// classify the leaf by the structural brush
		if( mapMesh->IsOpaque() )
		{
			node->opaque = true;
		}
		
		delete w;
		return 1;
	}
	
	// split it by the node plane
	w->Split( dmapGlobals.mapPlanes[ node->planenum ], ON_EPSILON, &front, &back );
	delete w;
	
	c = 0;
	c += FilterMeshesIntoTree_r( front, originalTri, node->children[0] );
	c += FilterMeshesIntoTree_r( back, originalTri, node->children[1] );
	
	return c;
}
Пример #6
0
/*
==================
FixTriangleAgainstHashVert

Returns a list of two new mapTri if the hashVert is
on an edge of the given mapTri, otherwise returns NULL.
==================
*/
static mapTri_t *FixTriangleAgainstHashVert( const mapTri_t *a, const hashVert_t *hv ) {
	int			i;
	const idDrawVert	*v1, *v2;
	idDrawVert	split;
	idVec3		dir;
	float		len;
	float		frac;
	mapTri_t	*new1, *new2;
	idVec3		temp;
	float		d, off;
	const idVec3 *v;
	idPlane		plane1, plane2;

	v = &hv->v;

	// if the triangle already has this hashVert as a vert,
	// it can't be split by it
	if ( a->hashVert[0] == hv || a->hashVert[1] == hv || a->hashVert[2] == hv ) {
		return NULL;
	}

	split.Clear();

	// we probably should find the edge that the vertex is closest to.
	// it is possible to be < 1 unit away from multiple
	// edges, but we only want to split by one of them
	for ( i = 0 ; i < 3 ; i++ ) {
		v1 = &a->v[i];
		v2 = &a->v[(i+1)%3];
		VectorSubtract( v2->xyz, v1->xyz, dir );
		len = dir.Normalize();

		// if it is close to one of the edge vertexes, skip it
		VectorSubtract( *v, v1->xyz, temp );
		d = DotProduct( temp, dir );
		if ( d <= 0 || d >= len ) {
			continue;
		}

		// make sure it is on the line
		VectorMA( v1->xyz, d, dir, temp );
		VectorSubtract( temp, *v, temp );
		off = temp.Length();
		if ( off <= -COLINEAR_EPSILON || off >= COLINEAR_EPSILON ) {
			continue;
		}

		// take the x/y/z from the splitter,
		// but interpolate everything else from the original tri
		VectorCopy( *v, split.xyz );
		frac = d / len;
		split.st[0] = v1->st[0] + frac * ( v2->st[0] - v1->st[0] );
		split.st[1] = v1->st[1] + frac * ( v2->st[1] - v1->st[1] );
		split.normal[0] = v1->normal[0] + frac * ( v2->normal[0] - v1->normal[0] );
		split.normal[1] = v1->normal[1] + frac * ( v2->normal[1] - v1->normal[1] );
		split.normal[2] = v1->normal[2] + frac * ( v2->normal[2] - v1->normal[2] );
		split.normal.Normalize();

		// split the tri
		new1 = CopyMapTri( a );
		new1->v[(i+1)%3] = split;
		new1->hashVert[(i+1)%3] = hv;
		new1->next = NULL;

		new2 = CopyMapTri( a );
		new2->v[i] = split;
		new2->hashVert[i] = hv;
		new2->next = new1;

		plane1.FromPoints( new1->hashVert[0]->v, new1->hashVert[1]->v, new1->hashVert[2]->v );
		plane2.FromPoints( new2->hashVert[0]->v, new2->hashVert[1]->v, new2->hashVert[2]->v );

		d = DotProduct( plane1, plane2 );

		// if the two split triangle's normals don't face the same way,
		// it should not be split
		if ( d <= 0 ) {
			FreeTriList( new2 );
			continue;
		}

		return new2;
	}


	return NULL;
}
/*
=================
ClipTriByLight

Carves a triangle by the frustom planes of a light, producing
a (possibly empty) list of triangles on the inside and outside.

The original triangle is not modified.

If no clipping is required, the result will be a copy of the original.

If clipping was required, the outside fragments will be planar clips, which
will benefit from re-optimization.
=================
*/
static void ClipTriByLight( const mapLight_t *light, const mapTri_t *tri,
						   mapTri_t **in, mapTri_t **out ) {
	idWinding	*inside, *oldInside;
	idWinding	*outside[6];
	bool	hasOutside;
	int			i;

	*in = NULL;
	*out = NULL;

	// clip this winding to the light
	inside = WindingForTri( tri );
	hasOutside = false;
	for ( i = 0 ; i < 6 ; i++ ) {
		oldInside = inside;
		if ( oldInside ) {
			oldInside->Split( light->def.frustum[i], 0, &outside[i], &inside );
			delete oldInside;
		}
		else {
			outside[i] = NULL;
		}
		if ( outside[i] ) {
			hasOutside = true;
		}
	}

	if ( !inside ) {
		// the entire winding is outside this light

		// free the clipped fragments
		for ( i = 0 ; i < 6 ; i++ ) {
			if ( outside[i] ) {
				delete outside[i];
			}
		}

		*out = CopyMapTri( tri );
		(*out)->next = NULL;

		return;
	}

	if ( !hasOutside ) {
		// the entire winding is inside this light

		// free the inside copy
		delete inside;

		*in = CopyMapTri( tri );
		(*in)->next = NULL;

		return;
	}

	// the winding is split
	*in = WindingToTriList( inside, tri );
	delete inside;

	// combine all the outside fragments
	for ( i = 0 ; i < 6 ; i++ ) {
		if ( outside[i] ) {
			mapTri_t	*list;

			list = WindingToTriList( outside[i], tri );
			delete outside[i];
			*out = MergeTriLists( *out, list );
		}
	}
}