/* ================ MakeBrushWindings makes basewindigs for sides and mins / maxs for the brush ================ */ 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[0] < -4096 || ob->maxs[0] > 4096 ) { Sys_Printf( "entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum ); } if ( ob->mins[0] > 4096 || ob->maxs[0] < -4096 ) { Sys_Printf( "entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum ); } } return true; }
/* ================ TestExpandBrushes Expands all the brush planes and saves a new map out ================ */ void TestExpandBrushes (void) { FILE *f; side_t *s; int i, j, bn; winding_t *w; char *name = "expanded.map"; mapbrush_t *brush; vec_t dist; printf ("writing %s\n", name); f = fopen (name, "wb"); if (!f) Error ("Can't write %s\b", name); fprintf (f, "{\n\"classname\" \"worldspawn\"\n"); for (bn=0 ; bn<nummapbrushes ; bn++) { brush = &mapbrushes[bn]; fprintf (f, "{\n"); for (i=0 ; i<brush->numsides ; i++) { s = brush->original_sides + i; dist = mapplanes[s->planenum].dist; for (j=0 ; j<3 ; j++) dist += fabs( 16 * mapplanes[s->planenum].normal[j] ); w = BaseWindingForPlane (mapplanes[s->planenum].normal, dist); fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]); fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]); fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]); fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture); FreeWinding (w); } fprintf (f, "}\n"); } fprintf (f, "}\n"); fclose (f); Error ("can't proceed after expanding brushes"); }
/* ================== 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 ) { 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 the planes from the other portals. Each portal tracks the node that created it, so unused nodes can be removed later. ================== */ void MakeNodePortal (node_t *node) { portal_t *new_portal, *p; dplane_t *plane; dplane_t clipplane; winding_t *w; int side; plane = &dplanes[node->planenum]; w = BaseWindingForPlane (plane); new_portal = AllocPortal (); new_portal->plane = *plane; new_portal->onnode = node; side = 0; // shut up compiler warning for (p = node->portals ; p ; p = p->next[side]) { clipplane = p->plane; if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) { clipplane.dist = -clipplane.dist; VectorSubtract (vec3_origin, clipplane.normal, clipplane.normal); side = 1; } else Error ("MakeNodePortal: mislinked portal"); w = ClipWinding (w, &clipplane, true); if (!w) { printf ("WARNING: MakeNodePortal:new portal was clipped away from node@(%.0f,%.0f,%.0f)-(%.0f,%.0f,%.0f)\n", node->mins[0], node->mins[1], node->mins[2], node->maxs[0], node->maxs[1], node->maxs[2]); FreePortal (new_portal); return; } } new_portal->winding = w; AddPortalToNodes (new_portal, node->children[0], node->children[1]); }
/** * @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; }
//=========================================================================== // // 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
/* * 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
void WriteBSPBrushMap( char *name, brush_t *list ){ FILE *f; side_t *s; int i; winding_t *w; /* note it */ Sys_Printf( "Writing %s\n", name ); /* open the map file */ f = fopen( name, "wb" ); if ( f == NULL ) { Error( "Can't write %s\b", name ); } fprintf( f, "{\n\"classname\" \"worldspawn\"\n" ); for ( ; list ; list = list->next ) { fprintf( f, "{\n" ); for ( i = 0,s = list->sides ; i < list->numsides ; i++,s++ ) { // TODO: See if we can use a smaller winding to prevent resolution loss. // Is WriteBSPBrushMap() used only to decompile maps? w = BaseWindingForPlane( mapplanes[s->planenum].normal, mapplanes[s->planenum].dist ); fprintf( f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2] ); fprintf( f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2] ); fprintf( f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2] ); fprintf( f, "notexture 0 0 0 1 1\n" ); FreeWinding( w ); } fprintf( f, "}\n" ); } fprintf( f, "}\n" ); fclose( f ); }
/* ================== 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 WriteBSPBrushMap( char *name, brush_t *list ) { FILE *f; side_t *s; int i; winding_t *w; /* note it */ Sys_Printf( "writing %s\n", name ); /* open the map file */ f = fopen( name, "wb" ); if( f == NULL ) Error( "Can't write %s\b", name ); fprintf (f, "{\n\"classname\" \"worldspawn\"\n"); for ( ; list ; list=list->next ) { fprintf (f, "{\n"); for (i=0,s=list->sides ; i<list->numsides ; i++,s++) { w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist); fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]); fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]); fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]); if ( s->shaderInfo == NULL ) fprintf (f, "notexture 0 0 0 1 1 0 0 0\n" ); else fprintf (f, "%s %i %i 0 1 1 0 0 0\n", s->shaderInfo->shader + 9, s->shaderInfo->shaderWidth, s->shaderInfo->shaderHeight ); FreeWinding (w); } fprintf (f, "}\n"); } fprintf (f, "}\n"); fclose (f); }
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]; }
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]; }
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 ); }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_FixMapBrush(mapbrush_t *brush) { int i, j, planenum; float dist; winding_t *w; plane_t *plane, *plane1, *plane2; side_t *side; vec3_t normal; //calculate the brush bounds ClearBounds(brush->mins, brush->maxs); for (i = 0; i < brush->numsides; i++) { plane = &mapplanes[brush->original_sides[i].planenum]; w = BaseWindingForPlane(plane->normal, plane->dist); for (j = 0; j < brush->numsides && w; j++) { if (i == j) continue; //there are no brush bevels marked but who cares :) if (brush->original_sides[j].flags & SFL_BEVEL) continue; plane = &mapplanes[brush->original_sides[j].planenum^1]; ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); } //end for side = &brush->original_sides[i]; side->winding = w; if (w) { for (j = 0; j < w->numpoints; j++) { AddPointToBounds(w->p[j], brush->mins, brush->maxs); } //end for } //end if } //end for // for (i = 0; i < brush->numsides; i++) { for (j = 0; j < brush->numsides; j++) { if (i == j) continue; plane1 = &mapplanes[brush->original_sides[i].planenum]; plane2 = &mapplanes[brush->original_sides[j].planenum]; if (WindingsNonConvex(brush->original_sides[i].winding, brush->original_sides[j].winding, plane1->normal, plane2->normal, plane1->dist, plane2->dist)) { Log_Print("non convex brush"); } //end if } //end for } //end for //NOW close the f*****g brush!! for (i = 0; i < 3; i++) { if (brush->mins[i] < -MAX_MAP_BOUNDS) { VectorClear(normal); normal[i] = -1; dist = MAX_MAP_BOUNDS - 10; planenum = FindFloatPlane(normal, dist); // Log_Print("mins out of range: added extra brush side\n"); AAS_AddMapBrushSide(brush, planenum); } //end if if (brush->maxs[i] > MAX_MAP_BOUNDS) { VectorClear(normal); normal[i] = 1; dist = MAX_MAP_BOUNDS - 10; planenum = FindFloatPlane(normal, dist); // Log_Print("maxs out of range: added extra brush side\n"); AAS_AddMapBrushSide(brush, planenum); } //end if if (brush->mins[i] > MAX_MAP_BOUNDS || brush->maxs[i] < -MAX_MAP_BOUNDS) { Log_Print("entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum); } //end if } //end for //free all the windings FreeBrushWindings(brush); } //end of the function AAS_FixMapBrush
//=========================================================================== // 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
/* ================ 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]; }
/* ================ CutNodePortals_r ================ */ static void CutNodePortals_r(node_t *node) { plane_t *plane, clipplane; node_t *f, *b, *other_node; portal_t *p, *new_portal, *next_portal; winding_t *w, *frontwinding, *backwinding; int side; #ifdef PARANOID CheckLeafPortalConsistancy (node); #endif // separate the portals on node into it's children if (node->contents) return; // at a leaf, no more dividing plane = &pPlanes[node->planenum]; f = node->children[0]; b = node->children[1]; // create the new portal by taking the full plane winding for the cutting plane // and clipping it by all of the planes from the other portals new_portal = AllocMem(PORTAL, 1, true); new_portal->planenum = node->planenum; w = BaseWindingForPlane(&pPlanes[node->planenum]); side = 0; // shut up compiler warning for (p = node->portals; p; p = p->next[side]) { clipplane = pPlanes[p->planenum]; if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) { clipplane.dist = -clipplane.dist; VectorSubtract(vec3_origin, clipplane.normal, clipplane.normal); side = 1; } else Message(msgError, errMislinkedPortal); w = ClipWinding(w, &clipplane, true); if (!w) { Message(msgWarning, warnPortalClippedAway); break; } } if (w) { // if the plane was not clipped on all sides, there was an error new_portal->winding = w; AddPortalToNodes(new_portal, f, b); } // partition the portals for (p = node->portals; p; p = next_portal) { if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) side = 1; else Message(msgError, errMislinkedPortal); next_portal = p->next[side]; other_node = p->nodes[!side]; RemovePortalFromNode(p, p->nodes[0]); RemovePortalFromNode(p, p->nodes[1]); // cut the portal into two portals, one on each side of the cut plane DivideWinding(p->winding, plane, &frontwinding, &backwinding); if (!frontwinding) { if (side == 0) AddPortalToNodes(p, b, other_node); else AddPortalToNodes(p, other_node, b); continue; } if (!backwinding) { if (side == 0) AddPortalToNodes(p, f, other_node); else AddPortalToNodes(p, other_node, f); continue; } // the winding is split new_portal = AllocMem(PORTAL, 1, true); *new_portal = *p; new_portal->winding = backwinding; FreeMem(p->winding, WINDING, 1); p->winding = frontwinding; if (side == 0) { AddPortalToNodes(p, f, other_node); AddPortalToNodes(new_portal, b, other_node); } else { AddPortalToNodes(p, other_node, f); AddPortalToNodes(new_portal, other_node, b); } } // Display progress iNodesDone++; Message(msgPercent, iNodesDone, splitnodes); CutNodePortals_r(f); CutNodePortals_r(b); }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean AAS_MakeBrushWindings(mapbrush_t *ob) { int i, j; winding_t *w; side_t *side; plane_t *plane, *plane1, *plane2; 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].flags & SFL_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->flags |= SFL_VISIBLE; for (j = 0; j < w->numpoints; j++) AddPointToBounds (w->p[j], ob->mins, ob->maxs); } } //check if the brush is convex for (i = 0; i < ob->numsides; i++) { for (j = 0; j < ob->numsides; j++) { if (i == j) continue; plane1 = &mapplanes[ob->original_sides[i].planenum]; plane2 = &mapplanes[ob->original_sides[j].planenum]; if (WindingsNonConvex(ob->original_sides[i].winding, ob->original_sides[j].winding, plane1->normal, plane2->normal, plane1->dist, plane2->dist)) { Log_Print("non convex brush"); } //end if } //end for } //end for //check for out of bound brushes for (i = 0; i < 3; i++) { //IDBUG: all the indexes into the mins and maxs were zero (not using i) if (ob->mins[i] < -MAX_MAP_BOUNDS || ob->maxs[i] > MAX_MAP_BOUNDS) { Log_Print("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum); Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, ob->mins[i], i, ob->maxs[i]); ob->numsides = 0; //remove the brush break; } //end if if (ob->mins[i] > MAX_MAP_BOUNDS || ob->maxs[i] < -MAX_MAP_BOUNDS) { Log_Print("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum); Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, ob->mins[i], i, ob->maxs[i]); ob->numsides = 0; //remove the brush break; } //end if } //end for return true; } //end of the function AAS_MakeBrushWindings
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 }
/* ================== 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 }
/* =========== MakeHullFaces =========== */ void MakeHullFaces (brush_t *b, brushhull_t *h) { bface_t *f, *f2; winding_t *w; plane_t *p; int i, j; vec_t v; vec_t area; restart: h->mins[0] = h->mins[1] = h->mins[2] = 9999; h->maxs[0] = h->maxs[1] = h->maxs[2] = -9999; for (f = h->faces ; f ; f=f->next) { // w = BaseWindingForIPlane (f->plane); w = BaseWindingForPlane (f->plane->normal, f->plane->dist); for (f2 = h->faces ; f2 && w ; f2=f2->next) { if (f == f2) continue; p = &mapplanes[f2->planenum ^ 1]; w = ChopWinding (w, p->normal, p->dist); } area = w ? WindingArea(w) : 0; if (area < 0.1) { qprintf ("Entity %i, Brush %i: plane with area %4.2f\n" , b->entitynum, b->brushnum, area); // remove the face and regenerate the hull if (h->faces == f) h->faces = f->next; else { for (f2=h->faces ; f2->next != f ; f2=f2->next) ; f2->next = f->next; } goto restart; } f->w = w; f->contents = CONTENTS_EMPTY; if (w) { for (i=0 ; i<w->numpoints ; i++) { for (j=0 ; j<3 ; j++) { v = w->p[i][j]; // w->p[i][j] = floor (v+0.5); // round to int if (v<h->mins[j]) h->mins[j] = v; if (v>h->maxs[j]) h->maxs[j] = v; } } } } for (i=0 ; i<3 ; i++) { if (h->mins[i] < -BOGUS_RANGE/2 || h->maxs[i] > BOGUS_RANGE/2) { vec3_t eorigin = { 0, 0, 0}; char *pszClass = "Unknown Class"; if ( b->entitynum ) { entity_t *e = entities + b->entitynum; pszClass = ValueForKey(e, "classname" ); GetVectorForKey( e, "origin", eorigin ); } printf( "Entity %i, Brush %i: A '%s' @(%.0f,%.0f,%.0f)\n", b->entitynum, b->brushnum, pszClass, eorigin[0], eorigin[1], eorigin[2] ); printf( "\toutside world(+/-%d): (%.0f, %.0f, %.0f)-(%.0f,%.0f,%.0f)\n", BOGUS_RANGE/2, h->mins[0], h->mins[1], h->mins[2], h->maxs[0], h->maxs[1], h->maxs[2] ); break; } } }
/** * @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]; }
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 AAS_CreateCurveBrushes(void) { int i, j, n, planenum, numcurvebrushes = 0; q3_dsurface_t *surface; q3_drawVert_t *dv_p; vec3_t points[MAX_PATCH_VERTS]; int width, height, c; patchCollide_t *pc; facet_t *facet; mapbrush_t *brush; side_t *side; entity_t *mapent; winding_t *winding; qprintf("nummapbrushsides = %d\n", nummapbrushsides); mapent = &entities[0]; for(i = 0; i < q3_numDrawSurfaces; i++) { surface = &q3_drawSurfaces[i]; if(!surface->patchWidth) { continue; } //if the curve is not solid if(!(q3_dshaders[surface->shaderNum].contentFlags & (CONTENTS_SOLID | CONTENTS_PLAYERCLIP))) { //Log_Print("skipped non-solid curve\n"); continue; } //end if // width = surface->patchWidth; height = surface->patchHeight; c = width * height; if(c > MAX_PATCH_VERTS) { Error("ParseMesh: MAX_PATCH_VERTS"); } //end if dv_p = q3_drawVerts + surface->firstVert; for(j = 0 ; j < c ; j++, dv_p++) { points[j][0] = dv_p->xyz[0]; points[j][1] = dv_p->xyz[1]; points[j][2] = dv_p->xyz[2]; } //end for // create the internal facet structure pc = CM_GeneratePatchCollide(width, height, points); // for(j = 0; j < pc->numFacets; j++) { facet = &pc->facets[j]; // brush = &mapbrushes[nummapbrushes]; brush->original_sides = &brushsides[nummapbrushsides]; brush->entitynum = 0; brush->brushnum = nummapbrushes - mapent->firstbrush; // brush->numsides = facet->numBorders + 2; nummapbrushsides += brush->numsides; brush->contents = CONTENTS_SOLID; // //qprintf("\r%6d curve brushes", nummapbrushsides);//++numcurvebrushes); qprintf("\r%6d curve brushes", ++numcurvebrushes); // planenum = FindFloatPlane(pc->planes[facet->surfacePlane].plane, pc->planes[facet->surfacePlane].plane[3]); // side = &brush->original_sides[0]; side->planenum = planenum; side->contents = CONTENTS_SOLID; side->flags |= SFL_TEXTURED | SFL_VISIBLE | SFL_CURVE; side->surf = 0; // side = &brush->original_sides[1]; if(create_aas) { //the plane is expanded later so it's not a problem that //these first two opposite sides are coplanar side->planenum = planenum ^ 1; } //end if else { side->planenum = FindFloatPlane(mapplanes[planenum ^ 1].normal, mapplanes[planenum ^ 1].dist + 1); side->flags |= SFL_TEXTURED | SFL_VISIBLE; } //end else side->contents = CONTENTS_SOLID; side->flags |= SFL_CURVE; side->surf = 0; // winding = BaseWindingForPlane(mapplanes[side->planenum].normal, mapplanes[side->planenum].dist); for(n = 0; n < facet->numBorders; n++) { //never use the surface plane as a border if(facet->borderPlanes[n] == facet->surfacePlane) { continue; } // side = &brush->original_sides[2 + n]; side->planenum = FindFloatPlane(pc->planes[facet->borderPlanes[n]].plane, pc->planes[facet->borderPlanes[n]].plane[3]); if(facet->borderInward[n]) { side->planenum ^= 1; } side->contents = CONTENTS_SOLID; side->flags |= SFL_TEXTURED | SFL_CURVE; side->surf = 0; //chop the winding in place if(winding) { ChopWindingInPlace(&winding, mapplanes[side->planenum ^ 1].normal, mapplanes[side->planenum ^ 1].dist, 0.1); //CLIP_EPSILON); } } //end for //VectorCopy(pc->bounds[0], brush->mins); //VectorCopy(pc->bounds[1], brush->maxs); if(!winding) { Log_Print("WARNING: AAS_CreateCurveBrushes: no winding\n"); brush->numsides = 0; continue; } //end if brush->original_sides[0].winding = winding; WindingBounds(winding, brush->mins, brush->maxs); for(n = 0; n < 3; n++) { //IDBUG: all the indexes into the mins and maxs were zero (not using i) if(brush->mins[n] < -MAX_MAP_BOUNDS || brush->maxs[n] > MAX_MAP_BOUNDS) { Log_Print("entity %i, brush %i: bounds out of range\n", brush->entitynum, brush->brushnum); Log_Print("brush->mins[%d] = %f, brush->maxs[%d] = %f\n", n, brush->mins[n], n, brush->maxs[n]); brush->numsides = 0; //remove the brush break; } //end if if(brush->mins[n] > MAX_MAP_BOUNDS || brush->maxs[n] < -MAX_MAP_BOUNDS) { Log_Print("entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum); Log_Print("brush->mins[%d] = %f, brush->maxs[%d] = %f\n", n, brush->mins[n], n, brush->maxs[n]); brush->numsides = 0; //remove the brush break; } //end if } //end for if(create_aas) { //NOTE: brush bevels now already added //AddBrushBevels(brush); AAS_CreateMapBrushes(brush, mapent, false); } //end if else { // create windings for sides and bounds for brush MakeBrushWindings(brush); AddBrushBevels(brush); nummapbrushes++; mapent->numbrushes++; } //end else } //end for } //end for //qprintf("\r%6d curve brushes", nummapbrushsides);//++numcurvebrushes); qprintf("\r%6d curve brushes\n", numcurvebrushes); } //end of the function AAS_CreateCurveBrushes
/* ================ CutNodePortals_r ================ */ static void CutNodePortals_r (node_t *node) { plane_t *plane, clipplane; node_t *f, *b, *other_node; portal_t *p, *new_portal, *next_portal; winding_t *w, *frontwinding, *backwinding; int side; // Vic: properly calculate the bounding box CalcNodeBounds (node); // // separate the portals on node into it's children // if (node->contents) return; // at a leaf, no more dividing plane = &mapplanes[node->planenum]; f = node->children[0]; b = node->children[1]; // // create the new portal by taking the full plane winding for the cutting plane // and clipping it by all of the planes from the other portals // w = BaseWindingForPlane (&mapplanes[node->planenum]); side = 0; // shut up compiler warning for (p = node->portals ; p ; p = p->next[side]) { clipplane = mapplanes[p->planenum]; if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) { clipplane.dist = -clipplane.dist; VectorNegate (clipplane.normal, clipplane.normal); side = 1; } else Error ("CutNodePortals_r: mislinked portal"); w = ClipWinding (w, &clipplane, true); if (!w) { printf ("WARNING: CutNodePortals_r:new portal was clipped away\n"); break; } } if (w) { // if the plane was not clipped on all sides, there was an error new_portal = AllocPortal (); new_portal->planenum = node->planenum; new_portal->winding = w; AddPortalToNodes (new_portal, f, b); } // partition the portals for (p = node->portals ; p ; p = next_portal) { if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) side = 1; else Error ("CutNodePortals_r: mislinked portal"); next_portal = p->next[side]; other_node = p->nodes[!side]; RemovePortalFromNode (p, p->nodes[0]); RemovePortalFromNode (p, p->nodes[1]); // cut the portal into two portals, one on each side of the cut plane DivideWindingEpsilon( p->winding, plane, &frontwinding, &backwinding, ON_EPSILON ); if (!frontwinding) { if (side == 0) AddPortalToNodes (p, b, other_node); else AddPortalToNodes (p, other_node, b); continue; } if (!backwinding) { if (side == 0) AddPortalToNodes (p, f, other_node); else AddPortalToNodes (p, other_node, f); continue; } // the winding is split new_portal = AllocPortal (); *new_portal = *p; new_portal->winding = backwinding; FreeWinding (p->winding); p->winding = frontwinding; if (side == 0) { AddPortalToNodes (p, f, other_node); AddPortalToNodes (new_portal, b, other_node); } else { AddPortalToNodes (p, other_node, f); AddPortalToNodes (new_portal, other_node, b); } } CutNodePortals_r (f); CutNodePortals_r (b); }
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 }
static clipleaf_t * carve_leaf (hull_t *hull, nodeleaf_t *nodeleafs, clipleaf_t *leaf, int num) { mclipnode_t *node; plane_t *plane; winding_t *winding, *fw, *bw; clipport_t *portal; clipport_t *new_portal; clipport_t *next_portal; clipleaf_t *other_leaf; clipleaf_t *new_leaf; plane_t clipplane; int side; if (num < 0) { // we've hit a leaf. all done leaf->contents = num; return leaf; } node = hull->clipnodes + num; plane = hull->planes + node->planenum; winding = BaseWindingForPlane (plane); for (portal = leaf->portals; portal; portal = portal->next[side]) { clipplane = hull->planes[portal->planenum]; side = (portal->leafs[1] == leaf); if (side) PlaneFlip (&clipplane, &clipplane); winding = ClipWinding (winding, &clipplane, true); } new_leaf = alloc_leaf (); portal = leaf->portals; leaf->portals = 0; for (; portal; portal = next_portal) { side = (portal->leafs[1] == leaf); next_portal = portal->next[side]; other_leaf = portal->leafs[!side]; remove_portal (portal, other_leaf); DivideWinding (portal->winding, plane, &fw, &bw); if (!fw) { if (side) add_portal (portal, other_leaf, new_leaf); else add_portal (portal, new_leaf, other_leaf); continue; } if (!bw) { if (side) add_portal (portal, other_leaf, leaf); else add_portal (portal, leaf, other_leaf); continue; } new_portal = alloc_portal (); new_portal->planenum = portal->planenum; new_portal->winding = bw; FreeWinding (portal->winding); portal->winding = fw; if (side) { add_portal (portal, other_leaf, leaf); add_portal (new_portal, other_leaf, new_leaf); } else { add_portal (portal, leaf, other_leaf); add_portal (new_portal, new_leaf, other_leaf); } } new_portal = alloc_portal (); new_portal->planenum = node->planenum; new_portal->winding = winding; add_portal (new_portal, leaf, new_leaf); nodeleafs[num].leafs[0] = carve_leaf (hull, nodeleafs, leaf, node->children[0]); nodeleafs[num].leafs[1] = carve_leaf (hull, nodeleafs, new_leaf, node->children[1]); return 0; }
void CreateBrushFaces (void) { int i,j, k; vec_t r; face_t *f; winding_t *w; plane_t plane; mface_t *mf; brush_mins[0] = brush_mins[1] = brush_mins[2] = 99999; brush_maxs[0] = brush_maxs[1] = brush_maxs[2] = -99999; brush_faces = NULL; for (i=0 ; i<numbrushfaces ; i++) { mf = &faces[i]; w = BaseWindingForPlane (&mf->plane); for (j=0 ; j<numbrushfaces && w ; j++) { if (j == i) continue; // flip the plane, because we want to keep the back side VectorSubtract (vec3_origin,faces[j].plane.normal, plane.normal); plane.dist = -faces[j].plane.dist; w = ClipWinding (w, &plane, false); } if (!w) continue; // overcontrained plane // this face is a keeper f = AllocFace (); f->numpoints = w->numpoints; if (f->numpoints > MAXEDGES) Error ("f->numpoints > MAXEDGES"); for (j=0 ; j<w->numpoints ; j++) { for (k=0 ; k<3 ; k++) { r = Q_rint (w->points[j][k]); if ( fabs(w->points[j][k] - r) < ZERO_EPSILON) f->pts[j][k] = r; else f->pts[j][k] = w->points[j][k]; if (f->pts[j][k] < brush_mins[k]) brush_mins[k] = f->pts[j][k]; if (f->pts[j][k] > brush_maxs[k]) brush_maxs[k] = f->pts[j][k]; } } FreeWinding (w); f->texturenum = mf->texinfo; f->planenum = FindPlane (&mf->plane, &f->planeside); f->next = brush_faces; brush_faces = f; CheckFace (f); } }
void MakeHeadnodePortals(tree_t *tree) { vec3_t 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 leaves 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); } //end for } //end for } //end of the function MakeHeadNodePortals