summaryrefslogtreecommitdiff
path: root/indra/llmath/llvolume.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmath/llvolume.cpp')
-rw-r--r--indra/llmath/llvolume.cpp1626
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 &params)
{
+ 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 &params)
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 &params, const F32 detail, const BOOL generate_single_face, const BOOL is_unique) : mParams(params)
+LLVolume::LLVolume(const LLVolumeParams &params, 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 &params, 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 &params, 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 &params) const
void LLVolumeParams::copyParams(const LLVolumeParams &params)
{
+ 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(