/* ================= SnapPlane snaps a plane to normal/distance epsilons ================= */ void SnapPlane( vec3_t normal, vec_t *dist ) { SnapNormal( normal ); if( fabs( *dist - Q_rint( *dist )) < distanceEpsilon ) *dist = Q_rint( *dist ); }
/* SnapPlaneImproved() snaps a plane to normal/distance epsilons, improved code */ void SnapPlaneImproved(vec3_t normal, vec_t *dist, int numPoints, const vec3_t *points) { int i; vec3_t center; vec_t distNearestInt; if (SnapNormal(normal)) { if (numPoints > 0) { // Adjust the dist so that the provided points don't drift away. VectorClear(center); for (i = 0; i < numPoints; i++) { VectorAdd(center, points[i], center); } for (i = 0; i < 3; i++) { center[i] = center[i] / numPoints; } *dist = DotProduct(normal, center); } } if (VectorIsOnAxis(normal)) { // Only snap distance if the normal is an axis. Otherwise there // is nothing "natural" about snapping the distance to an integer. distNearestInt = Q_rint(*dist); if (-distanceEpsilon < *dist - distNearestInt && *dist - distNearestInt < distanceEpsilon) { *dist = distNearestInt; } } }
void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center ) { // SnapPlane disabled by LordHavoc because it often messes up collision // brushes made from triangles of embedded models, and it has little effect // on anything else (axial planes are usually derived from snapped points) /* SnapPlane reenabled by namespace because of multiple reports of q3map2-crashes which were triggered by this patch. */ SnapNormal( normal ); // TODO: Rambetter has some serious comments here as well. First off, // in the case where a normal is non-axial, there is nothing special // about integer distances. I would think that snapping a distance might // make sense for axial normals, but I'm not so sure about snapping // non-axial normals. A shift by 0.01 in a plane, multiplied by a clipping // against another plane that is 5 degrees off, and we introduce 0.1 error // easily. A 0.1 error in a vertex is where problems start to happen, such // as disappearing triangles. // Second, assuming we have snapped the normal above, let's say that the // plane we just snapped was defined for some points that are actually // quite far away from normal * dist. Well, snapping the normal in this // case means that we've just moved those points by potentially many units! // Therefore, if we are going to snap the normal, we need to know the // points we're snapping for so that the plane snaps with those points in // mind (points remain close to the plane). // I would like to know exactly which problems SnapPlane() is trying to // solve so that we can better engineer it (I'm not saying that SnapPlane() // should be removed altogether). Fix all this snapping code at some point! if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon ) *dist = Q_rint( *dist ); }
/* * @brief */ static void SnapPlane(vec3_t normal, dvec_t *dist) { SnapNormal(normal); // snap axial planes to integer distances if (PlaneTypeForNormal(normal) <= PLANE_Z) { const vec_t f = floor(*dist + 0.5); if (fabs(*dist - f) < DIST_EPSILON) *dist = f; } }
/* ================= AddBrushBevels adds any additional planes necessary to allow the brush being built to be expanded against axial bounding boxes 2003-01-20: added mr.Elusive fixes ================= */ void AddBrushBevels( void ) { int axis, dir; int i, j, k, l, order = 0; side_t sidetemp; side_t *s, *s2; winding_t *w, *w2; vec3_t normal; float dist; vec3_t vec, vec2; float d, minBack; // add the axial planes for( axis = 0; axis < 3; axis++ ) { for( dir = -1; dir <= 1; dir += 2, order++ ) { // see if the plane is allready present for( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ ) { if( mapplanes[s->planenum].normal[axis] == dir ) break; } if( i == buildBrush->numsides ) { // add a new side if( buildBrush->numsides == MAX_BUILD_SIDES ) Sys_Break( "Entity %i, Brush %i MAX_BUILD_SIDES\n", buildBrush->entityNum, buildBrush->brushNum ); Mem_Set( s, 0, sizeof( *s )); buildBrush->numsides++; VectorClear (normal); normal[axis] = dir; if( dir == 1 ) { // adding bevel plane snapping for fewer bsp planes if( bevelSnap > 0 ) dist = floor( buildBrush->maxs[axis] / bevelSnap ) * bevelSnap; else dist = buildBrush->maxs[axis]; } else { // adding bevel plane snapping for fewer bsp planes if( bevelSnap > 0 ) dist = -ceil( buildBrush->mins[axis] / bevelSnap ) * bevelSnap; else dist = -buildBrush->mins[axis]; } s->planenum = FindFloatPlane( normal, dist, 0, NULL ); s->contentFlags = buildBrush->sides[0].contentFlags; s->bevel = true; c_boxbevels++; } // if the plane is not in it canonical order, swap it if( i != order ) { sidetemp = buildBrush->sides[order]; buildBrush->sides[order] = buildBrush->sides[i]; buildBrush->sides[i] = sidetemp; } } } // add the edge bevels if( buildBrush->numsides == 6 ) return; // pure axial // test the non-axial plane edges for( i = 6; i < buildBrush->numsides; i++ ) { s = buildBrush->sides + i; w = s->winding; if( !w ) continue; for( j = 0; j < w->numpoints; j++ ) { k = (j+1)%w->numpoints; VectorSubtract( w->p[j], w->p[k], vec ); if( VectorNormalizeLength( vec ) < 0.5f ) continue; SnapNormal( vec ); for( k = 0; k < 3; k++ ) { if( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f)) 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, normal ); if( VectorNormalizeLength( normal ) < 0.5f ) continue; dist = DotProduct( w->p[j], normal ); // if all the points on all the sides are // behind this plane, it is a proper edge bevel for( k = 0; k < buildBrush->numsides; k++ ) { // if this plane has allready been used, skip it if( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist )) break; w2 = buildBrush->sides[k].winding; if( !w2 ) continue; minBack = 0.0f; for( l = 0; l < w2->numpoints; l++ ) { d = DotProduct( w2->p[l], normal ) - dist; if( d > 0.1f ) break; // point in front if( d < minBack ) minBack = d; } // if some point was at the front if( l != w2->numpoints ) break; // if no points at the back then the winding is on the bevel plane if( minBack > -0.1f ) break; } if( k != buildBrush->numsides ) continue; // wasn't part of the outer hull // add this plane if( buildBrush->numsides == MAX_BUILD_SIDES ) Sys_Break( "Entity %i, Brush %i MAX_BUILD_SIDES\n", buildBrush->entityNum, buildBrush->brushNum ); s2 = &buildBrush->sides[buildBrush->numsides]; buildBrush->numsides++; Mem_Set( s2, 0, sizeof( *s2 ) ); s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[j] ); s2->contentFlags = buildBrush->sides[0].contentFlags; s2->bevel = true; c_edgebevels++; } } } } }
/* * @brief Adds any additional planes necessary to allow the brush to be expanded * against axial bounding boxes */ static void AddBrushBevels(map_brush_t * b) { int32_t axis, dir; int32_t i, j, k, l, order; side_t sidetemp; map_brush_texture_t tdtemp; side_t *s, *s2; vec3_t normal; vec_t dist; winding_t *w, *w2; vec3_t vec, vec2; vec_t d; // add the axial planes order = 0; for (axis = 0; axis < 3; axis++) { for (dir = -1; dir <= 1; dir += 2, order++) { // see if the plane is already present for (i = 0, s = b->original_sides; i < b->num_sides; i++, s++) { if (map_planes[s->plane_num].normal[axis] == dir) break; } if (i == b->num_sides) { // add a new side if (num_map_brush_sides == MAX_BSP_BRUSH_SIDES) Com_Error(ERR_FATAL, "MAX_BSP_BRUSH_SIDES\n"); num_map_brush_sides++; b->num_sides++; VectorClear(normal); normal[axis] = dir; if (dir == 1) dist = b->maxs[axis]; else dist = -b->mins[axis]; s->plane_num = FindPlane(normal, dist); s->texinfo = b->original_sides[0].texinfo; s->contents = b->original_sides[0].contents; s->bevel = true; c_box_bevels++; } // if the plane is not in it canonical order, swap it if (i != order) { sidetemp = b->original_sides[order]; b->original_sides[order] = b->original_sides[i]; b->original_sides[i] = sidetemp; j = b->original_sides - map_brush_sides; tdtemp = map_brush_textures[j + order]; map_brush_textures[j + order] = map_brush_textures[j + i]; map_brush_textures[j + i] = tdtemp; } } } // add the edge bevels if (b->num_sides == 6) return; // pure axial // test the non-axial plane edges for (i = 6; i < b->num_sides; i++) { s = b->original_sides + i; w = s->winding; if (!w) continue; for (j = 0; j < w->num_points; j++) { k = (j + 1) % w->num_points; VectorSubtract(w->points[j], w->points[k], vec); if (VectorNormalize(vec) < 0.5) { continue; } SnapNormal(vec); for (k = 0; k < 3; k++) { if (vec[k] == -1.0 || vec[k] == 1.0 || (vec[k] == 0.0 && vec[(k + 1) % 3] == 0.0)) { 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, normal); if (VectorNormalize(normal) < 0.5) continue; dist = DotProduct(w->points[j], normal); // if all the points on all the sides are // behind this plane, it is a proper edge bevel for (k = 0; k < b->num_sides; k++) { vec_t minBack; // if this plane has already been used, skip it if (PlaneEqual(&map_planes[b->original_sides[k].plane_num], normal, dist)) break; w2 = b->original_sides[k].winding; if (!w2) continue; minBack = 0.0f; for (l = 0; l < w2->num_points; l++) { d = DotProduct(w2->points[l], normal) - dist; if (d > 0.1) break; // point in front if (d < minBack) minBack = d; } // if some point was at the front if (l != w2->num_points) break; // if no points at the back then the winding is on the // bevel plane if (minBack > -0.1f) break; } if (k != b->num_sides) continue; // wasn't part of the outer hull // add this plane if (num_map_brush_sides == MAX_BSP_BRUSH_SIDES) Com_Error(ERR_FATAL, "MAX_BSP_BRUSH_SIDES\n"); s2 = &b->original_sides[b->num_sides++]; s2->plane_num = FindPlane(normal, dist); s2->texinfo = b->original_sides[0].texinfo; s2->contents = b->original_sides[0].contents; s2->bevel = true; num_map_brush_sides++; c_edge_bevels++; } } } } }