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.cpp887
1 files changed, 622 insertions, 265 deletions
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index ecc4b09d10..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.
+ *
+ * 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.
*
- * 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 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.
*
- * 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.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -82,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)
{
@@ -104,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;
+
+ LLVector3 edge2 = vert2 - vert0;;
+
+ /* begin calculating determinant - also used to calculate U parameter */
+ LLVector3 pvec = dir % edge2;
- F32 dotprod = norm * vect;
+ /* if determinant is near zero, ray lies in plane of triangle */
+ F32 det = edge1 * pvec;
- if(dotprod < 0)
+ 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;
+ }
- // if ds is neg line started past triangle so can't hit triangle.
- if (t > 0)
+ /* calculate distance from vert0 to ray origin */
+ LLVector3 tvec = orig - vert0;
+
+ /* 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;
}
@@ -198,9 +273,6 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3
F32 t, t_step, t_first, t_fraction, ang, ang_step;
LLVector3 pt1,pt2;
- mMaxX = 0.f;
- mMinX = 0.f;
-
F32 begin = params.getBegin();
F32 end = params.getEnd();
@@ -236,15 +308,6 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3
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);
}
@@ -254,16 +317,6 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3
// 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++) {
@@ -287,15 +340,6 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3
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];
@@ -472,31 +516,9 @@ LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F3
}
-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(const LLProfileParams& params, 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);
@@ -640,7 +662,7 @@ BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detai
S32 sides = (S32)circle_detail;
if (is_sculpted)
- sides = sculpt_sides(detail);
+ sides = sculpt_size;
genNGon(params, sides);
@@ -1131,7 +1153,8 @@ const LLVector2 LLPathParams::getEndScale() const
return end_scale;
}
-BOOL LLPath::generate(const LLPathParams& params, 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);
@@ -1194,7 +1217,7 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, BOOL is
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(params, sides);
}
@@ -1259,7 +1282,8 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, BOOL is
return TRUE;
}
-BOOL LLDynamicPath::generate(const LLPathParams& params, 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);
@@ -1624,9 +1648,13 @@ 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 ;
+ }
}
@@ -1656,7 +1684,7 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
mGenerateSingleFace = generate_single_face;
generate();
- if (mParams.getSculptID().isNull())
+ if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE)
{
createVolumeFaces();
}
@@ -1683,7 +1711,11 @@ LLVolume::~LLVolume()
{
sNumMeshPoints -= mMesh.size();
delete mPathp;
+
+ profile_delete_lock = 0 ;
delete mProfilep;
+ profile_delete_lock = 1 ;
+
mPathp = NULL;
mProfilep = NULL;
mVolumeFaces.clear();
@@ -1728,18 +1760,47 @@ BOOL LLVolume::generate()
mLODScaleBias.setVec(0.6f, 0.6f, 0.6f);
}
+ //********************************************************************
+ //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.
@@ -1799,6 +1860,11 @@ void LLVolume::createVolumeFaces()
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;
@@ -1842,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
@@ -1909,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;
}
}
@@ -1979,6 +2044,12 @@ 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();
@@ -1993,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;
}
@@ -2008,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;
}
@@ -2018,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;
}
@@ -2027,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;
}
@@ -2041,12 +2120,83 @@ 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)
{
@@ -2061,11 +2211,16 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components,
data_is_empty = TRUE;
}
- mPathp->generate(mParams.getPathParams(), mDetail, 0, TRUE);
- mProfilep->generate(mParams.getProfileParams(), 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))
@@ -2076,20 +2231,29 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components,
sNumMeshPoints -= mMesh.size();
mMesh.resize(sizeS * sizeT);
sNumMeshPoints += mMesh.size();
-
- if (!data_is_empty && 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;
@@ -3216,7 +3380,8 @@ 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);
@@ -3224,12 +3389,17 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
normals.clear();
segments.clear();
+ S32 cur_index = 0;
//for each face
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)) {
}
@@ -3405,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;
+
+ S32 start_face;
+ S32 end_face;
- LLVector3 vec = end - start;
+ 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 (S32 i = 0; i < getNumFaces(); i++)
+ for (S32 i = start_face; i <= end_face; i++)
{
- const LLVolumeFace& face = getVolumeFace(i);
+ const LLVolumeFace &face = getVolumeFace((U32)i);
+
+ 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];
- for (U32 j = 0; j < face.mIndices.size()/3; j++)
+ 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
@@ -3605,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;
@@ -4056,7 +4279,7 @@ LLFaceID LLVolume::generateFaceMask()
}
break;
default:
- llerrs << "Unknown profile!" << llendl
+ llerrs << "Unknown profile!" << llendl;
break;
}
@@ -4303,16 +4526,74 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, 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;
@@ -4553,6 +4834,8 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
pt2--;
}
}
+
+ makeTriStrip();
}
else
{
@@ -4657,67 +4940,112 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, 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 (S32 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 (S32 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 (S32 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 (S32 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);
@@ -4768,6 +5096,13 @@ 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 = volume->getMesh();
@@ -4789,11 +5124,10 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, 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;
@@ -4829,6 +5163,11 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, 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)
{
@@ -4845,15 +5184,6 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, 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++;
@@ -4887,12 +5217,22 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, 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;
@@ -4901,9 +5241,18 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, 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
@@ -4913,6 +5262,16 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, 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;
@@ -4953,46 +5312,44 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, 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 S32 i0 = mIndices[i*3+0];
- const S32 i1 = mIndices[i*3+1];
- const S32 i2 = mIndices[i*3+2];
- const VertexData& v0 = mVertices[i0];
- const VertexData& v1 = mVertices[i1];
- const VertexData& v2 = mVertices[i2];
+ 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
- const S32 idx = mIndices[i*3+j];
- mVertices[idx].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 & 1) == 0)
- {
- mVertices[i2].mNormal += norm;
- }
- else
- {
- mVertices[i1].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 = volume->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 (volume->getPath().isOpen() == FALSE)
{ //wrap normals on T
@@ -5041,15 +5398,15 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, 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;