/* ================== CopyFacesToNode Do a final merge attempt, then subdivide the faces to surface cache size if needed. These are final faces that will be drawable in the game. Copies of these faces are further chopped up into the leafs, but they will reference these originals. ================== */ void CopyFacesToNode (node_t *node, surface_t *surf) { face_t **prevptr, *f, *newf; // merge as much as possible MergePlaneFaces (surf); // subdivide large faces prevptr = &surf->faces; while (1) { f = *prevptr; if (!f) break; SubdivideFace (f, prevptr); f = *prevptr; prevptr = &f->next; } // copy the faces to the node, and consider them the originals node->surfaces = NULL; node->faces = NULL; for (f=surf->faces ; f ; f=f->next) { if (f->contents != CONTENTS_SOLID) { newf = AllocFace (); *newf = *f; f->original = newf; newf->next = node->faces; node->faces = newf; c_nodefaces++; } } }
/* ================== CopyFacesToOutside ================== */ static void CopyFacesToOutside (brush_t *b) { face_t *f, *newf; outside = NULL; for (f = b->faces ; f ; f = f->next) { brushfaces++; #if 0 { int i; for (i = 0 ; i < f->numpoints ; i++) printf ("(%f,%f,%f) ",f->pts[i][0], f->pts[i][1], f->pts[i][2]); printf ("\n"); } #endif newf = AllocFace (); *newf = *f; newf->next = outside; newf->contents[0] = CONTENTS_EMPTY; newf->contents[1] = b->contents; outside = newf; } }
/* * @brief */ static face_t *NewFaceFromFace(const face_t *f) { face_t *newf; newf = AllocFace(); *newf = *f; newf->merged = NULL; newf->split[0] = newf->split[1] = NULL; newf->w = NULL; return newf; }
/* ================== NewFaceFromFace Duplicates the non point information of a face, used by SplitFace and MergeFace. ================== */ face_t *NewFaceFromFace (face_t *in) { face_t *newf; newf = AllocFace (); newf->planenum = in->planenum; newf->texturenum = in->texturenum; newf->planeside = in->planeside; newf->original = in->original; newf->contents[0] = in->contents[0]; newf->contents[1] = in->contents[1]; newf->Light = in->Light; return newf; }
static face_t* FaceFromPortal (portal_t* p, bool pside) { face_t* f; side_t* side = p->side; /* portal does not bridge different visible contents */ if (!side) return nullptr; /* nodraw/caulk faces */ if (side->surfaceFlags & SURF_NODRAW) return nullptr; f = AllocFace(); f->texinfo = side->texinfo; f->planenum = (side->planenum & ~1) | pside; f->portal = p; if ((p->nodes[pside]->contentFlags & CONTENTS_WINDOW) && VisibleContents(p->nodes[!pside]->contentFlags ^ p->nodes[pside]->contentFlags) == CONTENTS_WINDOW) return nullptr; /* don't show insides of windows */ /* do back-clipping */ if (!config.nobackclip && mapplanes[f->planenum].normal[2] < -0.9) { /* this face is not visible from birds view - optimize away * but only if it's not light emitting surface */ const entity_t* e = &entities[side->brush->entitynum]; if (!Q_streq(ValueForKey(e, "classname"), "func_rotating")) { if (!(curTile->texinfo[f->texinfo].surfaceFlags & SURF_LIGHT)) { /* e.g. water surfaces are removed if we set the surfaceFlags * to SURF_NODRAW for this side */ /*side->surfaceFlags |= SURF_NODRAW;*/ return nullptr; } } } if (pside) { f->w = ReverseWinding(p->winding); f->contentFlags = p->nodes[1]->contentFlags; } else { f->w = CopyWinding(p->winding); f->contentFlags = p->nodes[0]->contentFlags; } return f; }
//----------------------------------------------------------------------------- // Purpose: Given an original side and chopped winding, make a face_t // Input : *side - side of the original brush // *winding - winding for this face (portion of the side) // Output : face_t //----------------------------------------------------------------------------- face_t *MakeBrushFace( side_t *originalSide, winding_t *winding ) { face_t *f = AllocFace(); f->merged = NULL; f->split[0] = f->split[1] = NULL; f->w = CopyWinding( winding ); f->originalface = originalSide; // // save material info // f->texinfo = originalSide->texinfo; f->dispinfo = -1; // save plane info f->planenum = originalSide->planenum; f->contents = originalSide->contents; return f; }
/* ================== CopyFacesToOutside ================== */ static void CopyFacesToOutside( const brush_t *b ) { face_t *f, *newf; outside = NULL; for( f = b->faces; f; f = f->next ) { if( !f->winding ) continue; numcsgbrushfaces++; newf = AllocFace (); newf->texturenum = f->texturenum; newf->planenum = f->planenum; newf->planeside = f->planeside; newf->original = f->original; newf->winding = CopyWinding( f->winding ); newf->next = outside; newf->contents[0] = CONTENTS_EMPTY; newf->contents[1] = b->contents; outside = newf; } }
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); } }
/* ================= CreateBrushFaces ================= */ void CreateBrushFaces (void) { int i,j, k; vec_t r; face_t *f, *next; winding_t *w; plane_t clipplane, faceplane; mface_t *mf; vec3_t offset, point; offset[0] = offset[1] = offset[2] = 0; ClearBounds( brush_mins, brush_maxs ); brush_faces = NULL; if (!strncmp(ValueForKey(CurrentEntity, "classname"), "rotate_", 7)) { entity_t *FoundEntity; char *searchstring; char text[20]; searchstring = ValueForKey (CurrentEntity, "target"); FoundEntity = FindTargetEntity(searchstring); if (FoundEntity) GetVectorForKey(FoundEntity, "origin", offset); sprintf(text, "%g %g %g", offset[0], offset[1], offset[2]); SetKeyValue(CurrentEntity, "origin", text); } GetVectorForKey(CurrentEntity, "origin", offset); //printf("%i brushfaces at offset %f %f %f\n", numbrushfaces, offset[0], offset[1], offset[2]); for (i = 0;i < numbrushfaces;i++) { mf = &faces[i]; //printf("plane %f %f %f %f\n", mf->plane.normal[0], mf->plane.normal[1], mf->plane.normal[2], mf->plane.dist); faceplane = mf->plane; w = BaseWindingForPlane (&faceplane); //VectorNegate( faceplane.normal, point ); for (j = 0;j < numbrushfaces && w;j++) { clipplane = faces[j].plane; if( j == i/* || VectorCompare( clipplane.normal, point )*/ ) continue; // flip the plane, because we want to keep the back side VectorNegate(clipplane.normal, clipplane.normal); clipplane.dist *= -1; w = ClipWindingEpsilon (w, &clipplane, ON_EPSILON, true); } if (!w) { //printf("----- skipped plane -----\n"); continue; // overcontrained plane } // this face is a keeper f = AllocFace (); f->winding = w; 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) w->points[j][k] = r; else w->points[j][k] = point[k]; // check for incomplete brushes if( w->points[j][k] >= BOGUS_RANGE || w->points[j][k] <= -BOGUS_RANGE ) break; } // remove this brush if (k < 3) { FreeFace (f); for (f = brush_faces; f; f = next) { next = f->next; FreeFace (f); } brush_faces = NULL; //printf("----- skipped brush -----\n"); return; } AddPointToBounds( w->points[j], brush_mins, brush_maxs ); } CheckWinding( w ); faceplane.dist -= DotProduct(faceplane.normal, offset); f->texturenum = mf->texinfo; f->planenum = FindPlane (&faceplane, &f->planeside); f->next = brush_faces; brush_faces = f; } // Rotatable objects have to have a bounding box big enough // to account for all its rotations. if (DotProduct(offset, offset)) { vec_t delta; delta = RadiusFromBounds( brush_mins, brush_maxs ); for (k = 0;k < 3;k++) { brush_mins[k] = -delta; brush_maxs[k] = delta; } } //printf("%i : %f %f %f : %f %f %f\n", numbrushfaces, brush_mins[0], brush_mins[1], brush_mins[2], brush_maxs[0], brush_maxs[1], brush_maxs[2]); }
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; } } }