コード例 #1
0
ファイル: cm_polylib.c プロジェクト: Justasic/RTCW-MP
/*
=================
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 ( p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE ) {
				Com_Error( ERR_DROP, "CheckFace: BUGUS_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 ) {
			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" );
			}
		}
	}
}
コード例 #2
0
ファイル: qrad.c プロジェクト: 6779660/halflife
/*
=============
SubdividePatch
=============
*/
void	SubdividePatch (patch_t *patch)
{
	winding_t *w, *o1, *o2;
	vec3_t	total;
	vec3_t	split;
	vec_t	dist;
	vec_t	widest = -1;
	int		i, j, widest_axis = -1;
	int		subdivide_it = 0;
	vec_t	v;
	patch_t	*newp;

	w = patch->winding;

	VectorSubtract (patch->maxs, patch->mins, total);
	for (i=0 ; i<3 ; i++)
	{
		if ( total[i] > widest )
			{
			widest_axis = i;
			widest = total[i];
			}
		if ( total[i] > patch->chop
		  || (patch->face_maxs[i] == patch->maxs[i] || patch->face_mins[i] == patch->mins[i] )
		  && total[i] > minchop )
		{
			subdivide_it = 1;
		}
	}

	if ( subdivide_it )
	{
		//
		// split the winding
		//
		VectorCopy (vec3_origin, split);
		split[widest_axis] = 1;
		dist = (patch->mins[widest_axis] + patch->maxs[widest_axis])*0.5f;
		ClipWinding (w, split, dist, &o1, &o2);

		//
		// create a new patch
		//
		if (num_patches == MAX_PATCHES)
			Error ("MAX_PATCHES");
		newp = &patches[num_patches];

		newp->next = patch->next;
		patch->next = newp;

		patch->winding = o1;
		newp->winding = o2;

		VectorCopy( patch->face_mins, newp->face_mins );
		VectorCopy( patch->face_maxs, newp->face_maxs );

		VectorCopy( patch->baselight, newp->baselight );
		VectorCopy( patch->directlight, newp->directlight );
		VectorCopy( patch->totallight, newp->totallight );
		VectorCopy( patch->reflectivity, newp->reflectivity );
		newp->plane = patch->plane;
		newp->sky = patch->sky;
		newp->chop = patch->chop;
		newp->faceNumber = patch->faceNumber;

		num_patches++;

		patch->area = WindingArea (patch->winding);
		newp->area = WindingArea (newp->winding);

		WindingCenter (patch->winding, patch->origin);
		WindingCenter (newp->winding, newp->origin);

#ifdef PHONG_NORMAL_PATCHES
// This seems to be a bad idea for some reason.  Leave it turned off for now.
		// Set (Copy or Calculate) the synthetic normal for these new patches
		VectorAdd (patch->origin, patch->plane->normal, patch->origin);
		VectorAdd (newp->origin, newp->plane->normal, newp->origin);
		GetPhongNormal( patch->faceNumber, patch->origin, patch->normal );
		GetPhongNormal( newp->faceNumber, newp->origin, newp->normal );
		VectorSubtract( patch->origin, patch->plane->normal, patch->origin);
		VectorSubtract( newp->origin, newp->plane->normal, newp->origin);
#else
		VectorCopy( patch->plane->normal, patch->normal );
		VectorCopy( newp->plane->normal, newp->normal );
#endif
		VectorAdd( patch->origin, patch->normal, patch->origin );
		VectorAdd( newp->origin, newp->normal, newp->origin );

		WindingBounds(patch->winding, patch->mins, patch->maxs);
		WindingBounds(newp->winding, newp->mins, newp->maxs);

		// Subdivide patch even more if on the edge of the face; this is a hack!
		VectorSubtract (patch->maxs, patch->mins, total);
		if ( total[0] < patch->chop && total[1] < patch->chop && total[2] < patch->chop )
			for ( i=0; i<3; i++ )
				if ( (patch->face_maxs[i] == patch->maxs[i] || patch->face_mins[i] == patch->mins[i] )
				  && total[i] > minchop )
				{
					patch->chop = max( minchop, patch->chop / 2 );
					break;
				}

		SubdividePatch (patch);

		// Subdivide patch even more if on the edge of the face; this is a hack!
		VectorSubtract (newp->maxs, newp->mins, total);
		if ( total[0] < newp->chop && total[1] < newp->chop && total[2] < newp->chop )
			for ( i=0; i<3; i++ )
				if ( (newp->face_maxs[i] == newp->maxs[i] || newp->face_mins[i] == newp->mins[i] )
				  && total[i] > minchop )
				{
					newp->chop = max( minchop, newp->chop / 2 );
					break;
				}

		SubdividePatch (newp);
	}
}
コード例 #3
0
void Sin_FixTextureReferences( void ) {
	int i, j, k, we;
	sin_dbrushside_t *brushside;
	sin_dbrush_t *brush;
	sin_dface_t *face;
	winding_t *w;

	memset( sin_dbrushsidetextured, false, SIN_MAX_MAP_BRUSHSIDES );
	//go over all the brushes
	for ( i = 0; i < sin_numbrushes; i++ )
	{
		brush = &sin_dbrushes[i];
		//hint brushes are not textured
		if ( Sin_HintSkipBrush( brush ) ) {
			continue;
		}
		//go over all the sides of the brush
		for ( j = 0; j < brush->numsides; j++ )
		{
			brushside = &sin_dbrushsides[brush->firstside + j];
			//
			w = Sin_BrushSideWinding( brush, brushside );
			if ( !w ) {
				sin_dbrushsidetextured[brush->firstside + j] = true;
				continue;
			} //end if
			else
			{
				//RemoveEqualPoints(w, 0.2);
				if ( WindingIsTiny( w ) ) {
					FreeWinding( w );
					sin_dbrushsidetextured[brush->firstside + j] = true;
					continue;
				} //end if
				else
				{
					we = WindingError( w );
					if ( we == WE_NOTENOUGHPOINTS
						 || we == WE_SMALLAREA
						 || we == WE_POINTBOGUSRANGE
//						|| we == WE_NONCONVEX
						 ) {
						FreeWinding( w );
						sin_dbrushsidetextured[brush->firstside + j] = true;
						continue;
					} //end if
				} //end else
			} //end else
			if ( WindingArea( w ) < 20 ) {
				sin_dbrushsidetextured[brush->firstside + j] = true;
			} //end if
			  //find a face for texturing this brush
			for ( k = 0; k < sin_numfaces; k++ )
			{
				face = &sin_dfaces[k];
				//if the face is in the same plane as the brush side
				if ( ( face->planenum & ~1 ) != ( brushside->planenum & ~1 ) ) {
					continue;
				}
				//if the face is partly or totally on the brush side
				if ( Sin_FaceOnWinding( face, w ) ) {
					brushside->texinfo = face->texinfo;
					sin_dbrushsidetextured[brush->firstside + j] = true;
					break;
				} //end if
			} //end for
			FreeWinding( w );
		} //end for
	} //end for
} //end of the function Sin_FixTextureReferences*/
コード例 #4
0
ファイル: l_bsp_q3.c プロジェクト: tkmorris/OpenMOHAA
void Q3_FindVisibleBrushSides(void)
{
    int i, j, k, we, numtextured, numsides;
    float dot;
    dplane_t *plane;
    dbrushside_t *brushside;
    dbrush_t *brush;
    dsurface_t *surface;
    winding_t *w;

    memset(dbrushsidetextured, false, MAX_MAP_BRUSHSIDES);
    //
    numsides = 0;
    //create planes for the planar surfaces
    Q3_CreatePlanarSurfacePlanes();
    Log_Print("searching visible brush sides...\n");
    Log_Print("%6d brush sides", numsides);
    //go over all the brushes
    for (i = 0; i < q3_numbrushes; i++)
    {
        brush = &dbrushes[i];
        //go over all the sides of the brush
        for (j = 0; j < brush->numSides; j++)
        {
            qprintf("\r%6d", numsides++);
            brushside = &dbrushsides[brush->firstSide + j];
            //
            w = Q3_BrushSideWinding(brush, brushside);
            if (!w)
            {
                dbrushsidetextured[brush->firstSide + j] = true;
                continue;
            } //end if
            else
            {
                //RemoveEqualPoints(w, 0.2);
                if (WindingIsTiny(w))
                {
                    FreeWinding(w);
                    dbrushsidetextured[brush->firstSide + j] = true;
                    continue;
                } //end if
                else
                {
                    we = WindingError(w);
                    if (we == WE_NOTENOUGHPOINTS
                            || we == WE_SMALLAREA
                            || we == WE_POINTBOGUSRANGE
//						|| we == WE_NONCONVEX
                       )
                    {
                        FreeWinding(w);
                        dbrushsidetextured[brush->firstSide + j] = true;
                        continue;
                    } //end if
                } //end else
            } //end else
            if (WindingArea(w) < 20)
            {
                dbrushsidetextured[brush->firstSide + j] = true;
                continue;
            } //end if
            //find a face for texturing this brush
            for (k = 0; k < q3_numDrawSurfaces; k++)
            {
                surface = &drawSurfaces[k];
                if (surface->surfaceType != MST_PLANAR) continue;
                //
                //Q3_SurfacePlane(surface, plane.normal, &plane.dist);
                plane = &q3_surfaceplanes[k];
                //the surface plane and the brush side plane should be pretty much the same
                if (fabs(fabs(plane->dist) - fabs(dplanes[brushside->planeNum].dist)) > 5) continue;
                dot = DotProduct(plane->normal, dplanes[brushside->planeNum].normal);
                if (dot > -0.9 && dot < 0.9) continue;
                //if the face is partly or totally on the brush side
                if (Q3_FaceOnWinding(surface, w))
                {
                    dbrushsidetextured[brush->firstSide + j] = true;
                    //Log_Write("Q3_FaceOnWinding");
                    break;
                } //end if
            } //end for
            FreeWinding(w);
        } //end for
    } //end for
    qprintf("\r%6d brush sides\n", numsides);
    numtextured = 0;
    for (i = 0; i < q3_numbrushsides; i++)
    {
        if (forcesidesvisible) dbrushsidetextured[i] = true;
        if (dbrushsidetextured[i]) numtextured++;
    } //end for
    Log_Print("%d brush sides textured out of %d\n", numtextured, q3_numbrushsides);
} //end of the function Q3_FindVisibleBrushSides
コード例 #5
0
ファイル: qrad.c プロジェクト: 6779660/halflife
void MakePatchForFace (int fn, winding_t *w)
{
	dface_t *f = dfaces + fn;

	// No patches at all for the sky!
	if ( !IsSky(f) )
	{
		float	area;
		patch_t		*patch;
		vec3_t light;
		vec3_t		centroid = {0,0,0};
		int			i, j;
		texinfo_t	*tx = &texinfo[f->texinfo];

		area = WindingArea (w);
		totalarea += area;

		patch = &patches[num_patches];
		if (num_patches == MAX_PATCHES)
			Error ("num_patches == MAX_PATCHES");
		patch->next = face_patches[fn];
		face_patches[fn] = patch;

		if ( texscale )
			{
			// Compute the texture "scale" in s,t
			for( i=0; i<2; i++ )
				{
				patch->scale[i] = 0.0;
				for( j=0; j<3; j++ )
					patch->scale[i] += tx->vecs[i][j] * tx->vecs[i][j];
				patch->scale[i] = sqrt( patch->scale[i] );
				}
			}
		else
			patch->scale[0] = patch->scale[1] = 1.0;

		patch->area = area;
		patch->chop = maxchop / (int)((patch->scale[0]+patch->scale[1])/2);
		patch->sky = FALSE;

		patch->winding = w;

		if (f->side)
			patch->plane = &backplanes[f->planenum];
		else
			patch->plane = &dplanes[f->planenum];

		for (j=0 ; j<f->numedges ; j++)
		{
			int edge = dsurfedges[ f->firstedge + j ];
			int edge2 = dsurfedges[ j==f->numedges-1 ? f->firstedge : f->firstedge + j + 1 ];

			if (edge > 0)
			{
				VectorAdd( dvertexes[dedges[edge].v[0]].point, centroid, centroid );
				VectorAdd( dvertexes[dedges[edge].v[1]].point, centroid, centroid );
			}
			else
			{
				VectorAdd( dvertexes[dedges[-edge].v[1]].point, centroid, centroid );
				VectorAdd( dvertexes[dedges[-edge].v[0]].point, centroid, centroid );
			}
		}
		VectorScale( centroid, 1.0 / (f->numedges * 2), centroid );
		VectorCopy( centroid, face_centroids[fn] );  // Save them for generating the patch normals later.

		patch->faceNumber = fn;
		WindingCenter (w, patch->origin);

#ifdef PHONG_NORMAL_PATCHES
// This seems to be a bad idea for some reason.  Leave it turned off for now.
		VectorAdd (patch->origin, patch->plane->normal, patch->origin);
		GetPhongNormal( fn, patch->origin, patch->normal );
		VectorSubtract (patch->origin, patch->plane->normal, patch->origin);
		if ( !VectorCompare( patch->plane->normal, patch->normal ) )
			patch->chop = 16; // Chop it fine!
#else
		VectorCopy( patch->plane->normal, patch->normal );
#endif
		VectorAdd (patch->origin, patch->normal, patch->origin);

		WindingBounds (w, patch->face_mins, patch->face_maxs);
		VectorCopy( patch->face_mins, patch->mins );
		VectorCopy( patch->face_maxs, patch->maxs );

		BaseLightForFace( f, light, patch->reflectivity );
		VectorCopy( light, patch->totallight );
		VectorCopy( light, patch->baselight );

		// Chop all texlights very fine.
		if ( !VectorCompare( light, vec3_origin ) )
			patch->chop = extra ? minchop / 2 : minchop;

		num_patches++;
	}
}
コード例 #6
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_RemoveTinyAreas( void ) {
	//RF, disabled, can cause problems, should do checks on minsidelength instead, and also this should be a post-clustering
	// process, as in "-reachableonly"
	return;
#if 0
	int side, gside, nummerges;
	tmp_area_t *tmparea;
	tmp_face_t *face, *gface;
	vec_t windingArea;

	if ( !mingroundarea ) {
		return;
	}

	nummerges = 0;
	Log_Write( "AAS_RemoveTinyAreas\r\n" );
	qprintf( "%6d tiny areas removed", 1 );
	//
	for ( tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next )
	{
		//if the area is invalid
		if ( tmparea->invalid ) {
			continue;
		} //end if
		  //
		  // never remove liquid areas
		if ( tmparea->contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
			continue;
		}
		//
		windingArea = 0;
		//
		for ( face = tmparea->tmpfaces; face; face = face->next[side] )
		{
			side = ( face->frontarea != tmparea );
			//
			// never remove ladder areas
			if ( face->faceflags & FACE_LADDER ) {
				break;
			}
			//
			//if this face touches a grounded face, and there is no area on the other side, then dont remove it
			if ( !( face->faceflags & FACE_GROUND ) ) {
				// does this face share an edge with a ground face?
				for ( gface = tmparea->tmpfaces; gface; gface = gface->next[gside] ) {
					gside = ( gface->frontarea != tmparea );
					//
					if ( gface == face ) {
						continue;
					}
					if ( !( gface->faceflags & FACE_GROUND ) ) {
						continue;
					}
					//
					if ( AAS_FacesTouching( face, gface ) ) {
						break;
					}
				}

				// if this face touches a grounded face, and there is no area on the other side, then this area must stay
				if ( gface && ( !face->frontarea || face->frontarea->invalid || !face->backarea || face->backarea->invalid || ( face->faceflags & FACE_SOLID ) ) ) {
					break;
				}
			}
			//
			if ( face->faceflags & FACE_GROUND ) {
				// get the area of this face
				windingArea += WindingArea( face->winding );
			}
		} //end for
		  //
		  // if this area has a windingArea low enough, then remove it
		if ( !face && windingArea && windingArea < mingroundarea ) {
			qprintf( "\r%6d", ++nummerges );
			tmparea->invalid = 1;
		}

	} //end for
	qprintf( "\n" );
	Log_Write( "%6d tiny areas removed\r\n", nummerges );
#endif
} //end of the function AAS_MergeAreas
コード例 #7
0
ファイル: facebsp.c プロジェクト: xonotic/netradient
static void SelectSplitPlaneNum( node_t *node, face_t *list, int *splitPlaneNum, int *compileFlags ){
	face_t *split;
	face_t *check;
	face_t *bestSplit;
	int splits, facing, front, back;
	int side;
	plane_t *plane;
	int value, bestValue;
	int i;
	vec3_t normal;
	float dist;
	int planenum;
	float sizeBias;

	/* ydnar: set some defaults */
	*splitPlaneNum = -1; /* leaf */
	*compileFlags = 0;

	/* ydnar 2002-06-24: changed this to split on z-axis as well */
	/* ydnar 2002-09-21: changed blocksize to be a vector, so mappers can specify a 3 element value */

	/* if it is crossing a block boundary, force a split */
	for ( i = 0; i < 3; i++ )
	{
		if ( blockSize[ i ] <= 0 ) {
			continue;
		}
		dist = blockSize[ i ] * ( floor( node->mins[ i ] / blockSize[ i ] ) + 1 );
		if ( node->maxs[ i ] > dist ) {
			VectorClear( normal );
			normal[ i ] = 1;
			planenum = FindFloatPlane( normal, dist, 0, NULL );
			*splitPlaneNum = planenum;
			return;
		}
	}

	/* pick one of the face planes */
	bestValue = -99999;
	bestSplit = list;


	// div0: this check causes detail/structural mixes
	//for( split = list; split; split = split->next )
	//	split->checked = qfalse;

	for ( split = list; split; split = split->next )
	{
		//if ( split->checked )
		//	continue;

		plane = &mapplanes[ split->planenum ];
		splits = 0;
		facing = 0;
		front = 0;
		back = 0;
		for ( check = list ; check ; check = check->next ) {
			if ( check->planenum == split->planenum ) {
				facing++;
				//check->checked = qtrue;	// won't need to test this plane again
				continue;
			}
			side = WindingOnPlaneSide( check->w, plane->normal, plane->dist );
			if ( side == SIDE_CROSS ) {
				splits++;
			}
			else if ( side == SIDE_FRONT ) {
				front++;
			}
			else if ( side == SIDE_BACK ) {
				back++;
			}
		}

		if ( bspAlternateSplitWeights ) {
			// from 27

			//Bigger is better
			sizeBias = WindingArea( split->w );

			//Base score = 20000 perfectly balanced
			value = 20000 - ( abs( front - back ) );
			value -= plane->counter; // If we've already used this plane sometime in the past try not to use it again
			value -= facing ;       // if we're going to have alot of other surfs use this plane, we want to get it in quickly.
			value -= splits * 5;        //more splits = bad
			value +=  sizeBias * 10; //We want a huge score bias based on plane size
		}
		else
		{
			value =  5 * facing - 5 * splits; // - abs(front-back);
			if ( plane->type < 3 ) {
				value += 5;       // axial is better
			}
		}

		value += split->priority;       // prioritize hints higher

		if ( value > bestValue ) {
			bestValue = value;
			bestSplit = split;
		}
	}

	/* nothing, we have a leaf */
	if ( bestValue == -99999 ) {
		return;
	}

	/* set best split data */
	*splitPlaneNum = bestSplit->planenum;
	*compileFlags = bestSplit->compileFlags;

	if ( *splitPlaneNum > -1 ) {
		mapplanes[ *splitPlaneNum ].counter++;
	}
}
コード例 #8
0
ファイル: brush.c プロジェクト: LAxBANDA/cs16nd
/*
===========
MakeHullFaces
===========
*/
void MakeHullFaces (brush_t *b, brushhull_t *h)
{
    bface_t	*f, *f2;
    winding_t	*w;
    plane_t		*p;
    int			i, j;
    vec_t		v;
    vec_t		area;

restart:
    h->mins[0] = h->mins[1] = h->mins[2] = 9999;
    h->maxs[0] = h->maxs[1] = h->maxs[2] = -9999;

    for (f = h->faces ; f ; f=f->next)
    {
//		w = BaseWindingForIPlane (f->plane);
        w = BaseWindingForPlane (f->plane->normal, f->plane->dist);
        for (f2 = h->faces ; f2 && w ; f2=f2->next)
        {
            if (f == f2)
                continue;
            p = &mapplanes[f2->planenum ^ 1];

            w = ChopWinding (w, p->normal, p->dist);
        }
        area = w ? WindingArea(w) : 0;
        if (area < 0.1)
        {
            qprintf ("Entity %i, Brush %i: plane with area %4.2f\n"
                     , b->entitynum, b->brushnum, area);
            // remove the face and regenerate the hull
            if (h->faces == f)
                h->faces = f->next;
            else
            {
                for (f2=h->faces ; f2->next != f ; f2=f2->next)
                    ;
                f2->next = f->next;
            }
            goto restart;
        }
        f->w = w;
        f->contents = CONTENTS_EMPTY;
        if (w)
        {
            for (i=0 ; i<w->numpoints ; i++)
            {
                for (j=0 ; j<3 ; j++)
                {
                    v = w->p[i][j];
//					w->p[i][j] = floor (v+0.5);	// round to int
                    if (v<h->mins[j])
                        h->mins[j] = v;
                    if (v>h->maxs[j])
                        h->maxs[j] = v;
                }
            }
        }
    }

    for (i=0 ; i<3 ; i++)
    {
        if (h->mins[i] < -BOGUS_RANGE/2
                || h->maxs[i] > BOGUS_RANGE/2)
        {
            vec3_t eorigin = { 0, 0, 0};
            char *pszClass = "Unknown Class";
            if ( b->entitynum )
            {
                entity_t	*e = entities + b->entitynum;
                pszClass = ValueForKey(e, "classname" );
                GetVectorForKey( e, "origin", eorigin );
            }

            printf( "Entity %i, Brush %i: A '%s' @(%.0f,%.0f,%.0f)\n",
                    b->entitynum, b->brushnum, pszClass, eorigin[0], eorigin[1], eorigin[2] );
            printf( "\toutside world(+/-%d): (%.0f, %.0f, %.0f)-(%.0f,%.0f,%.0f)\n",
                    BOGUS_RANGE/2, h->mins[0], h->mins[1], h->mins[2], h->maxs[0], h->maxs[1], h->maxs[2] );
            break;
        }
    }
}
コード例 #9
0
void GetBestSurfaceTriangleMatchForBrushside(side_t * buildSide, bspDrawVert_t * bestVert[3])
{
	bspDrawSurface_t *s;
	int             i;
	int             t;
	vec_t           best = 0;
	vec_t           thisarea;
	vec3_t          normdiff;
	vec3_t          v1v0, v2v0, norm;
	bspDrawVert_t  *vert[3];
	winding_t      *polygon;
	plane_t        *buildPlane = &mapplanes[buildSide->planenum];
	int             matches = 0;

	// first, start out with NULLs
	bestVert[0] = bestVert[1] = bestVert[2] = NULL;

	// brute force through all surfaces
	for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s)
	{
		if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP)
			continue;
		if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader))
			continue;
		for(t = 0; t + 3 <= s->numIndexes; t += 3)
		{
			vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]];
			vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]];
			vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]];
			if(s->surfaceType == MST_PLANAR)
			{
				VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff);
				if(VectorLength(normdiff) >= normalEpsilon)
					continue;
				VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff);
				if(VectorLength(normdiff) >= normalEpsilon)
					continue;
				VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff);
				if(VectorLength(normdiff) >= normalEpsilon)
					continue;
			}
			else
			{
				// this is more prone to roundoff errors, but with embedded
				// models, there is no better way
				VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0);
				VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0);
				CrossProduct(v2v0, v1v0, norm);
				VectorNormalize(norm);
				VectorSubtract(norm, buildPlane->normal, normdiff);
				if(VectorLength(normdiff) >= normalEpsilon)
					continue;
			}
			if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon)
				continue;
			if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon)
				continue;
			if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon)
				continue;
			// Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
			polygon = CopyWinding(buildSide->winding);
			for(i = 0; i < 3; ++i)
			{
				// 0: 1, 2
				// 1: 2, 0
				// 2; 0, 1
				vec3_t         *v1 = &vert[(i + 1) % 3]->xyz;
				vec3_t         *v2 = &vert[(i + 2) % 3]->xyz;
				vec3_t          triNormal;
				vec_t           triDist;
				vec3_t          sideDirection;

				// we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
				VectorSubtract(*v2, *v1, sideDirection);
				CrossProduct(sideDirection, buildPlane->normal, triNormal);
				triDist = DotProduct(*v1, triNormal);
				ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon);
				if(!polygon)
					goto exwinding;
			}
			thisarea = WindingArea(polygon);
			if(thisarea > 0)
				++matches;
			if(thisarea > best)
			{
				best = thisarea;
				bestVert[0] = vert[0];
				bestVert[1] = vert[1];
				bestVert[2] = vert[2];
			}
			FreeWinding(polygon);
		  exwinding:
			;
		}
	}
	//if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
	//  fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
}
コード例 #10
0
ファイル: qcsg.c プロジェクト: 6779660/halflife
/*
===========
CSGBrush
===========
*/
void CSGBrush (int brushnum)
{
	int			hull;
	brush_t		*b1, *b2;
	brushhull_t	*bh1, *bh2;
	int			bn;
	qboolean	overwrite;
	int			i;
	bface_t		*f, *f2, *next, *fcopy;
	bface_t		*outside, *oldoutside;
	entity_t	*e;
	vec_t		area;

	SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL);

	b1 = &mapbrushes[brushnum];

	e = &entities[b1->entitynum];

	for (hull = 0 ; hull<NUM_HULLS ; hull++)
	{
		bh1 = &b1->hulls[hull];

		// set outside to a copy of the brush's faces
		outside = CopyFacesToOutside (bh1);
		overwrite = false;

		for (bn=0 ; bn<e->numbrushes ; bn++)
		{
			// see if b2 needs to clip a chunk out of b1

			if (bn==brushnum)
			{
				overwrite = true;	// later brushes now overwrite
				continue;
			}

			b2 = &mapbrushes[e->firstbrush + bn];
			bh2 = &b2->hulls[hull];

			if (!bh2->faces)
				continue;		// brush isn't in this hull

			// check brush bounding box first
			for (i=0 ; i<3 ; i++)
				if (bh1->mins[i] > bh2->maxs[i] 
				|| bh1->maxs[i] < bh2->mins[i])
					break;
			if (i<3)
				continue;

			// divide faces by the planes of the b2 to find which
			// fragments are inside
		
			f = outside;
			outside = NULL;
			for ( ; f ; f=next)
			{
				next = f->next;

				// check face bounding box first
				for (i=0 ; i<3 ; i++)
					if (bh2->mins[i] > f->maxs[i] 
					|| bh2->maxs[i] < f->mins[i])
						break;
				if (i<3)
				{	// this face doesn't intersect brush2's bbox
					f->next = outside;
					outside = f;
					continue;
				}

				oldoutside = outside;
				fcopy = CopyFace (f);	// save to avoid fake splits

				// throw pieces on the front sides of the planes
				// into the outside list, return the remains on the inside
				for (f2=bh2->faces ; f2 && f ; f2=f2->next)
					f = ClipFace (b1, f, &outside, f2->planenum, overwrite);

				area = f ? WindingArea (f->w) : 0;
				if (f && area < 1.0)
				{
					qprintf ("Entity %i, Brush %i: tiny penetration\n"
						, b1->entitynum, b1->brushnum);
					c_tiny_clip++;
					FreeFace (f);
					f = NULL;
				}
				if (f)
				{
					// there is one convex fragment of the original
					// face left inside brush2
					FreeFace (fcopy);

					if (b1->contents > b2->contents)
					{	// inside a water brush
						f->contents = b2->contents;
						f->next = outside;
						outside = f;
					}
					else	// inside a solid brush
						FreeFace (f);	// throw it away
				}
				else
				{	// the entire thing was on the outside, even
					// though the bounding boxes intersected,
					// which will never happen with axial planes

					// free the fragments chopped to the outside
					while (outside != oldoutside)
					{
						f2 = outside->next;
						FreeFace (outside);
						outside = f2;
					}

					// revert to the original face to avoid
					// unneeded false cuts
					fcopy->next = outside;
					outside = fcopy;
				}
			}

		}

		// all of the faces left in outside are real surface faces
		SaveOutside (b1, hull, outside, b1->contents);
	}
}
コード例 #11
0
ファイル: patches.c プロジェクト: Garux/netradiant-custom
void MakePatchForFace( int fn, winding_t *w ){
	dface_t *f;
	float area;
	patch_t     *patch;
	dplane_t    *pl;
	int i;
	vec3_t color;
	dleaf_t     *leaf;

	f = &dfaces[fn];

	area = WindingArea( w );
	totalarea += area;

	patch = &patches[num_patches];
	if ( num_patches == MAX_PATCHES ) {
		Error( "num_patches == MAX_PATCHES" );
	}
	patch->next = face_patches[fn];
	face_patches[fn] = patch;

	patch->winding = w;

	if ( f->side ) {
		patch->plane = &backplanes[f->planenum];
	}
	else{
		patch->plane = &dplanes[f->planenum];
	}
	if ( face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] ) { // origin offset faces must create new planes
		if ( numplanes + fakeplanes >= MAX_MAP_PLANES ) {
			Error( "numplanes + fakeplanes >= MAX_MAP_PLANES" );
		}
		pl = &dplanes[numplanes + fakeplanes];
		fakeplanes++;

		*pl = *( patch->plane );
		pl->dist += DotProduct( face_offset[fn], pl->normal );
		patch->plane = pl;
	}

	WindingCenter( w, patch->origin );
	VectorAdd( patch->origin, patch->plane->normal, patch->origin );
	leaf = Rad_PointInLeaf( patch->origin );
	patch->cluster = leaf->cluster;
	if ( patch->cluster == -1 ) {
		Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n" );
	}

	patch->area = area;
	if ( patch->area <= 1 ) {
		patch->area = 1;
	}
	patch->sky = IsSky( f );

	VectorCopy( texture_reflectivity[f->texinfo], patch->reflectivity );

	// non-bmodel patches can emit light
	if ( fn < dmodels[0].numfaces ) {
		BaseLightForFace( f, patch->baselight );

		ColorNormalize( patch->reflectivity, color );

		for ( i = 0 ; i < 3 ; i++ )
			patch->baselight[i] *= color[i];

		VectorCopy( patch->baselight, patch->totallight );
	}
	num_patches++;
}
コード例 #12
0
ファイル: l_poly.c プロジェクト: smokin-guns/bspc
//===========================================================================
//
// 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
コード例 #13
0
static void SelectSplitPlaneNum(node_t * node, face_t * list, int *splitPlaneNum, int *compileFlags)
{
	face_t         *split;
	face_t         *check;
	face_t         *bestSplit;
	int             splits, facing, front, back;
	int             side;
	plane_t        *plane;
	int             value, bestValue;
	int             i;
	vec3_t          normal;
	float           dist;
	int             planenum;
	//float           sizeBias;
	//int				checks;
	int				frontC, backC, splitsC, facingC;


	/* ydnar: set some defaults */
	*splitPlaneNum = -1;		/* leaf */
	*compileFlags = 0;

	/* ydnar 2002-06-24: changed this to split on z-axis as well */
	/* ydnar 2002-09-21: changed blocksize to be a vector, so mappers can specify a 3 element value */

	/* if it is crossing a block boundary, force a split */
#if 1
	for(i = 0; i < 3; i++)
	{
		if(blockSize[i] <= 0)
			continue;

		dist = blockSize[i] * (floor(node->mins[i] / blockSize[i]) + 1);
		if(node->maxs[i] > dist)
		{
			VectorClear(normal);
			normal[i] = 1;
			planenum = FindFloatPlane(normal, dist, 0, NULL);
			*splitPlaneNum = planenum;
			return;
		}
	}
#endif

	/* pick one of the face planes */
	bestValue = -99999;
	bestSplit = list;

	//checks = 0;

#if 1
	// div0: this check causes detail/structural mixes
	//for(split = list; split; split = split->next)
	//	split->checked = qfalse;

#if defined(DEBUG_SPLITS)
	Sys_FPrintf(SYS_VRB, "split scores: [");
#endif
	for(split = list; split; split = split->next)
	{
		//if(split->checked)
		//	continue;

		//checks++;

		plane = &mapplanes[split->planenum];
		splits = 0;
		facing = 0;
		front = 0;
		back = 0;

		for(check = list; check; check = check->next)
		{
			if(check->planenum == split->planenum)
			{
				facing++;
				//check->checked = qtrue;   // won't need to test this plane again
				continue;
			}
			side = WindingOnPlaneSide(check->w, plane->normal, plane->dist);
			if(side == SIDE_CROSS)
			{
				splits++;
			}
			else if(side == SIDE_FRONT)
			{
				front++;
			}
			else if(side == SIDE_BACK)
			{
				back++;
			}
		}

		if(bspAlternateSplitWeights)
		{
			//Base score = 20000 perfectly balanced
			value = 0;//20000;
			value -= abs(front - back);	// prefer centered planes
			value -= plane->counter;	// if we've already used this plane sometime in the past try not to use it again
			value += facing * 5;		// if we're going to have alot of other surfs use this plane, we want to get it in quickly.
			value -= splits * 5;		// more splits = bad
			//value += sizeBias * 10;		// we want a huge score bias based on plane size

			if(plane->type < 3)
			{
				value += 5;		// axial is better
			}

			// we want a huge score bias based on plane size
			#if 0
			{
				winding_t      *w;
				node_t         *n;
				plane_t        *plane;
				vec3_t          normal;
				vec_t           dist;

				// create temporary winding to draw the split plane
				w = CopyWinding(split->w);

				// clip by all the parents
				for(n = node->parent; n && w;)
				{
					plane = &mapplanes[n->planenum];

					if(n->children[0] == node)
					{
						// take front
						ChopWindingInPlace(&w, plane->normal, plane->dist, 0.001);	// BASE_WINDING_EPSILON
					}
					else
					{
						// take back
						VectorNegate(plane->normal, normal);
						dist = -plane->dist;
						ChopWindingInPlace(&w, normal, dist, 0.001); // BASE_WINDING_EPSILON
					}
					node = n;
					n = n->parent;
				}

				// clip by node AABB
				if(w != NULL)
					ChopWindingByBounds(&w, node->mins, node->maxs, CLIP_EPSILON);

				if(w != NULL)
					value += WindingArea(w);
			}
			#endif
		}
		else
		{
			value = 5 * facing - 5 * splits;	// - abs(front-back);
			if(plane->type < 3)
			{
				value += 5;		// axial is better
			}
		}

		value += split->priority;	// prioritize hints higher

		#if defined(DEBUG_SPLITS)
		Sys_FPrintf(SYS_VRB, " %d", value);
		#endif

		if(value > bestValue)
		{
			bestValue = value;
			bestSplit = split;

			frontC = front;
			backC = back;
			splitsC = splits;
			facingC = facing;
		}
	}
#if defined(DEBUG_SPLITS)
	Sys_FPrintf(SYS_VRB, "]\n");
#endif

#endif

	/* nothing, we have a leaf */
	if(bestValue == -99999)
		return;

	//Sys_FPrintf(SYS_VRB, "F: %9d B:%9d S:%9d FA:%9d\n", frontC, backC, splitsC, facingC);

	/* set best split data */
	*splitPlaneNum = bestSplit->planenum;
	*compileFlags = bestSplit->compileFlags;

#if defined(DEBUG_SPLITS)
	if(bestSplit->compileFlags & C_DETAIL)
		for(split = list; split; split = split->next)
			if(!(split->compileFlags & C_DETAIL))
				Sys_FPrintf(SYS_ERR, "DON'T DO SUCH SPLITS (1)\n");
	if((node->compileFlags & C_DETAIL) && !(bestSplit->compileFlags & C_DETAIL))
		Sys_FPrintf(SYS_ERR, "DON'T DO SUCH SPLITS (2)\n");
#endif

	if(*splitPlaneNum > -1)
		mapplanes[*splitPlaneNum].counter++;
}
コード例 #14
0
ファイル: writebsp.cpp プロジェクト: Baer42/source-sdk-2013
/*
==================
EmitFace
==================
*/
void EmitFace( face_t *f, qboolean onNode )
{
	dface_t	*df;
	int		i;
	int		e;

//	void SubdivideFaceBySubdivSize( face_t *f ); // garymcthack
//	SubdivideFaceBySubdivSize( f );
    
	// set initial output number
	f->outputnumber = -1;

    // degenerated
	if( f->numpoints < 3 )
		return;
    
    // not a final face
	if( f->merged || f->split[0] || f->split[1] )
		return;

	// don't emit NODRAW faces for runtime
	if ( texinfo[f->texinfo].flags & SURF_NODRAW )
	{
		// keep NODRAW terrain surfaces though
		if ( f->dispinfo == -1 )
			return;
		Warning("NODRAW on terrain surface!\n");
	}

	// save output number so leaffaces can use
	f->outputnumber = numfaces;

    //
    // get the next available .bsp face slot
    //
	if (numfaces >= MAX_MAP_FACES)
		Error( "Too many faces in map, max = %d", MAX_MAP_FACES );
	df = &dfaces[numfaces];

	// Save the correlation between dfaces and faces -- since dfaces doesnt have worldcraft face id
	dfaceids.AddToTail();
	dfaceids[numfaces].hammerfaceid = f->originalface->id;

	numfaces++;

    //
	// plane info - planenum is used by qlight, but not quake
    //
	df->planenum = f->planenum;
	df->onNode = onNode;
	df->side = f->planenum & 1;
    
    //
    // material info
    //
	df->texinfo = f->texinfo;
	df->dispinfo = f->dispinfo;
	df->smoothingGroups = f->smoothingGroups;

    // save the original "side"/face data
    df->origFace = FindOrCreateOrigFace( f );
	df->surfaceFogVolumeID = -1;
	dfacenodes[numfaces-1] = f->fogVolumeLeaf;
	if ( f->fogVolumeLeaf )
	{
		Assert( f->fogVolumeLeaf->planenum == PLANENUM_LEAF );
	}

    //
    // edge info
    //
	df->firstedge = numsurfedges;
	df->numedges = f->numpoints;

	// UNDONE: Nodraw faces have no winding - revisit to see if this is necessary
	if ( f->w )
	{
		df->area = WindingArea( f->w );
	}
	else
	{
		df->area = 0;
	}

	df->firstPrimID = f->firstPrimID;
	df->SetNumPrims( f->numPrims );
	df->SetDynamicShadowsEnabled( f->originalface->m_bDynamicShadowsEnabled );

    //
    // save off points -- as edges
    //
	for( i = 0; i < f->numpoints; i++ )
	{
		//e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f);
		e = GetEdge2 (f->vertexnums[i], f->vertexnums[(i+1)%f->numpoints], f);

		if (numsurfedges >= MAX_MAP_SURFEDGES)
			Error( "Too much brush geometry in bsp, numsurfedges == MAX_MAP_SURFEDGES" );                
		dsurfedges[numsurfedges] = e;
		numsurfedges++;
	}

	// Create overlay face lists.
	side_t *pSide = f->originalface;
	if ( pSide )
	{
		int nOverlayCount = pSide->aOverlayIds.Count();
		if ( nOverlayCount > 0 )
		{
			Overlay_AddFaceToLists( ( numfaces - 1 ), pSide );
		}

		nOverlayCount = pSide->aWaterOverlayIds.Count();
		if ( nOverlayCount > 0 )
		{
			OverlayTransition_AddFaceToLists( ( numfaces - 1 ), pSide );
		}
	}
}