diff options
Diffstat (limited to 'indra/llmath/llvolume.cpp')
-rw-r--r-- | indra/llmath/llvolume.cpp | 266 |
1 files changed, 182 insertions, 84 deletions
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 0c711cabcd..43b42bf182 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2510,12 +2510,19 @@ bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 h return true; } -#define MAX_INDEX 10000 S32 *LLVolume::getTriangleIndices(U32 &num_indices) const { - S32 index[MAX_INDEX]; + S32 expected_num_triangle_indices = getNumTriangleIndices(); + if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES) + { + // we don't allow LLVolumes with this many vertices + llwarns << "Couldn't allocate triangle indices" << llendl; + num_indices = 0; + return NULL; + } + + S32* index = new S32[expected_num_triangle_indices]; S32 count = 0; - S32 *indices = NULL; // Let's do this totally diffently, as we don't care about faces... // Counter-clockwise triangles are forward facing... @@ -2529,6 +2536,9 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const size_s_out = getProfile().getTotalOut(); size_t = getPath().mPath.size(); + // NOTE -- if the construction of the triangles below ever changes + // then getNumTriangleIndices() method may also have to be updated. + if (open) /* Flawfinder: ignore */ { if (hollow) @@ -2536,9 +2546,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const // Open hollow -- much like the closed solid, except we // we need to stitch up the gap between s=0 and s=size_s-1 - if ( (size_t - 1) * (((size_s -1) * 6) + 6) >= MAX_INDEX) - goto noindices; - for (t = 0; t < size_t - 1; t++) { // The outer face, first cut, and inner face @@ -2652,8 +2659,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const if (use_tri1a2) { - if (count + 3 >= MAX_INDEX) - goto noindices; index[count++] = pt1 + i; index[count++] = pt1 + 1 + i; index[count++] = pt2 + i; @@ -2661,8 +2666,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const } else { - if (count + 3 >= MAX_INDEX) - goto noindices; index[count++] = pt1 + i; index[count++] = pt2 - 1 + i; index[count++] = pt2 + i; @@ -2753,8 +2756,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const if (use_tri1a2) { - if (count + 3 >= MAX_INDEX) - goto noindices; index[count++] = pt1; index[count++] = pt2; index[count++] = pt1 + 1; @@ -2762,8 +2763,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const } else { - if (count + 3 >= MAX_INDEX) - goto noindices; index[count++] = pt1; index[count++] = pt2; index[count++] = pt2 - 1; @@ -2776,9 +2775,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const { // Open solid - if ( (size_t - 1) * (((size_s -1) * 6) + 6) >= MAX_INDEX) - goto noindices; - for (t = 0; t < size_t - 1; t++) { // Outer face + 1 cut face @@ -2808,8 +2804,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const // Do the top and bottom caps, if necessary if (path_open) { - if ( count + (size_s - 2) * 3 >= MAX_INDEX) - goto noindices; for (s = 0; s < size_s - 2; s++) { index[count++] = s+1; @@ -2819,8 +2813,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const // We've got a top cap S32 offset = (size_t - 1)*size_s; - if ( count + (size_s - 2) * 3 >= MAX_INDEX) - goto noindices; for (s = 0; s < size_s - 2; s++) { // Inverted ordering from bottom cap. @@ -2836,8 +2828,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const // Closed hollow // Outer face - if ( (size_t - 1) * (size_s_out - 1) * 6 >= MAX_INDEX) - goto noindices; for (t = 0; t < size_t - 1; t++) { for (s = 0; s < size_s_out - 1; s++) @@ -2856,8 +2846,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const // Inner face // Invert facing from outer face - if ( count + (size_t - 1) * ((size_s - 1) - size_s_out) * 6 >= MAX_INDEX) - goto noindices; for (t = 0; t < size_t - 1; t++) { for (s = size_s_out; s < size_s - 1; s++) @@ -2962,8 +2950,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const if (use_tri1a2) { - if (count + 3 >= MAX_INDEX) - goto noindices; index[count++] = pt1 + i; index[count++] = pt1 + 1 + i; index[count++] = pt2 + i; @@ -2971,8 +2957,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const } else { - if (count + 3 >= MAX_INDEX) - goto noindices; index[count++] = pt1 + i; index[count++] = pt2 - 1 + i; index[count++] = pt2 + i; @@ -3063,8 +3047,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const if (use_tri1a2) { - if (count + 3 >= MAX_INDEX) - goto noindices; index[count++] = pt1; index[count++] = pt2; index[count++] = pt1 + 1; @@ -3072,8 +3054,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const } else { - if (count + 3 >= MAX_INDEX) - goto noindices; index[count++] = pt1; index[count++] = pt2; index[count++] = pt2 - 1; @@ -3085,8 +3065,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const else { // Closed solid. Easy case. - if ( (size_t - 1) * (size_s - 1) * 6 > MAX_INDEX) - goto noindices; for (t = 0; t < size_t - 1; t++) { for (s = 0; s < size_s - 1; s++) @@ -3108,8 +3086,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const if (path_open) { // bottom cap - if ( count + (size_s - 2 - 1) * 3 >= MAX_INDEX) - goto noindices; for (s = 1; s < size_s - 2; s++) { index[count++] = s+1; @@ -3119,8 +3095,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const // top cap S32 offset = (size_t - 1)*size_s; - if ( count + (size_s - 2 - 1) * 3 >= MAX_INDEX) - goto noindices; for (s = 1; s < size_s - 2; s++) { // Inverted ordering from bottom cap. @@ -3131,7 +3105,18 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const } } +#ifdef LL_DEBUG + // assert that we computed the correct number of indices + if (count != expected_num_triangle_indices ) + { + llerrs << "bad index count prediciton:" + << " expected=" << expected_num_triangle_indices + << " actual=" << count << llendl; + } +#endif + #if 0 + // verify that each index does not point beyond the size of the mesh S32 num_vertices = mMesh.size(); for (i = 0; i < count; i+=3) { @@ -3142,17 +3127,65 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const } #endif - indices = new S32[count]; -noindices: - if (!indices) + num_indices = count; + return index; +} + +S32 LLVolume::getNumTriangleIndices() const +{ + BOOL profile_open = getProfile().isOpen(); + BOOL hollow = getProfile().isHollow(); + BOOL path_open = getPath().isOpen(); + + S32 size_s, size_s_out, size_t; + size_s = getProfile().getTotal(); + size_s_out = getProfile().getTotalOut(); + size_t = getPath().mPath.size(); + + S32 count = 0; + if (profile_open) /* Flawfinder: ignore */ { - llwarns << "Couldn't allocate triangle indices" << llendl; - num_indices = 0; - return NULL; + if (hollow) + { + // Open hollow -- much like the closed solid, except we + // we need to stitch up the gap between s=0 and s=size_s-1 + count = (size_t - 1) * (((size_s -1) * 6) + 6); + } + else + { + count = (size_t - 1) * (((size_s -1) * 6) + 6); + } } - num_indices = count; - memcpy(indices, index, count * sizeof(S32)); /* Flawfinder: ignore */ - return indices; + else if (hollow) + { + // Closed hollow + // Outer face + count = (size_t - 1) * (size_s_out - 1) * 6; + + // Inner face + count += (size_t - 1) * ((size_s - 1) - size_s_out) * 6; + } + else + { + // Closed solid. Easy case. + count = (size_t - 1) * (size_s - 1) * 6; + } + + if (path_open) + { + S32 cap_triangle_count = size_s - 3; + if ( profile_open + || hollow ) + { + cap_triangle_count = size_s - 2; + } + if ( cap_triangle_count > 0 ) + { + // top and bottom caps + count += cap_triangle_count * 2 * 3; + } + } + return count; } //----------------------------------------------------------------------------- @@ -3483,7 +3516,7 @@ struct lessTriangle BOOL equalTriangle(const S32 *a, const S32 *b) { - if ((*a == *b) && (*(a+1) == *(b+1)) && ((*a+2) == (*b+2))) + if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2))) { return TRUE; } @@ -3499,6 +3532,21 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices, S32 &num_output_triangles, S32 **output_triangles) { + /* Testing: avoid any cleanup + num_output_vertices = num_input_vertices; + num_output_triangles = num_input_triangles; + + *output_vertices = new LLVector3[num_input_vertices]; + for (S32 i = 0; i < num_input_vertices; i++) + { + (*output_vertices)[i] = input_vertices[i].mPos; + } + + *output_triangles = new S32[num_input_triangles*3]; + memcpy(*output_triangles, input_triangles, 3*num_input_triangles*sizeof(S32)); // Flawfinder: ignore + return TRUE; + */ + // Here's how we do this: // Create a structure which contains the original vertex index and the // LLVector3 data. @@ -3549,7 +3597,7 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices, } else { - //llinfos << "Removed duplicate vertex " << pairp->mVertex << llendl; + //llinfos << "Removed duplicate vertex " << pairp->mVertex << ", distance magVecSquared() is " << (pairp->mVertex - prev_pairp->mVertex).magVecSquared() << llendl; } vertex_mapping[pairp->mIndex] = new_num_vertices - 1; } @@ -3561,50 +3609,54 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices, for (i = 0; i < num_input_triangles; i++) { - //llinfos << "Checking triangle " << input_triangles[i*3] << ":" << input_triangles[i*3+1] << ":" << input_triangles[i*3+2] << llendl; - input_triangles[i*3] = vertex_mapping[input_triangles[i*3]]; - input_triangles[i*3+1] = vertex_mapping[input_triangles[i*3+1]]; - input_triangles[i*3+2] = vertex_mapping[input_triangles[i*3+2]]; + S32 v1 = i*3; + S32 v2 = i*3 + 1; + S32 v3 = i*3 + 2; + + //llinfos << "Checking triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl; + input_triangles[v1] = vertex_mapping[input_triangles[v1]]; + input_triangles[v2] = vertex_mapping[input_triangles[v2]]; + input_triangles[v3] = vertex_mapping[input_triangles[v3]]; - if ((input_triangles[i*3] == input_triangles[i*3+1]) - || (input_triangles[i*3] == input_triangles[i*3+2]) - || (input_triangles[i*3+1] == input_triangles[i*3+2])) + if ((input_triangles[v1] == input_triangles[v2]) + || (input_triangles[v1] == input_triangles[v3]) + || (input_triangles[v2] == input_triangles[v3])) { - //llinfos << "Removing degenerate triangle " << input_triangles[i*3] << ":" << input_triangles[i*3+1] << ":" << input_triangles[i*3+2] << llendl; + //llinfos << "Removing degenerate triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl; // Degenerate triangle, skip continue; } - if (input_triangles[i*3] < input_triangles[i*3+1]) + if (input_triangles[v1] < input_triangles[v2]) { - if (input_triangles[i*3] < input_triangles[i*3+2]) + if (input_triangles[v1] < input_triangles[v3]) { // (0 < 1) && (0 < 2) - new_triangles[new_num_triangles*3] = input_triangles[i*3]; - new_triangles[new_num_triangles*3+1] = input_triangles[i*3+1]; - new_triangles[new_num_triangles*3+2] = input_triangles[i*3+2]; + new_triangles[new_num_triangles*3] = input_triangles[v1]; + new_triangles[new_num_triangles*3+1] = input_triangles[v2]; + new_triangles[new_num_triangles*3+2] = input_triangles[v3]; } else { // (0 < 1) && (2 < 0) - new_triangles[new_num_triangles*3] = input_triangles[i*3+2]; - new_triangles[new_num_triangles*3+1] = input_triangles[i*3]; - new_triangles[new_num_triangles*3+2] = input_triangles[i*3+1]; + new_triangles[new_num_triangles*3] = input_triangles[v3]; + new_triangles[new_num_triangles*3+1] = input_triangles[v1]; + new_triangles[new_num_triangles*3+2] = input_triangles[v2]; } } - else if (input_triangles[i*3+1] < input_triangles[i*3+2]) + else if (input_triangles[v2] < input_triangles[v3]) { // (1 < 0) && (1 < 2) - new_triangles[new_num_triangles*3] = input_triangles[i*3+1]; - new_triangles[new_num_triangles*3+1] = input_triangles[i*3+2]; - new_triangles[new_num_triangles*3+2] = input_triangles[i*3]; + new_triangles[new_num_triangles*3] = input_triangles[v2]; + new_triangles[new_num_triangles*3+1] = input_triangles[v3]; + new_triangles[new_num_triangles*3+2] = input_triangles[v1]; } else { // (1 < 0) && (2 < 1) - new_triangles[new_num_triangles*3] = input_triangles[i*3+2]; - new_triangles[new_num_triangles*3+1] = input_triangles[i*3]; - new_triangles[new_num_triangles*3+2] = input_triangles[i*3+1]; + new_triangles[new_num_triangles*3] = input_triangles[v3]; + new_triangles[new_num_triangles*3+1] = input_triangles[v1]; + new_triangles[new_num_triangles*3+2] = input_triangles[v2]; } new_num_triangles++; } @@ -3845,23 +3897,44 @@ void LLVolumeParams::reduceT(F32 begin, F32 end) mPathParams.setEnd(a + end * (b - a)); } +const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f; // 1/8 unity +const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity + +// returns TRUE if the shape can be approximated with a convex shape +// for collison purposes BOOL LLVolumeParams::isConvex() const { - // The logic for determining convexity is a little convoluted. + F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); - // Do we need to take getTwistBegin into account? DK 08/12/04 - if ( mProfileParams.getHollow() != 0.0f - || mPathParams.getTwist() != mPathParams.getTwistBegin() ) + if ( mPathParams.getTwist() != mPathParams.getTwistBegin() + && path_length > MIN_CONCAVE_PATH_WEDGE ) { - // hollow or twist gaurantees concavity + // twist along a "not too short" path is concave return FALSE; } F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin(); - BOOL concave_profile = (profile_length < 1.0f) && (profile_length > 0.5f); - if (concave_profile) + F32 hollow = mProfileParams.getHollow(); + BOOL same_hole = hollow == 0.f + || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME; + + F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE; + U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; + if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) { - // concave profile + // it is a sphere and spheres get twice the minimum profile wedge + min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE; + } + + BOOL convex_profile = ( ( profile_length == 1.f + || profile_length <= 0.5f ) + && hollow == 0.f ) // trivially convex + || ( profile_length <= min_profile_wedge + && same_hole ); // effectvely convex (even when hollow) + + if (!convex_profile) + { + // profile is concave return FALSE; } @@ -3872,7 +3945,6 @@ BOOL LLVolumeParams::isConvex() const return TRUE; } - F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f); if (concave_path) { @@ -3880,17 +3952,43 @@ BOOL LLVolumeParams::isConvex() const } // we're left with spheres, toroids and tubes - // only the spheres can be convex - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) { + // at this stage all spheres must be convex return TRUE; } // it's a toroid or tube + if ( path_length <= MIN_CONCAVE_PATH_WEDGE ) + { + // effectively convex + return TRUE; + } + return FALSE; } +// debug +void LLVolumeParams::setCube() +{ + mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE); + mProfileParams.setBegin(0.f); + mProfileParams.setEnd(1.f); + mProfileParams.setHollow(0.f); + + mPathParams.setBegin(0.f); + mPathParams.setEnd(1.f); + mPathParams.setScale(1.f, 1.f); + mPathParams.setShear(0.f, 0.f); + mPathParams.setCurveType(LL_PCODE_PATH_LINE); + mPathParams.setTwistBegin(0.f); + mPathParams.setTwistEnd(0.f); + mPathParams.setRadiusOffset(0.f); + mPathParams.setTaper(0.f, 0.f); + mPathParams.setRevolutions(0.f); + mPathParams.setSkew(0.f); +} + LLFaceID LLVolume::generateFaceMask() { LLFaceID new_mask = 0x0000; |