winding.cpp
来自「quake3工具源码。包括生成bsp文件」· C++ 代码 · 共 797 行 · 第 1/2 页
CPP
797 行
for (i=0 ; i<in->numpoints ; i++)
{
p1 = in->points[i];
if (sides[i] == SIDE_ON)
{
VectorCopy (p1, neww->points[neww->numpoints]);
neww->numpoints++;
continue;
}
if (sides[i] == SIDE_FRONT)
{
VectorCopy (p1, neww->points[neww->numpoints]);
neww->numpoints++;
}
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
continue;
// generate a split point
p2 = in->points[(i+1)%in->numpoints];
dot = dists[i] / (dists[i]-dists[i+1]);
for (j=0 ; j<3 ; j++)
{ // avoid round off error when possible
if (split->normal[j] == 1)
mid[j] = split->dist;
else if (split->normal[j] == -1)
mid[j] = -split->dist;
else
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
}
VectorCopy (mid, neww->points[neww->numpoints]);
neww->numpoints++;
}
if (neww->numpoints > maxpts)
Error ("Winding_Clip: points exceeded estimate");
// free the original winding
Winding_Free (in);
return neww;
}
/*
=============
Winding_SplitEpsilon
split the input winding with the plane
the input winding stays untouched
=============
*/
void Winding_SplitEpsilon (winding_t *in, vec3_t normal, double dist,
vec_t epsilon, winding_t **front, winding_t **back)
{
vec_t dists[MAX_POINTS_ON_WINDING+4];
int sides[MAX_POINTS_ON_WINDING+4];
int counts[3];
vec_t dot;
int i, j;
vec_t *p1, *p2;
vec3_t mid;
winding_t *f, *b;
int maxpts;
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for (i = 0; i < in->numpoints; i++)
{
dot = DotProduct (in->points[i], normal);
dot -= dist;
dists[i] = dot;
if (dot > epsilon)
sides[i] = SIDE_FRONT;
else if (dot < -epsilon)
sides[i] = SIDE_BACK;
else
{
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
*front = *back = NULL;
if (!counts[0])
{
*back = Winding_Clone(in);
return;
}
if (!counts[1])
{
*front = Winding_Clone(in);
return;
}
maxpts = in->numpoints+4; // cant use counts[0]+2 because
// of fp grouping errors
*front = f = Winding_Alloc (maxpts);
*back = b = Winding_Alloc (maxpts);
for (i = 0; i < in->numpoints; i++)
{
p1 = in->points[i];
if (sides[i] == SIDE_ON)
{
VectorCopy (p1, f->points[f->numpoints]);
f->numpoints++;
VectorCopy (p1, b->points[b->numpoints]);
b->numpoints++;
continue;
}
if (sides[i] == SIDE_FRONT)
{
VectorCopy (p1, f->points[f->numpoints]);
f->numpoints++;
}
if (sides[i] == SIDE_BACK)
{
VectorCopy (p1, b->points[b->numpoints]);
b->numpoints++;
}
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
continue;
// generate a split point
p2 = in->points[(i+1)%in->numpoints];
dot = dists[i] / (dists[i]-dists[i+1]);
for (j = 0; j < 3; j++)
{
// avoid round off error when possible
if (normal[j] == 1)
mid[j] = dist;
else if (normal[j] == -1)
mid[j] = -dist;
else
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
}
VectorCopy (mid, f->points[f->numpoints]);
f->numpoints++;
VectorCopy (mid, b->points[b->numpoints]);
b->numpoints++;
}
if (f->numpoints > maxpts || b->numpoints > maxpts)
Error ("Winding_Clip: points exceeded estimate");
if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
Error ("Winding_Clip: MAX_POINTS_ON_WINDING");
}
/*
=============
Winding_TryMerge
If two windings share a common edge and the edges that meet at the
common points are both inside the other polygons, merge them
Returns NULL if the windings couldn't be merged, or the new winding.
The originals will NOT be freed.
if keep is true no points are ever removed
=============
*/
#define CONTINUOUS_EPSILON 0.005
winding_t *Winding_TryMerge(winding_t *f1, winding_t *f2, vec3_t planenormal, int keep)
{
vec_t *p1, *p2, *p3, *p4, *back;
winding_t *newf;
int i, j, k, l;
vec3_t normal, delta;
vec_t dot;
qboolean keep1, keep2;
//
// find a common edge
//
p1 = p2 = NULL; // stop compiler warning
j = 0; //
for (i = 0; i < f1->numpoints; i++)
{
p1 = f1->points[i];
p2 = f1->points[(i+1) % f1->numpoints];
for (j = 0; j < f2->numpoints; j++)
{
p3 = f2->points[j];
p4 = f2->points[(j+1) % f2->numpoints];
for (k = 0; k < 3; k++)
{
if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME
break;
if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME
break;
} //end for
if (k==3)
break;
} //end for
if (j < f2->numpoints)
break;
} //end for
if (i == f1->numpoints)
return NULL; // no matching edges
//
// check slope of connected lines
// if the slopes are colinear, the point can be removed
//
back = f1->points[(i+f1->numpoints-1)%f1->numpoints];
VectorSubtract (p1, back, delta);
CrossProduct (planenormal, delta, normal);
VectorNormalize (normal);
back = f2->points[(j+2)%f2->numpoints];
VectorSubtract (back, p1, delta);
dot = DotProduct (delta, normal);
if (dot > CONTINUOUS_EPSILON)
return NULL; // not a convex polygon
keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON);
back = f1->points[(i+2)%f1->numpoints];
VectorSubtract (back, p2, delta);
CrossProduct (planenormal, delta, normal);
VectorNormalize (normal);
back = f2->points[(j+f2->numpoints-1)%f2->numpoints];
VectorSubtract (back, p2, delta);
dot = DotProduct (delta, normal);
if (dot > CONTINUOUS_EPSILON)
return NULL; // not a convex polygon
keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON);
//
// build the new polygon
//
newf = Winding_Alloc (f1->numpoints + f2->numpoints);
// copy first polygon
for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
{
if (!keep && k==(i+1)%f1->numpoints && !keep2)
continue;
VectorCopy (f1->points[k], newf->points[newf->numpoints]);
newf->numpoints++;
}
// copy second polygon
for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
{
if (!keep && l==(j+1)%f2->numpoints && !keep1)
continue;
VectorCopy (f2->points[l], newf->points[newf->numpoints]);
newf->numpoints++;
}
return newf;
}
/*
============
Winding_Plane
============
*/
void Winding_Plane (winding_t *w, vec3_t normal, double *dist)
{
vec3_t v1, v2;
int i;
//find two vectors each longer than 0.5 units
for (i = 0; i < w->numpoints; i++)
{
VectorSubtract(w->points[(i+1) % w->numpoints], w->points[i], v1);
VectorSubtract(w->points[(i+2) % w->numpoints], w->points[i], v2);
if (VectorLength(v1) > 0.5 && VectorLength(v2) > 0.5) break;
}
CrossProduct(v2, v1, normal);
VectorNormalize(normal);
*dist = DotProduct(w->points[0], normal);
}
/*
=============
Winding_Area
=============
*/
float Winding_Area (winding_t *w)
{
int i;
vec3_t d1, d2, cross;
float total;
total = 0;
for (i=2 ; i<w->numpoints ; i++)
{
VectorSubtract (w->points[i-1], w->points[0], d1);
VectorSubtract (w->points[i], w->points[0], d2);
CrossProduct (d1, d2, cross);
total += 0.5 * VectorLength ( cross );
}
return total;
}
/*
=============
Winding_Bounds
=============
*/
void Winding_Bounds (winding_t *w, vec3_t mins, vec3_t maxs)
{
vec_t v;
int i,j;
mins[0] = mins[1] = mins[2] = 99999;
maxs[0] = maxs[1] = maxs[2] = -99999;
for (i=0 ; i<w->numpoints ; i++)
{
for (j=0 ; j<3 ; j++)
{
v = w->points[i][j];
if (v < mins[j])
mins[j] = v;
if (v > maxs[j])
maxs[j] = v;
}
}
}
/*
=================
Winding_PointInside
=================
*/
int Winding_PointInside(winding_t *w, plane_t *plane, vec3_t point, float epsilon)
{
int i;
vec3_t dir, normal, pointvec;
for (i = 0; i < w->numpoints; i++)
{
VectorSubtract(w->points[(i+1) % w->numpoints], w->points[i], dir);
VectorSubtract(point, w->points[i], pointvec);
//
CrossProduct(dir, plane->normal, normal);
//
if (DotProduct(pointvec, normal) < -epsilon) return false;
}
return true;
}
/*
=================
Winding_VectorIntersect
=================
*/
int Winding_VectorIntersect(winding_t *w, plane_t *plane, vec3_t p1, vec3_t p2, float epsilon)
{
float front, back, frac;
vec3_t mid;
front = DotProduct(p1, plane->normal) - plane->dist;
back = DotProduct(p2, plane->normal) - plane->dist;
//if both points at the same side of the plane
if (front < -epsilon && back < -epsilon) return false;
if (front > epsilon && back > epsilon) return false;
//get point of intersection with winding plane
if (fabs(front-back) < 0.001)
{
VectorCopy(p2, mid);
}
else
{
frac = front/(front-back);
mid[0] = p1[0] + (p2[0] - p1[0]) * frac;
mid[1] = p1[1] + (p2[1] - p1[1]) * frac;
mid[2] = p1[2] + (p2[2] - p1[2]) * frac;
}
return Winding_PointInside(w, plane, mid, epsilon);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?