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 + -
显示快捷键?