Exemple #1
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_FlipAreaFaces(tmp_area_t *tmparea)
{
	int side;
	tmp_face_t *face;
	plane_t *plane;
	vec3_t wcenter, acenter = {0, 0, 0};
	//winding_t *w;
	float n;

	for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side])
	{
		if (!face->frontarea) Error("face %d has no front area\n", face->num);
		//side of the face the area is on
		side = face->frontarea != tmparea;
		WindingCenter(face->winding, wcenter);
		VectorAdd(acenter, wcenter, acenter);
		n++;
	} //end for
	n = 1 / n;
	VectorScale(acenter, n, acenter);
	for (face = tmparea->tmpfaces; face; face = face->next[side])
	{
		//side of the face the area is on
		side = face->frontarea != tmparea;

		plane = &mapplanes[face->planenum ^ side];

		if (DotProduct(plane->normal, acenter) - plane->dist < 0)
		{
			Log_Print("area %d face %d flipped: front area %d, back area %d\n", tmparea->areanum, face->num,
					face->frontarea ? face->frontarea->areanum : 0,
					face->backarea ? face->backarea->areanum : 0);
			/*
			face->planenum = face->planenum ^ 1;
			w = face->winding;
			face->winding = ReverseWinding(w);
			FreeWinding(w);
			*/
		} //end if
#ifdef L_DEBUG
		{
			float dist;
			vec3_t normal;

			//check if the winding plane is the same as the face plane
			WindingPlane(face->winding, normal, &dist);
			plane = &mapplanes[face->planenum];
			if (fabs(dist - plane->dist) > 0.4 ||
					fabs(normal[0] - plane->normal[0]) > 0.0001 ||
					fabs(normal[1] - plane->normal[1]) > 0.0001 ||
					fabs(normal[2] - plane->normal[2]) > 0.0001)
			{
				Log_Write("area %d face %d winding plane unequal to face plane\r\n",
											tmparea->areanum, face->num);
			} //end if
		}
#endif
	} //end for
} //end of the function AAS_FlipAreaFaces
Exemple #2
0
/*
=================
CheckWinding
=================
*/
void CheckWinding(winding_t * w) {
	int             i, j;
	vec_t          *p1, *p2, d, edgedist, area, facedist;
	vec3_t          dir, edgenormal, facenormal;

	if(w->numpoints < 3) {
		Com_Error(ERR_DROP, "CheckWinding: %i points", w->numpoints);
	}

	area = WindingArea(w);
	if(area < 1) {
		Com_Error(ERR_DROP, "CheckWinding: %f area", area);
	}

	WindingPlane(w, facenormal, &facedist);

	for(i = 0; i < w->numpoints; i++) {
		p1 = w->p[i];

		for(j = 0; j < 3; j++)
			if(p1[j] > MAX_MAP_BOUNDS || p1[j] < -MAX_MAP_BOUNDS) {
				Com_Error(ERR_DROP, "CheckFace: MAX_MAP_BOUNDS: %f", p1[j]);
			}

		j = i + 1 == w->numpoints ? 0 : i + 1;

		// check the point is on the face plane
		d = DotProduct(p1, facenormal) - facedist;
		if(d < -ON_EPSILON || d > ON_EPSILON) {
			Com_Error(ERR_DROP, "CheckWinding: point off plane");
		}

		// check the edge isnt degenerate
		p2 = w->p[j];
		VectorSubtract(p2, p1, dir);

		if(VectorLength(dir) < ON_EPSILON) {
			Com_Error(ERR_DROP, "CheckWinding: degenerate edge");
		}

		CrossProduct(facenormal, dir, edgenormal);
		VectorNormalize2(edgenormal, edgenormal);
		edgedist = DotProduct(p1, edgenormal);
		edgedist += ON_EPSILON;

		// all other points must be on front side
		for(j = 0; j < w->numpoints; j++) {
			if(j == i) {
				continue;
			}
			d = DotProduct(w->p[j], edgenormal);
			if(d > edgedist) {
				Com_Error(ERR_DROP, "CheckWinding: non-convex");
			}
		}
	}
}
Exemple #3
0
/*
=================
CheckWinding

=================
*/
void CheckWinding (winding_t *w)
{
	int		i, j;
	vec_t	d, edgedist;
	Vector	dir, edgenormal, facenormal;
	vec_t	area;
	vec_t	facedist;

	if (w->numpoints < 3)
		Error ("CheckWinding: %i points",w->numpoints);
	
	area = WindingArea(w);
	if (area < 1)
		Error ("CheckWinding: %f area", area);

	WindingPlane (w, facenormal, &facedist);
	
	for (i=0 ; i<w->numpoints ; i++)
	{
		Vector& p1 = w->p[i];

		for (j=0 ; j<3 ; j++)
		{
			if (p1[j] > MAX_COORD_INTEGER || p1[j] < MIN_COORD_INTEGER)
				Error ("CheckFace: out of range: %f",p1[j]);
		}

		j = i+1 == w->numpoints ? 0 : i+1;
		
	// check the point is on the face plane
		d = DotProduct (p1, facenormal) - facedist;
		if (d < -ON_EPSILON || d > ON_EPSILON)
			Error ("CheckWinding: point off plane");
	
	// check the edge isnt degenerate
		Vector& p2 = w->p[j];
		VectorSubtract (p2, p1, dir);
		
		if (VectorLength (dir) < ON_EPSILON)
			Error ("CheckWinding: degenerate edge");
			
		CrossProduct (facenormal, dir, edgenormal);
		VectorNormalize (edgenormal);
		edgedist = DotProduct (p1, edgenormal);
		edgedist += ON_EPSILON;
		
	// all other points must be on front side
		for (j=0 ; j<w->numpoints ; j++)
		{
			if (j == i)
				continue;
			d = DotProduct (w->p[j], edgenormal);
			if (d > edgedist)
				Error ("CheckWinding: non-convex");
		}
	}
}
Exemple #4
0
/*
=================
WritePortalFile_r
=================
*/
void WritePortalFile_r (node_t *node)
{
	int			i, s;	
	portal_t	*p;
	winding_t	*w;
	vec3_t		normal;
	vec_t		dist;

	// decision node
	if (node->planenum != PLANENUM_LEAF) {
		WritePortalFile_r (node->children[0]);
		WritePortalFile_r (node->children[1]);
		return;
	}
	
	if (node->opaque) {
		return;
	}

	for (p = node->portals ; p ; p=p->next[s])
	{
		w = p->winding;
		s = (p->nodes[1] == node);
		if (w && p->nodes[0] == node)
		{
			if (!Portal_Passable(p))
				continue;
			// write out to the file
			
			// sometimes planes get turned around when they are very near
			// the changeover point between different axis.  interpret the
			// plane the same way vis will, and flip the side orders if needed
			// FIXME: is this still relevent?
			WindingPlane (w, normal, &dist);
			if ( DotProduct (p->plane.normal, normal) < 0.99 )
			{	// backwards...
				fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster);
			}
			else
				fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster);
			if (p->hint)
				fprintf (pf, "1 ");
			else
				fprintf (pf, "0 ");
			for (i=0 ; i<w->numpoints ; i++)
			{
				fprintf (pf,"(");
				WriteFloat (pf, w->p[i][0]);
				WriteFloat (pf, w->p[i][1]);
				WriteFloat (pf, w->p[i][2]);
				fprintf (pf,") ");
			}
			fprintf (pf,"\n");
		}
	}

}
Exemple #5
0
void DWinding::CheckWinding()
{
	vec_t	*p1, *p2;
	vec_t	edgedist;
	vec3_t	dir, edgenormal;

	if (numpoints < 3)
		Sys_Printf ("CheckWinding: %i points", numpoints);
	
	vec_t area = WindingArea();
	if (area < 1)
		Sys_Printf ("CheckWinding: %f area", area);

	DPlane* wPlane = WindingPlane ();
	int i;
	for (i = 0; i < numpoints; i++)
	{
		p1 = p[i];

		int j;
		for (j = 0; j < 3; j++)
			if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
				Sys_Printf ("CheckFace: BUGUS_RANGE: %f", p1[j]);

		j = i + 1 == numpoints ? 0 : i + 1;
		
		// check the point is on the face plane
		vec_t d = DotProduct (p1, wPlane->normal) - wPlane->_d;
		if (d < -ON_EPSILON || d > ON_EPSILON)
			Sys_Printf ("CheckWinding: point off plane");
	
		// check the edge isnt degenerate
		p2 = p[j];
		VectorSubtract (p2, p1, dir);
		
		if (VectorLength (dir) < ON_EPSILON)
			Sys_Printf ("CheckWinding: degenerate edge");
			
		CrossProduct (wPlane->normal, dir, edgenormal);
		VectorNormalize (edgenormal, edgenormal);
		edgedist = DotProduct (p1, edgenormal);
		
		// all other points must be on front side
		for (j = 0 ; j < numpoints ; j++)
		{
			if (j == i)
				continue;

			d = DotProduct (p[j], edgenormal);
			if (d > (edgedist + ON_EPSILON))
				Sys_Printf ("CheckWinding: non-convex");
		}
	}

	delete wPlane;
}
Exemple #6
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_CheckArea(tmp_area_t *tmparea)
{
	int side;
	tmp_face_t *face;
	plane_t *plane;
	vec3_t wcenter, acenter = {0, 0, 0};
	vec3_t normal;
	float n, dist;

	if (tmparea->invalid) Log_Print("AAS_CheckArea: invalid area\n");
	for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side])
	{
		//side of the face the area is on
		side = face->frontarea != tmparea;
		WindingCenter(face->winding, wcenter);
		VectorAdd(acenter, wcenter, acenter);
		n++;
	} //end for
	n = 1 / n;
	VectorScale(acenter, n, acenter);
	for (face = tmparea->tmpfaces; face; face = face->next[side])
	{
		//side of the face the area is on
		side = face->frontarea != tmparea;

#ifdef L_DEBUG
		if (WindingError(face->winding))
		{
			Log_Write("AAS_CheckArea: area %d face %d: %s\r\n", tmparea->areanum,
						face->num, WindingErrorString());
		} //end if
#endif

		plane = &mapplanes[face->planenum ^ side];

		if (DotProduct(plane->normal, acenter) - plane->dist < 0)
		{
			Log_Print("AAS_CheckArea: area %d face %d is flipped\n", tmparea->areanum, face->num);
			Log_Print("AAS_CheckArea: area %d center is %f %f %f\n", tmparea->areanum, acenter[0], acenter[1], acenter[2]);
		} //end if
		//check if the winding plane is the same as the face plane
		WindingPlane(face->winding, normal, &dist);
		plane = &mapplanes[face->planenum];
#ifdef L_DEBUG
		if (fabs(dist - plane->dist) > 0.4 ||
				fabs(normal[0] - plane->normal[0]) > 0.0001 ||
				fabs(normal[1] - plane->normal[1]) > 0.0001 ||
				fabs(normal[2] - plane->normal[2]) > 0.0001)
		{
			Log_Write("AAS_CheckArea: area %d face %d winding plane unequal to face plane\r\n",
										tmparea->areanum, face->num);
		} //end if
#endif
	} //end for
} //end of the function AAS_CheckArea
/*
 * =================
 * CheckWinding
 * =================
 */
