/*
=================
R_PatchSurfClipFragment
=================
*/
void R_PatchSurfClipFragment ( msurface_t *surf, vec3_t normal )
{
	int			i;
	fragment_t	*fr;
	vec4_t		*vert;
	index_t		*index;
	mesh_t		*mesh;
	vec4_t		verts[MAX_FRAGMENT_VERTS];
	vec3_t		dir1, dir2, snorm;

	// copy vertex data and clip to each triangle
	mesh = surf->mesh;
	index = mesh->indexes;
	vert = mesh->xyz_array;
	for ( i = 0; i < mesh->numindexes; i += 3, index += 3 ) {
		fr = &clippedFragments[numClippedFragments];
		fr->numverts = 0;

		VectorCopy ( vert[index[0]], verts[0] );
		VectorCopy ( vert[index[1]], verts[1] );
		VectorCopy ( vert[index[2]], verts[2] );
		
		// calculate two mostly perpendicular edge directions
		VectorSubtract ( verts[0], verts[1], dir1 );
		VectorSubtract ( verts[2], verts[1], dir2 );
			
		// we have two edge directions, we can calculate a third vector from
		// them, which is the direction of the surface normal
		CrossProduct ( dir1, dir2, snorm );

		// greater than 60 degrees
		// we multiply 0.5 by length of snorm to avoid normalizing
		if ( DotProduct (normal, snorm) < 0.5 * VectorLength (snorm) ) {
			continue;
		}

		R_ClipPoly ( 3, verts[0], 0, fr );

		if ( fr->numverts ) {
			numClippedFragments++;

			if ( numFragmentVerts >= maxFragmentVerts ||
				numClippedFragments >= maxClippedFragments ) {
				return;
			}
		}
	}
}
/*
=================
R_RecursiveFragmentNode
=================
*/
void R_RecursiveFragmentNode ( mnode_t *node, vec3_t origin, float radius, vec3_t normal )
{
	float dist;
	cplane_t *plane;

mark0:
	if ( numFragmentVerts >= maxFragmentVerts ||
		numClippedFragments >= maxClippedFragments) {
		return;			// already reached the limit somewhere else
	}

	if ( node->plane == NULL ) {	// leaf
		int c;
		mleaf_t *leaf;
		msurface_t *surf, **mark;
		mshaderref_t *shaderref;

		leaf = (mleaf_t *)node;
		if ( !(c = leaf->nummarksurfaces) ) {
			return;
		}

		mark = leaf->firstmarksurface;
		do
		{
			if ( numFragmentVerts >= maxFragmentVerts ||
				numClippedFragments >= maxClippedFragments ) {
				return;
			}

			surf = *mark++;
			if ( surf->fragmentframe == fragmentFrame ) {
				continue;
			}

			surf->fragmentframe = fragmentFrame;
			if ( !(shaderref = surf->shaderref) ) {
				continue;
			}
			if ( shaderref->flags & (SURF_NOMARKS|SURF_NOIMPACT) ) {
				continue;
			}

			if ( surf->facetype == FACETYPE_PLANAR ) {
				if ( shaderref->contents & CONTENTS_SOLID ) {
					R_PlanarSurfClipFragment ( surf, normal );
				}
			} else if ( surf->facetype == FACETYPE_PATCH ) {
				R_PatchSurfClipFragment ( surf, normal );
			}
		} while (--c);

		return;
	}

	plane = node->plane;
	dist = PlaneDiff ( origin, plane );

	if ( dist > radius )
	{
		node = node->children[0];
		goto mark0;
	}
	if ( dist < -radius )
	{
		node = node->children[1];
		goto mark0;
	}

	R_RecursiveFragmentNode ( node->children[0], origin, radius, normal );
	R_RecursiveFragmentNode ( node->children[1], origin, radius, normal );
}