/* =============== SubdivideFace If the face is >256 in either texture direction, carve a valid sized piece off and insert the remainder in the next link =============== */ void SubdivideFace (face_t *f, face_t **prevptr) { float mins, maxs; double v; int axis, i; plane_t plane; face_t *front, *back, *next; texinfo_t *tex; // special (non-surface cached) faces don't need subdivision tex = &texinfo[f->texturenum]; if ( tex->flags & TEX_SPECIAL) return; for (axis = 0 ; axis < 2 ; axis++) { while (1) { mins = 9999; maxs = -9999; for (i = 0 ; i < f->numpoints ; i++) { v = DotProduct (f->pts[i], tex->vecs[axis]); if (v < mins) mins = v; if (v > maxs) maxs = v; } if (maxs - mins <= 240) break; // split it subdivides++; VectorCopy (tex->vecs[axis], plane.normal); v = VectorLength (plane.normal); VectorNormalize (plane.normal); plane.dist = (mins + 224)/v; next = f->next; SplitFace (f, &plane, &front, &back); if (!front || !back) Error ("%s: didn't split the polygon", __thisfunc__); *prevptr = back; back->next = front; front->next = next; f = back; } } }
/* =============== SubdivideFace If the face is >256 in either texture direction, carve a valid sized piece off and insert the remainder in the next link =============== */ void SubdivideFace(face_t *f, face_t **prevptr) { vec_t mins, maxs; vec_t v; int axis, i; plane_t plane; face_t *front, *back, *next; texinfo_t *tex; vec3_t tmp; /* special (non-surface cached) faces don't need subdivision */ tex = (texinfo_t *)pWorldEnt->lumps[LUMP_TEXINFO].data + f->texinfo; if (tex->flags & (TEX_SPECIAL | TEX_SKIP | TEX_HINT)) return; for (axis = 0; axis < 2; axis++) { while (1) { mins = VECT_MAX; maxs = -VECT_MAX; tmp[0] = tex->vecs[axis][0]; tmp[1] = tex->vecs[axis][1]; tmp[2] = tex->vecs[axis][2]; for (i = 0; i < f->w.numpoints; i++) { v = DotProduct(f->w.points[i], tmp); if (v < mins) mins = v; if (v > maxs) maxs = v; } if (maxs - mins <= options.dxSubdivide) break; // split it VectorCopy(tmp, plane.normal); v = VectorLength(plane.normal); VectorNormalize(plane.normal); plane.dist = (mins + options.dxSubdivide - 16) / v; next = f->next; SplitFace(f, &plane, &front, &back); if (!front || !back) Error("Didn't split the polygon (%s)", __func__); *prevptr = back; back->next = front; front->next = next; f = back; } } }
/* ================= ClipInside Clips all of the faces in the inside list, possibly moving them to the outside list or spliting it into a piece in each list. Faces exactly on the plane will stay inside unless overdrawn by later brush frontside is the side of the plane that holds the outside list ================= */ static void ClipInside (int splitplane, int frontside, qboolean precedence) { face_t *f, *next; face_t *frags[2]; face_t *insidelist; plane_t *split; split = &planes[splitplane]; insidelist = NULL; for (f = inside ; f ; f = next) { next = f->next; if (f->planenum == splitplane) { // exactly on, handle special if ( frontside != f->planeside || precedence ) { // always clip off opposite faceing frags[frontside] = NULL; frags[!frontside] = f; } else { // leave it on the outside frags[frontside] = f; frags[!frontside] = NULL; } } else { // proper split SplitFace (f, split, &frags[0], &frags[1]); } if (frags[frontside]) { frags[frontside]->next = outside; outside = frags[frontside]; } if (frags[!frontside]) { frags[!frontside]->next = insidelist; insidelist = frags[!frontside]; } } inside = insidelist; }
/* ================== DivideSurface ================== */ void DivideSurface (surface_t *in, dplane_t *split, surface_t **front, surface_t **back) { face_t *facet, *next; face_t *frontlist, *backlist; face_t *frontfrag, *backfrag; surface_t *news; dplane_t *inplane; inplane = &dplanes[in->planenum]; // parallel case is easy if (inplane->normal[0] == split->normal[0] && inplane->normal[1] == split->normal[1] && inplane->normal[2] == split->normal[2]) { if (inplane->dist > split->dist) { *front = in; *back = NULL; } else if (inplane->dist < split->dist) { *front = NULL; *back = in; } else { // split the surface into front and back frontlist = NULL; backlist = NULL; for (facet = in->faces ; facet ; facet = next) { next = facet->next; if (facet->planenum & 1) { facet->next = backlist; backlist = facet; } else { facet->next = frontlist; frontlist = facet; } } goto makesurfs; } return; } // do a real split. may still end up entirely on one side // OPTIMIZE: use bounding box for fast test frontlist = NULL; backlist = NULL; for (facet = in->faces ; facet ; facet = next) { next = facet->next; SplitFace (facet, split, &frontfrag, &backfrag); if (frontfrag) { frontfrag->next = frontlist; frontlist = frontfrag; } if (backfrag) { backfrag->next = backlist; backlist = backfrag; } } // if nothing actually got split, just move the in plane makesurfs: if (frontlist == NULL) { *front = NULL; *back = in; in->faces = backlist; return; } if (backlist == NULL) { *front = in; *back = NULL; in->faces = frontlist; return; } // stuff got split, so allocate one new surface and reuse in news = AllocSurface (); *news = *in; news->faces = backlist; *back = news; in->faces = frontlist; *front = in; // recalc bboxes and flags CalcSurfaceInfo (news); CalcSurfaceInfo (in); }
/* =============== SubdivideFace If the face is >256 in either texture direction, carve a valid sized piece off and insert the remainder in the next link =============== */ void SubdivideFace (face_t *f, face_t **prevptr) { float mins, maxs; vec_t v; int axis, i; dplane_t plane; face_t *front, *back, *next; texinfo_t *tex; vec3_t temp; // special (non-surface cached) faces don't need subdivision tex = &texinfo[f->texturenum]; if ( tex->flags & TEX_SPECIAL) return; for (axis = 0 ; axis < 2 ; axis++) { while (1) { mins = 999999; maxs = -999999; for (i=0 ; i<f->numpoints ; i++) { v = DotProduct (f->pts[i], tex->vecs[axis]); if (v < mins) mins = v; if (v > maxs) maxs = v; } if (maxs - mins <= subdivide_size) break; // split it subdivides++; VectorCopy (tex->vecs[axis], temp); v = VectorNormalize (temp); VectorCopy (temp, plane.normal); plane.dist = (mins + subdivide_size - 16)/v; next = f->next; SplitFace (f, &plane, &front, &back); if (!front || !back) { //PrintMemory(); printf("SubdivideFace: didn't split the %d-sided polygon @(%.0f,%.0f,%.0f)", f->numpoints, f->pts[0][0], f->pts[0][1], f->pts[0][2] ); break; } *prevptr = back; back->next = front; front->next = next; f = back; } } }
/* =============== SubdivideFace If the face is >256 in either texture direction, carve a valid sized piece off and insert the remainder in the next link =============== */ void SubdivideFace (face_t *f, face_t **prevptr) { vec3_t mins, maxs; double v; int i, j; plane_t plane; face_t *front, *back, *next; float size[3]; // special (non-surface cached) faces don't need subdivision if ( texinfo[f->texturenum].flags & TEX_SPECIAL) return; do { mins[0] = mins[1] = mins[2] = 9999; maxs[0] = maxs[1] = maxs[2] = -9999; for (i = 0 ; i < f->numpoints ; i++) { for (j = 0 ; j < 3 ; j++) { v = f->pts[i][j]; if (v < mins[j]) mins[j] = v; if (v > maxs[j]) maxs[j] = v; } } for (i = 0 ; i < 3 ; i++) size[i] = maxs[i] - mins[i]; # if 0 if ( !size[0] && size[1] <= 496 && size[2] <= 496 && size[1]*size[2]<0x10000) return; if ( !size[1] && size[0] <= 496 && size[2] <= 496 && size[0]*size[2]<0x10000) return; if ( !size[2] && size[0] <= 496 && size[1] <= 496 && size[0]*size[1]<0x10000) return; # endif for (i = 0 ; i < 3 ; i++) { v = maxs[i] - mins[i]; if (v <= 240) // NOT 256, because of 16 pixel edge crossings continue; // split it subdivides++; plane.normal[0] = plane.normal[1] = plane.normal[2] = 0; plane.normal[i] = 1; plane.dist = maxs[i] - 224; // not 240, because of epsilons next = f->next; SplitFace (f, &plane, &front, &back); if (!front || !back) Error ("%s: didn't split the polygon", __thisfunc__); *prevptr = front; front->next = back; back->next = next; f = front; break; } } while (i < 3); }
/* ================== DividePlane ================== */ static void DividePlane(surface_t *in, plane_t *split, surface_t **front, surface_t **back) { face_t *facet, *next; face_t *frontlist, *backlist; face_t *frontfrag, *backfrag; surface_t *news; plane_t *inplane; inplane = &pPlanes[in->planenum]; *front = *back = NULL; // parallel case is easy if (VectorCompare(inplane->normal, split->normal)) { // check for exactly on node if (inplane->dist == split->dist) { facet = in->faces; in->faces = NULL; in->onnode = true; // divide the facets to the front and back sides news = AllocMem(SURFACE, 1, true); *news = *in; // Prepend each face in facet list to either in or news lists for (; facet; facet = next) { next = facet->next; if (facet->planeside == 1) { facet->next = news->faces; news->faces = facet; } else { facet->next = in->faces; in->faces = facet; } } if (in->faces) *front = in; else FreeMem(in, SURFACE, 1); if (news->faces) *back = news; else FreeMem(news, SURFACE, 1); return; } if (inplane->dist > split->dist) *front = in; else *back = in; return; } // do a real split. may still end up entirely on one side // OPTIMIZE: use bounding box for fast test frontlist = NULL; backlist = NULL; for (facet = in->faces; facet; facet = next) { next = facet->next; SplitFace(facet, split, &frontfrag, &backfrag); if (frontfrag) { frontfrag->next = frontlist; frontlist = frontfrag; } if (backfrag) { backfrag->next = backlist; backlist = backfrag; } } // if nothing actually got split, just move the in plane if (frontlist == NULL) { *back = in; in->faces = backlist; return; } if (backlist == NULL) { *front = in; in->faces = frontlist; return; } // stuff got split, so allocate one new plane and reuse in news = AllocMem(SURFACE, 1, true); *news = *in; news->faces = backlist; *back = news; in->faces = frontlist; *front = in; // recalc bboxes and flags CalcSurfaceInfo(news); CalcSurfaceInfo(in); }
// ===================================================================================== // SubdivideFace // If the face is >256 in either texture direction, carve a valid sized // piece off and insert the remainder in the next link // ===================================================================================== void SubdivideFace(face_t* f, face_t** prevptr) { vec_t mins, maxs; vec_t v; int axis; int i; dplane_t plane; face_t* front; face_t* back; face_t* next; texinfo_t* tex; vec3_t temp; // special (non-surface cached) faces don't need subdivision #ifdef HLCSG_HLBSP_VOIDTEXINFO if (f->texturenum == -1) { return; } #endif tex = &g_texinfo[f->texturenum]; if (tex->flags & TEX_SPECIAL) { return; } if (f->facestyle == face_hint) { return; } if (f->facestyle == face_skip) { return; } #ifdef ZHLT_NULLTEX // AJM if (f->facestyle == face_null) return; // ideally these should have their tex_special flag set, so its here jic #endif #ifdef HLCSG_HLBSP_SOLIDHINT if (f->facestyle == face_discardable) return; #endif for (axis = 0; axis < 2; axis++) { while (1) { #ifdef HLBSP_SUBDIVIDE_INMID const int maxlightmapsize = g_subdivide_size / TEXTURE_STEP + 1; int lightmapmins, lightmapmaxs; if (f->numpoints == 0) { break; } for (i = 0; i < f->numpoints; i++) { v = DotProduct (f->pts[i], tex->vecs[axis]) + tex->vecs[axis][3]; if (i == 0 || v < mins) { mins = v; } if (i == 0 || v > maxs) { maxs = v; } } lightmapmins = (int)floor (mins / TEXTURE_STEP - 0.05); // the worst case lightmapmaxs = (int)ceil (maxs / TEXTURE_STEP + 0.05); // the worst case if (lightmapmaxs - lightmapmins <= maxlightmapsize) { break; } #else mins = 999999; maxs = -999999; for (i = 0; i < f->numpoints; i++) { v = DotProduct(f->pts[i], tex->vecs[axis]); if (v < mins) { mins = v; } if (v > maxs) { maxs = v; } } if ((maxs - mins) <= g_subdivide_size) { break; } #endif // split it subdivides++; VectorCopy(tex->vecs[axis], temp); v = VectorNormalize(temp); VectorCopy(temp, plane.normal); #ifdef HLBSP_SUBDIVIDE_INMID int splitpos; if ((lightmapmaxs - lightmapmins - 1) - (maxlightmapsize - 1) < (maxlightmapsize - 1) / 4) // don't create very thin face { splitpos = lightmapmins + (maxlightmapsize - 1) - (maxlightmapsize - 1) / 4; } else { splitpos = lightmapmins + (maxlightmapsize - 1); } plane.dist = ((splitpos + 0.5) * TEXTURE_STEP - tex->vecs[axis][3]) / v; #else plane.dist = (mins + g_subdivide_size - TEXTURE_STEP) / v; //plane.dist = (mins + g_subdivide_size - 16) / v; //--vluzacn #endif next = f->next; SplitFace(f, &plane, &front, &back); if (!front || !back) { Developer(DEVELOPER_LEVEL_SPAM, "SubdivideFace: didn't split the %d-sided polygon @(%.0f,%.0f,%.0f)", f->numpoints, f->pts[0][0], f->pts[0][1], f->pts[0][2]); #ifndef HLBSP_SubdivideFace_FIX break; #endif } #ifdef HLBSP_SubdivideFace_FIX f = next; if (front) { front->next = f; f = front; } if (back) { back->next = f; f = back; } *prevptr = f; #else *prevptr = back; back->next = front; front->next = next; f = back; #endif } } }