brush.cpp

来自「quake3工具源码。包括生成bsp文件」· C++ 代码 · 共 2,619 行 · 第 1/5 页

CPP
2,619
字号
	}
#endif

	if (g_qeglobals.d_savedinfo.show_names)
	{
		name = ValueForKey (b->owner, "classname");
		qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4);
		qglCallLists (strlen(name), GL_UNSIGNED_BYTE, name);
	}
}

/*
=================
Brush_MakeFaceWinding

returns the visible polygon on a face
=================
*/
winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face)
{
	winding_t	*w;
	face_t		*clip;
	plane_t			plane;
	qboolean		past;

	// get a poly that covers an effectively infinite area
	w = Winding_BaseForPlane (&face->plane);

	// chop the poly by all of the other faces
	past = false;
	for (clip = b->brush_faces ; clip && w ; clip=clip->next)
	{
		if (clip == face)
		{
			past = true;
			continue;
		}
		if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999
			&& fabs(face->plane.dist - clip->plane.dist) < 0.01 )
		{	// identical plane, use the later one
			if (past)
			{
				free (w);
				return NULL;
			}
			continue;
		}

		// flip the plane, because we want to keep the back side
		VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);
		plane.dist = -clip->plane.dist;
		
		w = Winding_Clip (w, &plane, false);
		if (!w)
			return w;
	}
	
	if (w->numpoints < 3)
	{
		free(w);
		w = NULL;
	}

	if (!w)
		printf ("unused plane\n");

	return w;
}

/*
=================
Brush_SnapPlanepts
=================
*/
void Brush_SnapPlanepts (brush_t *b)
{
	int		i, j;
	face_t	*f;

  if (g_PrefsDlg.m_bNoClamp)
    return;

	for (f=b->brush_faces ; f; f=f->next)
		for (i=0 ; i<3 ; i++)
			for (j=0 ; j<3 ; j++)
				f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);
}
	
/*
** Brush_Build
**
** Builds a brush rendering data and also sets the min/max bounds
*/
// TTimo
// added a bConvert flag to convert between old and new brush texture formats
// TTimo
// brush grouping: update the group treeview if necessary
void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert )
{
	bool		bLocalConvert;

#ifdef _DEBUG
	if (!g_qeglobals.m_bBrushPrimitMode && bConvert)
		Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n");
#endif

	// if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only
	if (bConvert && !g_qeglobals.bNeedConvert)
	{
		bLocalConvert = true;
		g_qeglobals.bNeedConvert = true;
	}

	/*
	** build the windings and generate the bounding box
	*/
	Brush_BuildWindings(b, bSnap);

	Patch_BuildPoints (b);

	/*
	** move the points and edges if in select mode
	*/
	if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
		SetupVertexSelection ();

    if (b->itemOwner == NULL)
      Group_AddToProperGroup(b);

	if (bMarkMap)
	{
		Sys_MarkMapModified();
	}

	if (bLocalConvert)
		g_qeglobals.bNeedConvert = false;
}

/*
==============
Brush_SplitBrushByFace

The incoming brush is NOT freed.
The incoming face is NOT left referenced.
==============
*/
void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back)
{
	brush_t	*b;
	face_t	*nf;
	vec3_t	temp;

	b = Brush_Clone (in);
	nf = Face_Clone (f);

	nf->texdef = b->brush_faces->texdef;
	nf->next = b->brush_faces;
	b->brush_faces = nf;

	Brush_Build( b );
	Brush_RemoveEmptyFaces ( b );
	if ( !b->brush_faces )
	{	// completely clipped away
		Brush_Free (b);
		*back = NULL;
	}
	else
	{
		Entity_LinkBrush (in->owner, b);
		*back = b;
	}

	b = Brush_Clone (in);
	nf = Face_Clone (f);
	// swap the plane winding
	VectorCopy (nf->planepts[0], temp);
	VectorCopy (nf->planepts[1], nf->planepts[0]);
	VectorCopy (temp, nf->planepts[1]);

	nf->texdef = b->brush_faces->texdef;
	nf->next = b->brush_faces;
	b->brush_faces = nf;

	Brush_Build( b );
	Brush_RemoveEmptyFaces ( b );
	if ( !b->brush_faces )
	{	// completely clipped away
		Brush_Free (b);
		*front = NULL;
	}
	else
	{
		Entity_LinkBrush (in->owner, b);
		*front = b;
	}
}

