diff options
Diffstat (limited to 'indra/llmath/llvolume.cpp')
-rw-r--r-- | indra/llmath/llvolume.cpp | 1626 |
1 files changed, 1030 insertions, 596 deletions
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 44fef9daf6..14e1ca8d43 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1,30 +1,25 @@ /** * @file llvolume.cpp * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,6 +29,7 @@ #include <set> #include "llerror.h" +#include "llmemtype.h" #include "llvolumemgr.h" #include "v2math.h" @@ -81,12 +77,10 @@ const F32 TAPER_MAX = 1.f; const F32 SKEW_MIN = -0.95f; const F32 SKEW_MAX = 0.95f; -const S32 SCULPT_REZ_1 = 6; // changed from 4 to 6 - 6 looks round whereas 4 looks square -const S32 SCULPT_REZ_2 = 8; -const S32 SCULPT_REZ_3 = 16; -const S32 SCULPT_REZ_4 = 32; - const F32 SCULPT_MIN_AREA = 0.002f; +const S32 SCULPT_MIN_AREA_DETAIL = 1; + +#define GEN_TRI_STRIP 0 BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) { @@ -103,46 +97,128 @@ BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLV } } -// intersect test between triangle pt1,pt2,pt3 and line from linept to linept+vect -//returns TRUE if intersecting and moves linept to the point of intersection -BOOL LLTriangleLineSegmentIntersect( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, LLVector3& linept, const LLVector3& vect) +BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size) +{ + float fAWdU[3]; + LLVector3 dir; + LLVector3 diff; + + for (U32 i = 0; i < 3; i++) + { + dir.mV[i] = 0.5f * (end.mV[i] - start.mV[i]); + diff.mV[i] = (0.5f * (end.mV[i] + start.mV[i])) - center.mV[i]; + fAWdU[i] = fabsf(dir.mV[i]); + if(fabsf(diff.mV[i])>size.mV[i] + fAWdU[i]) return false; + } + + float f; + f = dir.mV[1] * diff.mV[2] - dir.mV[2] * diff.mV[1]; if(fabsf(f)>size.mV[1]*fAWdU[2] + size.mV[2]*fAWdU[1]) return false; + f = dir.mV[2] * diff.mV[0] - dir.mV[0] * diff.mV[2]; if(fabsf(f)>size.mV[0]*fAWdU[2] + size.mV[2]*fAWdU[0]) return false; + f = dir.mV[0] * diff.mV[1] - dir.mV[1] * diff.mV[0]; if(fabsf(f)>size.mV[0]*fAWdU[1] + size.mV[1]*fAWdU[0]) return false; + + return true; +} + + +// intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir. +// returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b, +// and returns the intersection point along dir in intersection_t. + +// Moller-Trumbore algorithm +BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, + F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided) { - LLVector3 V1 = pt2-pt1; - LLVector3 V2 = pt3-pt2; + F32 u, v, t; - LLVector3 norm = V1 % V2; + /* find vectors for two edges sharing vert0 */ + LLVector3 edge1 = vert1 - vert0; - F32 dotprod = norm * vect; + LLVector3 edge2 = vert2 - vert0;; - if(dotprod < 0) + /* begin calculating determinant - also used to calculate U parameter */ + LLVector3 pvec = dir % edge2; + + /* if determinant is near zero, ray lies in plane of triangle */ + F32 det = edge1 * pvec; + + if (!two_sided) { - //Find point of intersect to triangle plane. - //find t to intersect point - F32 t = -(norm * (linept-pt1))/dotprod; + if (det < F_APPROXIMATELY_ZERO) + { + return FALSE; + } + + /* calculate distance from vert0 to ray origin */ + LLVector3 tvec = orig - vert0; - // if ds is neg line started past triangle so can't hit triangle. - if (t > 0) + /* calculate U parameter and test bounds */ + u = tvec * pvec; + + if (u < 0.f || u > det) { return FALSE; } - LLVector3 pt_int = linept + (vect*t); + /* prepare to test V parameter */ + LLVector3 qvec = tvec % edge1; - if(check_same_clock_dir(pt1, pt2, pt_int, norm)) + /* calculate V parameter and test bounds */ + v = dir * qvec; + if (v < 0.f || u + v > det) { - if(check_same_clock_dir(pt2, pt3, pt_int, norm)) + return FALSE; + } + + /* calculate t, scale parameters, ray intersects triangle */ + t = edge2 * qvec; + F32 inv_det = 1.0 / det; + t *= inv_det; + u *= inv_det; + v *= inv_det; + } + + else // two sided { - if(check_same_clock_dir(pt3, pt1, pt_int, norm)) + if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO) { - // answer in pt_int is insde triangle - linept.setVec(pt_int); - return TRUE; + return FALSE; } + F32 inv_det = 1.0 / det; + + /* calculate distance from vert0 to ray origin */ + LLVector3 tvec = orig - vert0; + + /* calculate U parameter and test bounds */ + u = (tvec * pvec) * inv_det; + if (u < 0.f || u > 1.f) + { + return FALSE; } + + /* prepare to test V parameter */ + LLVector3 qvec = tvec - edge1; + + /* calculate V parameter and test bounds */ + v = (dir * qvec) * inv_det; + + if (v < 0.f || u + v > 1.f) + { + return FALSE; } + + /* calculate t, ray intersects triangle */ + t = (edge2 * qvec) * inv_det; } - return FALSE; + if (intersection_a != NULL) + *intersection_a = u; + if (intersection_b != NULL) + *intersection_b = v; + if (intersection_t != NULL) + *intersection_t = t; + + + return TRUE; } @@ -155,6 +231,8 @@ BOOL LLTriangleLineSegmentIntersect( const LLVector3& pt1, const LLVector3& pt2, LLProfile::Face* LLProfile::addCap(S16 faceID) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + Face *face = vector_append(mFaces, 1); face->mIndex = 0; @@ -167,6 +245,8 @@ LLProfile::Face* LLProfile::addCap(S16 faceID) LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BOOL flat) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + Face *face = vector_append(mFaces, 1); face->mIndex = i; @@ -182,8 +262,10 @@ LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BO // What is the bevel parameter used for? - DJS 04/05/02 // Bevel parameter is currently unused but presumedly would support // filleted and chamfered corners -void LLProfile::genNGon(S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split) +void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + // Generate an n-sided "circular" path. // 0 is (1,0), and we go counter-clockwise along a circular path from there. const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; @@ -191,11 +273,8 @@ void LLProfile::genNGon(S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 spl F32 t, t_step, t_first, t_fraction, ang, ang_step; LLVector3 pt1,pt2; - mMaxX = 0.f; - mMinX = 0.f; - - F32 begin = mParams.getBegin(); - F32 end = mParams.getEnd(); + F32 begin = params.getBegin(); + F32 end = params.getEnd(); t_step = 1.0f / sides; ang_step = 2.0f*F_PI*t_step*ang_scale; @@ -229,15 +308,6 @@ void LLProfile::genNGon(S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 spl if (t_fraction < 0.9999f) { LLVector3 new_pt = lerp(pt1, pt2, t_fraction); - F32 pt_x = new_pt.mV[VX]; - if (pt_x < mMinX) - { - mMinX = pt_x; - } - else if (pt_x > mMaxX) - { - mMaxX = pt_x; - } mProfile.push_back(new_pt); } @@ -247,16 +317,6 @@ void LLProfile::genNGon(S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 spl // Iterate through all the integer steps of t. pt1.setVec(cos(ang)*scale,sin(ang)*scale,t); - F32 pt_x = pt1.mV[VX]; - if (pt_x < mMinX) - { - mMinX = pt_x; - } - else if (pt_x > mMaxX) - { - mMaxX = pt_x; - } - if (mProfile.size() > 0) { LLVector3 p = mProfile[mProfile.size()-1]; for (S32 i = 0; i < split && mProfile.size() > 0; i++) { @@ -280,15 +340,6 @@ void LLProfile::genNGon(S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 spl if (t_fraction > 0.0001f) { LLVector3 new_pt = lerp(pt1, pt2, t_fraction); - F32 pt_x = new_pt.mV[VX]; - if (pt_x < mMinX) - { - mMinX = pt_x; - } - else if (pt_x > mMaxX) - { - mMaxX = pt_x; - } if (mProfile.size() > 0) { LLVector3 p = mProfile[mProfile.size()-1]; @@ -311,7 +362,7 @@ void LLProfile::genNGon(S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 spl mConcave = FALSE; } mOpen = TRUE; - if (!isHollow()) + if (params.getHollow() <= 0) { // put center point if not hollow. mProfile.push_back(LLVector3(0,0,0)); @@ -327,7 +378,7 @@ void LLProfile::genNGon(S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 spl mTotal = mProfile.size(); } -void LLProfile::genNormals() +void LLProfile::genNormals(const LLProfileParams& params) { S32 count = mProfile.size(); @@ -347,8 +398,7 @@ void LLProfile::genNormals() LLVector2 pt0,pt1; - BOOL hollow; - hollow = isHollow(); + BOOL hollow = (params.getHollow() > 0); S32 i0, i1, i2, i3, i4; @@ -428,7 +478,7 @@ void LLProfile::genNormals() // Hollow is percent of the original bounding box, not of this particular // profile's geometry. Thus, a swept triangle needs lower hollow values than // a swept square. -LLProfile::Face* LLProfile::addHole(BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split) +LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split) { // Note that addHole will NOT work for non-"circular" profiles, if we ever decide to use them. @@ -436,11 +486,12 @@ LLProfile::Face* LLProfile::addHole(BOOL flat, F32 sides, F32 offset, F32 box_ho mTotalOut = mTotal; // Why is the "bevel" parameter -1? DJS 04/05/02 - genNGon(llfloor(sides),offset,-1, ang_scale, split); + genNGon(params, llfloor(sides),offset,-1, ang_scale, split); Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat); - LLVector3 pt[128]; + std::vector<LLVector3> pt; + pt.resize(mTotal) ; for (S32 i=mTotalOut;i<mTotal;i++) { @@ -465,32 +516,12 @@ LLProfile::Face* LLProfile::addHole(BOOL flat, F32 sides, F32 offset, F32 box_ho } -S32 sculpt_sides(F32 detail) -{ - // detail is usually one of: 1, 1.5, 2.5, 4.0. - - if (detail <= 1.0) - { - return SCULPT_REZ_1; - } - if (detail <= 2.0) - { - return SCULPT_REZ_2; - } - if (detail <= 3.0) - { - return SCULPT_REZ_3; - } - else - { - return SCULPT_REZ_4; - } -} - - -BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) +BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split, + BOOL is_sculpted, S32 sculpt_size) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + if ((!mDirty) && (!is_sculpted)) { return FALSE; @@ -508,9 +539,9 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) // Generate the face data S32 i; - F32 begin = mParams.getBegin(); - F32 end = mParams.getEnd(); - F32 hollow = mParams.getHollow(); + F32 begin = params.getBegin(); + F32 end = params.getEnd(); + F32 hollow = params.getHollow(); // Quick validation to eliminate some server crashes. if (begin > end - 0.01f) @@ -521,11 +552,11 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) S32 face_num = 0; - switch (mParams.getCurveType() & LL_PCODE_PROFILE_MASK) + switch (params.getCurveType() & LL_PCODE_PROFILE_MASK) { case LL_PCODE_PROFILE_SQUARE: { - genNGon(4,-0.375, 0, 1, split); + genNGon(params, 4,-0.375, 0, 1, split); if (path_open) { addCap (LL_FACE_PATH_BEGIN); @@ -544,20 +575,20 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) if (hollow) { - switch (mParams.getCurveType() & LL_PCODE_HOLE_MASK) + switch (params.getCurveType() & LL_PCODE_HOLE_MASK) { case LL_PCODE_HOLE_TRIANGLE: // This offset is not correct, but we can't change it now... DK 11/17/04 - addHole(TRUE, 3, -0.375f, hollow, 1.f, split); + addHole(params, TRUE, 3, -0.375f, hollow, 1.f, split); break; case LL_PCODE_HOLE_CIRCLE: // TODO: Compute actual detail levels for cubes - addHole(FALSE, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f); + addHole(params, FALSE, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f); break; case LL_PCODE_HOLE_SAME: case LL_PCODE_HOLE_SQUARE: default: - addHole(TRUE, 4, -0.375f, hollow, 1.f, split); + addHole(params, TRUE, 4, -0.375f, hollow, 1.f, split); break; } } @@ -571,7 +602,7 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) case LL_PCODE_PROFILE_RIGHTTRI: case LL_PCODE_PROFILE_EQUALTRI: { - genNGon(3,0, 0, 1, split); + genNGon(params, 3,0, 0, 1, split); for (i = 0; i <(S32) mProfile.size(); i++) { // Scale by 3 to generate proper tex coords. @@ -593,19 +624,19 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) // because the triangle doesn't fill the bounding box. F32 triangle_hollow = hollow / 2.f; - switch (mParams.getCurveType() & LL_PCODE_HOLE_MASK) + switch (params.getCurveType() & LL_PCODE_HOLE_MASK) { case LL_PCODE_HOLE_CIRCLE: // TODO: Actually generate level of detail for triangles - addHole(FALSE, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f); + addHole(params, FALSE, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f); break; case LL_PCODE_HOLE_SQUARE: - addHole(TRUE, 4, 0, triangle_hollow, 1.f, split); + addHole(params, TRUE, 4, 0, triangle_hollow, 1.f, split); break; case LL_PCODE_HOLE_SAME: case LL_PCODE_HOLE_TRIANGLE: default: - addHole(TRUE, 3, 0, triangle_hollow, 1.f, split); + addHole(params, TRUE, 3, 0, triangle_hollow, 1.f, split); break; } } @@ -619,7 +650,7 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) F32 circle_detail = MIN_DETAIL_FACES * detail; if (hollow) { - hole_type = mParams.getCurveType() & LL_PCODE_HOLE_MASK; + hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK; if (hole_type == LL_PCODE_HOLE_SQUARE) { // Snap to the next multiple of four sides, @@ -631,9 +662,9 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) S32 sides = (S32)circle_detail; if (is_sculpted) - sides = sculpt_sides(detail); + sides = sculpt_size; - genNGon(sides); + genNGon(params, sides); if (path_open) { @@ -654,15 +685,15 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) switch (hole_type) { case LL_PCODE_HOLE_SQUARE: - addHole(TRUE, 4, 0, hollow, 1.f, split); + addHole(params, TRUE, 4, 0, hollow, 1.f, split); break; case LL_PCODE_HOLE_TRIANGLE: - addHole(TRUE, 3, 0, hollow, 1.f, split); + addHole(params, TRUE, 3, 0, hollow, 1.f, split); break; case LL_PCODE_HOLE_CIRCLE: case LL_PCODE_HOLE_SAME: default: - addHole(FALSE, circle_detail, 0, hollow, 1.f); + addHole(params, FALSE, circle_detail, 0, hollow, 1.f); break; } } @@ -677,7 +708,7 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) F32 circle_detail = MIN_DETAIL_FACES * detail * 0.5f; if (hollow) { - hole_type = mParams.getCurveType() & LL_PCODE_HOLE_MASK; + hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK; if (hole_type == LL_PCODE_HOLE_SQUARE) { // Snap to the next multiple of four sides (div 2), @@ -685,12 +716,12 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) circle_detail = llceil(circle_detail / 2.0f) * 2.0f; } } - genNGon(llfloor(circle_detail), 0.5f, 0.f, 0.5f); + genNGon(params, llfloor(circle_detail), 0.5f, 0.f, 0.5f); if (path_open) { addCap(LL_FACE_PATH_BEGIN); } - if (mOpen && !mParams.getHollow()) + if (mOpen && !params.getHollow()) { addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE); } @@ -704,21 +735,21 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) switch (hole_type) { case LL_PCODE_HOLE_SQUARE: - addHole(TRUE, 2, 0.5f, hollow, 0.5f, split); + addHole(params, TRUE, 2, 0.5f, hollow, 0.5f, split); break; case LL_PCODE_HOLE_TRIANGLE: - addHole(TRUE, 3, 0.5f, hollow, 0.5f, split); + addHole(params, TRUE, 3, 0.5f, hollow, 0.5f, split); break; case LL_PCODE_HOLE_CIRCLE: case LL_PCODE_HOLE_SAME: default: - addHole(FALSE, circle_detail, 0.5f, hollow, 0.5f); + addHole(params, FALSE, circle_detail, 0.5f, hollow, 0.5f); break; } } // Special case for openness of sphere - if ((mParams.getEnd() - mParams.getBegin()) < 1.f) + if ((params.getEnd() - params.getBegin()) < 1.f) { mOpen = TRUE; } @@ -731,7 +762,7 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) } break; default: - llerrs << "Unknown profile: getCurveType()=" << mParams.getCurveType() << llendl; + llerrs << "Unknown profile: getCurveType()=" << params.getCurveType() << llendl; break; }; @@ -754,15 +785,17 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted) } } - //genNormals(); + //genNormals(params); return TRUE; } -BOOL LLProfileParams::importFile(FILE *fp) +BOOL LLProfileParams::importFile(LLFILE *fp) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + const S32 BUFSIZE = 16384; char buffer[BUFSIZE]; /* Flawfinder: ignore */ // *NOTE: changing the size or type of these buffers will require @@ -823,7 +856,7 @@ BOOL LLProfileParams::importFile(FILE *fp) } -BOOL LLProfileParams::exportFile(FILE *fp) const +BOOL LLProfileParams::exportFile(LLFILE *fp) const { fprintf(fp,"\t\tprofile 0\n"); fprintf(fp,"\t\t{\n"); @@ -838,6 +871,8 @@ BOOL LLProfileParams::exportFile(FILE *fp) const BOOL LLProfileParams::importLegacyStream(std::istream& input_stream) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + const S32 BUFSIZE = 16384; char buffer[BUFSIZE]; /* Flawfinder: ignore */ // *NOTE: changing the size or type of these buffers will require @@ -929,6 +964,7 @@ bool LLProfileParams::fromLLSD(LLSD& sd) void LLProfileParams::copyParams(const LLProfileParams ¶ms) { + LLMemType m1(LLMemType::MTYPE_VOLUME); setCurveType(params.getCurveType()); setBegin(params.getBegin()); setEnd(params.getEnd()); @@ -940,22 +976,22 @@ LLPath::~LLPath() { } -void LLPath::genNGon(S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) +void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) { // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane. const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; - F32 revolutions = mParams.getRevolutions(); - F32 skew = mParams.getSkew(); + F32 revolutions = params.getRevolutions(); + F32 skew = params.getSkew(); F32 skew_mag = fabs(skew); - F32 hole_x = mParams.getScaleX() * (1.0f - skew_mag); - F32 hole_y = mParams.getScaleY(); + F32 hole_x = params.getScaleX() * (1.0f - skew_mag); + F32 hole_y = params.getScaleY(); // Calculate taper begin/end for x,y (Negative means taper the beginning) F32 taper_x_begin = 1.0f; - F32 taper_x_end = 1.0f - mParams.getTaperX(); + F32 taper_x_end = 1.0f - params.getTaperX(); F32 taper_y_begin = 1.0f; - F32 taper_y_end = 1.0f - mParams.getTaperY(); + F32 taper_y_end = 1.0f - params.getTaperY(); if ( taper_x_end > 1.0f ) { @@ -983,7 +1019,7 @@ void LLPath::genNGon(S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) // Now check the radius offset to calculate the start,end radius. (Negative means // decrease the start radius instead). F32 radius_end = radius_start; - F32 radius_offset = mParams.getRadiusOffset(); + F32 radius_offset = params.getRadiusOffset(); if (radius_offset < 0.f) { radius_start *= 1.f + radius_offset; @@ -994,7 +1030,7 @@ void LLPath::genNGon(S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) } // Is the path NOT a closed loop? - mOpen = ( (mParams.getEnd()*end_scale - mParams.getBegin() < 1.0f) || + mOpen = ( (params.getEnd()*end_scale - params.getBegin() < 1.0f) || (skew_mag > 0.001f) || (fabs(taper_x_end - taper_x_begin) > 0.001f) || (fabs(taper_y_end - taper_y_begin) > 0.001f) || @@ -1005,22 +1041,22 @@ void LLPath::genNGon(S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) PathPt *pt; LLVector3 path_axis (1.f, 0.f, 0.f); //LLVector3 twist_axis(0.f, 0.f, 1.f); - F32 twist_begin = mParams.getTwistBegin() * twist_scale; - F32 twist_end = mParams.getTwist() * twist_scale; + F32 twist_begin = params.getTwistBegin() * twist_scale; + F32 twist_end = params.getTwist() * twist_scale; // We run through this once before the main loop, to make sure // the path begins at the correct cut. F32 step= 1.0f / sides; - F32 t = mParams.getBegin(); + F32 t = params.getBegin(); pt = vector_append(mPath, 1); ang = 2.0f*F_PI*revolutions * t; s = sin(ang)*lerp(radius_start, radius_end, t); c = cos(ang)*lerp(radius_start, radius_end, t); - pt->mPos.setVec(0 + lerp(0,mParams.getShear().mV[0],s) + pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s) + lerp(-skew ,skew, t) * 0.5f, - c + lerp(0,mParams.getShear().mV[1],s), + c + lerp(0,params.getShear().mV[1],s), s); pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); @@ -1039,7 +1075,7 @@ void LLPath::genNGon(S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) t = ((S32)(t * sides)) / (F32)sides; // Run through the non-cut dependent points. - while (t < mParams.getEnd()) + while (t < params.getEnd()) { pt = vector_append(mPath, 1); @@ -1047,9 +1083,9 @@ void LLPath::genNGon(S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) c = cos(ang)*lerp(radius_start, radius_end, t); s = sin(ang)*lerp(radius_start, radius_end, t); - pt->mPos.setVec(0 + lerp(0,mParams.getShear().mV[0],s) + pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s) + lerp(-skew ,skew, t) * 0.5f, - c + lerp(0,mParams.getShear().mV[1],s), + c + lerp(0,params.getShear().mV[1],s), s); pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); @@ -1066,15 +1102,15 @@ void LLPath::genNGon(S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) } // Make one final pass for the end cut. - t = mParams.getEnd(); + t = params.getEnd(); pt = vector_append(mPath, 1); ang = 2.0f*F_PI*revolutions * t; c = cos(ang)*lerp(radius_start, radius_end, t); s = sin(ang)*lerp(radius_start, radius_end, t); - pt->mPos.setVec(0 + lerp(0,mParams.getShear().mV[0],s) + pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s) + lerp(-skew ,skew, t) * 0.5f, - c + lerp(0,mParams.getShear().mV[1],s), + c + lerp(0,params.getShear().mV[1],s), s); pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); @@ -1117,8 +1153,11 @@ const LLVector2 LLPathParams::getEndScale() const return end_scale; } -BOOL LLPath::generate(F32 detail, S32 split, BOOL is_sculpted) +BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, + BOOL is_sculpted, S32 sculpt_size) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + if ((!mDirty) && (!is_sculpted)) { return FALSE; @@ -1137,13 +1176,13 @@ BOOL LLPath::generate(F32 detail, S32 split, BOOL is_sculpted) mOpen = TRUE; // Is this 0xf0 mask really necessary? DK 03/02/05 - switch (mParams.getCurveType() & 0xf0) + switch (params.getCurveType() & 0xf0) { default: case LL_PCODE_PATH_LINE: { // Take the begin/end twist into account for detail. - np = llfloor(fabs(mParams.getTwistBegin() - mParams.getTwist()) * 3.5f * (detail-0.5f)) + 2; + np = llfloor(fabs(params.getTwistBegin() - params.getTwist()) * 3.5f * (detail-0.5f)) + 2; if (np < split+2) { np = split+2; @@ -1153,16 +1192,16 @@ BOOL LLPath::generate(F32 detail, S32 split, BOOL is_sculpted) mPath.resize(np); - LLVector2 start_scale = mParams.getBeginScale(); - LLVector2 end_scale = mParams.getEndScale(); + LLVector2 start_scale = params.getBeginScale(); + LLVector2 end_scale = params.getEndScale(); for (S32 i=0;i<np;i++) { - F32 t = lerp(mParams.getBegin(),mParams.getEnd(),(F32)i * mStep); - mPath[i].mPos.setVec(lerp(0,mParams.getShear().mV[0],t), - lerp(0,mParams.getShear().mV[1],t), + F32 t = lerp(params.getBegin(),params.getEnd(),(F32)i * mStep); + mPath[i].mPos.setVec(lerp(0,params.getShear().mV[0],t), + lerp(0,params.getShear().mV[1],t), t - 0.5f); - mPath[i].mRot.setQuat(lerp(F_PI * mParams.getTwistBegin(),F_PI * mParams.getTwist(),t),0,0,1); + mPath[i].mRot.setQuat(lerp(F_PI * params.getTwistBegin(),F_PI * params.getTwist(),t),0,0,1); mPath[i].mScale.mV[0] = lerp(start_scale.mV[0],end_scale.mV[0],t); mPath[i].mScale.mV[1] = lerp(start_scale.mV[1],end_scale.mV[1],t); mPath[i].mTexT = t; @@ -1173,27 +1212,27 @@ BOOL LLPath::generate(F32 detail, S32 split, BOOL is_sculpted) case LL_PCODE_PATH_CIRCLE: { // Increase the detail as the revolutions and twist increase. - F32 twist_mag = fabs(mParams.getTwistBegin() - mParams.getTwist()); + F32 twist_mag = fabs(params.getTwistBegin() - params.getTwist()); - S32 sides = (S32)llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * mParams.getRevolutions()); + S32 sides = (S32)llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * params.getRevolutions()); if (is_sculpted) - sides = sculpt_sides(detail); + sides = sculpt_size; - genNGon(sides); + genNGon(params, sides); } break; case LL_PCODE_PATH_CIRCLE2: { - if (mParams.getEnd() - mParams.getBegin() >= 0.99f && - mParams.getScaleX() >= .99f) + if (params.getEnd() - params.getBegin() >= 0.99f && + params.getScaleX() >= .99f) { mOpen = FALSE; } - //genNGon(llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f); - genNGon(llfloor(MIN_DETAIL_FACES * detail)); + //genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f); + genNGon(params, llfloor(MIN_DETAIL_FACES * detail)); F32 t = 0.f; F32 tStep = 1.0f / mPath.size(); @@ -1223,28 +1262,31 @@ BOOL LLPath::generate(F32 detail, S32 split, BOOL is_sculpted) { F32 t = (F32)i * mStep; mPath[i].mPos.setVec(0, - lerp(0, -sin(F_PI*mParams.getTwist()*t)*0.5f,t), - lerp(-0.5, cos(F_PI*mParams.getTwist()*t)*0.5f,t)); - mPath[i].mScale.mV[0] = lerp(1,mParams.getScale().mV[0],t); - mPath[i].mScale.mV[1] = lerp(1,mParams.getScale().mV[1],t); + lerp(0, -sin(F_PI*params.getTwist()*t)*0.5f,t), + lerp(-0.5, cos(F_PI*params.getTwist()*t)*0.5f,t)); + mPath[i].mScale.mV[0] = lerp(1,params.getScale().mV[0],t); + mPath[i].mScale.mV[1] = lerp(1,params.getScale().mV[1],t); mPath[i].mTexT = t; - mPath[i].mRot.setQuat(F_PI * mParams.getTwist() * t,1,0,0); + mPath[i].mRot.setQuat(F_PI * params.getTwist() * t,1,0,0); } break; }; - if (mParams.getTwist() != mParams.getTwistBegin()) mOpen = TRUE; + if (params.getTwist() != params.getTwistBegin()) mOpen = TRUE; - //if ((int(fabsf(mParams.getTwist() - mParams.getTwistBegin())*100))%100 != 0) { + //if ((int(fabsf(params.getTwist() - params.getTwistBegin())*100))%100 != 0) { // mOpen = TRUE; //} return TRUE; } -BOOL LLDynamicPath::generate(F32 detail, S32 split, BOOL is_sculpted) +BOOL LLDynamicPath::generate(const LLPathParams& params, F32 detail, S32 split, + BOOL is_sculpted, S32 sculpt_size) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + mOpen = TRUE; // Draw end caps if (getPathLength() == 0) { @@ -1264,8 +1306,10 @@ BOOL LLDynamicPath::generate(F32 detail, S32 split, BOOL is_sculpted) } -BOOL LLPathParams::importFile(FILE *fp) +BOOL LLPathParams::importFile(LLFILE *fp) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + const S32 BUFSIZE = 16384; char buffer[BUFSIZE]; /* Flawfinder: ignore */ // *NOTE: changing the size or type of these buffers will require @@ -1383,7 +1427,7 @@ BOOL LLPathParams::importFile(FILE *fp) } -BOOL LLPathParams::exportFile(FILE *fp) const +BOOL LLPathParams::exportFile(LLFILE *fp) const { fprintf(fp, "\t\tpath 0\n"); fprintf(fp, "\t\t{\n"); @@ -1410,6 +1454,8 @@ BOOL LLPathParams::exportFile(FILE *fp) const BOOL LLPathParams::importLegacyStream(std::istream& input_stream) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + const S32 BUFSIZE = 16384; char buffer[BUFSIZE]; /* Flawfinder: ignore */ // *NOTE: changing the size or type of these buffers will require @@ -1602,16 +1648,23 @@ void LLPathParams::copyParams(const LLPathParams ¶ms) setSkew(params.getSkew()); } +S32 profile_delete_lock = 1 ; LLProfile::~LLProfile() { - + if(profile_delete_lock) + { + llerrs << "LLProfile should not be deleted here!" << llendl ; + } } S32 LLVolume::sNumMeshPoints = 0; -LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL generate_single_face, const BOOL is_unique) : mParams(params) +LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL generate_single_face, const BOOL is_unique) + : mParams(params) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + mUnique = is_unique; mFaceMask = 0x0; mDetail = detail; @@ -1620,20 +1673,18 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge // set defaults if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) { - mPathp = new LLDynamicPath(mParams.getPathParams()); + mPathp = new LLDynamicPath(); } else { - mPathp = new LLPath(mParams.getPathParams()); + mPathp = new LLPath(); } - mProfilep = new LLProfile(mParams.getProfileParams()); + mProfilep = new LLProfile(); - mNumVolumeFaces = 0; - mVolumeFaces = NULL; mGenerateSingleFace = generate_single_face; generate(); - if (mParams.getSculptID().isNull()) + if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE) { createVolumeFaces(); } @@ -1642,11 +1693,7 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge void LLVolume::resizePath(S32 length) { mPathp->resizePath(length); - if (mVolumeFaces != NULL) - { - delete[] mVolumeFaces; - mVolumeFaces = NULL; - } + mVolumeFaces.clear(); } void LLVolume::regen() @@ -1664,16 +1711,19 @@ LLVolume::~LLVolume() { sNumMeshPoints -= mMesh.size(); delete mPathp; + + profile_delete_lock = 0 ; delete mProfilep; - delete[] mVolumeFaces; + profile_delete_lock = 1 ; mPathp = NULL; mProfilep = NULL; - mVolumeFaces = NULL; + mVolumeFaces.clear(); } BOOL LLVolume::generate() { + LLMemType m1(LLMemType::MTYPE_VOLUME); llassert_always(mProfilep); //Added 10.03.05 Dave Parks @@ -1682,13 +1732,13 @@ BOOL LLVolume::generate() // stretched due to twisting or scaling on the path. S32 split = (S32) ((mDetail)*0.66f); - if (mPathp->mParams.getCurveType() == LL_PCODE_PATH_LINE && - (mPathp->mParams.getScale().mV[0] != 1.0f || - mPathp->mParams.getScale().mV[1] != 1.0f) && - (mProfilep->mParams.getCurveType() == LL_PCODE_PROFILE_SQUARE || - mProfilep->mParams.getCurveType() == LL_PCODE_PROFILE_ISOTRI || - mProfilep->mParams.getCurveType() == LL_PCODE_PROFILE_EQUALTRI || - mProfilep->mParams.getCurveType() == LL_PCODE_PROFILE_RIGHTTRI)) + if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_LINE && + (mParams.getPathParams().getScale().mV[0] != 1.0f || + mParams.getPathParams().getScale().mV[1] != 1.0f) && + (mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_SQUARE || + mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_ISOTRI || + mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_EQUALTRI || + mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_RIGHTTRI)) { split = 0; } @@ -1698,8 +1748,8 @@ BOOL LLVolume::generate() F32 profile_detail = mDetail; F32 path_detail = mDetail; - U8 path_type = mPathp->mParams.getCurveType(); - U8 profile_type = mProfilep->mParams.getCurveType(); + U8 path_type = mParams.getPathParams().getCurveType(); + U8 profile_type = mParams.getProfileParams().getCurveType(); if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) { //cylinders don't care about Z-Axis @@ -1710,18 +1760,47 @@ BOOL LLVolume::generate() mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); } - BOOL regenPath = mPathp->generate(path_detail, split); - BOOL regenProf = mProfilep->generate(mPathp->isOpen(),profile_detail, split); + //******************************************************************** + //debug info, to be removed + if((U32)(mPathp->mPath.size() * mProfilep->mProfile.size()) > (1u << 20)) + { + llinfos << "sizeS: " << mPathp->mPath.size() << " sizeT: " << mProfilep->mProfile.size() << llendl ; + llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ; + llinfos << mParams << llendl ; + llinfos << "more info to check if mProfilep is deleted or not." << llendl ; + llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ; + + llerrs << "LLVolume corrupted!" << llendl ; + } + //******************************************************************** + + BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split); + BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split); if (regenPath || regenProf ) { - sNumMeshPoints -= mMesh.size(); - mMesh.resize(mProfilep->mProfile.size() * mPathp->mPath.size()); - sNumMeshPoints += mMesh.size(); - S32 sizeS = mPathp->mPath.size(); S32 sizeT = mProfilep->mProfile.size(); + //******************************************************************** + //debug info, to be removed + if((U32)(sizeS * sizeT) > (1u << 20)) + { + llinfos << "regenPath: " << (S32)regenPath << " regenProf: " << (S32)regenProf << llendl ; + llinfos << "sizeS: " << sizeS << " sizeT: " << sizeT << llendl ; + llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ; + llinfos << mParams << llendl ; + llinfos << "more info to check if mProfilep is deleted or not." << llendl ; + llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ; + + llerrs << "LLVolume corrupted!" << llendl ; + } + //******************************************************************** + + sNumMeshPoints -= mMesh.size(); + mMesh.resize(sizeT * sizeS); + sNumMeshPoints += mMesh.size(); + //generate vertex positions // Run along the path. @@ -1759,36 +1838,39 @@ BOOL LLVolume::generate() void LLVolume::createVolumeFaces() { - S32 i; + LLMemType m1(LLMemType::MTYPE_VOLUME); if (mGenerateSingleFace) { - mNumVolumeFaces = 0; + // do nothing } else { S32 num_faces = getNumFaces(); - mNumVolumeFaces = num_faces; BOOL partial_build = TRUE; - if (!mVolumeFaces) + if (num_faces != mVolumeFaces.size()) { partial_build = FALSE; - mVolumeFaces = new LLVolumeFace[num_faces]; + mVolumeFaces.resize(num_faces); } // Initialize volume faces with parameter data - for (i = 0; i < num_faces; i++) + for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++) { - LLVolumeFace &vf = mVolumeFaces[i]; - LLProfile::Face &face = mProfilep->mFaces[i]; - vf.mVolumep = this; + LLVolumeFace& vf = mVolumeFaces[i]; + LLProfile::Face& face = mProfilep->mFaces[i]; vf.mBeginS = face.mIndex; vf.mNumS = face.mCount; + if (vf.mNumS < 0) + { + llerrs << "Volume face corruption detected." << llendl; + } + vf.mBeginT = 0; vf.mNumT= getPath().mPath.size(); vf.mID = i; // Set the type mask bits correctly - if (mProfilep->isHollow()) + if (mParams.getProfileParams().getHollow() > 0) { vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK; } @@ -1826,6 +1908,10 @@ void LLVolume::createVolumeFaces() if (face.mFlat && vf.mNumS > 2) { //flat inner faces have to copy vert normals vf.mNumS = vf.mNumS*2; + if (vf.mNumS < 0) + { + llerrs << "Volume face corruption detected." << llendl; + } } } else @@ -1835,9 +1921,10 @@ void LLVolume::createVolumeFaces() } } - for (i = 0; i < mNumVolumeFaces; i++) + for (face_list_t::iterator iter = mVolumeFaces.begin(); + iter != mVolumeFaces.end(); ++iter) { - mVolumeFaces[i].create(partial_build); + (*iter).create(this, partial_build); } } } @@ -1857,10 +1944,6 @@ inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b) inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) { U32 index = (x + y * sculpt_width) * sculpt_components; - - // attempt to resolve DEV-11158 - remove assert later. - llassert(index < sculpt_width * sculpt_height * sculpt_components); - return index; } @@ -1896,34 +1979,29 @@ inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_ } -F32 LLVolume::sculptGetSurfaceArea(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) +F32 LLVolume::sculptGetSurfaceArea() { // test to see if image has enough variation to create non-degenerate geometry + F32 area = 0; + S32 sizeS = mPathp->mPath.size(); S32 sizeT = mProfilep->mProfile.size(); - - F32 area = 0; - - if ((sculpt_width != 0) && - (sculpt_height != 0) && - (sculpt_components != 0) && - (sculpt_data != NULL)) + + for (S32 s = 0; s < sizeS-1; s++) { - for (S32 s = 0; s < sizeS - 1; s++) + for (S32 t = 0; t < sizeT-1; t++) { - for (S32 t = 0; t < sizeT - 1; t++) - { - // convert image data to vectors - LLVector3 p1 = sculpt_st_to_vector(s, t, sizeS, sizeT, sculpt_width, sculpt_height, sculpt_components, sculpt_data); - LLVector3 p2 = sculpt_st_to_vector(s+1, t, sizeS, sizeT, sculpt_width, sculpt_height, sculpt_components, sculpt_data); - LLVector3 p3 = sculpt_st_to_vector(s, t+1, sizeS, sizeT, sculpt_width, sculpt_height, sculpt_components, sculpt_data); - - // compute the area of the parallelogram by taking the length of the cross product: - // (parallegram is an approximation of two triangles) - LLVector3 cross = (p1 - p2) % (p1 - p3); - area += cross.magVec(); - } + // get four corners of quad + LLVector3 p1 = mMesh[(s )*sizeT + (t )].mPos; + LLVector3 p2 = mMesh[(s+1)*sizeT + (t )].mPos; + LLVector3 p3 = mMesh[(s )*sizeT + (t+1)].mPos; + LLVector3 p4 = mMesh[(s+1)*sizeT + (t+1)].mPos; + + // compute the area of the quad by taking the length of the cross product of the two triangles + LLVector3 cross1 = (p1 - p2) % (p1 - p3); + LLVector3 cross2 = (p4 - p2) % (p4 - p3); + area += (cross1.magVec() + cross2.magVec()) / 2.0; } } @@ -1933,6 +2011,8 @@ F32 LLVolume::sculptGetSurfaceArea(U16 sculpt_width, U16 sculpt_height, S8 sculp // create placeholder shape void LLVolume::sculptGeneratePlaceholder() { + LLMemType m1(LLMemType::MTYPE_VOLUME); + S32 sizeS = mPathp->mPath.size(); S32 sizeT = mProfilep->mProfile.size(); @@ -1964,6 +2044,14 @@ void LLVolume::sculptGeneratePlaceholder() // create the vertices from the map void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type) { + U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; + BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; + BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; + BOOL reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR + + + LLMemType m1(LLMemType::MTYPE_VOLUME); + S32 sizeS = mPathp->mPath.size(); S32 sizeT = mProfilep->mProfile.size(); @@ -1976,13 +2064,21 @@ void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 S32 i = t + line; Point& pt = mMesh[i]; - U32 x = (U32) ((F32)t/(sizeT-1) * (F32) sculpt_width); + S32 reversed_t = t; + + if (reverse_horizontal) + { + reversed_t = sizeT - t - 1; + } + + U32 x = (U32) ((F32)reversed_t/(sizeT-1) * (F32) sculpt_width); U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height); + if (y == 0) // top row stitching { // pinch? - if (sculpt_type == LL_SCULPT_TYPE_SPHERE) + if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) { x = sculpt_width / 2; } @@ -1991,7 +2087,7 @@ void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 if (y == sculpt_height) // bottom row stitching { // wrap? - if (sculpt_type == LL_SCULPT_TYPE_TORUS) + if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) { y = 0; } @@ -2001,7 +2097,7 @@ void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 } // pinch? - if (sculpt_type == LL_SCULPT_TYPE_SPHERE) + if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) { x = sculpt_width / 2; } @@ -2010,9 +2106,9 @@ void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 if (x == sculpt_width) // side stitching { // wrap? - if ((sculpt_type == LL_SCULPT_TYPE_SPHERE) || - (sculpt_type == LL_SCULPT_TYPE_TORUS) || - (sculpt_type == LL_SCULPT_TYPE_CYLINDER)) + if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || + (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || + (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) { x = 0; } @@ -2024,30 +2120,107 @@ void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 } pt.mPos = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data); + + if (sculpt_mirror) + { + pt.mPos.mV[VX] *= -1.f; + } } + line += sizeT; } } +const S32 SCULPT_REZ_1 = 6; // changed from 4 to 6 - 6 looks round whereas 4 looks square +const S32 SCULPT_REZ_2 = 8; +const S32 SCULPT_REZ_3 = 16; +const S32 SCULPT_REZ_4 = 32; + +S32 sculpt_sides(F32 detail) +{ + + // detail is usually one of: 1, 1.5, 2.5, 4.0. + + if (detail <= 1.0) + { + return SCULPT_REZ_1; + } + if (detail <= 2.0) + { + return SCULPT_REZ_2; + } + if (detail <= 3.0) + { + return SCULPT_REZ_3; + } + else + { + return SCULPT_REZ_4; + } +} + + + +// determine the number of vertices in both s and t direction for this sculpt +void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t) +{ + // this code has the following properties: + // 1) the aspect ratio of the mesh is as close as possible to the ratio of the map + // while still using all available verts + // 2) the mesh cannot have more verts than is allowed by LOD + // 3) the mesh cannot have more verts than is allowed by the map + + S32 max_vertices_lod = (S32)pow((double)sculpt_sides(detail), 2.0); + S32 max_vertices_map = width * height / 4; + + S32 vertices; + if (max_vertices_map > 0) + vertices = llmin(max_vertices_lod, max_vertices_map); + else + vertices = max_vertices_lod; + + + F32 ratio; + if ((width == 0) || (height == 0)) + ratio = 1.f; + else + ratio = (F32) width / (F32) height; + + + s = (S32)fsqrtf(((F32)vertices / ratio)); + + s = llmax(s, 4); // no degenerate sizes, please + t = vertices / s; + + t = llmax(t, 4); // no degenerate sizes, please + s = vertices / t; +} + // sculpt replaces generate() for sculpted surfaces void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level) { + LLMemType m1(LLMemType::MTYPE_VOLUME); U8 sculpt_type = mParams.getSculptType(); BOOL data_is_empty = FALSE; - if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components == 0 || sculpt_data == NULL) + if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL) { sculpt_level = -1; data_is_empty = TRUE; } - mPathp->generate(mDetail, 0, TRUE); - mProfilep->generate(mPathp->isOpen(), mDetail, 0, TRUE); + S32 requested_sizeS = 0; + S32 requested_sizeT = 0; - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); + sculpt_calc_mesh_resolution(sculpt_width, sculpt_height, sculpt_type, mDetail, requested_sizeS, requested_sizeT); + + mPathp->generate(mParams.getPathParams(), mDetail, 0, TRUE, requested_sizeS); + mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, TRUE, requested_sizeT); + + S32 sizeS = mPathp->mPath.size(); // we requested a specific size, now see what we really got + S32 sizeT = mProfilep->mProfile.size(); // we requested a specific size, now see what we really got // weird crash bug - DEV-11158 - trying to collect more data: if ((sizeS == 0) || (sizeT == 0)) @@ -2058,26 +2231,39 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, sNumMeshPoints -= mMesh.size(); mMesh.resize(sizeS * sizeT); sNumMeshPoints += mMesh.size(); - - if (sculptGetSurfaceArea(sculpt_width, sculpt_height, sculpt_components, sculpt_data) < SCULPT_MIN_AREA) - data_is_empty = TRUE; //generate vertex positions - if (data_is_empty) // if empty, make a placeholder mesh - { - sculptGeneratePlaceholder(); - } - else + if (!data_is_empty) { sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type); + + // don't test lowest LOD to support legacy content DEV-33670 + if (mDetail > SCULPT_MIN_AREA_DETAIL) + { + if (sculptGetSurfaceArea() < SCULPT_MIN_AREA) + { + data_is_empty = TRUE; + } + } } + if (data_is_empty) + { + sculptGeneratePlaceholder(); + } + + + for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++) { mFaceMask |= mProfilep->mFaces[i].mFaceID; } mSculptLevel = sculpt_level; + + // Delete any existing faces so that they get regenerated + mVolumeFaces.clear(); + createVolumeFaces(); } @@ -2136,6 +2322,7 @@ bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const void LLVolumeParams::copyParams(const LLVolumeParams ¶ms) { + LLMemType m1(LLMemType::MTYPE_VOLUME); mProfileParams.copyParams(params.mProfileParams); mPathParams.copyParams(params.mPathParams); mSculptID = params.getSculptID(); @@ -2505,18 +2692,27 @@ 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]; + LLMemType m1(LLMemType::MTYPE_VOLUME); + + 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... BOOL open = getProfile().isOpen(); - BOOL hollow = getProfile().isHollow(); + BOOL hollow = (mParams.getProfileParams().getHollow() > 0); BOOL path_open = getPath().isOpen(); S32 size_s, size_s_out, size_t; S32 s, t, i; @@ -2524,6 +2720,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) @@ -2531,9 +2730,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 @@ -2647,8 +2843,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; @@ -2656,8 +2850,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; @@ -2748,8 +2940,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; @@ -2757,8 +2947,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; @@ -2771,9 +2959,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 @@ -2803,8 +2988,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; @@ -2814,8 +2997,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. @@ -2831,8 +3012,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++) @@ -2851,8 +3030,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++) @@ -2957,8 +3134,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; @@ -2966,8 +3141,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; @@ -3058,8 +3231,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; @@ -3067,8 +3238,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; @@ -3080,8 +3249,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++) @@ -3103,8 +3270,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; @@ -3114,8 +3279,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. @@ -3126,7 +3289,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) { @@ -3137,17 +3311,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 = (mParams.getProfileParams().getHollow() > 0); + 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; } //----------------------------------------------------------------------------- @@ -3158,16 +3380,26 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, std::vector<S32> &segments, const LLVector3& obj_cam_vec, const LLMatrix4& mat, - const LLMatrix3& norm_mat) + const LLMatrix3& norm_mat, + S32 face_mask) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + vertices.clear(); normals.clear(); segments.clear(); + S32 cur_index = 0; //for each face - for (S32 i = 0; i < getNumVolumeFaces(); i++) { - LLVolumeFace face = this->getVolumeFace(i); + for (face_list_t::iterator iter = mVolumeFaces.begin(); + iter != mVolumeFaces.end(); ++iter) + { + const LLVolumeFace& face = *iter; + if (!(face_mask & (0x1 << cur_index++))) + { + continue; + } if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { } @@ -3343,47 +3575,99 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, } } -S32 LLVolume::lineSegmentIntersect(const LLVector3& start, LLVector3& end) const +S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + S32 face, + LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) { - S32 ret = -1; + S32 hit_face = -1; - LLVector3 vec = end - start; + S32 start_face; + S32 end_face; + + if (face == -1) // ALL_SIDES + { + start_face = 0; + end_face = getNumVolumeFaces() - 1; + } + else + { + start_face = face; + end_face = face; + } + + LLVector3 dir = end - start; + + F32 closest_t = 2.f; // must be larger than 1 - for (U32 i = 0; i < (U32)getNumFaces(); i++) + for (S32 i = start_face; i <= end_face; i++) { - LLVolumeFace face = getVolumeFace(i); + const LLVolumeFace &face = getVolumeFace((U32)i); - for (U32 j = 0; j < face.mIndices.size()/3; j++) + LLVector3 box_center = (face.mExtents[0] + face.mExtents[1]) / 2.f; + LLVector3 box_size = face.mExtents[1] - face.mExtents[0]; + + if (LLLineSegmentBoxIntersect(start, end, box_center, box_size)) + { + if (bi_normal != NULL) // if the caller wants binormals, we may need to generate them + { + genBinormals(i); + } + + for (U32 tri = 0; tri < face.mIndices.size()/3; tri++) + { + S32 index1 = face.mIndices[tri*3+0]; + S32 index2 = face.mIndices[tri*3+1]; + S32 index3 = face.mIndices[tri*3+2]; + + F32 a, b, t; + + if (LLTriangleRayIntersect(face.mVertices[index1].mPosition, + face.mVertices[index2].mPosition, + face.mVertices[index3].mPosition, + start, dir, &a, &b, &t, FALSE)) + { + if ((t >= 0.f) && // if hit is after start + (t <= 1.f) && // and before end + (t < closest_t)) // and this hit is closer { - //approximate normal - S32 v1 = face.mIndices[j*3+0]; - S32 v2 = face.mIndices[j*3+1]; - S32 v3 = face.mIndices[j*3+2]; + closest_t = t; + hit_face = i; - LLVector3 norm = (face.mVertices[v2].mPosition - face.mVertices[v1].mPosition) % - (face.mVertices[v3].mPosition - face.mVertices[v2].mPosition); + if (intersection != NULL) + { + *intersection = start + dir * closest_t; + } - if (norm.magVecSquared() >= 0.00000001f) + if (tex_coord != NULL) { - //get view vector - //LLVector3 view = (start-face.mVertices[v1].mPosition); - //if (view * norm < 0.0f) + *tex_coord = ((1.f - a - b) * face.mVertices[index1].mTexCoord + + a * face.mVertices[index2].mTexCoord + + b * face.mVertices[index3].mTexCoord); + + } + + if (normal != NULL) { - if (LLTriangleLineSegmentIntersect( face.mVertices[v1].mPosition, - face.mVertices[v2].mPosition, - face.mVertices[v3].mPosition, - end, - vec)) + *normal = ((1.f - a - b) * face.mVertices[index1].mNormal + + a * face.mVertices[index2].mNormal + + b * face.mVertices[index3].mNormal); + } + + if (bi_normal != NULL) { - vec = end-start; - ret = (S32) i; + *bi_normal = ((1.f - a - b) * face.mVertices[index1].mBinormal + + a * face.mVertices[index2].mBinormal + + b * face.mVertices[index3].mBinormal); + } + } } } } } - return ret; + + return hit_face; } class LLVertexIndexPair @@ -3478,7 +3762,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; } @@ -3494,6 +3778,27 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices, S32 &num_output_triangles, S32 **output_triangles) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + + /* Testing: avoid any cleanup + static BOOL skip_cleanup = TRUE; + if ( skip_cleanup ) + { + num_output_vertices = num_input_vertices; + num_output_triangles = num_input_triangles; + + *output_vertices = new LLVector3[num_input_vertices]; + for (S32 index = 0; index < num_input_vertices; index++) + { + (*output_vertices)[index] = input_vertices[index].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. @@ -3522,6 +3827,7 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices, // Generate the vertex mapping and the list of vertices without // duplicates. This will crash if there are no vertices. + llassert(num_input_vertices > 0); // check for no vertices! S32 *vertex_mapping = new S32[num_input_vertices]; LLVector3 *new_vertices = new LLVector3[num_input_vertices]; LLVertexIndexPair *prev_pairp = NULL; @@ -3544,7 +3850,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; } @@ -3556,50 +3862,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 = v1 + 1; + S32 v3 = v1 + 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++; } @@ -3690,8 +4000,10 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices, } -BOOL LLVolumeParams::importFile(FILE *fp) +BOOL LLVolumeParams::importFile(LLFILE *fp) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + //llinfos << "importing volume" << llendl; const S32 BUFSIZE = 16384; char buffer[BUFSIZE]; /* Flawfinder: ignore */ @@ -3733,7 +4045,7 @@ BOOL LLVolumeParams::importFile(FILE *fp) return TRUE; } -BOOL LLVolumeParams::exportFile(FILE *fp) const +BOOL LLVolumeParams::exportFile(LLFILE *fp) const { fprintf(fp,"\tshape 0\n"); fprintf(fp,"\t{\n"); @@ -3746,6 +4058,8 @@ BOOL LLVolumeParams::exportFile(FILE *fp) const BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + //llinfos << "importing volume" << llendl; const S32 BUFSIZE = 16384; // *NOTE: changing the size or type of this buffer will require @@ -3785,6 +4099,8 @@ BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream) BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const { + LLMemType m1(LLMemType::MTYPE_VOLUME); + output_stream <<"\tshape 0\n"; output_stream <<"\t{\n"; mPathParams.exportLegacyStream(output_stream); @@ -3840,34 +4156,56 @@ 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(); + F32 hollow = mProfileParams.getHollow(); - // Do we need to take getTwistBegin into account? DK 08/12/04 - if ( mProfileParams.getHollow() != 0.0f - || mPathParams.getTwist() != mPathParams.getTwistBegin() ) + U8 path_type = mPathParams.getCurveType(); + if ( path_length > MIN_CONCAVE_PATH_WEDGE + && ( mPathParams.getTwist() != mPathParams.getTwistBegin() + || (hollow > 0.f + && LL_PCODE_PATH_LINE != path_type) ) ) { - // 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) + 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; } - U8 path_type = mPathParams.getCurveType(); if ( LL_PCODE_PATH_LINE == path_type ) { // straight paths with convex profile return TRUE; } - F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f); if (concave_path) { @@ -3875,22 +4213,48 @@ 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; - switch(mProfilep->mParams.getCurveType() & LL_PCODE_PROFILE_MASK) + switch(mParams.getProfileParams().getCurveType() & LL_PCODE_PROFILE_MASK) { case LL_PCODE_PROFILE_CIRCLE: case LL_PCODE_PROFILE_CIRCLE_HALF: @@ -3898,7 +4262,7 @@ LLFaceID LLVolume::generateFaceMask() break; case LL_PCODE_PROFILE_SQUARE: { - for(S32 side = (S32)(mProfilep->mParams.getBegin() * 4.f); side < llceil(mProfilep->mParams.getEnd() * 4.f); side++) + for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 4.f); side < llceil(mParams.getProfileParams().getEnd() * 4.f); side++) { new_mask |= LL_FACE_OUTER_SIDE_0 << side; } @@ -3908,19 +4272,19 @@ LLFaceID LLVolume::generateFaceMask() case LL_PCODE_PROFILE_EQUALTRI: case LL_PCODE_PROFILE_RIGHTTRI: { - for(S32 side = (S32)(mProfilep->mParams.getBegin() * 3.f); side < llceil(mProfilep->mParams.getEnd() * 3.f); side++) + for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 3.f); side < llceil(mParams.getProfileParams().getEnd() * 3.f); side++) { new_mask |= LL_FACE_OUTER_SIDE_0 << side; } } break; default: - llerrs << "Unknown profile!" << llendl + llerrs << "Unknown profile!" << llendl; break; } // handle hollow objects - if (mProfilep->isHollow()) + if (mParams.getProfileParams().getHollow() > 0) { new_mask |= LL_FACE_INNER_SIDE; } @@ -4022,7 +4386,7 @@ std::ostream& operator<<(std::ostream &s, const LLPath &path) std::ostream& operator<<(std::ostream &s, const LLVolume &volume) { - s << "{params = " << volume.mParams; + s << "{params = " << volume.getParams(); s << ", path = " << *volume.mPathp; s << ", profile = " << *volume.mProfilep; s << "}"; @@ -4032,7 +4396,7 @@ std::ostream& operator<<(std::ostream &s, const LLVolume &volume) std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) { - s << "{params = " << volumep->mParams; + s << "{params = " << volumep->getParams(); s << ", path = " << *(volumep->mPathp); s << ", profile = " << *(volumep->mProfilep); s << "}"; @@ -4040,27 +4404,15 @@ std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) } -LLVolumeFace::LLVolumeFace() -{ - mTypeMask = 0; - mID = 0; - mBeginS = 0; - mBeginT = 0; - mNumS = 0; - mNumT = 0; - mHasBinormals = FALSE; -} - - -BOOL LLVolumeFace::create(BOOL partial_build) +BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) { if (mTypeMask & CAP_MASK) { - return createCap(partial_build); + return createCap(volume, partial_build); } else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) { - return createSide(partial_build); + return createSide(volume, partial_build); } else { @@ -4082,12 +4434,14 @@ void LerpPlanarVertex(LLVolumeFace::VertexData& v0, vout.mBinormal = v0.mBinormal; } -BOOL LLVolumeFace::createUnCutCubeCap(BOOL partial_build) +BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) { - const std::vector<LLVolume::Point>& mesh = mVolumep->getMesh(); - const std::vector<LLVector3>& profile = mVolumep->getProfile().mProfile; - S32 max_s = mVolumep->getProfile().getTotal(); - S32 max_t = mVolumep->getPath().mPath.size(); + LLMemType m1(LLMemType::MTYPE_VOLUME); + + const std::vector<LLVolume::Point>& mesh = volume->getMesh(); + const std::vector<LLVector3>& profile = volume->getProfile().mProfile; + S32 max_s = volume->getProfile().getTotal(); + S32 max_t = volume->getPath().mPath.size(); // S32 i; S32 num_vertices = 0, num_indices = 0; @@ -4172,39 +4526,98 @@ BOOL LLVolumeFace::createUnCutCubeCap(BOOL partial_build) if (!partial_build) { - int idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; - for(int gx = 0;gx<grid_size;gx++){ - for(int gy = 0;gy<grid_size;gy++){ - if (mTypeMask & TOP_MASK){ - for(int i=5;i>=0;i--)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); - }else{ - for(int i=0;i<6;i++)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); +#if GEN_TRI_STRIP + mTriStrip.clear(); +#endif + S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; + for(S32 gx = 0;gx<grid_size;gx++) + { + + for(S32 gy = 0;gy<grid_size;gy++) + { + if (mTypeMask & TOP_MASK) + { + for(S32 i=5;i>=0;i--) + { + mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); + } + +#if GEN_TRI_STRIP + if (gy == 0) + { + mTriStrip.push_back((gx+1)*(grid_size+1)); + mTriStrip.push_back((gx+1)*(grid_size+1)); + mTriStrip.push_back(gx*(grid_size+1)); + } + + mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1)); + mTriStrip.push_back(gy+1+gx*(grid_size+1)); + + + if (gy == grid_size-1) + { + mTriStrip.push_back(gy+1+gx*(grid_size+1)); + } +#endif + } + else + { + for(S32 i=0;i<6;i++) + { + mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); + } + +#if GEN_TRI_STRIP + if (gy == 0) + { + mTriStrip.push_back(gx*(grid_size+1)); + mTriStrip.push_back(gx*(grid_size+1)); + mTriStrip.push_back((gx+1)*(grid_size+1)); + } + + mTriStrip.push_back(gy+1+gx*(grid_size+1)); + mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1)); + + if (gy == grid_size-1) + { + mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1)); + } +#endif } } + } + +#if GEN_TRI_STRIP + if (mTriStrip.size()%2 == 1) + { + mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + } +#endif } return TRUE; } -BOOL LLVolumeFace::createCap(BOOL partial_build) +BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK) && - ((this->mVolumep->getParams().getPathParams().getBegin()==0.0f)&& - (this->mVolumep->getParams().getPathParams().getEnd()==1.0f))&& - (mVolumep->getProfile().mParams.getCurveType()==LL_PCODE_PROFILE_SQUARE && - mVolumep->getPath().mParams.getCurveType()==LL_PCODE_PATH_LINE) + ((volume->getParams().getPathParams().getBegin()==0.0f)&& + (volume->getParams().getPathParams().getEnd()==1.0f))&& + (volume->getParams().getProfileParams().getCurveType()==LL_PCODE_PROFILE_SQUARE && + volume->getParams().getPathParams().getCurveType()==LL_PCODE_PATH_LINE) ){ - return createUnCutCubeCap(partial_build); + return createUnCutCubeCap(volume, partial_build); } - S32 i; S32 num_vertices = 0, num_indices = 0; - const std::vector<LLVolume::Point>& mesh = mVolumep->getMesh(); - const std::vector<LLVector3>& profile = mVolumep->getProfile().mProfile; + const std::vector<LLVolume::Point>& mesh = volume->getMesh(); + const std::vector<LLVector3>& profile = volume->getProfile().mProfile; // All types of caps have the same number of vertices and indices num_vertices = profile.size(); @@ -4217,8 +4630,8 @@ BOOL LLVolumeFace::createCap(BOOL partial_build) mIndices.resize(num_indices); } - S32 max_s = mVolumep->getProfile().getTotal(); - S32 max_t = mVolumep->getPath().mPath.size(); + S32 max_s = volume->getProfile().getTotal(); + S32 max_t = volume->getPath().mPath.size(); mCenter.clearVec(); @@ -4242,7 +4655,7 @@ BOOL LLVolumeFace::createCap(BOOL partial_build) LLVector3& max = mExtents[1]; // Copy the vertices into the array - for (i = 0; i < num_vertices; i++) + for (S32 i = 0; i < num_vertices; i++) { if (mTypeMask & TOP_MASK) { @@ -4306,7 +4719,7 @@ BOOL LLVolumeFace::createCap(BOOL partial_build) } - for (i = 0; i < num_vertices; i++) + for (S32 i = 0; i < num_vertices; i++) { mVertices[i].mBinormal = binormal; mVertices[i].mNormal = normal; @@ -4327,7 +4740,7 @@ BOOL LLVolumeFace::createCap(BOOL partial_build) // Does it matter if it's open or closed? - djs S32 pt1 = 0, pt2 = num_vertices - 1; - i = 0; + S32 i = 0; while (pt2 - pt1 > 1) { // Use the profile points instead of the mesh, since you want @@ -4421,6 +4834,8 @@ BOOL LLVolumeFace::createCap(BOOL partial_build) pt2--; } } + + makeTriStrip(); } else { @@ -4430,7 +4845,7 @@ BOOL LLVolumeFace::createCap(BOOL partial_build) llassert(mTypeMask & BOTTOM_MASK); S32 pt1 = 0, pt2 = num_vertices - 1; - i = 0; + S32 i = 0; while (pt2 - pt1 > 1) { // Use the profile points instead of the mesh, since you want @@ -4525,69 +4940,116 @@ BOOL LLVolumeFace::createCap(BOOL partial_build) pt2--; } } + + makeTriStrip(); } } else { // Not hollow, generate the triangle fan. + U16 v1 = 2; + U16 v2 = 1; + if (mTypeMask & TOP_MASK) { - if (mTypeMask & OPEN_MASK) - { - // SOLID OPEN TOP - // Generate indices - // This is a tri-fan, so we reuse the same first point for all triangles. - for (i = 0; i < (num_vertices - 2); i++) - { - mIndices[3*i] = num_vertices - 1; - mIndices[3*i+1] = i; - mIndices[3*i+2] = i + 1; - } - } - else - { - // SOLID CLOSED TOP - for (i = 0; i < (num_vertices - 2); i++) - { - //MSMSM fix these caps but only for the un-cut case - mIndices[3*i] = num_vertices - 1; - mIndices[3*i+1] = i; - mIndices[3*i+2] = i + 1; - } - } + v1 = 1; + v2 = 2; + } + + for (S32 i = 0; i < (num_vertices - 2); i++) + { + mIndices[3*i] = num_vertices - 1; + mIndices[3*i+v1] = i; + mIndices[3*i+v2] = i + 1; + } + +#if GEN_TRI_STRIP + //make tri strip + if (mTypeMask & OPEN_MASK) + { + makeTriStrip(); } else { - if (mTypeMask & OPEN_MASK) + S32 j = num_vertices-2; + if (mTypeMask & TOP_MASK) { - // SOLID OPEN BOTTOM - // Generate indices - // This is a tri-fan, so we reuse the same first point for all triangles. - for (i = 0; i < (num_vertices - 2); i++) + mTriStrip.push_back(0); + for (S32 i = 0; i <= j; ++i) { - mIndices[3*i] = num_vertices - 1; - mIndices[3*i+1] = i + 1; - mIndices[3*i+2] = i; + mTriStrip.push_back(i); + if (i != j) + { + mTriStrip.push_back(j); + } + --j; } } else { - // SOLID CLOSED BOTTOM - for (i = 0; i < (num_vertices - 2); i++) + mTriStrip.push_back(j); + for (S32 i = 0; i <= j; ++i) { - //MSMSM fix these caps but only for the un-cut case - mIndices[3*i] = num_vertices - 1; - mIndices[3*i+1] = i + 1; - mIndices[3*i+2] = i; + if (i != j) + { + mTriStrip.push_back(j); + } + mTriStrip.push_back(i); + --j; } } + + mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + + if (mTriStrip.size()%2 == 1) + { + mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + } } +#endif } + return TRUE; } +void LLVolumeFace::makeTriStrip() +{ +#if GEN_TRI_STRIP + for (U32 i = 0; i < mIndices.size(); i+=3) + { + U16 i0 = mIndices[i]; + U16 i1 = mIndices[i+1]; + U16 i2 = mIndices[i+2]; + + if ((i/3)%2 == 1) + { + mTriStrip.push_back(i0); + mTriStrip.push_back(i0); + mTriStrip.push_back(i1); + mTriStrip.push_back(i2); + mTriStrip.push_back(i2); + } + else + { + mTriStrip.push_back(i2); + mTriStrip.push_back(i2); + mTriStrip.push_back(i1); + mTriStrip.push_back(i0); + mTriStrip.push_back(i0); + } + } + + if (mTriStrip.size()%2 == 1) + { + mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + } +#endif +} + void LLVolumeFace::createBinormals() { + LLMemType m1(LLMemType::MTYPE_VOLUME); + if (!mHasBinormals) { //generate binormals @@ -4629,16 +5091,25 @@ void LLVolumeFace::createBinormals() } } -BOOL LLVolumeFace::createSide(BOOL partial_build) +BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { + LLMemType m1(LLMemType::MTYPE_VOLUME); + BOOL flat = mTypeMask & FLAT_MASK; + + U8 sculpt_type = volume->getParams().getSculptType(); + U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; + BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; + BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; + BOOL sculpt_reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR + S32 num_vertices, num_indices; - const std::vector<LLVolume::Point>& mesh = mVolumep->getMesh(); - const std::vector<LLVector3>& profile = mVolumep->getProfile().mProfile; - const std::vector<LLPath::PathPt>& path_data = mVolumep->getPath().mPath; + const std::vector<LLVolume::Point>& mesh = volume->getMesh(); + const std::vector<LLVector3>& profile = volume->getProfile().mProfile; + const std::vector<LLPath::PathPt>& path_data = volume->getPath().mPath; - S32 max_s = mVolumep->getProfile().getTotal(); + S32 max_s = volume->getProfile().getTotal(); S32 s, t, i; F32 ss, tt; @@ -4653,11 +5124,10 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) mIndices.resize(num_indices); mEdge.resize(num_indices); } - - LLVector3& face_min = mExtents[0]; - LLVector3& face_max = mExtents[1]; - - mCenter.clearVec(); + else + { + mHasBinormals = FALSE; + } S32 begin_stex = llfloor( profile[mBeginS].mV[2] ); S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS; @@ -4693,6 +5163,11 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) } } + if (sculpt_reverse_horizontal) + { + ss = 1.f - ss; + } + // Check to see if this triangle wraps around the array. if (mBeginS + s >= max_s) { @@ -4709,15 +5184,6 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) mVertices[cur_vertex].mNormal = LLVector3(0,0,0); mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); - - if (cur_vertex == 0) - { - face_min = face_max = mesh[i].mPos; - } - else - { - update_min_max(face_min, face_max, mesh[i].mPos); - } cur_vertex++; @@ -4751,12 +5217,22 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) mVertices[cur_vertex].mNormal = LLVector3(0,0,0); mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); - update_min_max(face_min,face_max,mesh[i].mPos); - cur_vertex++; } } + + //get bounding box for this side + LLVector3& face_min = mExtents[0]; + LLVector3& face_max = mExtents[1]; + mCenter.clearVec(); + + face_min = face_max = mVertices[0].mPosition; + for (U32 i = 1; i < mVertices.size(); ++i) + { + update_min_max(face_min, face_max, mVertices[i].mPosition); + } + mCenter = (face_min + face_max) * 0.5f; S32 cur_index = 0; @@ -4765,9 +5241,18 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) if (!partial_build) { +#if GEN_TRI_STRIP + mTriStrip.clear(); +#endif + // Now we generate the indices. for (t = 0; t < (mNumT-1); t++) { +#if GEN_TRI_STRIP + //prepend terminating index to strip + mTriStrip.push_back(mNumS*t); +#endif + for (s = 0; s < (mNumS-1); s++) { mIndices[cur_index++] = s + mNumS*t; //bottom left @@ -4777,11 +5262,21 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) mIndices[cur_index++] = s+1 + mNumS*t; //bottom right mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right +#if GEN_TRI_STRIP + if (s == 0) + { + mTriStrip.push_back(s+mNumS*t); + mTriStrip.push_back(s+mNumS*(t+1)); + } + mTriStrip.push_back(s+1+mNumS*t); + mTriStrip.push_back(s+1+mNumS*(t+1)); +#endif + mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; //bottom left/top right neighbor face if (t < mNumT-2) { //top right/top left neighbor face mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1; } - else if (mNumT <= 3 || mVolumep->getPath().isOpen() == TRUE) { //no neighbor + else if (mNumT <= 3 || volume->getPath().isOpen() == TRUE) { //no neighbor mEdge[cur_edge++] = -1; } else { //wrap on T @@ -4790,7 +5285,7 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) if (s > 0) { //top left/bottom left neighbor face mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1; } - else if (flat_face || mVolumep->getProfile().isOpen() == TRUE) { //no neighbor + else if (flat_face || volume->getProfile().isOpen() == TRUE) { //no neighbor mEdge[cur_edge++] = -1; } else { //wrap on S @@ -4800,7 +5295,7 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) if (t > 0) { //bottom left/bottom right neighbor face mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2; } - else if (mNumT <= 3 || mVolumep->getPath().isOpen() == TRUE) { //no neighbor + else if (mNumT <= 3 || volume->getPath().isOpen() == TRUE) { //no neighbor mEdge[cur_edge++] = -1; } else { //wrap on T @@ -4809,7 +5304,7 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) if (s < mNumS-2) { //bottom right/top right neighbor face mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2; } - else if (flat_face || mVolumep->getProfile().isOpen() == TRUE) { //no neighbor + else if (flat_face || volume->getProfile().isOpen() == TRUE) { //no neighbor mEdge[cur_edge++] = -1; } else { //wrap on S @@ -4817,44 +5312,46 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) } mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; //top right/bottom left neighbor face } +#if GEN_TRI_STRIP + //append terminating vertex to strip + mTriStrip.push_back(mNumS-1+mNumS*(t+1)); +#endif } + +#if GEN_TRI_STRIP + if (mTriStrip.size()%2 == 1) + { + mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + } +#endif } - //generate normals - for (U32 i = 0; i < mIndices.size()/3; i++) { //for each triangle - const VertexData& v0 = mVertices[mIndices[i*3+0]]; - const VertexData& v1 = mVertices[mIndices[i*3+1]]; - const VertexData& v2 = mVertices[mIndices[i*3+2]]; + //generate normals + for (U32 i = 0; i < mIndices.size()/3; i++) //for each triangle + { + const U16* idx = &(mIndices[i*3]); + + VertexData* v[] = + { &mVertices[idx[0]], &mVertices[idx[1]], &mVertices[idx[2]] }; //calculate triangle normal - LLVector3 norm = (v0.mPosition-v1.mPosition)% - (v0.mPosition-v2.mPosition); + LLVector3 norm = (v[0]->mPosition-v[1]->mPosition) % (v[0]->mPosition-v[2]->mPosition); - for (U32 j = 0; j < 3; j++) - { //add triangle normal to vertices - mVertices[mIndices[i*3+j]].mNormal += norm; // * (weight_sum - d[j])/weight_sum; - } + v[0]->mNormal += norm; + v[1]->mNormal += norm; + v[2]->mNormal += norm; //even out quad contributions - if (i % 2 == 0) - { - mVertices[mIndices[i*3+2]].mNormal += norm; - } - else - { - mVertices[mIndices[i*3+1]].mNormal += norm; - } + v[i%2+1]->mNormal += norm; } // adjust normals based on wrapping and stitching BOOL s_bottom_converges = ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f); BOOL s_top_converges = ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 0.000001f); - U8 sculpt_type = mVolumep->getParams().getSculptType(); - - if (sculpt_type == LL_SCULPT_TYPE_NONE) // logic for non-sculpt volumes + if (sculpt_stitching == LL_SCULPT_TYPE_NONE) // logic for non-sculpt volumes { - if (mVolumep->getPath().isOpen() == FALSE) + if (volume->getPath().isOpen() == FALSE) { //wrap normals on T for (S32 i = 0; i < mNumS; i++) { @@ -4864,7 +5361,7 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) } } - if ((mVolumep->getProfile().isOpen() == FALSE) && !(s_bottom_converges)) + if ((volume->getProfile().isOpen() == FALSE) && !(s_bottom_converges)) { //wrap normals on S for (S32 i = 0; i < mNumT; i++) { @@ -4874,8 +5371,8 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) } } - if (mVolumep->getPathType() == LL_PCODE_PATH_CIRCLE && - ((mVolumep->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF)) + if (volume->getPathType() == LL_PCODE_PATH_CIRCLE && + ((volume->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF)) { if (s_bottom_converges) { //all lower S have same normal @@ -4901,15 +5398,15 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) BOOL wrap_s = FALSE; BOOL wrap_t = FALSE; - if (sculpt_type == LL_SCULPT_TYPE_SPHERE) + if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) average_poles = TRUE; - if ((sculpt_type == LL_SCULPT_TYPE_SPHERE) || - (sculpt_type == LL_SCULPT_TYPE_TORUS) || - (sculpt_type == LL_SCULPT_TYPE_CYLINDER)) + if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || + (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || + (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) wrap_s = TRUE; - if (sculpt_type == LL_SCULPT_TYPE_TORUS) + if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) wrap_t = TRUE; @@ -4974,69 +5471,6 @@ BOOL LLVolumeFace::createSide(BOOL partial_build) return TRUE; } -// Static -BOOL LLVolumeFace::updateColors(LLColor4U *old_colors, const S32 num_old, const LLVolumeFace &old_vf, - LLStrider<LLColor4U> &new_colors, const S32 num_new, const LLVolumeFace &new_vf) -{ - if (new_vf.mTypeMask & CAP_MASK) - { - // These aren't interpolated correctly. Need to fix when shadows go in... - F32 ratio = (F32)num_old / (F32)num_new; - S32 v = 0; - for (v = 0; v < num_new; v++) - { - new_colors[v] = old_colors[(S32)(v*ratio)]; - } - return FALSE; - } - else if (new_vf.mTypeMask & END_MASK) - { - // These aren't interpolated correctly. Need to fix when shadows go in... - F32 ratio = (F32)num_old / (F32)num_new; - S32 v = 0; - for (v = 0; v < num_new; v++) - { - new_colors[v] = old_colors[(S32)(v*ratio)]; - } - return FALSE; - } - else if (new_vf.mTypeMask & SIDE_MASK) - { - S32 s, t; - F32 s_ratio = (F32)old_vf.mNumS / (F32)new_vf.mNumS; - F32 t_ratio = (F32)old_vf.mNumT / (F32)new_vf.mNumT; - - S32 v = 0; - for (t = 0; t < new_vf.mNumT; t++) - { - F32 t_frac = t * t_ratio; - S32 old_t = (S32)t_frac; - S32 t_target = llmin(old_t + 1, (old_vf.mNumT - 1)); - t_frac -= old_t; - for (s = 0; s < new_vf.mNumS; s++) - { - F32 s_frac = s * s_ratio; - S32 old_s = (S32)s_frac; - S32 s_target = llmin(old_s + 1, (old_vf.mNumS - 1)); - s_frac -= old_s; - - // Interpolate along s, then along t. - LLColor4U s_interp0 = old_colors[old_t * old_vf.mNumS + old_s].multAll(1.f - s_frac).addClampMax(old_colors[old_t * old_vf.mNumS + s_target].multAll(s_frac)); - LLColor4U s_interp1 = old_colors[t_target * old_vf.mNumS + old_s].multAll(1.f - s_frac).addClampMax(old_colors[t_target * old_vf.mNumS + s_target].multAll(s_frac)); - new_colors[v] = s_interp0.multAll(1.f - t_frac).addClampMax(s_interp1.multAll(t_frac)); - v++; - } - } - } - else - { - llerrs << "Unknown/uninitialized face type!" << llendl; - return FALSE; - } - return TRUE; -} - - // Finds binormal based on three vertices with texture coordinates. // Fills in dummy values if the triangle has degenerate texture coordinates. LLVector3 calc_binormal_from_triangle( |