winding_t *BaseWindingForNode (node_t *node) { winding_t *w; node_t *n; plane_t *plane; Vector normal; vec_t dist; w = BaseWindingForPlane (mapplanes[node->planenum].normal , mapplanes[node->planenum].dist); // clip by all the parents for (n=node->parent ; n && w ; ) { plane = &mapplanes[n->planenum]; if (n->children[0] == node) { // take front ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON); } else { // take back VectorSubtract (vec3_origin, plane->normal, normal); dist = -plane->dist; ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON); } node = n; n = n->parent; } return w; }
static winding_t *BaseWindingForNode (node_t *node) { node_t *n; winding_t *w; w = BaseWindingForPlane(mapplanes[node->planenum].normal , mapplanes[node->planenum].dist); /* clip by all the parents */ for (n = node->parent; n && w;) { const plane_t *plane = &mapplanes[n->planenum]; if (n->children[0] == node) { /* take front */ ChopWindingInPlace(&w, plane->normal, plane->dist, BASE_WINDING_EPSILON); } else { /* take back */ const vec_t dist = -plane->dist; vec3_t normal; VectorSubtract(vec3_origin, plane->normal, normal); ChopWindingInPlace(&w, normal, dist, BASE_WINDING_EPSILON); } node = n; n = n->parent; } return w; }
//=========================================================================== // creates a winding for the given brush side on the given brush // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== winding_t *Sin_BrushSideWinding( sin_dbrush_t *brush, sin_dbrushside_t *baseside ) { int i; sin_dplane_t *baseplane, *plane; sin_dbrushside_t *side; winding_t *w; //create a winding for the brush side with the given planenumber baseplane = &sin_dplanes[baseside->planenum]; w = BaseWindingForPlane( baseplane->normal, baseplane->dist ); for ( i = 0; i < brush->numsides && w; i++ ) { side = &sin_dbrushsides[brush->firstside + i]; //don't chop with the base plane if ( side->planenum == baseside->planenum ) { continue; } //also don't use planes that are almost equal plane = &sin_dplanes[side->planenum]; if ( DotProduct( baseplane->normal, plane->normal ) > 0.999 && fabs( baseplane->dist - plane->dist ) < 0.01 ) { continue; } // plane = &sin_dplanes[side->planenum ^ 1]; ChopWindingInPlace( &w, plane->normal, plane->dist, 0 ); //CLIP_EPSILON); } //end for return w; } //end of the function Sin_BrushSideWinding
//=========================================================================== // 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
qboolean MakeBrushWindings (mapbrush_t *ob) { int i, j; winding_t *w; side_t *side; plane_t *plane; ClearBounds (ob->mins, ob->maxs); for (i=0 ; i<ob->numsides ; i++) { plane = &mapplanes[ob->original_sides[i].planenum]; w = BaseWindingForPlane (plane->normal, plane->dist); for (j=0 ; j<ob->numsides && w; j++) { if (i == j) continue; if (ob->original_sides[j].bevel) continue; plane = &mapplanes[ob->original_sides[j].planenum^1]; ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); } side = &ob->original_sides[i]; side->winding = w; if (w) { side->visible = true; for (j=0 ; j<w->numpoints ; j++) AddPointToBounds (w->p[j], ob->mins, ob->maxs); } } for (i=0 ; i<3 ; i++) { if (ob->mins[i] < -max_bounds || ob->maxs[i] > max_bounds) // was -4096, 4096 { printf ("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum); printf(" Brush: %s\n", brush_info); printf(" Bounds: %g %g %g -> %g %g %g\n", ob->mins[0], ob->mins[1], ob->mins[2], ob->maxs[0], ob->maxs[1], ob->maxs[2]); return true; } if (ob->mins[i] > max_bounds || ob->maxs[i] < -max_bounds) // was -4096, 4096 { printf ("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum); printf(" Brush: %s\n", brush_info); printf(" Bounds: %g %g %g -> %g %g %g\n", ob->mins[0], ob->mins[1], ob->mins[2], ob->maxs[0], ob->maxs[1], ob->maxs[2]); return true; } } return true; }
/* ================== CreateBrushWindings ================== */ void CreateBrushWindings (bspbrush_t *brush) { int i, j; winding_t *w; side_t *side; plane_t *plane; for (i=0 ; i<brush->numsides ; i++) { side = &brush->sides[i]; plane = &mapplanes[side->planenum]; w = BaseWindingForPlane (plane->normal, plane->dist); for (j=0 ; j<brush->numsides && w; j++) { if (i == j) continue; if (brush->sides[j].bevel) continue; plane = &mapplanes[brush->sides[j].planenum^1]; ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); } side->winding = w; } BoundBrush (brush); }
/* ================== CreateBrushWindings ================== */ void CreateBrushWindings (bspbrush_t *brush) { int i, j; winding_t *w; side_t *side; plane_t *plane; // translate the CSG problem to improve precision Vector insidePoint = PointInsideBrush( brush ); Vector offset = -insidePoint; for (i=0 ; i<brush->numsides ; i++) { side = &brush->sides[i]; plane = &g_MainMap->mapplanes[side->planenum]; w = BaseWindingForPlane (plane->normal, plane->dist + DotProduct(plane->normal, offset)); for (j=0 ; j<brush->numsides && w; j++) { if (i == j) continue; if (brush->sides[j].bevel) continue; plane = &g_MainMap->mapplanes[brush->sides[j].planenum^1]; ChopWindingInPlace (&w, plane->normal, plane->dist + DotProduct(plane->normal, offset), 0); //CLIP_EPSILON); } TranslateWinding( w, -offset ); side->winding = w; } BoundBrush (brush); }
/** * @brief makes basewindigs for sides and mins/maxs for the brush * @returns false if the brush doesn't enclose a valid volume */ static void CreateBrushWindings (bspbrush_t* brush) { int i; for (i = 0; i < brush->numsides; i++) { side_t* side = &brush->sides[i]; const plane_t* plane = &mapplanes[side->planenum]; int j; /* evidence that winding_t represents a hessian normal plane */ winding_t* w = BaseWindingForPlane(plane->normal, plane->dist); for (j = 0; j < brush->numsides && w; j++) { if (i == j) continue; /* back side clipaway */ if (brush->sides[j].planenum == (side->planenum ^ 1)) continue; if (brush->sides[j].bevel) continue; plane = &mapplanes[brush->sides[j].planenum ^ 1]; ChopWindingInPlace(&w, plane->normal, plane->dist, 0); /*CLIP_EPSILON); */ /* fix broken windings that would generate trifans */ if (!FixWinding(w)) Verb_Printf(VERB_EXTRA, "removed degenerated edge(s) from winding\n"); } side->winding = w; } BoundBrush(brush); }
void MakeHeadnodePortals (tree_t *tree) { Vector bounds[2]; int i, j, n; portal_t *p, *portals[6]; plane_t bplanes[6], *pl; node_t *node; node = tree->headnode; // pad with some space so there will never be null volume leafs for (i=0 ; i<3 ; i++) { bounds[0][i] = tree->mins[i] - SIDESPACE; bounds[1][i] = tree->maxs[i] + SIDESPACE; } tree->outside_node.planenum = PLANENUM_LEAF; tree->outside_node.brushlist = NULL; tree->outside_node.portals = NULL; tree->outside_node.contents = 0; for (i=0 ; i<3 ; i++) for (j=0 ; j<2 ; j++) { n = j*3 + i; p = AllocPortal (); portals[n] = p; pl = &bplanes[n]; memset (pl, 0, sizeof(*pl)); if (j) { pl->normal[i] = -1; pl->dist = -bounds[j][i]; } else { pl->normal[i] = 1; pl->dist = bounds[j][i]; } p->plane = *pl; p->winding = BaseWindingForPlane (pl->normal, pl->dist); AddPortalToNodes (p, node, &tree->outside_node); } // clip the basewindings by all the other planes for (i=0 ; i<6 ; i++) { for (j=0 ; j<6 ; j++) { if (j == i) continue; ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON); } } }
/* ================== CM_ValidateFacet If the facet isn't bounded by its borders, we screwed up. ================== */ static qboolean CM_ValidateFacet(facet_t *facet) { float plane[4]; int j; winding_t *w; vec3_t bounds[2]; if (facet->surfacePlane == -1) { return qfalse; } Vector4Copy(planes[facet->surfacePlane].plane, plane); w = BaseWindingForPlane(plane, plane[3]); for (j = 0 ; j < facet->numBorders && w ; j++) { if (facet->borderPlanes[j] == -1) { FreeWinding(w); return qfalse; } 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 qfalse; // winding was completely chopped away } // see if the facet is unreasonably large WindingBounds(w, bounds[0], bounds[1]); FreeWinding(w); for (j = 0 ; j < 3 ; j++) { if (bounds[1][j] - bounds[0][j] > MAX_MAP_BOUNDS) { return qfalse; // we must be missing a plane } if (bounds[0][j] >= MAX_MAP_BOUNDS) { return qfalse; } if (bounds[1][j] <= -MAX_MAP_BOUNDS) { return qfalse; } } return qtrue; // winding is fine }
/* ================== MakeNodePortal create the new portal by taking the full plane winding for the cutting plane and clipping it by all of parents of this node ================== */ void MakeNodePortal (node_t *node) { portal_t *new_portal, *p; winding_t *w; Vector normal; float dist = 0.0f; int side = 0; w = BaseWindingForNode (node); // clip the portal by all the other portals in the node for (p = node->portals ; p && w; p = p->next[side]) { if (p->nodes[0] == node) { side = 0; VectorCopy (p->plane.normal, normal); dist = p->plane.dist; } else if (p->nodes[1] == node) { side = 1; VectorSubtract (vec3_origin, p->plane.normal, normal); dist = -p->plane.dist; } else { Error ("CutNodePortals_r: mislinked portal"); } ChopWindingInPlace (&w, normal, dist, 0.1); } if (!w) { return; } if (WindingIsTiny (w)) { c_tinyportals++; FreeWinding (w); return; } new_portal = AllocPortal (); new_portal->plane = mapplanes[node->planenum]; new_portal->onnode = node; new_portal->winding = w; AddPortalToNodes (new_portal, node->children[0], node->children[1]); }
void CPlaneList::AddBrushes( void ) { CUtlVector<listplane_t> temp; for ( int brushnumber = 0; brushnumber < numbrushes; brushnumber++ ) { if ( IsBrushReferenced(brushnumber) ) { CUtlVector<winding_t *> windings; for ( int i = 0; i < dbrushes[brushnumber].numsides; i++ ) { dbrushside_t *pside = dbrushsides + i + dbrushes[brushnumber].firstside; if (pside->bevel) continue; dplane_t *pplane = dplanes + pside->planenum; winding_t *w = BaseWindingForPlane( pplane->normal, pplane->dist - m_shrink ); for ( int j = 0; j < dbrushes[brushnumber].numsides && w; j++ ) { if (i == j) continue; dbrushside_t *pClipSide = dbrushsides + j + dbrushes[brushnumber].firstside; if (pClipSide->bevel) continue; dplane_t *pClipPlane = dplanes + pClipSide->planenum; ChopWindingInPlace (&w, -pClipPlane->normal, -pClipPlane->dist+m_shrink, 0); //CLIP_EPSILON); } if ( w ) { windings.AddToTail( w ); } } CUtlVector<Vector *> vertList; for ( int p = 0; p < windings.Count(); p++ ) { for ( int v = 0; v < windings[p]->numpoints; v++ ) { vertList.AddToTail( windings[p]->p + v ); } } CPhysConvex *pConvex = physcollision->ConvexFromVerts( vertList.Base(), vertList.Count() ); if ( pConvex ) { physcollision->SetConvexGameData( pConvex, brushnumber ); AddConvex( pConvex ); } temp.RemoveAll(); } } }
/* ================== CM_ValidateFacet If the facet isn't bounded by its borders, we screwed up. ================== */ static qboolean CM_ValidateFacet( facet_t *facet ) { planeDef_t plane; int j; winding_t *w; bvec3_t bounds[2]; if ( facet->surfacePlane == -1 ) { return qfalse; } plane=planes[ facet->surfacePlane ].pd; w = BaseWindingForPlane( plane.normal, plane.dist ); for ( j = 0 ; j < facet->numBorders && w ; j++ ) { if ( facet->borderPlanes[j] == -1 ) { return qfalse; } 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 qfalse; // winding was completely chopped away } // see if the facet is unreasonably large WindingBounds( w, bounds[0], bounds[1] ); FreeWinding( w ); for ( j = 0 ; j < 3 ; j++ ) { if ( bounds[1][j] - bounds[0][j] > BFIXED(MAX_MAP_BOUNDS,0) ) { return qfalse; // we must be missing a plane } if ( bounds[0][j] >= BFIXED(MAX_MAP_BOUNDS,0) ) { return qfalse; } if ( bounds[1][j] <= -BFIXED(MAX_MAP_BOUNDS,0) ) { return qfalse; } } return qtrue; // winding is fine }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void BSPBrushWindings(bspbrush_t *brush) { int i, j; winding_t *w; plane_t *plane; for (i = 0; i < brush->numsides; i++) { plane = &mapplanes[brush->sides[i].planenum]; w = BaseWindingForPlane(plane->normal, plane->dist); for (j = 0; j < brush->numsides && w; j++) { if (i == j) continue; plane = &mapplanes[brush->sides[j].planenum^1]; ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); } //end for brush->sides[i].winding = w; } //end for } //end of the function BSPBrushWindings
//=========================================================================== // 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
/** * @brief makes basewindings for sides and mins / maxs for the brush */ static bool MakeBrushWindings (mapbrush_t* brush) { int i, j; brush->mbBox.setNegativeVolume(); for (i = 0; i < brush->numsides; i++) { const plane_t* plane = &mapplanes[brush->original_sides[i].planenum]; winding_t* w = BaseWindingForPlane(plane->normal, plane->dist); for (j = 0; j < brush->numsides && w; j++) { if (i == j) continue; /* back side clipaway */ if (brush->original_sides[j].planenum == (brush->original_sides[j].planenum ^ 1)) continue; if (brush->original_sides[j].bevel) continue; plane = &mapplanes[brush->original_sides[j].planenum ^ 1]; ChopWindingInPlace(&w, plane->normal, plane->dist, 0); /*CLIP_EPSILON); */ } side_t* side = &brush->original_sides[i]; side->winding = w; if (w) { side->visible = true; for (j = 0; j < w->numpoints; j++) brush->mbBox.add(w->p[j]); } } for (i = 0; i < 3; i++) { if (brush->mbBox.mins[i] < -MAX_WORLD_WIDTH || brush->mbBox.maxs[i] > MAX_WORLD_WIDTH) Com_Printf("entity %i, brush %i: bounds out of world range (%f:%f)\n", brush->entitynum, brush->brushnum, brush->mbBox.mins[i], brush->mbBox.maxs[i]); if (brush->mbBox.mins[i] > MAX_WORLD_WIDTH || brush->mbBox.maxs[i] < -MAX_WORLD_WIDTH) { Com_Printf("entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum); VectorClear(brush->mbBox.mins); VectorClear(brush->mbBox.maxs); } } return true; }
/* * MakeBrushWindings * * Makes basewindigs for sides and mins / maxs for the brush */ static boolean_t MakeBrushWindings(map_brush_t * ob) { int i, j; side_t *side; ClearBounds(ob->mins, ob->maxs); for (i = 0; i < ob->num_sides; i++) { const map_plane_t *plane = &map_planes[ob->original_sides[i].plane_num]; winding_t *w = BaseWindingForPlane(plane->normal, plane->dist); for (j = 0; j < ob->num_sides && w; j++) { if (i == j) continue; // back side clipaway if (ob->original_sides[j].plane_num == (ob->original_sides[j].plane_num ^ 1)) continue; if (ob->original_sides[j].bevel) continue; plane = &map_planes[ob->original_sides[j].plane_num ^ 1]; ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); } side = &ob->original_sides[i]; side->winding = w; if (w) { side->visible = true; for (j = 0; j < w->numpoints; j++) AddPointToBounds(w->p[j], ob->mins, ob->maxs); } } for (i = 0; i < 3; i++) { if (ob->mins[0] < -MAX_WORLD_WIDTH || ob->maxs[0] > MAX_WORLD_WIDTH) Com_Verbose("entity %i, brush %i: bounds out of range\n", ob->entity_num, ob->brush_num); if (ob->mins[0] > MAX_WORLD_WIDTH || ob->maxs[0] < -MAX_WORLD_WIDTH) Com_Verbose("entity %i, brush %i: no visible sides on brush\n", ob->entity_num, ob->brush_num); } return true; }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== winding_t *AAS_SplitWinding( tmp_area_t *tmparea, int planenum ) { tmp_face_t *face; plane_t *plane; int side; winding_t *splitwinding; // plane = &mapplanes[planenum]; //create a split winding, first base winding for plane splitwinding = BaseWindingForPlane( plane->normal, plane->dist ); //chop with all the faces of the area for ( face = tmparea->tmpfaces; face && splitwinding; face = face->next[side] ) { //side of the face the original area was on side = face->frontarea != tmparea; plane = &mapplanes[face->planenum ^ side]; ChopWindingInPlace( &splitwinding, plane->normal, plane->dist, 0 ); // PLANESIDE_EPSILON); } //end for return splitwinding; } //end of the function AAS_SplitWinding
/* ================== CreateBrushWindings makes basewindigs for sides and mins / maxs for the brush returns false if the brush doesn't enclose a valid volume ================== */ qboolean CreateBrushWindings(bspBrush_t * brush) { int i, j; winding_t *w; side_t *side; plane_t *plane; for(i = 0; i < brush->numsides; i++) { side = &brush->sides[i]; // don't create a winding for a bevel if(side->bevel) { continue; } plane = &mapPlanes[side->planenum]; w = BaseWindingForPlane(plane->normal, plane->dist); for(j = 0; j < brush->numsides && w; j++) { if(i == j) continue; if(brush->sides[j].planenum == (brush->sides[i].planenum ^ 1)) continue; // back side clipaway if(brush->sides[j].bevel) continue; if(brush->sides[j].backSide) continue; plane = &mapPlanes[brush->sides[j].planenum ^ 1]; ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); } // free any existing winding if(side->winding) { FreeWinding(side->winding); } side->winding = w; } return BoundBrush(brush); }
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 CM_DrawDebugSurface( void ( *drawPoly )( int color, int numPoints, float *points ) ) { static cvar_t *cv; #ifndef BSPC static cvar_t *cv2; #endif const patchCollide_t *pc; facet_t *facet; winding_t *w; int i, j, k, n; int curplanenum, planenum, curinward, inward; float plane[4]; vec3_t mins = {-15, -15, -28}, maxs = {15, 15, 28}; //vec3_t mins = {0, 0, 0}, maxs = {0, 0, 0}; vec3_t v1, v2; #ifndef BSPC if ( !cv2 ) { cv2 = Cvar_Get( "r_debugSurface", "0", 0 ); } if ( cv2->integer != 1 ) { BotDrawDebugPolygons( drawPoly, cv2->integer ); return; } #endif if ( !debugPatchCollide ) { return; } #ifndef BSPC if ( !cv ) { cv = Cvar_Get( "cm_debugSize", "2", 0 ); } #endif pc = debugPatchCollide; for ( i = 0, facet = pc->facets ; i < pc->numFacets ; i++, facet++ ) { for ( k = 0 ; k < facet->numBorders + 1; k++ ) { // if ( k < facet->numBorders ) { planenum = facet->borderPlanes[k]; inward = facet->borderInward[k]; } else { planenum = facet->surfacePlane; inward = qfalse; //continue; } Vector4Copy( pc->planes[ planenum ].plane, plane ); //planenum = facet->surfacePlane; if ( inward ) { VectorSubtract( vec3_origin, plane, plane ); plane[3] = -plane[3]; } plane[3] += cv->value; //* for ( n = 0; n < 3; n++ ) { if ( plane[n] > 0 ) { v1[n] = maxs[n]; } else { v1[n] = mins[n];} } //end for VectorNegate( plane, v2 ); plane[3] += fabs( DotProduct( v1, v2 ) ); //*/ w = BaseWindingForPlane( plane, plane[3] ); for ( j = 0 ; j < facet->numBorders + 1 && w; j++ ) { // if ( j < facet->numBorders ) { curplanenum = facet->borderPlanes[j]; curinward = facet->borderInward[j]; } else { curplanenum = facet->surfacePlane; curinward = qfalse; //continue; } // if ( curplanenum == planenum ) { continue; } Vector4Copy( pc->planes[ curplanenum ].plane, plane ); if ( !curinward ) { VectorSubtract( vec3_origin, plane, plane ); plane[3] = -plane[3]; } // if ( !facet->borderNoAdjust[j] ) { plane[3] -= cv->value; // } for ( n = 0; n < 3; n++ ) { if ( plane[n] > 0 ) { v1[n] = maxs[n]; } else { v1[n] = mins[n];} } //end for VectorNegate( plane, v2 ); plane[3] -= fabs( DotProduct( v1, v2 ) ); ChopWindingInPlace( &w, plane, plane[3], 0.1f ); } if ( w ) { if ( facet == debugFacet ) { drawPoly( 4, w->numpoints, w->p[0] ); //Com_Printf("blue facet has %d border planes\n", facet->numBorders); } else { drawPoly( 1, w->numpoints, w->p[0] ); } FreeWinding( w ); } else { Com_Printf( "winding chopped away by border planes\n" ); } } } // draw the debug block { vec3_t v[3]; VectorCopy( debugBlockPoints[0], v[0] ); VectorCopy( debugBlockPoints[1], v[1] ); VectorCopy( debugBlockPoints[2], v[2] ); drawPoly( 2, 3, v[0] ); VectorCopy( debugBlockPoints[2], v[0] ); VectorCopy( debugBlockPoints[3], v[1] ); VectorCopy( debugBlockPoints[0], v[2] ); drawPoly( 2, 3, v[0] ); } #if 0 vec3_t v[4]; v[0][0] = pc->bounds[1][0]; v[0][1] = pc->bounds[1][1]; v[0][2] = pc->bounds[1][2]; v[1][0] = pc->bounds[1][0]; v[1][1] = pc->bounds[0][1]; v[1][2] = pc->bounds[1][2]; v[2][0] = pc->bounds[0][0]; v[2][1] = pc->bounds[0][1]; v[2][2] = pc->bounds[1][2]; v[3][0] = pc->bounds[0][0]; v[3][1] = pc->bounds[1][1]; v[3][2] = pc->bounds[1][2]; drawPoly( 4, v[0] ); #endif }
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]; }
qboolean CreateBrushWindings( brush_t *brush ){ int i, j; #if Q3MAP2_EXPERIMENTAL_HIGH_PRECISION_MATH_FIXES winding_accu_t *w; #else winding_t *w; #endif side_t *side; plane_t *plane; /* walk the list of brush sides */ for ( i = 0; i < brush->numsides; i++ ) { /* get side and plane */ side = &brush->sides[ i ]; plane = &mapplanes[ side->planenum ]; /* make huge winding */ #if Q3MAP2_EXPERIMENTAL_HIGH_PRECISION_MATH_FIXES w = BaseWindingForPlaneAccu( plane->normal, plane->dist ); #else w = BaseWindingForPlane( plane->normal, plane->dist ); #endif /* walk the list of brush sides */ for ( j = 0; j < brush->numsides && w != NULL; j++ ) { if ( i == j ) { continue; } if ( brush->sides[ j ].planenum == ( brush->sides[ i ].planenum ^ 1 ) ) { continue; /* back side clipaway */ } if ( brush->sides[ j ].bevel ) { continue; } plane = &mapplanes[ brush->sides[ j ].planenum ^ 1 ]; #if Q3MAP2_EXPERIMENTAL_HIGH_PRECISION_MATH_FIXES ChopWindingInPlaceAccu( &w, plane->normal, plane->dist, 0 ); #else ChopWindingInPlace( &w, plane->normal, plane->dist, 0 ); // CLIP_EPSILON ); #endif /* ydnar: fix broken windings that would generate trifans */ #if Q3MAP2_EXPERIMENTAL_HIGH_PRECISION_MATH_FIXES // I think it's better to FixWindingAccu() once after we chop with all planes // so that error isn't multiplied. There is nothing natural about welding // the points unless they are the final endpoints. ChopWindingInPlaceAccu() // is able to handle all kinds of degenerate windings. #else FixWinding( w ); #endif } /* set side winding */ #if Q3MAP2_EXPERIMENTAL_HIGH_PRECISION_MATH_FIXES if ( w != NULL ) { FixWindingAccu( w ); if ( w->numpoints < 3 ) { FreeWindingAccu( w ); w = NULL; } } side->winding = ( w ? CopyWindingAccuToRegular( w ) : NULL ); if ( w ) { FreeWindingAccu( w ); } #else side->winding = w; #endif } /* find brush bounds */ return BoundBrush( brush ); }
void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, bfixed *points) ) { static cvar_t *cv; #ifndef BSPC static cvar_t *cv2; #endif const patchCollide_t *pc; facet_t *facet; winding_t *w; int i, j, k, n; int curplanenum, planenum, curinward, inward; planeDef_t plane; bvec3_t mins = {-BFIXED(15,0), -BFIXED(15,0), -BFIXED(28,0)}, maxs = {BFIXED(15,0), BFIXED(15,0), BFIXED(28,0)}; //bvec3_t mins = {BFIXED_0, BFIXED_0, BFIXED_0}, maxs = {BFIXED_0, BFIXED_0, BFIXED_0}; bvec3_t v1; avec3_t v2; #ifndef BSPC if ( !cv2 ) { cv2 = Cvar_Get( "r_debugSurface", "0", 0 ); } if (cv2->integer != 1) { BotDrawDebugPolygons(drawPoly, cv2->integer); return; } #endif if ( !debugPatchCollide ) { return; } #ifndef BSPC if ( !cv ) { cv = Cvar_Get( "cm_debugSize", "2", 0 ); } #endif pc = debugPatchCollide; for ( i = 0, facet = pc->facets ; i < pc->numFacets ; i++, facet++ ) { for ( k = 0 ; k < facet->numBorders + 1; k++ ) { // if (k < facet->numBorders) { planenum = facet->borderPlanes[k]; inward = facet->borderInward[k]; } else { planenum = facet->surfacePlane; inward = qfalse; //continue; } VectorCopy( pc->planes[ planenum ].pd.normal, plane.normal ); plane.dist=pc->planes[ planenum ].pd.dist; //planenum = facet->surfacePlane; if ( inward ) { VectorSubtract( avec3_origin, plane.normal, plane.normal ); plane.dist = -plane.dist; } plane.dist += MAKE_BFIXED(cv->value); //* for (n = 0; n < 3; n++) { if (plane.normal[n] > AFIXED_0) v1[n] = maxs[n]; else v1[n] = mins[n]; } //end for VectorNegate(plane.normal, v2); plane.dist += FIXED_ABS(FIXED_VEC3DOT(v1, v2)); //*/ w = BaseWindingForPlane( plane.normal, plane.dist ); for ( j = 0 ; j < facet->numBorders + 1 && w; j++ ) { // if (j < facet->numBorders) { curplanenum = facet->borderPlanes[j]; curinward = facet->borderInward[j]; } else { curplanenum = facet->surfacePlane; curinward = qfalse; //continue; } // if (curplanenum == planenum) continue; VectorCopy( pc->planes[ curplanenum ].pd.normal, plane.normal ); plane.dist=pc->planes[ curplanenum ].pd.dist; if ( !curinward ) { VectorSubtract( avec3_origin, plane.normal, plane.normal ); plane.dist = -plane.dist; } // if ( !facet->borderNoAdjust[j] ) { plane.dist -= MAKE_BFIXED(cv->value); // } for (n = 0; n < 3; n++) { if (plane.normal[n] > AFIXED_0) v1[n] = maxs[n]; else v1[n] = mins[n]; } //end for VectorNegate(plane.normal, v2); plane.dist -= FIXED_ABS(FIXED_VEC3DOT(v1, v2)); ChopWindingInPlace( &w, plane.normal, plane.dist, BFIXED(0,1) ); } if ( w ) { if ( facet == debugFacet ) { drawPoly( 4, w->numpoints, w->p[0] ); //Com_Printf("blue facet has %d border planes\n", facet->numBorders); } else { drawPoly( 1, w->numpoints, w->p[0] ); } FreeWinding( w ); } else Com_Printf("winding chopped away by border planes\n"); } } // draw the debug block { bvec3_t v[3]; VectorCopy( debugBlockPoints[0], v[0] ); VectorCopy( debugBlockPoints[1], v[1] ); VectorCopy( debugBlockPoints[2], v[2] ); drawPoly( 2, 3, v[0] ); VectorCopy( debugBlockPoints[2], v[0] ); VectorCopy( debugBlockPoints[3], v[1] ); VectorCopy( debugBlockPoints[0], v[2] ); drawPoly( 2, 3, v[0] ); } #if 0 bvec3_t v[4]; v[0][0] = pc->bounds[1][0]; v[0][1] = pc->bounds[1][1]; v[0][2] = pc->bounds[1][2]; v[1][0] = pc->bounds[1][0]; v[1][1] = pc->bounds[0][1]; v[1][2] = pc->bounds[1][2]; v[2][0] = pc->bounds[0][0]; v[2][1] = pc->bounds[0][1]; v[2][2] = pc->bounds[1][2]; v[3][0] = pc->bounds[0][0]; v[3][1] = pc->bounds[1][1]; v[3][2] = pc->bounds[1][2]; drawPoly( 4, v[0] ); #endif }
//=========================================================================== // 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
/* ================== 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 }
/* ================ 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]; }
/** * @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]; }
/** * @brief Generates two new brushes, leaving the original unchanged */ void SplitBrush(brush_t *brush, int32_t plane_num, brush_t **front, brush_t **back) { brush_t *b[2]; int32_t i, j; winding_t *w, *cw[2], *midwinding; map_plane_t *plane, *plane2; side_t *s, *cs; vec_t d, d_front, d_back; *front = *back = NULL; plane = &map_planes[plane_num]; // check all points d_front = d_back = 0; for (i = 0; i < brush->num_sides; i++) { w = brush->sides[i].winding; if (!w) { continue; } for (j = 0; j < w->num_points; j++) { d = DotProduct(w->points[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 = WindingForPlane(plane->normal, plane->dist); for (i = 0; i < brush->num_sides && w; i++) { plane2 = &map_planes[brush->sides[i].plane_num ^ 1]; ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON); } if (!w || WindingIsTiny(w)) { // the brush isn't really split int32_t side; side = BrushMostlyOnSide(brush, plane); if (side == SIDE_FRONT) { *front = CopyBrush(brush); } if (side == SIDE_BACK) { *back = CopyBrush(brush); } return; } if (WindingIsHuge(w)) { Mon_SendWinding(ERROR_WARN, (const vec3_t *) w->points, w->num_points, "Large winding"); } midwinding = w; // split it for real for (i = 0; i < 2; i++) { b[i] = AllocBrush(brush->num_sides + 1); b[i]->original = brush->original; } // split all the current windings for (i = 0; i < brush->num_sides; 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; } cs = &b[j]->sides[b[j]->num_sides]; b[j]->num_sides++; *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] < MIN_WORLD_COORD || b[i]->maxs[j] > MAX_WORLD_COORD) { Com_Debug(DEBUG_ALL, "bogus brush after clip\n"); break; } } if (b[i]->num_sides < 3 || j < 3) { FreeBrush(b[i]); b[i] = NULL; } } if (!(b[0] && b[1])) { if (!b[0] && !b[1]) { Com_Debug(DEBUG_ALL, "split removed brush\n"); } else { Com_Debug(DEBUG_ALL, "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]->num_sides]; b[i]->num_sides++; cs->plane_num = plane_num ^ 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; for (i = 0; i < 2; i++) { v1 = BrushVolume(b[i]); if (v1 < 1.0) { FreeBrush(b[i]); b[i] = NULL; Com_Debug(DEBUG_ALL, "tiny volume after clip\n"); } } } *front = b[0]; *back = b[1]; }