void
CheckWinding(winding_t * w)
{
    int i, j;
    vec_t *p1, *p2;
    vec_t d, edgedist;
    vec3_t dir, edgenormal, facenormal;
    vec_t area;
    vec_t facedist;

    if (w->numpoints < 3)
	Error("%s: %i points", __func__, w->numpoints);

    area = WindingArea(w);
    if (area < 1)
	Error("%s: %f area", __func__, area);

    WindingPlane(w, facenormal, &facedist);

    for (i = 0; i < w->numpoints; i++) {
	p1 = w->p[i];

	for (j = 0; j < 3; j++)
	    if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
		Error("%s: BUGUS_RANGE: %f", __func__, p1[j]);

	j = i + 1 == w->numpoints ? 0 : i + 1;

	/* check the point is on the face plane */
	d = DotProduct(p1, facenormal) - facedist;
	if (d < -ON_EPSILON || d > ON_EPSILON)
	    Error("%s: point off plane", __func__);

	/* check the edge isn't degenerate */
	p2 = w->p[j];
	VectorSubtract(p2, p1, dir);

	if (VectorLength(dir) < ON_EPSILON)
	    Error("%s: degenerate edge", __func__);

	CrossProduct(facenormal, dir, edgenormal);
	VectorNormalize(edgenormal);
	edgedist = DotProduct(p1, edgenormal);
	edgedist += ON_EPSILON;

	/* all other points must be on front side */
	for (j = 0; j < w->numpoints; j++) {
	    if (j == i)
		continue;
	    d = DotProduct(w->p[j], edgenormal);
	    if (d > edgedist)
		Error("%s: non-convex", __func__);
	}
    }
}
Exemple #8
0
void CheckWinding (winding_t *w) {
	int		i, j;
	vector3	*p1, *p2;
	number	d, edgedist;
	vector3	dir, edgenormal, facenormal;
	number	area;
	number	facedist;

	if (w->numpoints < 3)
		Com_Error (ERR_DROP, "CheckWinding: %i points",w->numpoints);
	
	area = WindingArea(w);
	if (area < 1)
		Com_Error (ERR_DROP, "CheckWinding: %f area", area);

	WindingPlane (w, &facenormal, &facedist);
	
	for (i=0 ; i<w->numpoints ; i++)
	{
		p1 = &w->p[i];

		for (j=0 ; j<3 ; j++)
			if (p1->data[j] > MAX_MAP_BOUNDS || p1->data[j] < -MAX_MAP_BOUNDS)
				Com_Error (ERR_DROP, "CheckFace: BUGUS_RANGE: %f",p1->data[j]);

		j = i+1 == w->numpoints ? 0 : i+1;
		
	// check the point is on the face plane
		d = DotProduct (p1, &facenormal) - facedist;
		if (d < -ON_EPSILON || d > ON_EPSILON)
			Com_Error (ERR_DROP, "CheckWinding: point off plane");
	
	// check the edge isnt degenerate
		p2 = &w->p[j];
		VectorSubtract (p2, p1, &dir);
		
		if (VectorLength (&dir) < ON_EPSILON)
			Com_Error (ERR_DROP, "CheckWinding: degenerate edge");
			
		CrossProduct (&facenormal, &dir, &edgenormal);
		VectorNormalize2 (&edgenormal, &edgenormal);
		edgedist = DotProduct (p1, &edgenormal);
		edgedist += ON_EPSILON;
		
	// all other points must be on front side
		for (j=0 ; j<w->numpoints ; j++)
		{
			if (j == i)
				continue;
			d = DotProduct (&w->p[j], &edgenormal);
			if (d > edgedist)
				Com_Error (ERR_DROP, "CheckWinding: non-convex");
		}
	}
}
Exemple #9
0
//===========================================================================
//
// Parameter:               -
// Returns:                 -
// Changes Globals:     -
//===========================================================================
void AAS_CheckFaceWindingPlane(tmp_face_t *face)
{
	float dist, sign1, sign2;
	vec3_t normal;
	plane_t *plane;
	winding_t *w;

	//check if the winding plane is the same as the face plane
	WindingPlane(face->winding, normal, &dist);
	plane = &mapplanes[face->planenum];
	//
	sign1 = DotProduct(plane->normal, normal);

	//
	if(fabs(dist - plane->dist) > 0.4 ||
	        fabs(normal[0] - plane->normal[0]) > 0.0001 ||
	        fabs(normal[1] - plane->normal[1]) > 0.0001 ||
	        fabs(normal[2] - plane->normal[2]) > 0.0001)
	{
		VectorInverse(normal);
		dist = -dist;

		if(fabs(dist - plane->dist) > 0.4 ||
		        fabs(normal[0] - plane->normal[0]) > 0.0001 ||
		        fabs(normal[1] - plane->normal[1]) > 0.0001 ||
		        fabs(normal[2] - plane->normal[2]) > 0.0001)
		{
			Log_Write("AAS_CheckFaceWindingPlane: face %d winding plane unequal to face plane\r\n",
			          face->num);
			//
			sign2 = DotProduct(plane->normal, normal);

			if((sign1 < 0 && sign2 > 0) ||
			        (sign1 > 0 && sign2 < 0))
			{
				Log_Write("AAS_CheckFaceWindingPlane: face %d winding reversed\r\n",
				          face->num);
				w = face->winding;
				face->winding = ReverseWinding(w);
				FreeWinding(w);
			} //end if
		} //end if
		else
		{
			Log_Write("AAS_CheckFaceWindingPlane: face %d winding reversed\r\n",
			          face->num);
			w = face->winding;
			face->winding = ReverseWinding(w);
			FreeWinding(w);
		} //end else
	} //end if
} //end of the function AAS_CheckFaceWindingPlane
qboolean WindingIsTiny2 (winding_t *w)
{
	int		i, j;
	vec_t	len;
	Vector	delta;
	int		edges;

	vec_t maxLen = 0;
	Vector maxEdge = vec3_origin;

	edges = 0;
	for (i=0 ; i<w->numpoints ; i++)
	{
		j = i == w->numpoints - 1 ? 0 : i+1;
		VectorSubtract (w->p[j], w->p[i], delta);
		len = VectorLength (delta);
		if (len > maxLen)
		{
			maxEdge = delta;
			maxLen = len;
		}
	}
	Vector normal;
	vec_t dist;
	WindingPlane (w, normal, &dist); // normal can come back vec3_origin in some cases
	VectorNormalize(maxEdge);
	Vector cross = CrossProduct(normal, maxEdge);
	VectorNormalize(cross);
	Vector mins, maxs;
	ClearBounds( mins, maxs );
	for (i=0 ; i<w->numpoints ; i++)
	{
		Vector point;
		point.x = DotProduct( w->p[i], maxEdge );
		point.y = DotProduct( w->p[i], cross );
		point.z = DotProduct( w->p[i], normal );
		AddPointToBounds( point, mins, maxs );
	}

	// check to see if the size in the plane is too small in either dimension
	Vector size = maxs - mins;
	for ( i = 0; i < 2; i++ )
	{
		if ( size[i] < EDGE_LENGTH )
			return true;
	}
	return false;
}
Exemple #11
0
/*
 * @brief
 */