/*
=================
Brush_BestSplitFace

returns the best face to split the brush with.
return NULL if the brush is convex
=================
*/
face_t *Brush_BestSplitFace(brush_t *b)
{
	face_t *face, *f, *bestface;
	winding_t *front, *back;
	int splits, tinywindings, value, bestvalue;

	bestvalue = 999999;
	bestface = NULL;
	for (face = b->brush_faces; face; face = face->next)
	{
		splits = 0;
		tinywindings = 0;
		for (f = b->brush_faces; f; f = f->next)
		{
			if (f == face) continue;
			//
			Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1, &front, &back);

			if (!front)
			{
				Winding_Free(back);
			}
			else if (!back)
			{
				Winding_Free(front);
			}
			else
			{
				splits++;
				if (Winding_IsTiny(front)) tinywindings++;
				if (Winding_IsTiny(back)) tinywindings++;
			}
		}
		if (splits)
		{
			value = splits + 50 * tinywindings;
			if (value < bestvalue)
			{
				bestvalue = value;
				bestface = face;
			}
		}
	}
	return bestface;
}

/*
=================
Brush_MakeConvexBrushes

MrE FIXME: this doesn't work because the old
		   Brush_SplitBrushByFace is used
Turns the brush into a minimal number of convex brushes.
If the input brush is convex then it will be returned.
Otherwise the input brush will be freed.
NOTE: the input brush should have windings for the faces.
=================
*/
brush_t *Brush_MakeConvexBrushes(brush_t *b)
{
	brush_t *front, *back, *end;
	face_t *face;

	b->next = NULL;
	face = Brush_BestSplitFace(b);
	if (!face) return b;
	Brush_SplitBrushByFace(b, face, &front, &back);
	//this should never happen
	if (!front && !back) return b;
	Brush_Free(b);
	if (!front)
		return Brush_MakeConvexBrushes(back);
	b = Brush_MakeConvexBrushes(front);
	if (back)
	{
		for (end = b; end->next; end = end->next);
		end->next = Brush_MakeConvexBrushes(back);
	}
	return b;
}

/*
=================
Brush_Convex
=================
*/
int Brush_Convex(brush_t *b)
{
	face_t *face1, *face2;

	for (face1 = b->brush_faces; face1; face1 = face1->next)
	{
		if (!face1->face_winding) continue;
		for (face2 = b->brush_faces; face2; face2 = face2->next)
		{
			if (face1 == face2) continue;
			if (!face2->face_winding) continue;
			if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,
										face1->plane.normal, face2->plane.normal,
										face1->plane.dist, face2->plane.dist))
			{
				return false;
			}
		}
	}
	return true;
}

/*
=================
Brush_MoveVertexes_old1

- The input brush must have face windings.
- The input brush must be a brush with faces that do not intersect.
- The input brush does not have to be convex.
- The vertex will not be moved if the movement either causes the
  brush to have faces that intersect or causes the brush to be
  flipped inside out.
  (For instance a tetrahedron can easily be flipped inside out
  without having faces that intersect.)
- The created brush does not have to be convex.
- Returns true if the vertex movement is performed.
=================
*/

#define MAX_MOVE_FACES		64
#define INTERSECT_EPSILON	0.1
#define POINT_EPSILON		0.3

