Ejemplo n.º 1
0
/*
=================
R_MarkFragments

=================
*/
int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
				   int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
	int				numsurfaces, numPlanes;
	int				i, j, k, m, n;
	surfaceType_t	*surfaces[64];
	int				surfacesBmodel[64];
	int				lastBmodel;
	vec3_t			mins, maxs;
	int				returnedFragments;
	int				returnedPoints;
	vec3_t			normals[MAX_VERTS_ON_POLY+2], localNormals[MAX_VERTS_ON_POLY+2];
	float			dists[MAX_VERTS_ON_POLY+2], localDists[MAX_VERTS_ON_POLY+2];
	vec3_t			clipPoints[2][MAX_VERTS_ON_POLY];
	int				numClipPoints;
	float			*v;
	srfBspSurface_t	*cv;
	glIndex_t		*tri;
	srfVert_t		*dv;
	vec3_t			normal;
	vec3_t			projectionDir, localProjectionDir;
	vec3_t			v1, v2;

	if (numPoints <= 0) {
		return 0;
	}

	//increment view count for double check prevention
	tr.viewCount++;

	//
	VectorNormalize2( projection, projectionDir );
	// find all the brushes that are to be considered
	ClearBounds( mins, maxs );
	for ( i = 0 ; i < numPoints ; i++ ) {
		vec3_t	temp;

		AddPointToBounds( points[i], mins, maxs );
		VectorAdd( points[i], projection, temp );
		AddPointToBounds( temp, mins, maxs );
		// make sure we get all the leafs (also the one(s) in front of the hit surface)
		VectorMA( points[i], -20, projectionDir, temp );
		AddPointToBounds( temp, mins, maxs );
	}

	if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY;
	// create the bounding planes for the to be projected polygon
	for ( i = 0 ; i < numPoints ; i++ ) {
		VectorSubtract(points[(i+1)%numPoints], points[i], v1);
		VectorAdd(points[i], projection, v2);
		VectorSubtract(points[i], v2, v2);
		CrossProduct(v1, v2, normals[i]);
		VectorNormalizeFast(normals[i]);
		dists[i] = DotProduct(normals[i], points[i]);
	}
	// add near and far clipping planes for projection
	VectorCopy(projectionDir, normals[numPoints]);
	dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
	VectorCopy(projectionDir, normals[numPoints+1]);
	VectorInverse(normals[numPoints+1]);
	dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20;
	numPlanes = numPoints + 2;

	numsurfaces = 0;
	R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, surfacesBmodel, 64, &numsurfaces, projectionDir);
	//assert(numsurfaces <= 64);
	//assert(numsurfaces != 64);

	// add bmodel surfaces
	for ( j = 1; j < tr.world->numBModels; j++ ) {
		vec3_t localProjection, bmodelOrigin, bmodelAxis[3];

		R_TransformMarkProjection( j, projection, localProjection, 0, NULL, NULL, NULL, NULL );
		R_GetBmodelInfo( j, NULL, bmodelOrigin, bmodelAxis );

		VectorNormalize2( localProjection, localProjectionDir );
		// find all the brushes that are to be considered
		ClearBounds( mins, maxs );
		for ( i = 0 ; i < numPoints ; i++ ) {
			vec3_t	temp;
			vec3_t	delta;
			vec3_t	localPoint;

			// convert point to bmodel local space
			VectorSubtract( points[i], bmodelOrigin, delta );
			localPoint[0] = DotProduct( delta, bmodelAxis[0] );
			localPoint[1] = DotProduct( delta, bmodelAxis[1] );
			localPoint[2] = DotProduct( delta, bmodelAxis[2] );

			AddPointToBounds( localPoint, mins, maxs );
			VectorAdd( localPoint, localProjection, temp );
			AddPointToBounds( temp, mins, maxs );
			// make sure we get all the leafs (also the one(s) in front of the hit surface)
			VectorMA( localPoint, -20, localProjectionDir, temp );
			AddPointToBounds( temp, mins, maxs );
		}

		R_BmodelSurfaces( j, mins, maxs, surfaces, surfacesBmodel, 64, &numsurfaces, localProjectionDir);
	}

	returnedPoints = 0;
	returnedFragments = 0;
	lastBmodel = -1;

	for ( i = 0 ; i < numsurfaces ; i++ ) {
		if (i == 0 || surfacesBmodel[i] != lastBmodel) {
			R_TransformMarkProjection( surfacesBmodel[i], projectionDir, localProjectionDir, numPlanes, normals, dists, localNormals, localDists );
			lastBmodel = surfacesBmodel[i];

			// don't use projectionDir, normals, or dists beyond this point !!!
			// mins and maxs are not setup, so they are not valid !!!
		}

		if (*surfaces[i] == SF_GRID) {

			cv = (srfBspSurface_t *) surfaces[i];
			for ( m = 0 ; m < cv->height - 1 ; m++ ) {
				for ( n = 0 ; n < cv->width - 1 ; n++ ) {
					// We triangulate the grid and chop all triangles within
					// the bounding planes of the to be projected polygon.
					// LOD is not taken into account, not such a big deal though.
					//
					// It's probably much nicer to chop the grid itself and deal
					// with this grid as a normal SF_GRID surface so LOD will
					// be applied. However the LOD of that chopped grid must
					// be synced with the LOD of the original curve.
					// One way to do this; the chopped grid shares vertices with
					// the original curve. When LOD is applied to the original
					// curve the unused vertices are flagged. Now the chopped curve
					// should skip the flagged vertices. This still leaves the
					// problems with the vertices at the chopped grid edges.
					//
					// To avoid issues when LOD applied to "hollow curves" (like
					// the ones around many jump pads) we now just add a 2 unit
					// offset to the triangle vertices.
					// The offset is added in the vertex normal vector direction
					// so all triangles will still fit together.
					// The 2 unit offset should avoid pretty much all LOD problems.

					numClipPoints = 3;

					dv = cv->verts + m * cv->width + n;

					VectorCopy(dv[0].xyz, clipPoints[0][0]);
					VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);
					VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
					VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
					VectorCopy(dv[1].xyz, clipPoints[0][2]);
					VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);
					// check the normal of this triangle
					VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
					VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
					CrossProduct(v1, v2, normal);
					VectorNormalizeFast(normal);
					if (DotProduct(normal, localProjectionDir) < -0.1) {
						// add the fragments of this triangle
						R_AddMarkFragments(numClipPoints, clipPoints,
										   numPlanes, localNormals, localDists,
										   maxPoints, pointBuffer,
										   maxFragments, fragmentBuffer,
										   &returnedPoints, &returnedFragments, mins, maxs, lastBmodel, localProjectionDir);

						if ( returnedFragments == maxFragments ) {
							return returnedFragments;	// not enough space for more fragments
						}
					}

					VectorCopy(dv[1].xyz, clipPoints[0][0]);
					VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);
					VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
					VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
					VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);
					VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]);
					// check the normal of this triangle
					VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
					VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
					CrossProduct(v1, v2, normal);
					VectorNormalizeFast(normal);
					if (DotProduct(normal, localProjectionDir) < -0.05) {
						// add the fragments of this triangle
						R_AddMarkFragments(numClipPoints, clipPoints,
										   numPlanes, localNormals, localDists,
										   maxPoints, pointBuffer,
										   maxFragments, fragmentBuffer,
										   &returnedPoints, &returnedFragments, mins, maxs, lastBmodel, localProjectionDir);

						if ( returnedFragments == maxFragments ) {
							return returnedFragments;	// not enough space for more fragments
						}
					}
				}
			}
		}
		else if (*surfaces[i] == SF_FACE) {

			srfBspSurface_t *surf = ( srfBspSurface_t * ) surfaces[i];

			// check the normal of this face
			if (DotProduct(surf->cullPlane.normal, localProjectionDir) > -0.5) {
				continue;
			}

			for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
			{
				for(j = 0; j < 3; j++)
				{
					v = surf->verts[tri[j]].xyz;
					VectorMA(v, MARKER_OFFSET, surf->cullPlane.normal, clipPoints[0][j]);
				}

				// add the fragments of this face
				R_AddMarkFragments( 3 , clipPoints,
								   numPlanes, localNormals, localDists,
								   maxPoints, pointBuffer,
								   maxFragments, fragmentBuffer,
								   &returnedPoints, &returnedFragments, mins, maxs, lastBmodel, localProjectionDir);
				if ( returnedFragments == maxFragments ) {
					return returnedFragments;	// not enough space for more fragments
				}
			}
		}
		else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {

			srfBspSurface_t *surf = (srfBspSurface_t *) surfaces[i];

			for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
			{
				for(j = 0; j < 3; j++)
				{
					v = surf->verts[tri[j]].xyz;
					VectorMA(v, MARKER_OFFSET, surf->verts[tri[j]].normal, clipPoints[0][j]);
				}

				// add the fragments of this face
				R_AddMarkFragments(3, clipPoints,
								   numPlanes, localNormals, localDists,
								   maxPoints, pointBuffer,
								   maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs, lastBmodel, localProjectionDir);
				if(returnedFragments == maxFragments)
				{
					return returnedFragments;	// not enough space for more fragments
				}
			}
		}
	}
	return returnedFragments;
}
Ejemplo n.º 2
0
/*
=================
R_MarkFragments

=================
*/
int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
				   int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
	int				numsurfaces, numPlanes;
	int				i, j, k, m, n;
	surfaceType_t	*surfaces[64];
	vec3_t			mins, maxs;
	int				returnedFragments;
	int				returnedPoints;
	vec3_t			normals[MAX_VERTS_ON_POLY+2];
	float			dists[MAX_VERTS_ON_POLY+2];
	vec3_t			clipPoints[2][MAX_VERTS_ON_POLY];
	int				numClipPoints;
	float			*v;
	srfSurfaceFace_t *surf;
	srfGridMesh_t	*cv;
	drawVert_t		*dv;
	vec3_t			normal;
	vec3_t			projectionDir;
	vec3_t			v1, v2;
	int				*indexes;

	//increment view count for double check prevention
	tr.viewCount++;

	//
	VectorNormalize2( projection, projectionDir );
	// find all the brushes that are to be considered
	ClearBounds( mins, maxs );
	for ( i = 0 ; i < numPoints ; i++ ) {
		vec3_t	temp;

		AddPointToBounds( points[i], mins, maxs );
		VectorAdd( points[i], projection, temp );
		AddPointToBounds( temp, mins, maxs );
		// make sure we get all the leafs (also the one(s) in front of the hit surface)
		VectorMA( points[i], -20, projectionDir, temp );
		AddPointToBounds( temp, mins, maxs );
	}

	if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY;
	// create the bounding planes for the to be projected polygon
	for ( i = 0 ; i < numPoints ; i++ ) {
		VectorSubtract(points[(i+1)%numPoints], points[i], v1);
		VectorAdd(points[i], projection, v2);
		VectorSubtract(points[i], v2, v2);
		CrossProduct(v1, v2, normals[i]);
		VectorNormalizeFast(normals[i]);
		dists[i] = DotProduct(normals[i], points[i]);
	}
	// add near and far clipping planes for projection
	VectorCopy(projectionDir, normals[numPoints]);
	dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
	VectorCopy(projectionDir, normals[numPoints+1]);
	VectorInverse(normals[numPoints+1]);
	dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20;
	numPlanes = numPoints + 2;

	numsurfaces = 0;
	R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);
	//assert(numsurfaces <= 64);
	//assert(numsurfaces != 64);

	returnedPoints = 0;
	returnedFragments = 0;

	for ( i = 0 ; i < numsurfaces ; i++ ) {

		if (*surfaces[i] == SF_GRID) {

			cv = (srfGridMesh_t *) surfaces[i];
			for ( m = 0 ; m < cv->height - 1 ; m++ ) {
				for ( n = 0 ; n < cv->width - 1 ; n++ ) {
					// We triangulate the grid and chop all triangles within
					// the bounding planes of the to be projected polygon.
					// LOD is not taken into account, not such a big deal though.
					//
					// It's probably much nicer to chop the grid itself and deal
					// with this grid as a normal SF_GRID surface so LOD will
					// be applied. However the LOD of that chopped grid must
					// be synced with the LOD of the original curve.
					// One way to do this; the chopped grid shares vertices with
					// the original curve. When LOD is applied to the original
					// curve the unused vertices are flagged. Now the chopped curve
					// should skip the flagged vertices. This still leaves the
					// problems with the vertices at the chopped grid edges.
					//
					// To avoid issues when LOD applied to "hollow curves" (like
					// the ones around many jump pads) we now just add a 2 unit
					// offset to the triangle vertices.
					// The offset is added in the vertex normal vector direction
					// so all triangles will still fit together.
					// The 2 unit offset should avoid pretty much all LOD problems.

					numClipPoints = 3;

					dv = cv->verts + m * cv->width + n;

					VectorCopy(dv[0].xyz, clipPoints[0][0]);
					VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);
					VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
					VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
					VectorCopy(dv[1].xyz, clipPoints[0][2]);
					VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);
					// check the normal of this triangle
					VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
					VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
					CrossProduct(v1, v2, normal);
					VectorNormalizeFast(normal);
					if (DotProduct(normal, projectionDir) < -0.1) {
						// add the fragments of this triangle
						R_AddMarkFragments(numClipPoints, clipPoints,
										   numPlanes, normals, dists,
										   maxPoints, pointBuffer,
										   maxFragments, fragmentBuffer,
										   &returnedPoints, &returnedFragments, mins, maxs);

						if ( returnedFragments == maxFragments ) {
							return returnedFragments;	// not enough space for more fragments
						}
					}

					VectorCopy(dv[1].xyz, clipPoints[0][0]);
					VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);
					VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
					VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
					VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);
					VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]);
					// check the normal of this triangle
					VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
					VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
					CrossProduct(v1, v2, normal);
					VectorNormalizeFast(normal);
					if (DotProduct(normal, projectionDir) < -0.05) {
						// add the fragments of this triangle
						R_AddMarkFragments(numClipPoints, clipPoints,
										   numPlanes, normals, dists,
										   maxPoints, pointBuffer,
										   maxFragments, fragmentBuffer,
										   &returnedPoints, &returnedFragments, mins, maxs);

						if ( returnedFragments == maxFragments ) {
							return returnedFragments;	// not enough space for more fragments
						}
					}
				}
			}
		}
		else if (*surfaces[i] == SF_FACE) {

			surf = ( srfSurfaceFace_t * ) surfaces[i];
			// check the normal of this face
			if (DotProduct(surf->plane.normal, projectionDir) > -0.5) {
				continue;
			}

			/*
			VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
			VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
			CrossProduct(v1, v2, normal);
			VectorNormalize(normal);
			if (DotProduct(normal, projectionDir) > -0.5) continue;
			*/
			indexes = (int *)( (byte *)surf + surf->ofsIndices );
			for ( k = 0 ; k < surf->numIndices ; k += 3 ) {
				for ( j = 0 ; j < 3 ; j++ ) {
					v = surf->points[0] + VERTEXSIZE * indexes[k+j];;
					VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );
				}
				// add the fragments of this face
				R_AddMarkFragments( 3 , clipPoints,
								   numPlanes, normals, dists,
								   maxPoints, pointBuffer,
								   maxFragments, fragmentBuffer,
								   &returnedPoints, &returnedFragments, mins, maxs);
				if ( returnedFragments == maxFragments ) {
					return returnedFragments;	// not enough space for more fragments
				}
			}
			continue;
		}
		else {
			// ignore all other world surfaces
			// might be cool to also project polygons on a triangle soup
			// however this will probably create huge amounts of extra polys
			// even more than the projection onto curves
			continue;
		}
	}
	return returnedFragments;
}
Ejemplo n.º 3
0
/*
=================
R_MarkFragments

=================
*/
int R_MarkFragments(int orientation, const vec3_t *points, const vec3_t projection,
                    int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer)
{
	int           numsurfaces, numPlanes;
	int           i, j, k, m, n;
	surfaceType_t *surfaces[4096];
	vec3_t        mins, maxs;
	int           returnedFragments;
	int           returnedPoints;
	vec3_t        normals[MAX_VERTS_ON_POLY + 2];
	float         dists[MAX_VERTS_ON_POLY + 2];
	vec3_t        clipPoints[2][MAX_VERTS_ON_POLY];
	int           numClipPoints;
	float         *v;
	srfGridMesh_t *cv;
	srfTriangle_t *tri;
	srfVert_t     *dv;
	vec3_t        normal;
	vec3_t        projectionDir;
	vec3_t        v1, v2;
	float         radius;
	vec3_t        center;   // center of original mark
	//vec3_t			bestCenter;	// center point projected onto the closest surface
	float texCoordScale;
	//float			dot;
	int      numPoints  = 4;        // Ridah, we were only ever passing in 4, so I made this local and used the parameter for the orientation
	qboolean oldMapping = qfalse;

	if (numPoints <= 0)
	{
		return 0;
	}

	//increment view count for double check prevention
	tr.viewCount++;

	// RF, negative maxFragments means we want original mapping
	if (maxFragments < 0)
	{
		maxFragments = -maxFragments;
		//return R_OldMarkFragments( numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer );
		oldMapping = qtrue;
	}

	VectorClear(center);
	for (i = 0 ; i < numPoints ; i++)
	{
		VectorAdd(points[i], center, center);
	}
	VectorScale(center, 1.0 / numPoints, center);
	//
	radius   = VectorNormalize2(projection, projectionDir) / 2.0;
	bestdist = 0;
	VectorNegate(projectionDir, bestnormal);
	// find all the brushes that are to be considered
	ClearBounds(mins, maxs);
	for (i = 0 ; i < numPoints ; i++)
	{
		vec3_t temp;

		AddPointToBounds(points[i], mins, maxs);
		VectorMA(points[i], 1 * (1 + oldMapping * radius * 4), projection, temp);
		AddPointToBounds(temp, mins, maxs);
		// make sure we get all the leafs (also the one(s) in front of the hit surface)
		VectorMA(points[i], -20 * (1.0 + (float)oldMapping * (radius / 20.0) * 4), projectionDir, temp);
		AddPointToBounds(temp, mins, maxs);
	}

	if (numPoints > MAX_VERTS_ON_POLY)
	{
		numPoints = MAX_VERTS_ON_POLY;
	}
	// create the bounding planes for the to be projected polygon
	for (i = 0 ; i < numPoints ; i++)
	{
		VectorSubtract(points[(i + 1) % numPoints], points[i], v1);
		VectorAdd(points[i], projection, v2);
		VectorSubtract(points[i], v2, v2);
		CrossProduct(v1, v2, normals[i]);
		VectorNormalize(normals[i]);
		dists[i] = DotProduct(normals[i], points[i]);
	}
	// add near and far clipping planes for projection
	VectorCopy(projectionDir, normals[numPoints]);
	dists[numPoints] = DotProduct(normals[numPoints], points[0]) - radius * (1 + oldMapping * 10);
	VectorCopy(projectionDir, normals[numPoints + 1]);
	VectorInverse(normals[numPoints + 1]);
	dists[numPoints + 1] = DotProduct(normals[numPoints + 1], points[0]) - radius * (1 + oldMapping * 10);
	numPlanes            = numPoints + 2;

	numsurfaces = 0;
	R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 4096, &numsurfaces, projectionDir);
	//assert(numsurfaces <= 64);
	//assert(numsurfaces != 64);

	texCoordScale = 0.5 * 1.0 / radius;

	returnedPoints    = 0;
	returnedFragments = 0;

	// find the closest surface to center the decal there, and wrap around other surfaces
	if (!oldMapping)
	{
/*
        for ( i = 0 ; i < numsurfaces ; i++ ) {
            if (*surfaces[i] == SF_FACE) {
                surf = ( srfSurfaceFace_t * ) surfaces[i];
                // Ridah, check if this is the closest surface
                dot = DotProduct( center, surf->plane.normal );
                dot -= surf->plane.dist;
                if (!bestdist) {
                    if (dot < 0)
                        bestdist = fabs(dot) + 1000;	// avoid this surface, since the point is behind it
                    else
                        bestdist = dot;
                    VectorCopy( surf->plane.normal, bestnormal );
                    VectorMA( center, -dot, surf->plane.normal, bestCenter );
                } else if (dot >= 0 && dot < bestdist) {
                    bestdist = dot;
                    VectorCopy( surf->plane.normal, bestnormal );
                    VectorMA( center, -dot, surf->plane.normal, bestCenter );
                }
            }
        }
        // bestCenter is now the real center
        VectorCopy( bestCenter, center );
Com_Printf("bestnormal: %1.1f %1.1f %1.1f \n", bestnormal[0], bestnormal[1], bestnormal[2] );
*/
		VectorNegate(bestnormal, bestnormal);
	}

	for (i = 0 ; i < numsurfaces ; i++)
	{

		if (*surfaces[i] == SF_GRID)
		{

			cv = (srfGridMesh_t *) surfaces[i];
			for (m = 0 ; m < cv->height - 1 ; m++)
			{
				for (n = 0 ; n < cv->width - 1 ; n++)
				{
					// We triangulate the grid and chop all triangles within
					// the bounding planes of the to be projected polygon.
					// LOD is not taken into account, not such a big deal though.
					//
					// It's probably much nicer to chop the grid itself and deal
					// with this grid as a normal SF_GRID surface so LOD will
					// be applied. However the LOD of that chopped grid must
					// be synced with the LOD of the original curve.
					// One way to do this; the chopped grid shares vertices with
					// the original curve. When LOD is applied to the original
					// curve the unused vertices are flagged. Now the chopped curve
					// should skip the flagged vertices. This still leaves the
					// problems with the vertices at the chopped grid edges.
					//
					// To avoid issues when LOD applied to "hollow curves" (like
					// the ones around many jump pads) we now just add a 2 unit
					// offset to the triangle vertices.
					// The offset is added in the vertex normal vector direction
					// so all triangles will still fit together.
					// The 2 unit offset should avoid pretty much all LOD problems.

					numClipPoints = 3;

					dv = cv->verts + m * cv->width + n;

					VectorCopy(dv[0].xyz, clipPoints[0][0]);
					VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);
					VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
					VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
					VectorCopy(dv[1].xyz, clipPoints[0][2]);
					VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);
					// check the normal of this triangle
					VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
					VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
					CrossProduct(v1, v2, normal);
					VectorNormalize(normal);
					if (DotProduct(normal, projectionDir) < -0.1)
					{
						// add the fragments of this triangle
						R_AddMarkFragments(numClipPoints, clipPoints,
						                   numPlanes, normals, dists,
						                   maxPoints, pointBuffer,
						                   maxFragments, fragmentBuffer,
						                   &returnedPoints, &returnedFragments, mins, maxs);

						if (returnedFragments == maxFragments)
						{
							return returnedFragments;   // not enough space for more fragments
						}
					}

					VectorCopy(dv[1].xyz, clipPoints[0][0]);
					VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);
					VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
					VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
					VectorCopy(dv[cv->width + 1].xyz, clipPoints[0][2]);
					VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width + 1].normal, clipPoints[0][2]);
					// check the normal of this triangle
					VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
					VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
					CrossProduct(v1, v2, normal);
					VectorNormalize(normal);
					if (DotProduct(normal, projectionDir) < -0.05)
					{
						// add the fragments of this triangle
						R_AddMarkFragments(numClipPoints, clipPoints,
						                   numPlanes, normals, dists,
						                   maxPoints, pointBuffer,
						                   maxFragments, fragmentBuffer,
						                   &returnedPoints, &returnedFragments, mins, maxs);

						if (returnedFragments == maxFragments)
						{
							return returnedFragments;   // not enough space for more fragments
						}
					}
				}
			}
		}
		else if (*surfaces[i] == SF_FACE)
		{
			extern float VectorDistance(vec3_t v1, vec3_t v2);
			vec3_t axis[3];
			float  texCoordScale, dot;
			vec3_t originalPoints[4];
			vec3_t newCenter, delta;
			int    oldNumPoints;
			float  epsilon = 0.5;
			// duplicated so we don't mess with the original clips for the curved surfaces
			vec3_t lnormals[MAX_VERTS_ON_POLY + 2];
			float  ldists[MAX_VERTS_ON_POLY + 2];
			vec3_t lmins, lmaxs;

			srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i];

			if (!oldMapping)
			{

				// Ridah, create a new clip box such that this decal surface is mapped onto
				// the current surface without distortion. To find the center of the new clip box,
				// we project the center of the original impact center out along the projection vector,
				// onto the current surface

				// find the center of the new decal
				dot  = DotProduct(center, surf->plane.normal);
				dot -= surf->plane.dist;
				// check the normal of this face
				if (dot < -epsilon && DotProduct(surf->plane.normal, projectionDir) >= 0.01)
				{
					continue;
				}
				else if (fabs(dot) > radius)
				{
					continue;
				}
				// if the impact point is behind the surface, subtract the projection, otherwise add it
				VectorMA(center, -dot, bestnormal, newCenter);

				// recalc dot from the offset position
				dot  = DotProduct(newCenter, surf->plane.normal);
				dot -= surf->plane.dist;
				VectorMA(newCenter, -dot, surf->plane.normal, newCenter);

				VectorMA(newCenter, MARKER_OFFSET, surf->plane.normal, newCenter);

				// create the texture axis
				VectorNormalize2(surf->plane.normal, axis[0]);
				PerpendicularVector(axis[1], axis[0]);
				RotatePointAroundVector(axis[2], axis[0], axis[1], (float)orientation);
				CrossProduct(axis[0], axis[2], axis[1]);

				texCoordScale = 0.5 * 1.0 / radius;

				// create the full polygon
				for (j = 0 ; j < 3 ; j++)
				{
					originalPoints[0][j] = newCenter[j] - radius * axis[1][j] - radius * axis[2][j];
					originalPoints[1][j] = newCenter[j] + radius * axis[1][j] - radius * axis[2][j];
					originalPoints[2][j] = newCenter[j] + radius * axis[1][j] + radius * axis[2][j];
					originalPoints[3][j] = newCenter[j] - radius * axis[1][j] + radius * axis[2][j];
				}

				ClearBounds(lmins, lmaxs);

				// create the bounding planes for the to be projected polygon
				for (j = 0 ; j < 4 ; j++)
				{
					AddPointToBounds(originalPoints[j], lmins, lmaxs);

					VectorSubtract(originalPoints[(j + 1) % numPoints], originalPoints[j], v1);
					VectorSubtract(originalPoints[j], surf->plane.normal, v2);
					VectorSubtract(originalPoints[j], v2, v2);
					CrossProduct(v1, v2, lnormals[j]);
					VectorNormalize(lnormals[j]);
					ldists[j] = DotProduct(lnormals[j], originalPoints[j]);
				}
				numPlanes = numPoints;

				// done.

				for (k = 0, tri = surf->triangles; k < surf->numTriangles; k++, tri++)
				{
					for (j = 0; j < 3; j++)
					{
						v = surf->verts[tri->indexes[j]].xyz;
						VectorMA(v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j]);
					}

					oldNumPoints = returnedPoints;

					// add the fragments of this face
					R_AddMarkFragments(3, clipPoints,
					                   numPlanes, lnormals, ldists,
					                   maxPoints, pointBuffer,
					                   maxFragments, fragmentBuffer,
					                   &returnedPoints, &returnedFragments, lmins, lmaxs);

					if (oldNumPoints != returnedPoints)
					{
						// flag this surface as already having computed ST's
						fragmentBuffer[returnedFragments - 1].numPoints *= -1;

						// Ridah, calculate ST's
						for (j = 0 ; j < (returnedPoints - oldNumPoints) ; j++)
						{
							VectorSubtract((float *)pointBuffer + 5 * (oldNumPoints + j), newCenter, delta);
							*((float *)pointBuffer + 5 * (oldNumPoints + j) + 3) = 0.5 + DotProduct(delta, axis[1]) * texCoordScale;
							*((float *)pointBuffer + 5 * (oldNumPoints + j) + 4) = 0.5 + DotProduct(delta, axis[2]) * texCoordScale;
						}
					}

					if (returnedFragments == maxFragments)
					{
						return returnedFragments;   // not enough space for more fragments
					}
				}

			}
			else        // old mapping
			{   // check the normal of this face
				//if (DotProduct(surf->plane.normal, projectionDir) > 0.0) {
				//	continue;
				//}

				for (k = 0, tri = surf->triangles; k < surf->numTriangles; k++, tri++)
				{
					for (j = 0; j < 3; j++)
					{
						v = surf->verts[tri->indexes[j]].xyz;
						VectorMA(v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j]);
					}
					// add the fragments of this face
					R_AddMarkFragments(3, clipPoints,
					                   numPlanes, normals, dists,
					                   maxPoints, pointBuffer,
					                   maxFragments, fragmentBuffer,
					                   &returnedPoints, &returnedFragments, mins, maxs);
					if (returnedFragments == maxFragments)
					{
						return returnedFragments;   // not enough space for more fragments
					}
				}

			}

		}
		else if (*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer)
		{

			srfTriangles_t *surf = (srfTriangles_t *) surfaces[i];

			for (k = 0, tri = surf->triangles; k < surf->numTriangles; k++, tri++)
			{
				for (j = 0; j < 3; j++)
				{
					v = surf->verts[tri->indexes[j]].xyz;
					VectorMA(v, MARKER_OFFSET, surf->verts[tri->indexes[j]].normal, clipPoints[0][j]);
				}

				// add the fragments of this face
				R_AddMarkFragments(3, clipPoints,
				                   numPlanes, normals, dists,
				                   maxPoints, pointBuffer,
				                   maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
				if (returnedFragments == maxFragments)
				{
					return returnedFragments;   // not enough space for more fragments
				}
			}
		}
	}
	return returnedFragments;
}