static void WritePortalFile_r(node_t *node) {
    int32_t i, s;
    portal_t *p;
    winding_t *w;
    vec3_t normal;
    vec_t dist;

    // decision node
    if (node->plane_num != PLANENUM_LEAF && !node->detail_seperator) {
        WritePortalFile_r(node->children[0]);
        WritePortalFile_r(node->children[1]);
        return;
    }

    if (node->contents & CONTENTS_SOLID)
        return;

    for (p = node->portals; p; p = p->next[s]) {
        w = p->winding;
        s = (p->nodes[1] == node);
        if (w && p->nodes[0] == node) {
            if (!Portal_VisFlood(p))
                continue;
            // write out to the file

            // sometimes planes get turned around when they are very near
            // the changeover point between different axis. interpret the
            // plane the same way vis will, and flip the side orders if needed
            // FIXME: is this still relevent?
            WindingPlane(w, normal, &dist);
            if (DotProduct(p->plane.normal, normal) < 0.99) { // backwards...
                Fs_Print(prtfile, "%i %i %i ", w->num_points, p->nodes[1]->cluster,
                         p->nodes[0]->cluster);
            } else
                Fs_Print(prtfile, "%i %i %i ", w->num_points, p->nodes[0]->cluster,
                         p->nodes[1]->cluster);
            for (i = 0; i < w->num_points; i++) {
                Fs_Print(prtfile, "(");
                WriteFloat(prtfile, w->points[i][0]);
                WriteFloat(prtfile, w->points[i][1]);
                WriteFloat(prtfile, w->points[i][2]);
                Fs_Print(prtfile, ") ");
            }
            Fs_Print(prtfile, "\n");
        }
    }

}
Exemple #12
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
int WindingError( winding_t *w ) {
	int i, j;
	vec_t   *p1, *p2;
	vec_t d, edgedist;
	vec3_t dir, edgenormal, facenormal;
	vec_t area;
	vec_t facedist;

	if ( w->numpoints < 3 ) {
		sprintf( windingerror, "winding %i points", w->numpoints );
		return WE_NOTENOUGHPOINTS;
	} //end if

	area = WindingArea( w );
	if ( area < 1 ) {
		sprintf( windingerror, "winding %f area", area );
		return WE_SMALLAREA;
	} //end if

	WindingPlane( w, facenormal, &facedist );

	for ( i = 0 ; i < w->numpoints ; i++ )
	{
		p1 = w->p[i];

		for ( j = 0 ; j < 3 ; j++ )
		{
			if ( p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE ) {
				sprintf( windingerror, "winding point %d BUGUS_RANGE \'%f %f %f\'", j, p1[0], p1[1], p1[2] );
				return WE_POINTBOGUSRANGE;
			} //end if
		} //end for

		j = i + 1 == w->numpoints ? 0 : i + 1;

		// check the point is on the face plane
		d = DotProduct( p1, facenormal ) - facedist;
		if ( d < -ON_EPSILON || d > ON_EPSILON ) {
			sprintf( windingerror, "winding point %d off plane", i );
			return WE_POINTOFFPLANE;
		} //end if

		// check the edge isnt degenerate
		p2 = w->p[j];
		VectorSubtract( p2, p1, dir );

		if ( VectorLength( dir ) < ON_EPSILON ) {
			sprintf( windingerror, "winding degenerate edge %d-%d", i, j );
			return WE_DEGENERATEEDGE;
		} //end if

		CrossProduct( facenormal, dir, edgenormal );
		VectorNormalize( edgenormal );
		edgedist = DotProduct( p1, edgenormal );
		edgedist += ON_EPSILON;

		// all other points must be on front side
		for ( j = 0 ; j < w->numpoints ; j++ )
		{
			if ( j == i ) {
				continue;
			}
			d = DotProduct( w->p[j], edgenormal );
			if ( d > edgedist ) {
				sprintf( windingerror, "winding non-convex" );
				return WE_NONCONVEX;
			} //end if
		} //end for
	} //end for
	return WE_NONE;
} //end of the function WindingError
Exemple #13
0
/*
=================
CheckWinding

=================
*/
void CheckWinding( winding_t *w ) {
	int i, j;
	vec_t   *p1, *p2;
	vec_t d, edgedist;
	vec3_t dir, edgenormal, facenormal;
	vec_t area;
	vec_t facedist;

	if ( w->numpoints < 3 ) {
		Com_Error( ERR_DROP, "CheckWinding: %i points",w->numpoints );
	}

	area = WindingArea( w );
	if ( area < 1 ) {
		Com_Error( ERR_DROP, "CheckWinding: %f area", area );
	}

	WindingPlane( w, facenormal, &facedist );

	for ( i = 0 ; i < w->numpoints ; i++ )
	{
		p1 = w->p[i];

		for ( j = 0 ; j < 3 ; j++ )

#if !defined RTCW_MP
			if ( p1[j] > MAX_MAP_BOUNDS || p1[j] < -MAX_MAP_BOUNDS ) {
#else
			if ( p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE ) {
#endif // RTCW_XX

#if !defined RTCW_ET
				Com_Error( ERR_DROP, "CheckFace: BUGUS_RANGE: %f",p1[j] );
#else
				Com_Error( ERR_DROP, "CheckFace: MAX_MAP_BOUNDS: %f",p1[j] );
#endif // RTCW_XX

			}

		j = i + 1 == w->numpoints ? 0 : i + 1;

		// check the point is on the face plane
		d = DotProduct( p1, facenormal ) - facedist;
		if ( d < -ON_EPSILON || d > ON_EPSILON ) {
			Com_Error( ERR_DROP, "CheckWinding: point off plane" );
		}

		// check the edge isnt degenerate
		p2 = w->p[j];
		VectorSubtract( p2, p1, dir );

		if ( VectorLength( dir ) < ON_EPSILON ) {
			Com_Error( ERR_DROP, "CheckWinding: degenerate edge" );
		}

		CrossProduct( facenormal, dir, edgenormal );
		VectorNormalize2( edgenormal, edgenormal );
		edgedist = DotProduct( p1, edgenormal );
		edgedist += ON_EPSILON;

		// all other points must be on front side
		for ( j = 0 ; j < w->numpoints ; j++ )
		{
			if ( j == i ) {
				continue;
			}
			d = DotProduct( w->p[j], edgenormal );
			if ( d > edgedist ) {
				Com_Error( ERR_DROP, "CheckWinding: non-convex" );
			}
		}
	}
}


/*
============
WindingOnPlaneSide
============
*/
int     WindingOnPlaneSide( winding_t *w, vec3_t normal, vec_t dist ) {
	qboolean front, back;
	int i;
	vec_t d;

	front = qfalse;
	back = qfalse;
	for ( i = 0 ; i < w->numpoints ; i++ )
	{
		d = DotProduct( w->p[i], normal ) - dist;
		if ( d < -ON_EPSILON ) {
			if ( front ) {
				return SIDE_CROSS;
			}
			back = qtrue;
			continue;
		}
		if ( d > ON_EPSILON ) {
			if ( back ) {
				return SIDE_CROSS;
			}
			front = qtrue;
			continue;
		}
	}

	if ( back ) {
		return SIDE_BACK;
	}
	if ( front ) {
		return SIDE_FRONT;
	}
	return SIDE_ON;
}