/** * @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); }
/* ================== 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; vec3_t normal; float dist; int side; 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, CLIP_EPSILON); } if (!w) { return; } /* ydnar: adding this here to fix degenerate windings */ #if 0 if( FixWinding( w ) == qfalse ) { c_badportals++; FreeWinding( w ); return; } #endif 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; new_portal->compileFlags = node->compileFlags; AddPortalToNodes (new_portal, node->children[0], node->children[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 ); }
/* OPTIMIZATION: Union doesn't need to be all-or-nothing. A run of three or more convex paths with union ops could be locally resolved and still improve over doing the ops one at a time. */ bool SkOpBuilder::resolve(SkPath* result) { SkPath original = *result; int count = fOps.count(); bool allUnion = true; SkPathPriv::FirstDirection firstDir = SkPathPriv::kUnknown_FirstDirection; for (int index = 0; index < count; ++index) { SkPath* test = &fPathRefs[index]; if (kUnion_SkPathOp != fOps[index] || test->isInverseFillType()) { allUnion = false; break; } // If all paths are convex, track direction, reversing as needed. if (test->isConvex()) { SkPathPriv::FirstDirection dir; if (!SkPathPriv::CheapComputeFirstDirection(*test, &dir)) { allUnion = false; break; } if (firstDir == SkPathPriv::kUnknown_FirstDirection) { firstDir = dir; } else if (firstDir != dir) { SkPath temp; temp.reverseAddPath(*test); *test = temp; } continue; } // If the path is not convex but its bounds do not intersect the others, simplify is enough. const SkRect& testBounds = test->getBounds(); for (int inner = 0; inner < index; ++inner) { // OPTIMIZE: check to see if the contour bounds do not intersect other contour bounds? if (SkRect::Intersects(fPathRefs[inner].getBounds(), testBounds)) { allUnion = false; break; } } } if (!allUnion) { *result = fPathRefs[0]; for (int index = 1; index < count; ++index) { if (!Op(*result, fPathRefs[index], fOps[index], result)) { reset(); *result = original; return false; } } reset(); return true; } SkPath sum; for (int index = 0; index < count; ++index) { if (!Simplify(fPathRefs[index], &fPathRefs[index])) { reset(); *result = original; return false; } if (!fPathRefs[index].isEmpty()) { // convert the even odd result back to winding form before accumulating it if (!FixWinding(&fPathRefs[index])) { *result = original; return false; } sum.addPath(fPathRefs[index]); } } reset(); bool success = Simplify(sum, result); if (!success) { *result = original; } return success; }