//=========================================================================== // returns the amount the face and the winding overlap // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== float Q3_FaceOnWinding(dsurface_t *surface, winding_t *winding) { int i; float dist, area; dplane_t plane; vec_t *v1, *v2; vec3_t normal, edgevec; winding_t *w; //copy the winding before chopping w = CopyWinding(winding); //retrieve the surface plane Q3_SurfacePlane(surface, plane.normal, &plane.dist); //chop the winding with the surface edge planes for (i = 0; i < surface->numVerts && w; i++) { v1 = drawVerts[surface->firstVert + ((i) % surface->numVerts)].xyz; v2 = drawVerts[surface->firstVert + ((i+1) % surface->numVerts)].xyz; //create a plane through the edge from v1 to v2, orthogonal to the //surface plane and with the normal vector pointing inward VectorSubtract(v2, v1, edgevec); CrossProduct(edgevec, plane.normal, normal); VectorNormalize(normal); dist = DotProduct(normal, v1); // ChopWindingInPlace(&w, normal, dist, -0.1); //CLIP_EPSILON } //end for if (w) { area = WindingArea(w); FreeWinding(w); return area; } //end if return 0; } //end of the function Q3_FaceOnWinding
brush_t *CopyBrush( brush_t *brush ){ brush_t *newBrush; size_t size; int i; /* copy brush */ size = (size_t)&( ( (brush_t*) 0 )->sides[ brush->numsides ] ); newBrush = AllocBrush( brush->numsides ); memcpy( newBrush, brush, size ); /* ydnar: nuke linked list */ newBrush->next = NULL; /* copy sides */ for ( i = 0; i < brush->numsides; i++ ) { if ( brush->sides[ i ].winding != NULL ) { newBrush->sides[ i ].winding = CopyWinding( brush->sides[ i ].winding ); } } /* return it */ return newBrush; }
//----------------------------------------------------------------------------- // Purpose: Copies a face and its winding // Input : *pFace - // Output : face_t //----------------------------------------------------------------------------- face_t *CopyFace( face_t *pFace ) { face_t *f = NewFaceFromFace( pFace ); f->w = CopyWinding( pFace->w ); return f; }
void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, vec_t epsilon, winding_t **front, winding_t **back) { ClipWindingEpsilonStrict(in, normal, dist, epsilon, front, back); /* apparently most code expects that in the winding-on-plane case, the back winding is the original winding */ if(!*front && !*back) *back = CopyWinding(in); }
bface_t *CopyFace (bface_t *f) { bface_t *n; n = NewFaceFromFace (f); n->w = CopyWinding (f->w); VectorCopy (f->mins, n->mins); VectorCopy (f->maxs, n->maxs); return n; }
/* ================= BspFaceForPortal ================= */ bspFace_t *BspFaceForPortal(portal_t * p) { bspFace_t *f; f = AllocBspFace(); f->w = CopyWinding(p->winding); f->planenum = p->onnode->planenum & ~1; return f; }
face_t *MakeVisibleBSPFaceList( brush_t *list ){ brush_t *b; int i; side_t *s; winding_t *w; face_t *f, *flist; flist = NULL; for ( b = list; b != NULL; b = b->next ) { if ( b->detail ) { continue; } for ( i = 0; i < b->numsides; i++ ) { /* get side and winding */ s = &b->sides[ i ]; w = s->visibleHull; if ( w == NULL ) { continue; } /* ydnar: skip certain faces */ if ( s->compileFlags & C_SKIP ) { continue; } /* allocate a face */ f = AllocBspFace(); f->w = CopyWinding( w ); f->planenum = s->planenum & ~1; f->compileFlags = s->compileFlags; /* ydnar */ /* ydnar: set priority */ f->priority = 0; if ( f->compileFlags & C_HINT ) { f->priority += HINT_PRIORITY; } if ( f->compileFlags & C_ANTIPORTAL ) { f->priority += ANTIPORTAL_PRIORITY; } if ( f->compileFlags & C_AREAPORTAL ) { f->priority += AREAPORTAL_PRIORITY; } /* get next face */ f->next = flist; flist = f; } } return flist; }
void DivideWinding (winding_t *in, plane_t *split, winding_t **front, winding_t **back) { int i; int counts[3]; plane_t plane; vec_t dot; winding_t *tmp; counts[0] = counts[1] = counts[2] = 0; // determine sides for each point for (i = 0; i < in->numpoints; i++) { dot = DotProduct (in->points[i], split->normal) - split->dist; if (dot > ON_EPSILON) counts[SIDE_FRONT]++; else if (dot < -ON_EPSILON) counts[SIDE_BACK]++; } *front = *back = NULL; if (!counts[SIDE_FRONT]) { *back = in; return; } if (!counts[SIDE_BACK]) { *front = in; return; } tmp = CopyWinding (in); *front = ClipWinding (tmp, split, 0); plane.dist = -split->dist; VectorNegate (split->normal, plane.normal); tmp = CopyWinding (in); *back = ClipWinding (tmp, &plane, 0); }
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; }
/** * @brief Duplicates the brush, the sides, and the windings * @sa AllocBrush */ bspbrush_t* CopyBrush (const bspbrush_t* brush) { bspbrush_t* newbrush; int i; const size_t size = offsetof(bspbrush_t, sides) + sizeof(((bspbrush_t*)0)->sides) * brush->numsides; newbrush = AllocBrush(brush->numsides); memcpy(newbrush, brush, size); for (i = 0; i < brush->numsides; i++) { const side_t* side = &brush->sides[i]; if (side->winding) newbrush->sides[i].winding = CopyWinding(side->winding); } return newbrush; }
/** * @brief Duplicates the brush, the sides, and the windings */ brush_t *CopyBrush(brush_t *brush) { brush_t *newbrush; size_t size; int32_t i; size = (size_t) & (((brush_t *) 0)->sides[brush->num_sides]); newbrush = AllocBrush(brush->num_sides); memcpy(newbrush, brush, size); for (i = 0; i < brush->num_sides; i++) { if (brush->sides[i].winding) { newbrush->sides[i].winding = CopyWinding(brush->sides[i].winding); } } return newbrush; }
//=========================================================================== // Duplicates the brush, the sides, and the windings // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== bspbrush_t *CopyBrush (bspbrush_t *brush) { bspbrush_t *newbrush; size_t size; int i; size = sizeof(*newbrush) + sizeof(*brush->sides) * brush->numsides; newbrush = AllocBrush (brush->numsides); memcpy (newbrush, brush, size); for (i=0 ; i<brush->numsides ; i++) { if (brush->sides[i].winding) newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding); } return newbrush; } //end of the function CopyBrush
//=========================================================================== // returns the amount the face and the winding overlap // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== float Q1_FaceOnWinding(q1_dface_t *face, winding_t *winding) { int i, edgenum, side; float dist, area; q1_dplane_t plane; vec_t *v1, *v2; vec3_t normal, edgevec; winding_t *w; // w = CopyWinding(winding); memcpy(&plane, &q1_dplanes[face->planenum], sizeof(q1_dplane_t)); //check on which side of the plane the face is if (face->side) { VectorNegate(plane.normal, plane.normal); plane.dist = -plane.dist; } //end if for (i = 0; i < face->numedges && w; i++) { //get the first and second vertex of the edge edgenum = q1_dsurfedges[face->firstedge + i]; side = edgenum > 0; //if the face plane is flipped v1 = q1_dvertexes[q1_dedges[abs(edgenum)].v[side]].point; v2 = q1_dvertexes[q1_dedges[abs(edgenum)].v[!side]].point; //create a plane through the edge vector, orthogonal to the face plane //and with the normal vector pointing out of the face VectorSubtract(v1, v2, edgevec); CrossProduct(edgevec, plane.normal, normal); VectorNormalize(normal); dist = DotProduct(normal, v1); // ChopWindingInPlace(&w, normal, dist, 0.9); //CLIP_EPSILON } //end for if (w) { area = WindingArea(w); FreeWinding(w); return area; } //end if return 0; } //end of the function Q1_FaceOnWinding
/* ================== CopyBrush Duplicates the brush, the sides, and the windings ================== */ bspbrush_t *CopyBrush (bspbrush_t *brush) { bspbrush_t *newbrush; int size; int i; size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]); newbrush = AllocBrush (brush->numsides); memcpy (newbrush, brush, size); for (i=0 ; i<brush->numsides ; i++) { if (brush->sides[i].winding) newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding); } return newbrush; }
//----------------------------------------------------------------------------- // 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 DispGetFaceInfo( mapbrush_t *pBrush ) { int i; side_t *pSide; // we don't support displacement on entities at the moment!! if( pBrush->entitynum != 0 ) { char* pszEntityName = ValueForKey( &entities[pBrush->entitynum], "classname" ); Error( "Error: displacement found on a(n) %s entity - not supported\n", pszEntityName ); } for( i = 0; i < pBrush->numsides; i++ ) { pSide = &pBrush->original_sides[i]; if( pSide->pMapDisp ) { // error checking!! if( pSide->winding->numpoints != 4 ) Error( "Trying to create a non-quad displacement!\n" ); pSide->pMapDisp->face.originalface = pSide; pSide->pMapDisp->face.texinfo = pSide->texinfo; pSide->pMapDisp->face.dispinfo = -1; pSide->pMapDisp->face.planenum = pSide->planenum; pSide->pMapDisp->face.numpoints = pSide->winding->numpoints; pSide->pMapDisp->face.w = CopyWinding( pSide->winding ); pSide->pMapDisp->face.contents = pBrush->contents; pSide->pMapDisp->face.merged = FALSE; pSide->pMapDisp->face.split[0] = FALSE; pSide->pMapDisp->face.split[1] = FALSE; pSide->pMapDisp->entitynum = pBrush->entitynum; pSide->pMapDisp->brushSideID = pSide->id; } } }
/* ================= MakeVisibleBspFaceList ================= */ bspFace_t *MakeVisibleBspFaceList(bspBrush_t * list) { bspBrush_t *b; int i; side_t *s; winding_t *w; bspFace_t *f, *flist; flist = NULL; for(b = list; b; b = b->next) { if(b->detail) { continue; } for(i = 0; i < b->numsides; i++) { s = &b->sides[i]; w = s->visibleHull; if(!w) { continue; } f = AllocBspFace(); f->w = CopyWinding(w); f->planenum = s->planenum & ~1; f->next = flist; if(s->surfaceFlags & SURF_HINT) { //f->priority = HINT_PRIORITY; f->hint = qtrue; } flist = f; } } return flist; }
/* ================= CheckInside Quick test before running ClipInside; move any faces that are completely outside the brush to the outside list, without splitting them. This saves us time in mergefaces later on (and sometimes a lot of memory) ================= */ static void CheckInside(brush_t *b) { face_t *f, *bf, *next; face_t *insidelist; plane_t clip; winding_t *w; insidelist = NULL; f = inside; while (f) { next = f->next; w = CopyWinding(&f->w); for (bf = b->faces; bf; bf = bf->next) { clip = pPlanes[bf->planenum]; if (!bf->planeside) { VectorSubtract(vec3_origin, clip.normal, clip.normal); clip.dist = -clip.dist; } w = ClipWinding(w, &clip, true); if (!w) break; } if (!w) { /* The face is completely outside this brush */ f->next = outside; outside = f; } else { f->next = insidelist; insidelist = f; FreeMem(w, WINDING, 1); } f = next; } inside = insidelist; }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int CreateOrigFace( face_t *f ) { int i, j; dface_t *of; side_t *side; int vIndices[128]; int eIndex[2]; winding_t *pWinding; // not a real face! if( !f->w ) return -1; // get the original face -- the "side" side = f->originalface; // get the original face winding if( !side->winding ) { return -1; } // // get the next original face // if( numorigfaces >= MAX_MAP_FACES ) Error( "Too many faces in map, max = %d", MAX_MAP_FACES ); of = &dorigfaces[numorigfaces]; numorigfaces++; // set original face to -1 -- it is an origianl face! of->origFace = -1; // // add side to plane list // side->next = pOrigFaceSideList[f->planenum]; pOrigFaceSideList[f->planenum] = side; side->origIndex = numorigfaces - 1; pWinding = CopyWinding( side->winding ); // // plane info // of->planenum = side->planenum; if ( side->contents & CONTENTS_DETAIL ) of->onNode = 0; else of->onNode = 1; of->side = side->planenum & 1; // // edge info // of->firstedge = numsurfedges; of->numedges = side->winding->numpoints; // // material info // of->texinfo = side->texinfo; of->dispinfo = f->dispinfo; // // save the vertices // for( i = 0; i < pWinding->numpoints; i++ ) { // // compare vertices // vIndices[i] = GetVertexnum( pWinding->p[i] ); } // // save off points -- as edges // for( i = 0; i < pWinding->numpoints; i++ ) { // // look for matching edges first // eIndex[0] = vIndices[i]; eIndex[1] = vIndices[(i+1)%pWinding->numpoints]; for( j = firstmodeledge; j < numedges; j++ ) { if( ( eIndex[0] == dedges[j].v[1] ) && ( eIndex[1] == dedges[j].v[0] ) && ( edgefaces[j][0]->contents == f->contents ) ) { // check for multiple backward edges!! -- shouldn't have if( edgefaces[j][1] ) continue; // set back edge edgefaces[j][1] = f; // // get next surface edge // if( numsurfedges >= MAX_MAP_SURFEDGES ) Error( "Too much brush geometry in bsp, numsurfedges == MAX_MAP_SURFEDGES" ); dsurfedges[numsurfedges] = -j; numsurfedges++; break; } } if( j == numedges ) { // // get next edge // AddEdge( eIndex[0], eIndex[1], f ); // // get next surface edge // if( numsurfedges >= MAX_MAP_SURFEDGES ) Error( "Too much brush geometry in bsp, numsurfedges == MAX_MAP_SURFEDGES" ); dsurfedges[numsurfedges] = ( numedges - 1 ); numsurfedges++; } } // return the index return ( numorigfaces - 1 ); }
void CM_AddFacetBevels( facet_t *facet ) { int i, j, k, l; int axis, dir, order, flipped; float plane[4], d, newplane[4]; winding_t *w, *w2; vec3_t mins, maxs, vec, vec2; #ifndef ADDBEVELS return; #endif Vector4Copy( planes[ facet->surfacePlane ].plane, plane ); w = BaseWindingForPlane( plane, plane[3] ); for ( j = 0 ; j < facet->numBorders && w ; j++ ) { if ( facet->borderPlanes[j] == facet->surfacePlane ) { continue; } Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane ); if ( !facet->borderInward[j] ) { VectorSubtract( vec3_origin, plane, plane ); plane[3] = -plane[3]; } ChopWindingInPlace( &w, plane, plane[3], 0.1f ); } if ( !w ) { return; } WindingBounds( w, mins, maxs ); // add the axial planes order = 0; for ( axis = 0 ; axis < 3 ; axis++ ) { for ( dir = -1 ; dir <= 1 ; dir += 2, order++ ) { VectorClear( plane ); plane[axis] = dir; if ( dir == 1 ) { plane[3] = maxs[axis]; } else { plane[3] = -mins[axis]; } //if it's the surface plane if ( CM_PlaneEqual( &planes[facet->surfacePlane], plane, &flipped ) ) { continue; } // see if the plane is allready present for ( i = 0 ; i < facet->numBorders ; i++ ) { if ( CM_PlaneEqual( &planes[facet->borderPlanes[i]], plane, &flipped ) ) { break; } } if ( i == facet->numBorders ) { if ( facet->numBorders > 4 + 6 + 16 ) { Com_Printf( "ERROR: too many bevels\n" ); } facet->borderPlanes[facet->numBorders] = CM_FindPlane2( plane, &flipped ); facet->borderNoAdjust[facet->numBorders] = 0; facet->borderInward[facet->numBorders] = flipped; facet->numBorders++; } } } // // add the edge bevels // // test the non-axial plane edges for ( j = 0 ; j < w->numpoints ; j++ ) { k = ( j + 1 ) % w->numpoints; VectorSubtract( w->p[j], w->p[k], vec ); //if it's a degenerate edge if ( VectorNormalize( vec ) < 0.5 ) { continue; } CM_SnapVector( vec ); for ( k = 0; k < 3 ; k++ ) if ( vec[k] == -1 || vec[k] == 1 ) { break; } // axial if ( k < 3 ) { continue; // only test non-axial edges } // try the six possible slanted axials from this edge for ( axis = 0 ; axis < 3 ; axis++ ) { for ( dir = -1 ; dir <= 1 ; dir += 2 ) { // construct a plane VectorClear( vec2 ); vec2[axis] = dir; CrossProduct( vec, vec2, plane ); if ( VectorNormalize( plane ) < 0.5 ) { continue; } plane[3] = DotProduct( w->p[j], plane ); // if all the points of the facet winding are // behind this plane, it is a proper edge bevel for ( l = 0 ; l < w->numpoints ; l++ ) { d = DotProduct( w->p[l], plane ) - plane[3]; if ( d > 0.1 ) { break; // point in front } } if ( l < w->numpoints ) { continue; } //if it's the surface plane if ( CM_PlaneEqual( &planes[facet->surfacePlane], plane, &flipped ) ) { continue; } // see if the plane is allready present for ( i = 0 ; i < facet->numBorders ; i++ ) { if ( CM_PlaneEqual( &planes[facet->borderPlanes[i]], plane, &flipped ) ) { break; } } if ( i == facet->numBorders ) { if ( facet->numBorders > 4 + 6 + 16 ) { Com_Printf( "ERROR: too many bevels\n" ); } facet->borderPlanes[facet->numBorders] = CM_FindPlane2( plane, &flipped ); for ( k = 0 ; k < facet->numBorders ; k++ ) { if ( facet->borderPlanes[facet->numBorders] == facet->borderPlanes[k] ) { Com_Printf( "WARNING: bevel plane already used\n" ); } } facet->borderNoAdjust[facet->numBorders] = 0; facet->borderInward[facet->numBorders] = flipped; // w2 = CopyWinding( w ); Vector4Copy( planes[facet->borderPlanes[facet->numBorders]].plane, newplane ); if ( !facet->borderInward[facet->numBorders] ) { VectorNegate( newplane, newplane ); newplane[3] = -newplane[3]; } //end if ChopWindingInPlace( &w2, newplane, newplane[3], 0.1f ); if ( !w2 ) { // TTimo - can't stand this, useless and noisy //Com_DPrintf("WARNING: CM_AddFacetBevels... invalid bevel\n"); continue; } else { FreeWinding( w2 ); } // facet->numBorders++; //already got a bevel // break; } } } } FreeWinding( w ); #ifndef BSPC //add opposite plane facet->borderPlanes[facet->numBorders] = facet->surfacePlane; facet->borderNoAdjust[facet->numBorders] = 0; facet->borderInward[facet->numBorders] = qtrue; facet->numBorders++; #endif //BSPC }
void SplitBrush( bspbrush_t *brush, int planenum, bspbrush_t **front, bspbrush_t **back ) { bspbrush_t *b[2]; int i, j; winding_t *w, *cw[2], *midwinding; plane_t *plane, *plane2; side_t *s, *cs; float d, d_front, d_back; *front = *back = NULL; plane = &g_MainMap->mapplanes[planenum]; // check all points d_front = d_back = 0; for (i=0 ; i<brush->numsides ; i++) { w = brush->sides[i].winding; if (!w) continue; for (j=0 ; j<w->numpoints ; j++) { d = DotProduct (w->p[j], plane->normal) - plane->dist; if (d > 0 && d > d_front) d_front = d; if (d < 0 && d < d_back) d_back = d; } } if (d_front < 0.1) // PLANESIDE_EPSILON) { // only on back *back = CopyBrush (brush); return; } if (d_back > -0.1) // PLANESIDE_EPSILON) { // only on front *front = CopyBrush (brush); return; } // Move the CSG problem so that offset is at the origin // This gives us much better floating point precision in the clipping operations Vector offset = -0.5f * (brush->mins + brush->maxs); // create a new winding from the split plane w = BaseWindingForPlane (plane->normal, plane->dist + DotProduct(plane->normal,offset)); for (i=0 ; i<brush->numsides && w ; i++) { plane2 = &g_MainMap->mapplanes[brush->sides[i].planenum ^ 1]; ChopWindingInPlace (&w, plane2->normal, plane2->dist+DotProduct(plane2->normal,offset), 0); // PLANESIDE_EPSILON); } if (!w || WindingIsTiny (w) ) { // the brush isn't really split int side; side = BrushMostlyOnSide (brush, plane); if (side == PSIDE_FRONT) *front = CopyBrush (brush); if (side == PSIDE_BACK) *back = CopyBrush (brush); return; } if (WindingIsHuge (w)) { qprintf ("WARNING: huge winding\n"); } TranslateWinding( w, -offset ); midwinding = w; // // // split it for real // // // // allocate two new brushes referencing the original // for( i = 0; i < 2; i++ ) { b[i] = AllocBrush( brush->numsides + 1 ); b[i]->original = brush->original; } // // split all the current windings // for( i = 0; i < brush->numsides; i++ ) { // get the current side s = &brush->sides[i]; // get the sides winding w = s->winding; if( !w ) continue; // clip the winding ClipWindingEpsilon_Offset( w, plane->normal, plane->dist, 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1], offset ); for( j = 0; j < 2; j++ ) { // does winding exist? if( !cw[j] ) continue; #if 0 if (WindingIsTiny (cw[j])) { FreeWinding (cw[j]); continue; } #endif // // create a clipped "side" with the new winding // cs = &b[j]->sides[b[j]->numsides]; b[j]->numsides++; *cs = *s; cs->winding = cw[j]; cs->tested = false; // save the original side information //cs->original = s->original; } } // see if we have valid polygons on both sides for (i=0 ; i<2 ; i++) { BoundBrush (b[i]); for (j=0 ; j<3 ; j++) { if (b[i]->mins[j] < MIN_COORD_INTEGER || b[i]->maxs[j] > MAX_COORD_INTEGER) { qprintf ("bogus brush after clip\n"); break; } } if (b[i]->numsides < 3 || j < 3) { FreeBrush (b[i]); b[i] = NULL; } } if ( !(b[0] && b[1]) ) { if (!b[0] && !b[1]) qprintf ("split removed brush\n"); else qprintf ("split not on both sides\n"); if (b[0]) { FreeBrush (b[0]); *front = CopyBrush (brush); } if (b[1]) { FreeBrush (b[1]); *back = CopyBrush (brush); } return; } // add the midwinding to both sides for (i=0 ; i<2 ; i++) { cs = &b[i]->sides[b[i]->numsides]; b[i]->numsides++; cs->planenum = planenum^i^1; cs->texinfo = TEXINFO_NODE; // initialize the displacement map index cs->pMapDisp = NULL; cs->visible = false; cs->tested = false; if (i==0) cs->winding = CopyWinding (midwinding); else cs->winding = midwinding; } { vec_t v1; int i; for (i=0 ; i<2 ; i++) { v1 = BrushVolume (b[i]); if (v1 < 1.0) { FreeBrush (b[i]); b[i] = NULL; // qprintf ("tiny volume after clip\n"); } } } *front = b[0]; *back = b[1]; }
void SplitBrush( brush_t *brush, int planenum, brush_t **front, brush_t **back ){ brush_t *b[2]; int i, j; winding_t *w, *cw[2], *midwinding; plane_t *plane, *plane2; side_t *s, *cs; float d, d_front, d_back; *front = NULL; *back = NULL; plane = &mapplanes[planenum]; // check all points d_front = d_back = 0; for ( i = 0 ; i < brush->numsides ; i++ ) { w = brush->sides[i].winding; if ( !w ) { continue; } for ( j = 0 ; j < w->numpoints ; j++ ) { d = DotProduct( w->p[j], plane->normal ) - plane->dist; if ( d > 0 && d > d_front ) { d_front = d; } if ( d < 0 && d < d_back ) { d_back = d; } } } if ( d_front < 0.1 ) { // PLANESIDE_EPSILON) // only on back *back = CopyBrush( brush ); return; } if ( d_back > -0.1 ) { // PLANESIDE_EPSILON) // only on front *front = CopyBrush( brush ); return; } // create a new winding from the split plane w = BaseWindingForPlane( plane->normal, plane->dist ); for ( i = 0 ; i < brush->numsides && w ; i++ ) { plane2 = &mapplanes[brush->sides[i].planenum ^ 1]; ChopWindingInPlace( &w, plane2->normal, plane2->dist, 0 ); // PLANESIDE_EPSILON); } if ( !w || WindingIsTiny( w ) ) { // the brush isn't really split int side; side = BrushMostlyOnSide( brush, plane ); if ( side == PSIDE_FRONT ) { *front = CopyBrush( brush ); } if ( side == PSIDE_BACK ) { *back = CopyBrush( brush ); } return; } if ( WindingIsHuge( w ) ) { Sys_FPrintf( SYS_VRB,"WARNING: huge winding\n" ); } midwinding = w; // split it for real for ( i = 0 ; i < 2 ; i++ ) { b[i] = AllocBrush( brush->numsides + 1 ); memcpy( b[i], brush, sizeof( brush_t ) - sizeof( brush->sides ) ); b[i]->numsides = 0; b[i]->next = NULL; b[i]->original = brush->original; } // split all the current windings for ( i = 0 ; i < brush->numsides ; i++ ) { s = &brush->sides[i]; w = s->winding; if ( !w ) { continue; } /* strict, in parallel case we get the face back because it also is the midwinding */ ClipWindingEpsilonStrict( w, plane->normal, plane->dist, 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1] ); for ( j = 0 ; j < 2 ; j++ ) { if ( !cw[j] ) { continue; } cs = &b[j]->sides[b[j]->numsides]; b[j]->numsides++; *cs = *s; cs->winding = cw[j]; } } // see if we have valid polygons on both sides for ( i = 0 ; i < 2 ; i++ ) { if ( b[i]->numsides < 3 || !BoundBrush( b[i] ) ) { if ( b[i]->numsides >= 3 ) { Sys_FPrintf( SYS_VRB,"bogus brush after clip\n" ); } FreeBrush( b[i] ); b[i] = NULL; } } if ( !( b[0] && b[1] ) ) { if ( !b[0] && !b[1] ) { Sys_FPrintf( SYS_VRB,"split removed brush\n" ); } else{ Sys_FPrintf( SYS_VRB,"split not on both sides\n" ); } if ( b[0] ) { FreeBrush( b[0] ); *front = CopyBrush( brush ); } if ( b[1] ) { FreeBrush( b[1] ); *back = CopyBrush( brush ); } return; } // add the midwinding to both sides for ( i = 0 ; i < 2 ; i++ ) { cs = &b[i]->sides[b[i]->numsides]; b[i]->numsides++; cs->planenum = planenum ^ i ^ 1; cs->shaderInfo = NULL; if ( i == 0 ) { cs->winding = CopyWinding( midwinding ); } else{ cs->winding = midwinding; } } { vec_t v1; int i; for ( i = 0 ; i < 2 ; i++ ) { v1 = BrushVolume( b[i] ); if ( v1 < 1.0 ) { FreeBrush( b[i] ); b[i] = NULL; // Sys_FPrintf (SYS_VRB,"tiny volume after clip\n"); } } } *front = b[0]; *back = b[1]; }
//=========================================================================== // create a tmp AAS area from a leaf node // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== tmp_node_t *AAS_CreateArea(node_t *node) { int pside; int areafaceflags; portal_t *p; tmp_face_t *tmpface; tmp_area_t *tmparea; tmp_node_t *tmpnode; //create an area from this leaf tmparea = AAS_AllocTmpArea(); tmparea->tmpfaces = NULL; //clear the area face flags areafaceflags = 0; //make aas faces from the portals for (p = node->portals; p; p = p->next[pside]) { pside = (p->nodes[1] == node); //don't create faces from very small portals // if (WindingArea(p->winding) < 1) continue; //if there's already a face created for this portal if (p->tmpface) { //add the back side of the face to the area AAS_AddFaceSideToArea(p->tmpface, 1, tmparea); } //end if else { tmpface = AAS_AllocTmpFace(); //set the face pointer at the portal so we can see from //the portal there's a face created for it p->tmpface = tmpface; //FIXME: test this change //tmpface->planenum = (p->planenum & ~1) | pside; tmpface->planenum = p->planenum ^ pside; if (pside) tmpface->winding = ReverseWinding(p->winding); else tmpface->winding = CopyWinding(p->winding); #ifdef L_DEBUG // AAS_CheckFaceWindingPlane(tmpface); #endif //L_DEBUG //if there's solid at the other side of the portal if (p->nodes[!pside]->contents & (CONTENTS_SOLID | CONTENTS_PLAYERCLIP)) { tmpface->faceflags |= FACE_SOLID; } //end if //else there is no solid at the other side and if there //is a liquid at this side else if (node->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) { tmpface->faceflags |= FACE_LIQUID; //if there's no liquid at the other side if (!(p->nodes[!pside]->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))) { tmpface->faceflags |= FACE_LIQUIDSURFACE; } //end if } //end else //if there's ladder contents at other side of the portal if ((p->nodes[pside]->contents & CONTENTS_LADDER) || (p->nodes[!pside]->contents & CONTENTS_LADDER)) { //NOTE: doesn't have to be solid at the other side because // when standing one can use a crouch area (which is not solid) // as a ladder // imagine a ladder one can walk underthrough, // under the ladder against the ladder is a crouch area // the (vertical) sides of this crouch area area also used as // ladder sides when standing (not crouched) tmpface->faceflags |= FACE_LADDER; } //end if //if it is possible to stand on the face if (AAS_GroundFace(tmpface)) { tmpface->faceflags |= FACE_GROUND; } //end if // areafaceflags |= tmpface->faceflags; //no aas face number yet (zero is a dummy in the aasworld faces) tmpface->aasfacenum = 0; //add the front side of the face to the area AAS_AddFaceSideToArea(tmpface, 0, tmparea); } //end else } //end for qprintf("\r%6d", tmparea->areanum); //presence type in the area tmparea->presencetype = ~node->expansionbboxes & cfg.allpresencetypes; // tmparea->contents = 0; if (node->contents & CONTENTS_CLUSTERPORTAL) tmparea->contents |= AREACONTENTS_CLUSTERPORTAL; if (node->contents & CONTENTS_MOVER) tmparea->contents |= AREACONTENTS_MOVER; if (node->contents & CONTENTS_TELEPORTER) tmparea->contents |= AREACONTENTS_TELEPORTER; if (node->contents & CONTENTS_JUMPPAD) tmparea->contents |= AREACONTENTS_JUMPPAD; if (node->contents & CONTENTS_DONOTENTER) tmparea->contents |= AREACONTENTS_DONOTENTER; if (node->contents & CONTENTS_WATER) tmparea->contents |= AREACONTENTS_WATER; if (node->contents & CONTENTS_LAVA) tmparea->contents |= AREACONTENTS_LAVA; if (node->contents & CONTENTS_SLIME) tmparea->contents |= AREACONTENTS_SLIME; if (node->contents & CONTENTS_NOTTEAM1) tmparea->contents |= AREACONTENTS_NOTTEAM1; if (node->contents & CONTENTS_NOTTEAM2) tmparea->contents |= AREACONTENTS_NOTTEAM2; //store the bsp model that's inside this node tmparea->modelnum = node->modelnum; //sorta check for flipped area faces (remove??) AAS_FlipAreaFaces(tmparea); //check if the area is ok (remove??) AAS_CheckArea(tmparea); // tmpnode = AAS_AllocTmpNode(); tmpnode->planenum = 0; tmpnode->children[0] = 0; tmpnode->children[1] = 0; tmpnode->tmparea = tmparea; // return tmpnode; } //end of the function AAS_CreateArea
/* ================ SplitBrush Generates two new brushes, leaving the original unchanged ================ */ void SplitBrush (bspbrush_t *brush, int planenum, bspbrush_t **front, bspbrush_t **back) { bspbrush_t *b[2]; int i, j; winding_t *w, *cw[2], *midwinding; plane_t *plane, *plane2; side_t *s, *cs; float d, d_front, d_back; *front = *back = NULL; plane = &mapplanes[planenum]; // check all points d_front = d_back = 0; for (i=0 ; i<brush->numsides ; i++) { w = brush->sides[i].winding; if (!w) continue; for (j=0 ; j<w->numpoints ; j++) { d = DotProduct (w->p[j], plane->normal) - plane->dist; if (d > 0 && d > d_front) d_front = d; if (d < 0 && d < d_back) d_back = d; } } if (d_front < 0.1) // PLANESIDE_EPSILON) { // only on back *back = CopyBrush (brush); return; } if (d_back > -0.1) // PLANESIDE_EPSILON) { // only on front *front = CopyBrush (brush); return; } // create a new winding from the split plane w = BaseWindingForPlane (plane->normal, plane->dist); for (i=0 ; i<brush->numsides && w ; i++) { plane2 = &mapplanes[brush->sides[i].planenum ^ 1]; ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON); } if (!w || WindingIsTiny (w) ) { // the brush isn't really split int side; side = BrushMostlyOnSide (brush, plane); if (side == PSIDE_FRONT) *front = CopyBrush (brush); if (side == PSIDE_BACK) *back = CopyBrush (brush); return; } if (WindingIsHuge (w)) { qprintf ("WARNING: huge winding\n"); } midwinding = w; // split it for real for (i=0 ; i<2 ; i++) { b[i] = AllocBrush (brush->numsides+1); b[i]->original = brush->original; } // split all the current windings for (i=0 ; i<brush->numsides ; i++) { s = &brush->sides[i]; w = s->winding; if (!w) continue; ClipWindingEpsilon (w, plane->normal, plane->dist, 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]); for (j=0 ; j<2 ; j++) { if (!cw[j]) continue; #if 0 if (WindingIsTiny (cw[j])) { FreeWinding (cw[j]); continue; } #endif cs = &b[j]->sides[b[j]->numsides]; b[j]->numsides++; *cs = *s; // cs->planenum = s->planenum; // cs->texinfo = s->texinfo; // cs->visible = s->visible; // cs->original = s->original; cs->winding = cw[j]; cs->tested = false; } } // see if we have valid polygons on both sides for (i=0 ; i<2 ; i++) { BoundBrush (b[i]); for (j=0 ; j<3 ; j++) { if (b[i]->mins[j] < -4096 || b[i]->maxs[j] > 4096) { qprintf ("bogus brush after clip\n"); break; } } if (b[i]->numsides < 3 || j < 3) { FreeBrush (b[i]); b[i] = NULL; } } if ( !(b[0] && b[1]) ) { if (!b[0] && !b[1]) qprintf ("split removed brush\n"); else qprintf ("split not on both sides\n"); if (b[0]) { FreeBrush (b[0]); *front = CopyBrush (brush); } if (b[1]) { FreeBrush (b[1]); *back = CopyBrush (brush); } return; } // add the midwinding to both sides for (i=0 ; i<2 ; i++) { cs = &b[i]->sides[b[i]->numsides]; b[i]->numsides++; cs->planenum = planenum^i^1; cs->texinfo = TEXINFO_NODE; cs->visible = false; cs->tested = false; if (i==0) cs->winding = CopyWinding (midwinding); else cs->winding = midwinding; } { vec_t v1; int i; for (i=0 ; i<2 ; i++) { v1 = BrushVolume (b[i]); if (v1 < 1.0) { FreeBrush (b[i]); b[i] = NULL; // qprintf ("tiny volume after clip\n"); } } } *front = b[0]; *back = b[1]; }
//=========================================================================== // Generates two new brushes, leaving the original // unchanged // // modified for Half-Life because there are quite a lot of tiny node leaves // in the Half-Life bsps // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void Q1_SplitBrush(bspbrush_t *brush, int planenum, int nodenum, bspbrush_t **front, bspbrush_t **back) { bspbrush_t *b[2]; int i, j; winding_t *w, *cw[2], *midwinding; plane_t *plane, *plane2; side_t *s, *cs; float d, d_front, d_back; *front = *back = NULL; plane = &mapplanes[planenum]; // check all points d_front = d_back = 0; for (i=0 ; i<brush->numsides ; i++) { w = brush->sides[i].winding; if (!w) continue; for (j=0 ; j<w->numpoints ; j++) { d = DotProduct (w->p[j], plane->normal) - plane->dist; if (d > 0 && d > d_front) d_front = d; if (d < 0 && d < d_back) d_back = d; } //end for } //end for if (d_front < 0.1) // PLANESIDE_EPSILON) { // only on back *back = CopyBrush (brush); Log_Print("Q1_SplitBrush: only on back\n"); return; } //end if if (d_back > -0.1) // PLANESIDE_EPSILON) { // only on front *front = CopyBrush (brush); Log_Print("Q1_SplitBrush: only on front\n"); return; } //end if // create a new winding from the split plane w = BaseWindingForPlane (plane->normal, plane->dist); for (i = 0; i < brush->numsides && w; i++) { plane2 = &mapplanes[brush->sides[i].planenum ^ 1]; ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON); } //end for if (!w || WindingIsTiny(w)) { // the brush isn't really split int side; Log_Print("Q1_SplitBrush: no split winding\n"); side = BrushMostlyOnSide (brush, plane); if (side == PSIDE_FRONT) *front = CopyBrush (brush); if (side == PSIDE_BACK) *back = CopyBrush (brush); return; } if (WindingIsHuge(w)) { Log_Print("Q1_SplitBrush: WARNING huge split winding\n"); } //end of midwinding = w; // split it for real for (i = 0; i < 2; i++) { b[i] = AllocBrush (brush->numsides+1); b[i]->original = brush->original; } //end for // split all the current windings for (i=0 ; i<brush->numsides ; i++) { s = &brush->sides[i]; w = s->winding; if (!w) continue; ClipWindingEpsilon (w, plane->normal, plane->dist, 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]); for (j=0 ; j<2 ; j++) { if (!cw[j]) continue; #if 0 if (WindingIsTiny (cw[j])) { FreeWinding (cw[j]); continue; } #endif cs = &b[j]->sides[b[j]->numsides]; b[j]->numsides++; *cs = *s; // cs->planenum = s->planenum; // cs->texinfo = s->texinfo; // cs->visible = s->visible; // cs->original = s->original; cs->winding = cw[j]; cs->flags &= ~SFL_TESTED; } //end for } //end for // see if we have valid polygons on both sides for (i=0 ; i<2 ; i++) { BoundBrush (b[i]); for (j=0 ; j<3 ; j++) { if (b[i]->mins[j] < -4096 || b[i]->maxs[j] > 4096) { Log_Print("Q1_SplitBrush: bogus brush after clip\n"); break; } //end if } //end for if (b[i]->numsides < 3 || j < 3) { FreeBrush (b[i]); b[i] = NULL; Log_Print("Q1_SplitBrush: numsides < 3\n"); } //end if } //end for if ( !(b[0] && b[1]) ) { if (!b[0] && !b[1]) Log_Print("Q1_SplitBrush: split removed brush\n"); else Log_Print("Q1_SplitBrush: split not on both sides\n"); if (b[0]) { FreeBrush (b[0]); *front = CopyBrush (brush); } //end if if (b[1]) { FreeBrush (b[1]); *back = CopyBrush (brush); } //end if return; } //end if // add the midwinding to both sides for (i = 0; i < 2; i++) { cs = &b[i]->sides[b[i]->numsides]; b[i]->numsides++; cs->planenum = planenum^i^1; cs->texinfo = 0; //store the node number in the surf to find the texinfo later on cs->surf = nodenum; // cs->flags &= ~SFL_VISIBLE; cs->flags &= ~SFL_TESTED; cs->flags &= ~SFL_TEXTURED; if (i==0) cs->winding = CopyWinding (midwinding); else cs->winding = midwinding; } //end for { vec_t v1; int i; for (i=0 ; i<2 ; i++) { v1 = BrushVolume (b[i]); if (v1 < 1) { FreeBrush (b[i]); b[i] = NULL; Log_Print("Q1_SplitBrush: tiny volume after clip\n"); } //end if } //end for } //*/ *front = b[0]; *back = b[1]; } //end of the function Q1_SplitBrush
void AddWindingToConvexHull(winding_t * w, winding_t ** hull, vec3_t normal) { int i, j, k, numHullPoints, numNew; float *p, *copy, d; vec3_t dir; vec3_t hullPoints[MAX_HULL_POINTS], newHullPoints[MAX_HULL_POINTS], hullDirs[MAX_HULL_POINTS]; bool hullSide[MAX_HULL_POINTS], outside; if(!*hull) { *hull = CopyWinding(w); return; } numHullPoints = (*hull)->numpoints; Com_Memcpy(hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t)); for(i = 0; i < w->numpoints; i++) { p = w->p[i]; // calculate hull side vectors for(j = 0; j < numHullPoints; j++) { k = (j + 1) % numHullPoints; VectorSubtract(hullPoints[k], hullPoints[j], dir); VectorNormalize2(dir, dir); CrossProduct(normal, dir, hullDirs[j]); } outside = false; for(j = 0; j < numHullPoints; j++) { VectorSubtract(p, hullPoints[j], dir); d = DotProduct(dir, hullDirs[j]); if(d >= ON_EPSILON) { outside = true; } if(d >= -ON_EPSILON) { hullSide[j] = true; } else { hullSide[j] = false; } } // if the point is effectively inside, do nothing if(!outside) { continue; } // find the back side to front side transition for(j = 0; j < numHullPoints; j++) { if(!hullSide[j % numHullPoints] && hullSide[(j + 1) % numHullPoints]) { break; } } if(j == numHullPoints) { continue; } // insert the point here VectorCopy(p, newHullPoints[0]); numNew = 1; // copy over all points that aren't double fronts j = (j + 1) % numHullPoints; for(k = 0; k < numHullPoints; k++) { if(hullSide[(j + k) % numHullPoints] && hullSide[(j + k + 1) % numHullPoints]) { continue; } copy = hullPoints[(j + k + 1) % numHullPoints]; VectorCopy(copy, newHullPoints[numNew]); numNew++; } numHullPoints = numNew; Com_Memcpy(hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t)); } FreeWinding(*hull); w = AllocWinding(numHullPoints); w->numpoints = numHullPoints; *hull = w; Com_Memcpy(w->p, hullPoints, numHullPoints * sizeof(vec3_t)); }
/* ============= ClipWindingEpsilon ============= */ void ClipWindingEpsilon(winding_t * in, vec3_t normal, vec_t dist, vec_t epsilon, winding_t ** front, winding_t ** back) { vec_t dists[MAX_POINTS_ON_WINDING + 4], *p1, *p2; int sides[MAX_POINTS_ON_WINDING + 4], counts[3], i, j, maxpts; static vec_t dot; // VC 4.2 optimizer bug if not static vec3_t mid; winding_t *f, *b; counts[0] = counts[1] = counts[2] = 0; // determine sides for each point for(i = 0; i < in->numpoints; i++) { dot = DotProduct(in->p[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 = CopyWinding(in); return; } if(!counts[1]) { *front = CopyWinding(in); return; } maxpts = in->numpoints + 4; // cant use counts[0]+2 because // of fp grouping errors *front = f = AllocWinding(maxpts); *back = b = AllocWinding(maxpts); for(i = 0; i < in->numpoints; i++) { p1 = in->p[i]; if(sides[i] == SIDE_ON) { VectorCopy(p1, f->p[f->numpoints]); f->numpoints++; VectorCopy(p1, b->p[b->numpoints]); b->numpoints++; continue; } if(sides[i] == SIDE_FRONT) { VectorCopy(p1, f->p[f->numpoints]); f->numpoints++; } if(sides[i] == SIDE_BACK) { VectorCopy(p1, b->p[b->numpoints]); b->numpoints++; } if(sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i]) { continue; } // generate a split point p2 = in->p[(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->p[f->numpoints]); f->numpoints++; VectorCopy(mid, b->p[b->numpoints]); b->numpoints++; } if(f->numpoints > maxpts || b->numpoints > maxpts) { Com_Error(ERR_DROP, "ClipWinding: points exceeded estimate"); } if(f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) { Com_Error(ERR_DROP, "ClipWinding: MAX_POINTS_ON_WINDING"); } }
/** * @brief Generates two new brushes, leaving the original unchanged */ void SplitBrush (const bspbrush_t* brush, uint16_t planenum, bspbrush_t** front, bspbrush_t** back) { bspbrush_t* b[2]; int i, j; winding_t* w, *cw[2], *midwinding; plane_t* plane; float d_front, d_back; *front = *back = nullptr; plane = &mapplanes[planenum]; /* check all points */ d_front = d_back = 0; for (i = 0; i < brush->numsides; i++) { w = brush->sides[i].winding; if (!w) continue; for (j = 0; j < w->numpoints; j++) { const float d = DotProduct(w->p[j], plane->normal) - plane->dist; if (d > 0 && d > d_front) d_front = d; else if (d < 0 && d < d_back) d_back = d; } } if (d_front < 0.1) { /* PLANESIDE_EPSILON) */ /* only on back */ *back = CopyBrush(brush); return; } if (d_back > -0.1) { /* PLANESIDE_EPSILON) */ /* only on front */ *front = CopyBrush(brush); return; } /* create a new winding from the split plane */ w = BaseWindingForPlane(plane->normal, plane->dist); for (i = 0; i < brush->numsides && w; i++) { plane_t* plane2 = &mapplanes[brush->sides[i].planenum ^ 1]; ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0); /* PLANESIDE_EPSILON); */ } /* the brush isn't really split */ if (!w || WindingIsTiny(w)) { const int side = BrushMostlyOnSide(brush, plane); if (side == PSIDE_FRONT) *front = CopyBrush(brush); else if (side == PSIDE_BACK) *back = CopyBrush(brush); return; } if (WindingIsHuge(w)) { /** @todo Print brush and entnum either of the brush that was splitted * or the plane that was used as splitplane */ Com_Printf("WARNING: Large winding\n"); } midwinding = w; /* split it for real */ for (i = 0; i < 2; i++) { b[i] = AllocBrush(brush->numsides + 1); b[i]->original = brush->original; } /* split all the current windings */ for (i = 0; i < brush->numsides; i++) { const side_t* s = &brush->sides[i]; w = s->winding; if (!w) continue; ClipWindingEpsilon(w, plane->normal, plane->dist, 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]); for (j = 0; j < 2; j++) { side_t* cs; if (!cw[j]) continue; cs = &b[j]->sides[b[j]->numsides]; b[j]->numsides++; *cs = *s; cs->winding = cw[j]; cs->tested = false; } } /* see if we have valid polygons on both sides */ for (i = 0; i < 2; i++) { BoundBrush(b[i]); for (j = 0; j < 3; j++) { if (b[i]->mins[j] < -MAX_WORLD_WIDTH || b[i]->maxs[j] > MAX_WORLD_WIDTH) { /** @todo Print brush and entnum either of the brush that was split * or the plane that was used as splitplane */ Verb_Printf(VERB_EXTRA, "bogus brush after clip\n"); break; } } if (b[i]->numsides < 3 || j < 3) { FreeBrush(b[i]); b[i] = nullptr; } } if (!(b[0] && b[1])) { /** @todo Print brush and entnum either of the brush that was splitted * or the plane that was used as splitplane */ if (!b[0] && !b[1]) Verb_Printf(VERB_EXTRA, "split removed brush\n"); else Verb_Printf(VERB_EXTRA, "split not on both sides\n"); if (b[0]) { FreeBrush(b[0]); *front = CopyBrush(brush); } if (b[1]) { FreeBrush(b[1]); *back = CopyBrush(brush); } return; } /* add the midwinding to both sides */ for (i = 0; i < 2; i++) { side_t* cs = &b[i]->sides[b[i]->numsides]; b[i]->numsides++; cs->planenum = planenum ^ i ^ 1; cs->texinfo = TEXINFO_NODE; cs->visible = false; cs->tested = false; if (i == 0) cs->winding = CopyWinding(midwinding); else cs->winding = midwinding; } for (i = 0; i < 2; i++) { const vec_t v1 = BrushVolume(b[i]); if (v1 < 1.0) { FreeBrush(b[i]); b[i] = nullptr; /** @todo Print brush and entnum either of the brush that was splitted * or the plane that was used as splitplane */ Verb_Printf(VERB_EXTRA, "tiny volume after clip\n"); } } *front = b[0]; *back = b[1]; }
/* ================== CM_AddFacetBevels ================== */ void CM_AddFacetBevels( facet_t *facet ) { int i, j, k, l; int axis, dir, order, flipped; planeDef_t plane,newplane; bfixed d; winding_t *w, *w2; bvec3_t mins, maxs; avec3_t vec, vec2; plane=planes[ facet->surfacePlane ].pd; w = BaseWindingForPlane( plane.normal, plane.dist ); for ( j = 0 ; j < facet->numBorders && w ; j++ ) { if (facet->borderPlanes[j] == facet->surfacePlane) continue; plane=planes[ facet->borderPlanes[j] ].pd; if ( !facet->borderInward[j] ) { VectorSubtract( avec3_origin, plane.normal, plane.normal ); plane.dist = -plane.dist; } ChopWindingInPlace( &w, plane.normal, plane.dist, BFIXED(0,1) ); } if ( !w ) { return; } WindingBounds(w, mins, maxs); // add the axial planes order = 0; for ( axis = 0 ; axis < 3 ; axis++ ) { for ( dir = -1 ; dir <= 1 ; dir += 2, order++ ) { VectorClear(plane.normal); plane.normal[axis] = MAKE_AFIXED(dir); if (dir == 1) { plane.dist = maxs[axis]; } else { plane.dist = -mins[axis]; } //if it's the surface plane if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) { continue; } // see if the plane is allready present for ( i = 0 ; i < facet->numBorders ; i++ ) { if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) break; } if ( i == facet->numBorders ) { if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n"); facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped); facet->borderNoAdjust[facet->numBorders] = 0; facet->borderInward[facet->numBorders] = flipped; facet->numBorders++; } } } // // add the edge bevels // // test the non-axial plane edges for ( j = 0 ; j < w->numpoints ; j++ ) { k = (j+1)%w->numpoints; bvec3_t tmp; VectorSubtract (w->p[j], w->p[k], tmp); //if it's a degenerate edge if (VectorNormalizeB2A(tmp,vec) < BFIXED(0,5)) continue; CM_SnapVector(vec); for ( k = 0; k < 3 ; k++ ) if ( vec[k] == -AFIXED_1 || vec[k] == AFIXED_1 ) break; // axial if ( k < 3 ) continue; // only test non-axial edges // try the six possible slanted axials from this edge for ( axis = 0 ; axis < 3 ; axis++ ) { for ( dir = -1 ; dir <= 1 ; dir += 2 ) { // construct a plane VectorClear (vec2); vec2[axis] = MAKE_AFIXED(dir); CrossProduct (vec, vec2, plane.normal); if (VectorNormalize(plane.normal) < AFIXED(0,5)) continue; plane.dist = FIXED_VEC3DOT (w->p[j], plane.normal); // if all the points of the facet winding are // behind this plane, it is a proper edge bevel for ( l = 0 ; l < w->numpoints ; l++ ) { d = FIXED_VEC3DOT(w->p[l], plane.normal) - plane.dist; if (d > BFIXED(0,1)) break; // point in front } if ( l < w->numpoints ) continue; //if it's the surface plane if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) { continue; } // see if the plane is allready present for ( i = 0 ; i < facet->numBorders ; i++ ) { if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) { break; } } if ( i == facet->numBorders ) { if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n"); facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped); for ( k = 0 ; k < facet->numBorders ; k++ ) { if (facet->borderPlanes[facet->numBorders] == facet->borderPlanes[k]) Com_Printf("WARNING: bevel plane already used\n"); } facet->borderNoAdjust[facet->numBorders] = 0; facet->borderInward[facet->numBorders] = flipped; // w2 = CopyWinding(w); newplane=planes[facet->borderPlanes[facet->numBorders]].pd; if (!facet->borderInward[facet->numBorders]) { VectorNegate(newplane.normal, newplane.normal); newplane.dist = -newplane.dist; } //end if ChopWindingInPlace( &w2, newplane.normal, newplane.dist, BFIXED(0,1) ); if (!w2) { Com_DPrintf("WARNING: CM_AddFacetBevels... invalid bevel\n"); continue; } else { FreeWinding(w2); } // facet->numBorders++; //already got a bevel // break; } } } } FreeWinding( w ); #ifndef BSPC //add opposite plane facet->borderPlanes[facet->numBorders] = facet->surfacePlane; facet->borderNoAdjust[facet->numBorders] = 0; facet->borderInward[facet->numBorders] = qtrue; facet->numBorders++; #endif //BSPC }