//----------------------------------------------------------------------------- // Purpose: Check to see if the SSolid with displacement surfaces has valid // base face surfaces. //----------------------------------------------------------------------------- bool CSSolid::IsValidWithDisps( void ) { if ( !HasDisps() ) return true; for ( int iFace = 0; iFace < m_nFaces; ++iFace ) { // Get the face(s) that have displacements. CSSFace *pFace = &m_Faces[iFace]; if ( pFace->m_hDisp == EDITDISPHANDLE_INVALID ) continue; // Create a face point list. Vector *pFacePoints = CreatePointList( *pFace ); // If the face has changed the number of points - via merges, etc. if ( pFace->nEdges != 4 ) return false; // Check the face for validity. CCheckFaceInfo faceInfo; if ( !CheckFace( pFacePoints, pFace->nEdges, NULL, 0.0f, &faceInfo ) ) return false; } return true; }
// check faces for irregularities -> void CSSolid::CheckFaces() { for(int i = 0; i < m_nFaces; i++) { CSSFace &face = m_Faces[i]; // get points for face Vector *pts = CreatePointList(face); // call checkface function CCheckFaceInfo cfi; while(CheckFace(pts, face.nEdges, NULL, 0, &cfi) == FALSE) { CString str; str.Format("face %d - %s", i, cfi.szDescription); AfxMessageBox(str); } delete[] pts; } }
void CreateBrushFaces (void) { int i,j, k; vec_t r; face_t *f; winding_t *w; plane_t plane; mface_t *mf; brush_mins[0] = brush_mins[1] = brush_mins[2] = 99999; brush_maxs[0] = brush_maxs[1] = brush_maxs[2] = -99999; brush_faces = NULL; for (i=0 ; i<numbrushfaces ; i++) { mf = &faces[i]; w = BaseWindingForPlane (&mf->plane); for (j=0 ; j<numbrushfaces && w ; j++) { if (j == i) continue; // flip the plane, because we want to keep the back side VectorSubtract (vec3_origin,faces[j].plane.normal, plane.normal); plane.dist = -faces[j].plane.dist; w = ClipWinding (w, &plane, false); } if (!w) continue; // overcontrained plane // this face is a keeper f = AllocFace (); f->numpoints = w->numpoints; if (f->numpoints > MAXEDGES) Error ("f->numpoints > MAXEDGES"); for (j=0 ; j<w->numpoints ; j++) { for (k=0 ; k<3 ; k++) { r = Q_rint (w->points[j][k]); if ( fabs(w->points[j][k] - r) < ZERO_EPSILON) f->pts[j][k] = r; else f->pts[j][k] = w->points[j][k]; if (f->pts[j][k] < brush_mins[k]) brush_mins[k] = f->pts[j][k]; if (f->pts[j][k] > brush_maxs[k]) brush_maxs[k] = f->pts[j][k]; } } FreeWinding (w); f->texturenum = mf->texinfo; f->planenum = FindPlane (&mf->plane, &f->planeside); f->next = brush_faces; brush_faces = f; CheckFace (f); } }
/* ================== SplitFace ================== */ void SplitFace (face_t *in, plane_t *split, face_t **front, face_t **back) { double dists[MAXEDGES+1]; int sides[MAXEDGES+1]; int counts[3]; double dot; int i, j; face_t *newf, *new2; double *p1, *p2; vec3_t mid; if (in->numpoints < 0) Error ("%s: freed face", __thisfunc__); counts[0] = counts[1] = counts[2] = 0; // determine sides for each point for (i = 0 ; i < in->numpoints ; i++) { dot = DotProduct (in->pts[i], split->normal); dot -= split->dist; dists[i] = dot; if (dot > ON_EPSILON) sides[i] = SIDE_FRONT; else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK; else sides[i] = SIDE_ON; counts[sides[i]]++; } sides[i] = sides[0]; dists[i] = dists[0]; if (!counts[0]) { *front = NULL; *back = in; return; } if (!counts[1]) { *front = in; *back = NULL; return; } *back = newf = NewFaceFromFace (in); *front = new2 = NewFaceFromFace (in); // distribute the points and generate splits for (i = 0 ; i < in->numpoints ; i++) { if (newf->numpoints > MAXEDGES || new2->numpoints > MAXEDGES) Error ("%s: numpoints > MAXEDGES", __thisfunc__); p1 = in->pts[i]; if (sides[i] == SIDE_ON) { VectorCopy (p1, newf->pts[newf->numpoints]); newf->numpoints++; VectorCopy (p1, new2->pts[new2->numpoints]); new2->numpoints++; continue; } if (sides[i] == SIDE_FRONT) { VectorCopy (p1, new2->pts[new2->numpoints]); new2->numpoints++; } else { VectorCopy (p1, newf->pts[newf->numpoints]); newf->numpoints++; } if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) continue; // generate a split point p2 = in->pts[(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, newf->pts[newf->numpoints]); newf->numpoints++; VectorCopy (mid, new2->pts[new2->numpoints]); new2->numpoints++; } if (newf->numpoints > MAXEDGES || new2->numpoints > MAXEDGES) Error ("%s: numpoints > MAXEDGES", __thisfunc__); #if 0 CheckFace (newf); CheckFace (new2); #endif // free the original face now that is is represented by the fragments FreeFace (in); }
void CreateBrushFaces (void) { int i, j, k; vec3_t offset, point; vec_t r, max, min; face_t *f; winding_t *w; plane_t plane; mface_t *mf; qboolean IsRotate; offset[0] = offset[1] = offset[2] = 0; min = brush_mins[0] = brush_mins[1] = brush_mins[2] = 99999; max = brush_maxs[0] = brush_maxs[1] = brush_maxs[2] = -99999; // Hipnotic rotation IsRotate = !strncmp(ValueForKey(CurrEnt, "classname"), "rotate_", 7); if (IsRotate) FixRotateOrigin(CurrEnt, offset); brush_faces = NULL; for (i=0 ; i<numbrushfaces ; i++) { mf = &faces[i]; w = BaseWindingForPlane (&mf->plane); for (j=0 ; j<numbrushfaces && w ; j++) { if (j == i) continue; // flip the plane, because we want to keep the back side VectorSubtract (vec3_origin,faces[j].plane.normal, plane.normal); plane.dist = -faces[j].plane.dist; w = ClipWinding (w, &plane, false); } if (!w) continue; // overcontrained plane // this face is a keeper f = AllocFace (); ResizeFace (f, w->numpoints); if (f->numpoints > MAXEDGES) Message (MSGERR, "f->numpoints (%d) > MAXEDGES (%d)", f->numpoints, MAXEDGES); for (j=0 ; j<w->numpoints ; j++) { for (k=0 ; k<3 ; k++) { point[k] = w->points[j][k] - offset[k]; r = Q_rint(point[k]); if (fabs(point[k] - r) < ZERO_EPSILON) f->pts[j][k] = r; else f->pts[j][k] = point[k]; if (f->pts[j][k] < brush_mins[k]) brush_mins[k] = f->pts[j][k]; if (f->pts[j][k] > brush_maxs[k]) brush_maxs[k] = f->pts[j][k]; if (IsRotate) { if (f->pts[j][k] < min) min = f->pts[j][k]; if (f->pts[j][k] > max) max = f->pts[j][k]; } } } if (!IsRotate) plane = mf->plane; else { VectorCopy(mf->plane.normal, plane.normal); VectorScale(mf->plane.normal, mf->plane.dist, point); VectorSubtract(point, offset, point); plane.dist = DotProduct(plane.normal, point); } FreeWinding (w); f->texturenum = hullnum ? 0 : mf->texinfo; f->planenum = FindPlane (&plane, &f->planeside); f->next = brush_faces; brush_faces = f; CheckFace (f); } // Rotatable objects must have a bounding box big enough to // account for all its rotations if (IsRotate) { vec_t delta; delta = fabs(max); if (fabs(min) > delta) delta = fabs(min); for (k=0; k<3; k++) { brush_mins[k] = -delta; brush_maxs[k] = delta; } } }
/* ================= CheckFace Note: this will not catch 0 area polygons ================= */ void CheckFace (face_t *f) { int i, j; vec_t *p1, *p2; vec_t d, edgedist; vec3_t dir, edgenormal, facenormal; if (f->numpoints < 3) Message (MSGWARN, "CheckFace: Face with too few (%i) points at %s", f->numpoints, GetCoord (f->pts[0])); VectorCopy (planes[f->planenum].normal, facenormal); if (f->planeside) { VectorSubtract (vec3_origin, facenormal, facenormal); } for (i=0 ; i<f->numpoints ; i++) { p1 = f->pts[i]; for (j=0 ; j<3 ; j++) if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE) Message (MSGERR, "CheckFace: BOGUS_RANGE: %s", GetCoord (p1)); j = i+1 == f->numpoints ? 0 : i+1; // check the point is on the face plane d = DotProduct (p1, planes[f->planenum].normal) - planes[f->planenum].dist; if (d < -ON_EPSILON || d > ON_EPSILON) { Message (MSGWARN, "CheckFace: Healing point %s off plane by %.3g", GetCoord (p1), d); // Adjust point to plane VectorMA (p1, -d, planes[f->planenum].normal, f->pts[i]); p1 = f->pts[i]; } // check the edge isn't degenerate p2 = f->pts[j]; VectorSubtract (p2, p1, dir); if (VectorLength (dir) < ON_EPSILON) { Message (MSGWARN, "CheckFace: Healing degenerate edge at %s", GetCoord (p1)); for (j=i+1; j<f->numpoints; j++) VectorCopy(f->pts[j], f->pts[j-1]); ResizeFace (f, f->numpoints - 1); CheckFace(f); break; } 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<f->numpoints ; j++) { if (j == i) continue; d = DotProduct (f->pts[j], edgenormal); if (d > edgedist) Message (MSGERR, "CheckFace: Non-convex at %s", GetCoord (p1)); } } }