int Brush_MoveVertex_old1(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)
{
	face_t *f, *face, *newface, *lastface, *nextface;
	face_t *movefaces[MAX_MOVE_FACES];
	int movefacepoints[MAX_MOVE_FACES];
	winding_t *w, tmpw;
	int i, j, k, nummovefaces, result;
	float dot;

	result = false;
	//
	tmpw.numpoints = 3;
	tmpw.maxpoints = 3;
	VectorAdd(vertex, delta, end);
	//snap or not?
	if (bSnap)
		for (i = 0; i < 3; i++)
			end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
	//chop off triangles from all brush faces that use the to be moved vertex
	//store pointers to these chopped off triangles in movefaces[]
	nummovefaces = 0;
	for (face = b->brush_faces; face; face = face->next)
	{
		w = face->face_winding;
		if (!w) continue;
		for (i = 0; i < w->numpoints; i++)
		{
			if (Point_Equal(w->points[i], vertex, POINT_EPSILON))
			{
				if (face->face_winding->numpoints <= 3)
				{
					movefacepoints[nummovefaces] = i;
					movefaces[nummovefaces++] = face;
					break;
				}
				dot = DotProduct(end, face->plane.normal) - face->plane.dist;
				//if the end point is in front of the face plane
				if (dot > 0.1)
				{
					//fanout triangle subdivision
					for (k = i; k < i + w->numpoints-3; k++)
					{
						VectorCopy(w->points[i], tmpw.points[0]);
						VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);
						VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);
						//
						newface = Face_Clone(face);
						//get the original
						for (f = face; f->original; f = f->original) ;
						newface->original = f;
						//store the new winding
						if (newface->face_winding) Winding_Free(newface->face_winding);
						newface->face_winding = Winding_Clone(&tmpw);
						//get the texture
						newface->d_texture = Texture_ForName( newface->texdef.name );
						//add the face to the brush
						newface->next = b->brush_faces;
						b->brush_faces = newface;
						//add this new triangle to the move faces
						movefacepoints[nummovefaces] = 0;
						movefaces[nummovefaces++] = newface;
					}
					//give the original face a new winding
					VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);
					VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);
					VectorCopy(w->points[i], tmpw.points[2]);
					Winding_Free(face->face_winding);
					face->face_winding = Winding_Clone(&tmpw);
					//add the original face to the move faces
					movefacepoints[nummovefaces] = 2;
					movefaces[nummovefaces++] = face;
				}
				else
				{
					//chop a triangle off the face
					VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);
					VectorCopy(w->points[i], tmpw.points[1]);
					VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]);
					//remove the point from the face winding
					Winding_RemovePoint(w, i);
					//get texture crap right
					Face_SetColor(b, face, 1.0);
					for (j = 0; j < w->numpoints; j++)
						EmitTextureCoordinates(w->points[j], face->d_texture, face);
					//make a triangle face
					newface = Face_Clone(face);
					//get the original
					for (f = face; f->original; f = f->original) ;
					newface->original = f;
					//store the new winding
					if (newface->face_winding) Winding_Free(newface->face_winding);
					newface->face_winding = Winding_Clone(&tmpw);
					//get the texture
					newface->d_texture = Texture_ForName( newface->texdef.name );
					//add the face to the brush
					newface->next = b->brush_faces;
					b->brush_faces = newface;
					//
					movefacepoints[nummovefaces] = 1;
					movefaces[nummovefaces++] = newface;
				}
				break;
			}
		}
	}
	//now movefaces contains pointers to triangle faces that
	//contain the to be moved vertex

	//check if the move is valid
	int l;
	vec3_t p1, p2;
	winding_t *w2;
	plane_t plane;

	face = NULL;
	VectorCopy(vertex, tmpw.points[1]);
	VectorCopy(end, tmpw.points[2]);
	for (face = b->brush_faces; face; face = face->next)
	{
		for (i = 0; i < nummovefaces; i++)
		{
			if (face == movefaces[i])
				break;
		}
		if (i < nummovefaces)
			continue;
		//the delta vector may not intersect with any of the not move faces
		if (Winding_VectorIntersect(face->face_winding, &face->plane, vertex, end, INTERSECT_EPSILON))
			break;
		//if the end point of the to be moved vertex is near this not move face
		if (abs(DotProduct(face->plane.normal, end) - face->plane.dist) < 0.5)
		{
			//the end point may not be inside or very close to the not move face winding
			if (Winding_PointInside(face->face_winding, &face->plane, end, 0.5))
				break;
		}
		for (i = 0; i < nummovefaces; i++)
		{
			w = movefaces[i]->face_winding;
			j = movefacepoints[i];
			for (k = -1; k <= 1; k += 2)
			{
				//check if the new edge will not intersect with the not move face
				VectorCopy(w->points[(j + k + w->numpoints) % w->numpoints], tmpw.points[0]);
				if (Winding_VectorIntersect(face->face_winding, &face->plane, tmpw.points[0], end, INTERSECT_EPSILON))
				{
					//ok the new edge instersects with the not move face
					//we can't perform the vertex movement
					//break;
				}
				//check if the not move face intersects the "movement winding"
				Winding_Plane(&tmpw, plane.normal, &plane.dist);
				w2 = face->face_winding;
				for (l = 0; l < w2->numpoints; l++)
				{
					VectorCopy(w2->points[l], p1);
					if (Point_Equal(p1, tmpw.points[0], POINT_EPSILON)) continue;
					VectorCopy(w2->points[(l+1) % w2->numpoints], p2);
					if (Point_Equal(p2, tmpw.points[0], POINT_EPSILON)) continue;
					if (Winding_VectorIntersect(&tmpw, &plane, p1, p2, INTERSECT_EPSILON))
						break;
				}
				if (l < w2->numpoints)
				{
					//ok this not move face intersects the "movement winding"
					//we can't perform the vertex movement
					break;
				}
			}
			if (k <= 1) break;
		}
		if (i < nummovefaces)
			break;
	}
	if (!face)
	{
		//ok the move was valid
		//now move all the vertexes of the movefaces
		for (i = 0; i < nummovefaces; i++)
		{
			VectorCopy(end, movefaces[i]->face_winding->points[movefacepoints[i]]);
			//create new face plane
			for (j = 0; j < 3; j++)
			{
				VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
			}
			Face_MakePlane(movefaces[i]);
		}
		result = true;
	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?