llvolume.cpp

Go to the documentation of this file.
00001 
00031 #include "linden_common.h"
00032 #include "llmath.h"
00033 
00034 #include <set>
00035 
00036 #include "llerror.h"
00037 #include "llmemtype.h"
00038 
00039 #include "llvolumemgr.h"
00040 #include "v2math.h"
00041 #include "v3math.h"
00042 #include "v4math.h"
00043 #include "m4math.h"
00044 #include "m3math.h"
00045 #include "lldarray.h"
00046 #include "llvolume.h"
00047 #include "llstl.h"
00048 
00049 #define DEBUG_SILHOUETTE_BINORMALS 0
00050 #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
00051 #define DEBUG_SILHOUETTE_EDGE_MAP 0 // DaveP: Use this to display edge map using the silhouette
00052 
00053 const F32 CUT_MIN = 0.f;
00054 const F32 CUT_MAX = 1.f;
00055 const F32 MIN_CUT_DELTA = 0.02f;
00056 
00057 const F32 HOLLOW_MIN = 0.f;
00058 const F32 HOLLOW_MAX = 0.95f;
00059 const F32 HOLLOW_MAX_SQUARE     = 0.7f;
00060 
00061 const F32 TWIST_MIN = -1.f;
00062 const F32 TWIST_MAX =  1.f;
00063 
00064 const F32 RATIO_MIN = 0.f;
00065 const F32 RATIO_MAX = 2.f; // Tom Y: Inverted sense here: 0 = top taper, 2 = bottom taper
00066 
00067 const F32 HOLE_X_MIN= 0.05f;
00068 const F32 HOLE_X_MAX= 1.0f;
00069 
00070 const F32 HOLE_Y_MIN= 0.05f;
00071 const F32 HOLE_Y_MAX= 0.5f;
00072 
00073 const F32 SHEAR_MIN = -0.5f;
00074 const F32 SHEAR_MAX =  0.5f;
00075 
00076 const F32 REV_MIN = 1.f;
00077 const F32 REV_MAX = 4.f;
00078 
00079 const F32 TAPER_MIN = -1.f;
00080 const F32 TAPER_MAX =  1.f;
00081 
00082 const F32 SKEW_MIN      = -0.95f;
00083 const F32 SKEW_MAX      =  0.95f;
00084 
00085 const S32 SCULPT_REZ_1 = 6;  // changed from 4 to 6 - 6 looks round whereas 4 looks square
00086 const S32 SCULPT_REZ_2 = 8;
00087 const S32 SCULPT_REZ_3 = 16;
00088 const S32 SCULPT_REZ_4 = 32;
00089 
00090 const F32 SCULPT_MIN_AREA = 0.002f;
00091 
00092 BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
00093 {    
00094         LLVector3 test = (pt2-pt1)%(pt3-pt2);
00095 
00096         //answer
00097         if(test * norm < 0) 
00098         {
00099                 return FALSE;
00100         }
00101         else 
00102         {
00103                 return TRUE;
00104         }
00105 } 
00106 
00107 // intersect test between triangle pt1,pt2,pt3 and line from linept to linept+vect
00108 //returns TRUE if intersecting and moves linept to the point of intersection
00109 BOOL LLTriangleLineSegmentIntersect( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, LLVector3& linept, const LLVector3& vect)
00110 {
00111         LLVector3 V1 = pt2-pt1;
00112         LLVector3 V2 = pt3-pt2;
00113         
00114         LLVector3 norm = V1 % V2;
00115         
00116         F32 dotprod = norm * vect;
00117 
00118         if(dotprod < 0)
00119         {
00120                 //Find point of intersect to triangle plane.
00121                 //find t to intersect point
00122                 F32 t = -(norm * (linept-pt1))/dotprod;
00123 
00124                 // if ds is neg line started past triangle so can't hit triangle.
00125                 if (t > 0) 
00126                 {
00127                         return FALSE;
00128                 }
00129         
00130                 LLVector3 pt_int = linept + (vect*t);
00131                 
00132                 if(check_same_clock_dir(pt1, pt2, pt_int, norm))
00133                 {
00134                         if(check_same_clock_dir(pt2, pt3, pt_int, norm))
00135                         {
00136                                 if(check_same_clock_dir(pt3, pt1, pt_int, norm))
00137                                 {
00138                                         // answer in pt_int is insde triangle
00139                                         linept.setVec(pt_int);
00140                                         return TRUE;
00141                                 }
00142                         }
00143                 }
00144         }
00145         
00146         return FALSE;
00147 } 
00148 
00149 
00150 //-------------------------------------------------------------------
00151 // statics
00152 //-------------------------------------------------------------------
00153 
00154 
00155 //----------------------------------------------------
00156 
00157 LLProfile::Face* LLProfile::addCap(S16 faceID)
00158 {
00159         LLMemType m1(LLMemType::MTYPE_VOLUME);
00160         
00161         Face *face   = vector_append(mFaces, 1);
00162         
00163         face->mIndex = 0;
00164         face->mCount = mTotal;
00165         face->mScaleU= 1.0f;
00166         face->mCap   = TRUE;
00167         face->mFaceID = faceID;
00168         return face;
00169 }
00170 
00171 LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BOOL flat)
00172 {
00173         LLMemType m1(LLMemType::MTYPE_VOLUME);
00174         
00175         Face *face   = vector_append(mFaces, 1);
00176         
00177         face->mIndex = i;
00178         face->mCount = count;
00179         face->mScaleU= scaleU;
00180 
00181         face->mFlat = flat;
00182         face->mCap   = FALSE;
00183         face->mFaceID = faceID;
00184         return face;
00185 }
00186 
00187 // What is the bevel parameter used for? - DJS 04/05/02
00188 // Bevel parameter is currently unused but presumedly would support
00189 // filleted and chamfered corners
00190 void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split)
00191 {
00192         LLMemType m1(LLMemType::MTYPE_VOLUME);
00193         
00194         // Generate an n-sided "circular" path.
00195         // 0 is (1,0), and we go counter-clockwise along a circular path from there.
00196         const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f };
00197         F32 scale = 0.5f;
00198         F32 t, t_step, t_first, t_fraction, ang, ang_step;
00199         LLVector3 pt1,pt2;
00200 
00201         mMaxX = 0.f;
00202         mMinX = 0.f;
00203 
00204         F32 begin  = params.getBegin();
00205         F32 end    = params.getEnd();
00206 
00207         t_step = 1.0f / sides;
00208         ang_step = 2.0f*F_PI*t_step*ang_scale;
00209 
00210         // Scale to have size "match" scale.  Compensates to get object to generally fill bounding box.
00211 
00212         S32 total_sides = llround(sides / ang_scale);   // Total number of sides all around
00213 
00214         if (total_sides < 8)
00215         {
00216                 scale = tableScale[total_sides];
00217         }
00218 
00219         t_first = floor(begin * sides) / (F32)sides;
00220 
00221         // pt1 is the first point on the fractional face.
00222         // Starting t and ang values for the first face
00223         t = t_first;
00224         ang = 2.0f*F_PI*(t*ang_scale + offset);
00225         pt1.setVec(cos(ang)*scale,sin(ang)*scale, t);
00226 
00227         // Increment to the next point.
00228         // pt2 is the end point on the fractional face
00229         t += t_step;
00230         ang += ang_step;
00231         pt2.setVec(cos(ang)*scale,sin(ang)*scale,t);
00232 
00233         t_fraction = (begin - t_first)*sides;
00234 
00235         // Only use if it's not almost exactly on an edge.
00236         if (t_fraction < 0.9999f)
00237         {
00238                 LLVector3 new_pt = lerp(pt1, pt2, t_fraction);
00239                 F32 pt_x = new_pt.mV[VX];
00240                 if (pt_x < mMinX)
00241                 {
00242                         mMinX = pt_x;
00243                 }
00244                 else if (pt_x > mMaxX)
00245                 {
00246                         mMaxX = pt_x;
00247                 }
00248                 mProfile.push_back(new_pt);
00249         }
00250 
00251         // There's lots of potential here for floating point error to generate unneeded extra points - DJS 04/05/02
00252         while (t < end)
00253         {
00254                 // Iterate through all the integer steps of t.
00255                 pt1.setVec(cos(ang)*scale,sin(ang)*scale,t);
00256 
00257                 F32 pt_x = pt1.mV[VX];
00258                 if (pt_x < mMinX)
00259                 {
00260                         mMinX = pt_x;
00261                 }
00262                 else if (pt_x > mMaxX)
00263                 {
00264                         mMaxX = pt_x;
00265                 }
00266 
00267                 if (mProfile.size() > 0) {
00268                         LLVector3 p = mProfile[mProfile.size()-1];
00269                         for (S32 i = 0; i < split && mProfile.size() > 0; i++) {
00270                                 mProfile.push_back(p+(pt1-p) * 1.0f/(float)(split+1) * (float)(i+1));
00271                         }
00272                 }
00273                 mProfile.push_back(pt1);
00274 
00275                 t += t_step;
00276                 ang += ang_step;
00277         }
00278 
00279         t_fraction = (end - (t - t_step))*sides;
00280 
00281         // pt1 is the first point on the fractional face
00282         // pt2 is the end point on the fractional face
00283         pt2.setVec(cos(ang)*scale,sin(ang)*scale,t);
00284 
00285         // Find the fraction that we need to add to the end point.
00286         t_fraction = (end - (t - t_step))*sides;
00287         if (t_fraction > 0.0001f)
00288         {
00289                 LLVector3 new_pt = lerp(pt1, pt2, t_fraction);
00290                 F32 pt_x = new_pt.mV[VX];
00291                 if (pt_x < mMinX)
00292                 {
00293                         mMinX = pt_x;
00294                 }
00295                 else if (pt_x > mMaxX)
00296                 {
00297                         mMaxX = pt_x;
00298                 }
00299                 
00300                 if (mProfile.size() > 0) {
00301                         LLVector3 p = mProfile[mProfile.size()-1];
00302                         for (S32 i = 0; i < split && mProfile.size() > 0; i++) {
00303                                 mProfile.push_back(p+(new_pt-p) * 1.0f/(float)(split+1) * (float)(i+1));
00304                         }
00305                 }
00306                 mProfile.push_back(new_pt);
00307         }
00308 
00309         // If we're sliced, the profile is open.
00310         if ((end - begin)*ang_scale < 0.99f)
00311         {
00312                 if ((end - begin)*ang_scale > 0.5f)
00313                 {
00314                         mConcave = TRUE;
00315                 }
00316                 else
00317                 {
00318                         mConcave = FALSE;
00319                 }
00320                 mOpen = TRUE;
00321                 if (params.getHollow() <= 0)
00322                 {
00323                         // put center point if not hollow.
00324                         mProfile.push_back(LLVector3(0,0,0));
00325                 }
00326         }
00327         else
00328         {
00329                 // The profile isn't open.
00330                 mOpen = FALSE;
00331                 mConcave = FALSE;
00332         }
00333 
00334         mTotal = mProfile.size();
00335 }
00336 
00337 void LLProfile::genNormals(const LLProfileParams& params)
00338 {
00339         S32 count = mProfile.size();
00340 
00341         S32 outer_count;
00342         if (mTotalOut)
00343         {
00344                 outer_count = mTotalOut;
00345         }
00346         else
00347         {
00348                 outer_count = mTotal / 2;
00349         }
00350 
00351         mEdgeNormals.resize(count * 2);
00352         mEdgeCenters.resize(count * 2);
00353         mNormals.resize(count);
00354 
00355         LLVector2 pt0,pt1;
00356 
00357         BOOL hollow = (params.getHollow() > 0);
00358 
00359         S32 i0, i1, i2, i3, i4;
00360 
00361         // Parametrically generate normal
00362         for (i2 = 0; i2 < count; i2++)
00363         {
00364                 mNormals[i2].mV[0] = mProfile[i2].mV[0];
00365                 mNormals[i2].mV[1] = mProfile[i2].mV[1];
00366                 if (hollow && (i2 >= outer_count))
00367                 {
00368                         mNormals[i2] *= -1.f;
00369                 }
00370                 if (mNormals[i2].magVec() < 0.001)
00371                 {
00372                         // Special case for point at center, get adjacent points.
00373                         i1 = (i2 - 1) >= 0 ? i2 - 1 : count - 1;
00374                         i0 = (i1 - 1) >= 0 ? i1 - 1 : count - 1;
00375                         i3 = (i2 + 1) < count ? i2 + 1 : 0;
00376                         i4 = (i3 + 1) < count ? i3 + 1 : 0;
00377 
00378                         pt0.setVec(mProfile[i1].mV[VX] + mProfile[i1].mV[VX] - mProfile[i0].mV[VX], 
00379                                 mProfile[i1].mV[VY] + mProfile[i1].mV[VY] - mProfile[i0].mV[VY]);
00380                         pt1.setVec(mProfile[i3].mV[VX] + mProfile[i3].mV[VX] - mProfile[i4].mV[VX], 
00381                                 mProfile[i3].mV[VY] + mProfile[i3].mV[VY] - mProfile[i4].mV[VY]);
00382 
00383                         mNormals[i2] = pt0 + pt1;
00384                         mNormals[i2] *= 0.5f;
00385                 }
00386                 mNormals[i2].normVec();
00387         }
00388 
00389         S32 num_normal_sets = isConcave() ? 2 : 1;
00390         for (S32 normal_set = 0; normal_set < num_normal_sets; normal_set++)
00391         {
00392                 S32 point_num;
00393                 for (point_num = 0; point_num < mTotal; point_num++)
00394                 {
00395                         LLVector3 point_1 = mProfile[point_num];
00396                         point_1.mV[VZ] = 0.f;
00397 
00398                         LLVector3 point_2;
00399                         
00400                         if (isConcave() && normal_set == 0 && point_num == (mTotal - 1) / 2)
00401                         {
00402                                 point_2 = mProfile[mTotal - 1];
00403                         }
00404                         else if (isConcave() && normal_set == 1 && point_num == mTotal - 1)
00405                         {
00406                                 point_2 = mProfile[(mTotal - 1) / 2];
00407                         }
00408                         else
00409                         {
00410                                 LLVector3 delta_pos;
00411                                 S32 neighbor_point = (point_num + 1) % mTotal;
00412                                 while(delta_pos.magVecSquared() < 0.01f * 0.01f)
00413                                 {
00414                                         point_2 = mProfile[neighbor_point];
00415                                         delta_pos = point_2 - point_1;
00416                                         neighbor_point = (neighbor_point + 1) % mTotal;
00417                                         if (neighbor_point == point_num)
00418                                         {
00419                                                 break;
00420                                         }
00421                                 }
00422                         }
00423 
00424                         point_2.mV[VZ] = 0.f;
00425                         LLVector3 face_normal = (point_2 - point_1) % LLVector3::z_axis;
00426                         face_normal.normVec();
00427                         mEdgeNormals[normal_set * count + point_num] = face_normal;
00428                         mEdgeCenters[normal_set * count + point_num] = lerp(point_1, point_2, 0.5f);
00429                 }
00430         }
00431 }
00432 
00433 
00434 // Hollow is percent of the original bounding box, not of this particular
00435 // profile's geometry.  Thus, a swept triangle needs lower hollow values than
00436 // a swept square.
00437 LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split)
00438 {
00439         // Note that addHole will NOT work for non-"circular" profiles, if we ever decide to use them.
00440 
00441         // Total add has number of vertices on outside.
00442         mTotalOut = mTotal;
00443 
00444         // Why is the "bevel" parameter -1? DJS 04/05/02
00445         genNGon(params, llfloor(sides),offset,-1, ang_scale, split);
00446 
00447         Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat);
00448 
00449         std::vector<LLVector3> pt;
00450         pt.resize(mTotal) ;
00451 
00452         for (S32 i=mTotalOut;i<mTotal;i++)
00453         {
00454                 pt[i] = mProfile[i] * box_hollow;
00455         }
00456 
00457         S32 j=mTotal-1;
00458         for (S32 i=mTotalOut;i<mTotal;i++)
00459         {
00460                 mProfile[i] = pt[j--];
00461         }
00462 
00463         for (S32 i=0;i<(S32)mFaces.size();i++) 
00464         {
00465                 if (mFaces[i].mCap)
00466                 {
00467                         mFaces[i].mCount *= 2;
00468                 }
00469         }
00470 
00471         return face;
00472 }
00473 
00474 
00475 S32 sculpt_sides(F32 detail)
00476 {
00477 
00478         // detail is usually one of: 1, 1.5, 2.5, 4.0.
00479         
00480         if (detail <= 1.0)
00481         {
00482                 return SCULPT_REZ_1;
00483         }
00484         if (detail <= 2.0)
00485         {
00486                 return SCULPT_REZ_2;
00487         }
00488         if (detail <= 3.0)
00489         {
00490                 return SCULPT_REZ_3;
00491         }
00492         else
00493         {
00494                 return SCULPT_REZ_4;
00495         }
00496 }
00497 
00498 
00499 BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split, BOOL is_sculpted)
00500 {
00501         LLMemType m1(LLMemType::MTYPE_VOLUME);
00502         
00503         if ((!mDirty) && (!is_sculpted))
00504         {
00505                 return FALSE;
00506         }
00507         mDirty = FALSE;
00508 
00509         if (detail < MIN_LOD)
00510         {
00511                 llinfos << "Generating profile with LOD < MIN_LOD.  CLAMPING" << llendl;
00512                 detail = MIN_LOD;
00513         }
00514 
00515         mProfile.clear();
00516         mFaces.clear();
00517 
00518         // Generate the face data
00519         S32 i;
00520         F32 begin = params.getBegin();
00521         F32 end = params.getEnd();
00522         F32 hollow = params.getHollow();
00523 
00524         // Quick validation to eliminate some server crashes.
00525         if (begin > end - 0.01f)
00526         {
00527                 llwarns << "LLProfile::generate() assertion failed (begin >= end)" << llendl;
00528                 return FALSE;
00529         }
00530 
00531         S32 face_num = 0;
00532 
00533         switch (params.getCurveType() & LL_PCODE_PROFILE_MASK)
00534         {
00535         case LL_PCODE_PROFILE_SQUARE:
00536                 {
00537                         genNGon(params, 4,-0.375, 0, 1, split);
00538                         if (path_open)
00539                         {
00540                                 addCap (LL_FACE_PATH_BEGIN);
00541                         }
00542 
00543                         for (i = llfloor(begin * 4.f); i < llfloor(end * 4.f + .999f); i++)
00544                         {
00545                                 addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE);
00546                         }
00547 
00548                         for (i = 0; i <(S32) mProfile.size(); i++)
00549                         {
00550                                 // Scale by 4 to generate proper tex coords.
00551                                 mProfile[i].mV[2] *= 4.f;
00552                         }
00553 
00554                         if (hollow)
00555                         {
00556                                 switch (params.getCurveType() & LL_PCODE_HOLE_MASK)
00557                                 {
00558                                 case LL_PCODE_HOLE_TRIANGLE:
00559                                         // This offset is not correct, but we can't change it now... DK 11/17/04
00560                                         addHole(params, TRUE, 3, -0.375f, hollow, 1.f, split);
00561                                         break;
00562                                 case LL_PCODE_HOLE_CIRCLE:
00563                                         // TODO: Compute actual detail levels for cubes
00564                                         addHole(params, FALSE, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f);
00565                                         break;
00566                                 case LL_PCODE_HOLE_SAME:
00567                                 case LL_PCODE_HOLE_SQUARE:
00568                                 default:
00569                                         addHole(params, TRUE, 4, -0.375f, hollow, 1.f, split);
00570                                         break;
00571                                 }
00572                         }
00573                         
00574                         if (path_open) {
00575                                 mFaces[0].mCount = mTotal;
00576                         }
00577                 }
00578                 break;
00579         case  LL_PCODE_PROFILE_ISOTRI:
00580         case  LL_PCODE_PROFILE_RIGHTTRI:
00581         case  LL_PCODE_PROFILE_EQUALTRI:
00582                 {
00583                         genNGon(params, 3,0, 0, 1, split);
00584                         for (i = 0; i <(S32) mProfile.size(); i++)
00585                         {
00586                                 // Scale by 3 to generate proper tex coords.
00587                                 mProfile[i].mV[2] *= 3.f;
00588                         }
00589 
00590                         if (path_open)
00591                         {
00592                                 addCap(LL_FACE_PATH_BEGIN);
00593                         }
00594 
00595                         for (i = llfloor(begin * 3.f); i < llfloor(end * 3.f + .999f); i++)
00596                         {
00597                                 addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE);
00598                         }
00599                         if (hollow)
00600                         {
00601                                 // Swept triangles need smaller hollowness values,
00602                                 // because the triangle doesn't fill the bounding box.
00603                                 F32 triangle_hollow = hollow / 2.f;
00604 
00605                                 switch (params.getCurveType() & LL_PCODE_HOLE_MASK)
00606                                 {
00607                                 case LL_PCODE_HOLE_CIRCLE:
00608                                         // TODO: Actually generate level of detail for triangles
00609                                         addHole(params, FALSE, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f);
00610                                         break;
00611                                 case LL_PCODE_HOLE_SQUARE:
00612                                         addHole(params, TRUE, 4, 0, triangle_hollow, 1.f, split);
00613                                         break;
00614                                 case LL_PCODE_HOLE_SAME:
00615                                 case LL_PCODE_HOLE_TRIANGLE:
00616                                 default:
00617                                         addHole(params, TRUE, 3, 0, triangle_hollow, 1.f, split);
00618                                         break;
00619                                 }
00620                         }
00621                 }
00622                 break;
00623         case LL_PCODE_PROFILE_CIRCLE:
00624                 {
00625                         // If this has a square hollow, we should adjust the
00626                         // number of faces a bit so that the geometry lines up.
00627                         U8 hole_type=0;
00628                         F32 circle_detail = MIN_DETAIL_FACES * detail;
00629                         if (hollow)
00630                         {
00631                                 hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK;
00632                                 if (hole_type == LL_PCODE_HOLE_SQUARE)
00633                                 {
00634                                         // Snap to the next multiple of four sides,
00635                                         // so that corners line up.
00636                                         circle_detail = llceil(circle_detail / 4.0f) * 4.0f;
00637                                 }
00638                         }
00639 
00640                         S32 sides = (S32)circle_detail;
00641 
00642                         if (is_sculpted)
00643                                 sides = sculpt_sides(detail);
00644                         
00645                         genNGon(params, sides);
00646                         
00647                         if (path_open)
00648                         {
00649                                 addCap (LL_FACE_PATH_BEGIN);
00650                         }
00651 
00652                         if (mOpen && !hollow)
00653                         {
00654                                 addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE);
00655                         }
00656                         else
00657                         {
00658                                 addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE);
00659                         }
00660 
00661                         if (hollow)
00662                         {
00663                                 switch (hole_type)
00664                                 {
00665                                 case LL_PCODE_HOLE_SQUARE:
00666                                         addHole(params, TRUE, 4, 0, hollow, 1.f, split);
00667                                         break;
00668                                 case LL_PCODE_HOLE_TRIANGLE:
00669                                         addHole(params, TRUE, 3, 0, hollow, 1.f, split);
00670                                         break;
00671                                 case LL_PCODE_HOLE_CIRCLE:
00672                                 case LL_PCODE_HOLE_SAME:
00673                                 default:
00674                                         addHole(params, FALSE, circle_detail, 0, hollow, 1.f);
00675                                         break;
00676                                 }
00677                         }
00678                 }
00679                 break;
00680         case LL_PCODE_PROFILE_CIRCLE_HALF:
00681                 {
00682                         // If this has a square hollow, we should adjust the
00683                         // number of faces a bit so that the geometry lines up.
00684                         U8 hole_type=0;
00685                         // Number of faces is cut in half because it's only a half-circle.
00686                         F32 circle_detail = MIN_DETAIL_FACES * detail * 0.5f;
00687                         if (hollow)
00688                         {
00689                                 hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK;
00690                                 if (hole_type == LL_PCODE_HOLE_SQUARE)
00691                                 {
00692                                         // Snap to the next multiple of four sides (div 2),
00693                                         // so that corners line up.
00694                                         circle_detail = llceil(circle_detail / 2.0f) * 2.0f;
00695                                 }
00696                         }
00697                         genNGon(params, llfloor(circle_detail), 0.5f, 0.f, 0.5f);
00698                         if (path_open)
00699                         {
00700                                 addCap(LL_FACE_PATH_BEGIN);
00701                         }
00702                         if (mOpen && !params.getHollow())
00703                         {
00704                                 addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE);
00705                         }
00706                         else
00707                         {
00708                                 addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE);
00709                         }
00710 
00711                         if (hollow)
00712                         {
00713                                 switch (hole_type)
00714                                 {
00715                                 case LL_PCODE_HOLE_SQUARE:
00716                                         addHole(params, TRUE, 2, 0.5f, hollow, 0.5f, split);
00717                                         break;
00718                                 case LL_PCODE_HOLE_TRIANGLE:
00719                                         addHole(params, TRUE, 3,  0.5f, hollow, 0.5f, split);
00720                                         break;
00721                                 case LL_PCODE_HOLE_CIRCLE:
00722                                 case LL_PCODE_HOLE_SAME:
00723                                 default:
00724                                         addHole(params, FALSE, circle_detail,  0.5f, hollow, 0.5f);
00725                                         break;
00726                                 }
00727                         }
00728 
00729                         // Special case for openness of sphere
00730                         if ((params.getEnd() - params.getBegin()) < 1.f)
00731                         {
00732                                 mOpen = TRUE;
00733                         }
00734                         else if (!hollow)
00735                         {
00736                                 mOpen = FALSE;
00737                                 mProfile.push_back(mProfile[0]);
00738                                 mTotal++;
00739                         }
00740                 }
00741                 break;
00742         default:
00743             llerrs << "Unknown profile: getCurveType()=" << params.getCurveType() << llendl;
00744                 break;
00745         };
00746 
00747         if (path_open)
00748         {
00749                 addCap(LL_FACE_PATH_END); // bottom
00750         }
00751         
00752         if ( mOpen) // interior edge caps
00753         {
00754                 addFace(mTotal-1, 2,0.5,LL_FACE_PROFILE_BEGIN, TRUE); 
00755 
00756                 if (hollow)
00757                 {
00758                         addFace(mTotalOut-1, 2,0.5,LL_FACE_PROFILE_END, TRUE);
00759                 }
00760                 else
00761                 {
00762                         addFace(mTotal-2, 2,0.5,LL_FACE_PROFILE_END, TRUE);
00763                 }
00764         }
00765         
00766         //genNormals(params);
00767 
00768         return TRUE;
00769 }
00770 
00771 
00772 
00773 BOOL LLProfileParams::importFile(LLFILE *fp)
00774 {
00775         LLMemType m1(LLMemType::MTYPE_VOLUME);
00776         
00777         const S32 BUFSIZE = 16384;
00778         char buffer[BUFSIZE];   /* Flawfinder: ignore */
00779         // *NOTE: changing the size or type of these buffers will require
00780         // changing the sscanf below.
00781         char keyword[256];      /* Flawfinder: ignore */
00782         char valuestr[256];     /* Flawfinder: ignore */
00783         keyword[0] = 0;
00784         valuestr[0] = 0;
00785         F32 tempF32;
00786         U32 tempU32;
00787 
00788         while (!feof(fp))
00789         {
00790                 if (fgets(buffer, BUFSIZE, fp) == NULL)
00791                 {
00792                         buffer[0] = '\0';
00793                 }
00794                 
00795                 sscanf( /* Flawfinder: ignore */
00796                         buffer,
00797                         " %255s %255s",
00798                         keyword, valuestr);
00799                 if (!strcmp("{", keyword))
00800                 {
00801                         continue;
00802                 }
00803                 if (!strcmp("}",keyword))
00804                 {
00805                         break;
00806                 }
00807                 else if (!strcmp("curve", keyword))
00808                 {
00809                         sscanf(valuestr,"%d",&tempU32);
00810                         setCurveType((U8) tempU32);
00811                 }
00812                 else if (!strcmp("begin",keyword))
00813                 {
00814                         sscanf(valuestr,"%g",&tempF32);
00815                         setBegin(tempF32);
00816                 }
00817                 else if (!strcmp("end",keyword))
00818                 {
00819                         sscanf(valuestr,"%g",&tempF32);
00820                         setEnd(tempF32);
00821                 }
00822                 else if (!strcmp("hollow",keyword))
00823                 {
00824                         sscanf(valuestr,"%g",&tempF32);
00825                         setHollow(tempF32);
00826                 }
00827                 else
00828                 {
00829                         llwarns << "unknown keyword " << keyword << " in profile import" << llendl;
00830                 }
00831         }
00832 
00833         return TRUE;
00834 }
00835 
00836 
00837 BOOL LLProfileParams::exportFile(LLFILE *fp) const
00838 {
00839         fprintf(fp,"\t\tprofile 0\n");
00840         fprintf(fp,"\t\t{\n");
00841         fprintf(fp,"\t\t\tcurve\t%d\n", getCurveType());
00842         fprintf(fp,"\t\t\tbegin\t%g\n", getBegin());
00843         fprintf(fp,"\t\t\tend\t%g\n", getEnd());
00844         fprintf(fp,"\t\t\thollow\t%g\n", getHollow());
00845         fprintf(fp, "\t\t}\n");
00846         return TRUE;
00847 }
00848 
00849 
00850 BOOL LLProfileParams::importLegacyStream(std::istream& input_stream)
00851 {
00852         LLMemType m1(LLMemType::MTYPE_VOLUME);
00853         
00854         const S32 BUFSIZE = 16384;
00855         char buffer[BUFSIZE];   /* Flawfinder: ignore */
00856         // *NOTE: changing the size or type of these buffers will require
00857         // changing the sscanf below.
00858         char keyword[256];      /* Flawfinder: ignore */
00859         char valuestr[256];     /* Flawfinder: ignore */
00860         keyword[0] = 0;
00861         valuestr[0] = 0;
00862         F32 tempF32;
00863         U32 tempU32;
00864 
00865         while (input_stream.good())
00866         {
00867                 input_stream.getline(buffer, BUFSIZE);
00868                 sscanf( /* Flawfinder: ignore */
00869                         buffer,
00870                         " %255s %255s",
00871                         keyword,
00872                         valuestr);
00873                 if (!strcmp("{", keyword))
00874                 {
00875                         continue;
00876                 }
00877                 if (!strcmp("}",keyword))
00878                 {
00879                         break;
00880                 }
00881                 else if (!strcmp("curve", keyword))
00882                 {
00883                         sscanf(valuestr,"%d",&tempU32);
00884                         setCurveType((U8) tempU32);
00885                 }
00886                 else if (!strcmp("begin",keyword))
00887                 {
00888                         sscanf(valuestr,"%g",&tempF32);
00889                         setBegin(tempF32);
00890                 }
00891                 else if (!strcmp("end",keyword))
00892                 {
00893                         sscanf(valuestr,"%g",&tempF32);
00894                         setEnd(tempF32);
00895                 }
00896                 else if (!strcmp("hollow",keyword))
00897                 {
00898                         sscanf(valuestr,"%g",&tempF32);
00899                         setHollow(tempF32);
00900                 }
00901                 else
00902                 {
00903                 llwarns << "unknown keyword " << keyword << " in profile import" << llendl;
00904                 }
00905         }
00906 
00907         return TRUE;
00908 }
00909 
00910 
00911 BOOL LLProfileParams::exportLegacyStream(std::ostream& output_stream) const
00912 {
00913         output_stream <<"\t\tprofile 0\n";
00914         output_stream <<"\t\t{\n";
00915         output_stream <<"\t\t\tcurve\t" << (S32) getCurveType() << "\n";
00916         output_stream <<"\t\t\tbegin\t" << getBegin() << "\n";
00917         output_stream <<"\t\t\tend\t" << getEnd() << "\n";
00918         output_stream <<"\t\t\thollow\t" << getHollow() << "\n";
00919         output_stream << "\t\t}\n";
00920         return TRUE;
00921 }
00922 
00923 LLSD LLProfileParams::asLLSD() const
00924 {
00925         LLSD sd;
00926 
00927         sd["curve"] = getCurveType();
00928         sd["begin"] = getBegin();
00929         sd["end"] = getEnd();
00930         sd["hollow"] = getHollow();
00931         return sd;
00932 }
00933 
00934 bool LLProfileParams::fromLLSD(LLSD& sd)
00935 {
00936         setCurveType(sd["curve"].asInteger());
00937         setBegin((F32)sd["begin"].asReal());
00938         setEnd((F32)sd["end"].asReal());
00939         setHollow((F32)sd["hollow"].asReal());
00940         return true;
00941 }
00942 
00943 void LLProfileParams::copyParams(const LLProfileParams &params)
00944 {
00945         LLMemType m1(LLMemType::MTYPE_VOLUME);
00946         setCurveType(params.getCurveType());
00947         setBegin(params.getBegin());
00948         setEnd(params.getEnd());
00949         setHollow(params.getHollow());
00950 }
00951 
00952 
00953 LLPath::~LLPath()
00954 {
00955 }
00956 
00957 void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale)
00958 {
00959         // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane.
00960         const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f };
00961 
00962         F32 revolutions = params.getRevolutions();
00963         F32 skew                = params.getSkew();
00964         F32 skew_mag    = fabs(skew);
00965         F32 hole_x              = params.getScaleX() * (1.0f - skew_mag);
00966         F32 hole_y              = params.getScaleY();
00967 
00968         // Calculate taper begin/end for x,y (Negative means taper the beginning)
00969         F32 taper_x_begin       = 1.0f;
00970         F32 taper_x_end         = 1.0f - params.getTaperX();
00971         F32     taper_y_begin   = 1.0f;
00972         F32     taper_y_end             = 1.0f - params.getTaperY();
00973 
00974         if ( taper_x_end > 1.0f )
00975         {
00976                 // Flip tapering.
00977                 taper_x_begin   = 2.0f - taper_x_end;
00978                 taper_x_end             = 1.0f;
00979         }
00980         if ( taper_y_end > 1.0f )
00981         {
00982                 // Flip tapering.
00983                 taper_y_begin   = 2.0f - taper_y_end;
00984                 taper_y_end             = 1.0f;
00985         }
00986 
00987         // For spheres, the radius is usually zero.
00988         F32 radius_start = 0.5f;
00989         if (sides < 8)
00990         {
00991                 radius_start = tableScale[sides];
00992         }
00993 
00994         // Scale the radius to take the hole size into account.
00995         radius_start *= 1.0f - hole_y;
00996         
00997         // Now check the radius offset to calculate the start,end radius.  (Negative means
00998         // decrease the start radius instead).
00999         F32 radius_end    = radius_start;
01000         F32 radius_offset = params.getRadiusOffset();
01001         if (radius_offset < 0.f)
01002         {
01003                 radius_start *= 1.f + radius_offset;
01004         }
01005         else
01006         {
01007                 radius_end   *= 1.f - radius_offset;
01008         }       
01009 
01010         // Is the path NOT a closed loop?
01011         mOpen = ( (params.getEnd()*end_scale - params.getBegin() < 1.0f) ||
01012                       (skew_mag > 0.001f) ||
01013                           (fabs(taper_x_end - taper_x_begin) > 0.001f) ||
01014                           (fabs(taper_y_end - taper_y_begin) > 0.001f) ||
01015                           (fabs(radius_end - radius_start) > 0.001f) );
01016 
01017         F32 ang, c, s;
01018         LLQuaternion twist, qang;
01019         PathPt *pt;
01020         LLVector3 path_axis (1.f, 0.f, 0.f);
01021         //LLVector3 twist_axis(0.f, 0.f, 1.f);
01022         F32 twist_begin = params.getTwistBegin() * twist_scale;
01023         F32 twist_end   = params.getTwist() * twist_scale;
01024 
01025         // We run through this once before the main loop, to make sure
01026         // the path begins at the correct cut.
01027         F32 step= 1.0f / sides;
01028         F32 t   = params.getBegin();
01029         pt              = vector_append(mPath, 1);
01030         ang             = 2.0f*F_PI*revolutions * t;
01031         s               = sin(ang)*lerp(radius_start, radius_end, t);   
01032         c               = cos(ang)*lerp(radius_start, radius_end, t);
01033 
01034 
01035         pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s)
01036                                           + lerp(-skew ,skew, t) * 0.5f,
01037                                         c + lerp(0,params.getShear().mV[1],s), 
01038                                         s);
01039         pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
01040         pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
01041         pt->mTexT  = t;
01042         
01043         // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
01044         twist.setQuat  (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
01045         // Rotate the point around the circle's center.
01046         qang.setQuat   (ang,path_axis);
01047         pt->mRot   = twist * qang;
01048 
01049         t+=step;
01050 
01051         // Snap to a quantized parameter, so that cut does not
01052         // affect most sample points.
01053         t = ((S32)(t * sides)) / (F32)sides;
01054 
01055         // Run through the non-cut dependent points.
01056         while (t < params.getEnd())
01057         {
01058                 pt              = vector_append(mPath, 1);
01059 
01060                 ang = 2.0f*F_PI*revolutions * t;
01061                 c   = cos(ang)*lerp(radius_start, radius_end, t);
01062                 s   = sin(ang)*lerp(radius_start, radius_end, t);
01063 
01064                 pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s)
01065                                               + lerp(-skew ,skew, t) * 0.5f,
01066                                                 c + lerp(0,params.getShear().mV[1],s), 
01067                                                 s);
01068 
01069                 pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
01070                 pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
01071                 pt->mTexT  = t;
01072 
01073                 // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
01074                 twist.setQuat  (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
01075                 // Rotate the point around the circle's center.
01076                 qang.setQuat   (ang,path_axis);
01077                 pt->mRot        = twist * qang;
01078 
01079                 t+=step;
01080         }
01081 
01082         // Make one final pass for the end cut.
01083         t = params.getEnd();
01084         pt              = vector_append(mPath, 1);
01085         ang = 2.0f*F_PI*revolutions * t;
01086         c   = cos(ang)*lerp(radius_start, radius_end, t);
01087         s   = sin(ang)*lerp(radius_start, radius_end, t);
01088 
01089         pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s)
01090                                           + lerp(-skew ,skew, t) * 0.5f,
01091                                         c + lerp(0,params.getShear().mV[1],s), 
01092                                         s);
01093         pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
01094         pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
01095         pt->mTexT  = t;
01096         
01097         // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
01098         twist.setQuat  (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
01099         // Rotate the point around the circle's center.
01100         qang.setQuat   (ang,path_axis);
01101         pt->mRot   = twist * qang;
01102 
01103         mTotal = mPath.size();
01104 }
01105 
01106 const LLVector2 LLPathParams::getBeginScale() const
01107 {
01108         LLVector2 begin_scale(1.f, 1.f);
01109         if (getScaleX() > 1)
01110         {
01111                 begin_scale.mV[0] = 2-getScaleX();
01112         }
01113         if (getScaleY() > 1)
01114         {
01115                 begin_scale.mV[1] = 2-getScaleY();
01116         }
01117         return begin_scale;
01118 }
01119 
01120 const LLVector2 LLPathParams::getEndScale() const
01121 {
01122         LLVector2 end_scale(1.f, 1.f);
01123         if (getScaleX() < 1)
01124         {
01125                 end_scale.mV[0] = getScaleX();
01126         }
01127         if (getScaleY() < 1)
01128         {
01129                 end_scale.mV[1] = getScaleY();
01130         }
01131         return end_scale;
01132 }
01133 
01134 BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, BOOL is_sculpted)
01135 {
01136         LLMemType m1(LLMemType::MTYPE_VOLUME);
01137         
01138         if ((!mDirty) && (!is_sculpted))
01139         {
01140                 return FALSE;
01141         }
01142 
01143         if (detail < MIN_LOD)
01144         {
01145                 llinfos << "Generating path with LOD < MIN!  Clamping to 1" << llendl;
01146                 detail = MIN_LOD;
01147         }
01148 
01149         mDirty = FALSE;
01150         S32 np = 2; // hardcode for line
01151 
01152         mPath.clear();
01153         mOpen = TRUE;
01154 
01155         // Is this 0xf0 mask really necessary?  DK 03/02/05
01156         switch (params.getCurveType() & 0xf0)
01157         {
01158         default:
01159         case LL_PCODE_PATH_LINE:
01160                 {
01161                         // Take the begin/end twist into account for detail.
01162                         np    = llfloor(fabs(params.getTwistBegin() - params.getTwist()) * 3.5f * (detail-0.5f)) + 2;
01163                         if (np < split+2)
01164                         {
01165                                 np = split+2;
01166                         }
01167 
01168                         mStep = 1.0f / (np-1);
01169                         
01170                         mPath.resize(np);
01171 
01172                         LLVector2 start_scale = params.getBeginScale();
01173                         LLVector2 end_scale = params.getEndScale();
01174 
01175                         for (S32 i=0;i<np;i++)
01176                         {
01177                                 F32 t = lerp(params.getBegin(),params.getEnd(),(F32)i * mStep);
01178                                 mPath[i].mPos.setVec(lerp(0,params.getShear().mV[0],t),
01179                                                                          lerp(0,params.getShear().mV[1],t),
01180                                                                          t - 0.5f);
01181                                 mPath[i].mRot.setQuat(lerp(F_PI * params.getTwistBegin(),F_PI * params.getTwist(),t),0,0,1);
01182                                 mPath[i].mScale.mV[0] = lerp(start_scale.mV[0],end_scale.mV[0],t);
01183                                 mPath[i].mScale.mV[1] = lerp(start_scale.mV[1],end_scale.mV[1],t);
01184                                 mPath[i].mTexT        = t;
01185                         }
01186                 }
01187                 break;
01188 
01189         case LL_PCODE_PATH_CIRCLE:
01190                 {
01191                         // Increase the detail as the revolutions and twist increase.
01192                         F32 twist_mag = fabs(params.getTwistBegin() - params.getTwist());
01193 
01194                         S32 sides = (S32)llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * params.getRevolutions());
01195 
01196                         if (is_sculpted)
01197                                 sides = sculpt_sides(detail);
01198                         
01199                         genNGon(params, sides);
01200                 }
01201                 break;
01202 
01203         case LL_PCODE_PATH_CIRCLE2:
01204                 {
01205                         if (params.getEnd() - params.getBegin() >= 0.99f &&
01206                                 params.getScaleX() >= .99f)
01207                         {
01208                                 mOpen = FALSE;
01209                         }
01210 
01211                         //genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f);
01212                         genNGon(params, llfloor(MIN_DETAIL_FACES * detail));
01213 
01214                         F32 t     = 0.f;
01215                         F32 tStep = 1.0f / mPath.size();
01216 
01217                         F32 toggle = 0.5f;
01218                         for (S32 i=0;i<(S32)mPath.size();i++)
01219                         {
01220                                 mPath[i].mPos.mV[0] = toggle;
01221                                 if (toggle == 0.5f)
01222                                         toggle = -0.5f;
01223                                 else
01224                                         toggle = 0.5f;
01225                                 t += tStep;
01226                         }
01227                 }
01228 
01229                 break;
01230 
01231         case LL_PCODE_PATH_TEST:
01232 
01233                 np     = 5;
01234                 mStep = 1.0f / (np-1);
01235                 
01236                 mPath.resize(np);
01237 
01238                 for (S32 i=0;i<np;i++)
01239                 {
01240                         F32 t = (F32)i * mStep;
01241                         mPath[i].mPos.setVec(0,
01242                                                                 lerp(0,   -sin(F_PI*params.getTwist()*t)*0.5f,t),
01243                                                                 lerp(-0.5, cos(F_PI*params.getTwist()*t)*0.5f,t));
01244                         mPath[i].mScale.mV[0] = lerp(1,params.getScale().mV[0],t);
01245                         mPath[i].mScale.mV[1] = lerp(1,params.getScale().mV[1],t);
01246                         mPath[i].mTexT  = t;
01247                         mPath[i].mRot.setQuat(F_PI * params.getTwist() * t,1,0,0);
01248                 }
01249 
01250                 break;
01251         };
01252 
01253         if (params.getTwist() != params.getTwistBegin()) mOpen = TRUE;
01254 
01255         //if ((int(fabsf(params.getTwist() - params.getTwistBegin())*100))%100 != 0) {
01256         //      mOpen = TRUE;
01257         //}
01258         
01259         return TRUE;
01260 }
01261 
01262 BOOL LLDynamicPath::generate(const LLPathParams& params, F32 detail, S32 split, BOOL is_sculpted)
01263 {
01264         LLMemType m1(LLMemType::MTYPE_VOLUME);
01265         
01266         mOpen = TRUE; // Draw end caps
01267         if (getPathLength() == 0)
01268         {
01269                 // Path hasn't been generated yet.
01270                 // Some algorithms later assume at least TWO path points.
01271                 resizePath(2);
01272                 for (U32 i = 0; i < 2; i++)
01273                 {
01274                         mPath[i].mPos.setVec(0, 0, 0);
01275                         mPath[i].mRot.setQuat(0, 0, 0);
01276                         mPath[i].mScale.setVec(1, 1);
01277                         mPath[i].mTexT = 0;
01278                 }
01279         }
01280 
01281         return TRUE;
01282 }
01283 
01284 
01285 BOOL LLPathParams::importFile(LLFILE *fp)
01286 {
01287         LLMemType m1(LLMemType::MTYPE_VOLUME);
01288         
01289         const S32 BUFSIZE = 16384;
01290         char buffer[BUFSIZE];   /* Flawfinder: ignore */
01291         // *NOTE: changing the size or type of these buffers will require
01292         // changing the sscanf below.
01293         char keyword[256];      /* Flawfinder: ignore */
01294         char valuestr[256];     /* Flawfinder: ignore */
01295         keyword[0] = 0;
01296         valuestr[0] = 0;
01297 
01298         F32 tempF32;
01299         F32 x, y;
01300         U32 tempU32;
01301 
01302         while (!feof(fp))
01303         {
01304                 if (fgets(buffer, BUFSIZE, fp) == NULL)
01305                 {
01306                         buffer[0] = '\0';
01307                 }
01308                 
01309                 sscanf( /* Flawfinder: ignore */
01310                         buffer,
01311                         " %255s %255s",
01312                         keyword, valuestr);
01313                 if (!strcmp("{", keyword))
01314                 {
01315                         continue;
01316                 }
01317                 if (!strcmp("}",keyword))
01318                 {
01319                         break;
01320                 }
01321                 else if (!strcmp("curve", keyword))
01322                 {
01323                         sscanf(valuestr,"%d",&tempU32);
01324                         setCurveType((U8) tempU32);
01325                 }
01326                 else if (!strcmp("begin",keyword))
01327                 {
01328                         sscanf(valuestr,"%g",&tempF32);
01329                         setBegin(tempF32);
01330                 }
01331                 else if (!strcmp("end",keyword))
01332                 {
01333                         sscanf(valuestr,"%g",&tempF32);
01334                         setEnd(tempF32);
01335                 }
01336                 else if (!strcmp("scale",keyword))
01337                 {
01338                         // Legacy for one dimensional scale per path
01339                         sscanf(valuestr,"%g",&tempF32);
01340                         setScale(tempF32, tempF32);
01341                 }
01342                 else if (!strcmp("scale_x", keyword))
01343                 {
01344                         sscanf(valuestr, "%g", &x);
01345                         setScaleX(x);
01346                 }
01347                 else if (!strcmp("scale_y", keyword))
01348                 {
01349                         sscanf(valuestr, "%g", &y);
01350                         setScaleY(y);
01351                 }
01352                 else if (!strcmp("shear_x", keyword))
01353                 {
01354                         sscanf(valuestr, "%g", &x);
01355                         setShearX(x);
01356                 }
01357                 else if (!strcmp("shear_y", keyword))
01358                 {
01359                         sscanf(valuestr, "%g", &y);
01360                         setShearY(y);
01361                 }
01362                 else if (!strcmp("twist",keyword))
01363                 {
01364                         sscanf(valuestr,"%g",&tempF32);
01365                         setTwist(tempF32);
01366                 }
01367                 else if (!strcmp("twist_begin", keyword))
01368                 {
01369                         sscanf(valuestr, "%g", &y);
01370                         setTwistBegin(y);
01371                 }
01372                 else if (!strcmp("radius_offset", keyword))
01373                 {
01374                         sscanf(valuestr, "%g", &y);
01375                         setRadiusOffset(y);
01376                 }
01377                 else if (!strcmp("taper_x", keyword))
01378                 {
01379                         sscanf(valuestr, "%g", &y);
01380                         setTaperX(y);
01381                 }
01382                 else if (!strcmp("taper_y", keyword))
01383                 {
01384                         sscanf(valuestr, "%g", &y);
01385                         setTaperY(y);
01386                 }
01387                 else if (!strcmp("revolutions", keyword))
01388                 {
01389                         sscanf(valuestr, "%g", &y);
01390                         setRevolutions(y);
01391                 }
01392                 else if (!strcmp("skew", keyword))
01393                 {
01394                         sscanf(valuestr, "%g", &y);
01395                         setSkew(y);
01396                 }
01397                 else
01398                 {
01399                         llwarns << "unknown keyword " << " in path import" << llendl;
01400                 }
01401         }
01402         return TRUE;
01403 }
01404 
01405 
01406 BOOL LLPathParams::exportFile(LLFILE *fp) const
01407 {
01408         fprintf(fp, "\t\tpath 0\n");
01409         fprintf(fp, "\t\t{\n");
01410         fprintf(fp, "\t\t\tcurve\t%d\n", getCurveType());
01411         fprintf(fp, "\t\t\tbegin\t%g\n", getBegin());
01412         fprintf(fp, "\t\t\tend\t%g\n", getEnd());
01413         fprintf(fp, "\t\t\tscale_x\t%g\n", getScaleX() );
01414         fprintf(fp, "\t\t\tscale_y\t%g\n", getScaleY() );
01415         fprintf(fp, "\t\t\tshear_x\t%g\n", getShearX() );
01416         fprintf(fp, "\t\t\tshear_y\t%g\n", getShearY() );
01417         fprintf(fp,"\t\t\ttwist\t%g\n", getTwist());
01418         
01419         fprintf(fp,"\t\t\ttwist_begin\t%g\n", getTwistBegin());
01420         fprintf(fp,"\t\t\tradius_offset\t%g\n", getRadiusOffset());
01421         fprintf(fp,"\t\t\ttaper_x\t%g\n", getTaperX());
01422         fprintf(fp,"\t\t\ttaper_y\t%g\n", getTaperY());
01423         fprintf(fp,"\t\t\trevolutions\t%g\n", getRevolutions());
01424         fprintf(fp,"\t\t\tskew\t%g\n", getSkew());
01425 
01426         fprintf(fp, "\t\t}\n");
01427         return TRUE;
01428 }
01429 
01430 
01431 BOOL LLPathParams::importLegacyStream(std::istream& input_stream)
01432 {
01433         LLMemType m1(LLMemType::MTYPE_VOLUME);
01434         
01435         const S32 BUFSIZE = 16384;
01436         char buffer[BUFSIZE];   /* Flawfinder: ignore */
01437         // *NOTE: changing the size or type of these buffers will require
01438         // changing the sscanf below.
01439         char keyword[256];      /* Flawfinder: ignore */
01440         char valuestr[256];     /* Flawfinder: ignore */
01441         keyword[0] = 0;
01442         valuestr[0] = 0;
01443 
01444         F32 tempF32;
01445         F32 x, y;
01446         U32 tempU32;
01447 
01448         while (input_stream.good())
01449         {
01450                 input_stream.getline(buffer, BUFSIZE);
01451                 sscanf( /* Flawfinder: ignore */
01452                         buffer,
01453                         " %255s %255s",
01454                         keyword, valuestr);
01455                 if (!strcmp("{", keyword))
01456                 {
01457                         continue;
01458                 }
01459                 if (!strcmp("}",keyword))
01460                 {
01461                         break;
01462                 }
01463                 else if (!strcmp("curve", keyword))
01464                 {
01465                         sscanf(valuestr,"%d",&tempU32);
01466                         setCurveType((U8) tempU32);
01467                 }
01468                 else if (!strcmp("begin",keyword))
01469                 {
01470                         sscanf(valuestr,"%g",&tempF32);
01471                         setBegin(tempF32);
01472                 }
01473                 else if (!strcmp("end",keyword))
01474                 {
01475                         sscanf(valuestr,"%g",&tempF32);
01476                         setEnd(tempF32);
01477                 }
01478                 else if (!strcmp("scale",keyword))
01479                 {
01480                         // Legacy for one dimensional scale per path
01481                         sscanf(valuestr,"%g",&tempF32);
01482                         setScale(tempF32, tempF32);
01483                 }
01484                 else if (!strcmp("scale_x", keyword))
01485                 {
01486                         sscanf(valuestr, "%g", &x);
01487                         setScaleX(x);
01488                 }
01489                 else if (!strcmp("scale_y", keyword))
01490                 {
01491                         sscanf(valuestr, "%g", &y);
01492                         setScaleY(y);
01493                 }
01494                 else if (!strcmp("shear_x", keyword))
01495                 {
01496                         sscanf(valuestr, "%g", &x);
01497                         setShearX(x);
01498                 }
01499                 else if (!strcmp("shear_y", keyword))
01500                 {
01501                         sscanf(valuestr, "%g", &y);
01502                         setShearY(y);
01503                 }
01504                 else if (!strcmp("twist",keyword))
01505                 {
01506                         sscanf(valuestr,"%g",&tempF32);
01507                         setTwist(tempF32);
01508                 }
01509                 else if (!strcmp("twist_begin", keyword))
01510                 {
01511                         sscanf(valuestr, "%g", &y);
01512                         setTwistBegin(y);
01513                 }
01514                 else if (!strcmp("radius_offset", keyword))
01515                 {
01516                         sscanf(valuestr, "%g", &y);
01517                         setRadiusOffset(y);
01518                 }
01519                 else if (!strcmp("taper_x", keyword))
01520                 {
01521                         sscanf(valuestr, "%g", &y);
01522                         setTaperX(y);
01523                 }
01524                 else if (!strcmp("taper_y", keyword))
01525                 {
01526                         sscanf(valuestr, "%g", &y);
01527                         setTaperY(y);
01528                 }
01529                 else if (!strcmp("revolutions", keyword))
01530                 {
01531                         sscanf(valuestr, "%g", &y);
01532                         setRevolutions(y);
01533                 }
01534                 else if (!strcmp("skew", keyword))
01535                 {
01536                         sscanf(valuestr, "%g", &y);
01537                         setSkew(y);
01538                 }
01539                 else
01540                 {
01541                         llwarns << "unknown keyword " << " in path import" << llendl;
01542                 }
01543         }
01544         return TRUE;
01545 }
01546 
01547 
01548 BOOL LLPathParams::exportLegacyStream(std::ostream& output_stream) const
01549 {
01550         output_stream << "\t\tpath 0\n";
01551         output_stream << "\t\t{\n";
01552         output_stream << "\t\t\tcurve\t" << (S32) getCurveType() << "\n";
01553         output_stream << "\t\t\tbegin\t" << getBegin() << "\n";
01554         output_stream << "\t\t\tend\t" << getEnd() << "\n";
01555         output_stream << "\t\t\tscale_x\t" << getScaleX()  << "\n";
01556         output_stream << "\t\t\tscale_y\t" << getScaleY()  << "\n";
01557         output_stream << "\t\t\tshear_x\t" << getShearX()  << "\n";
01558         output_stream << "\t\t\tshear_y\t" << getShearY()  << "\n";
01559         output_stream <<"\t\t\ttwist\t" << getTwist() << "\n";
01560         
01561         output_stream <<"\t\t\ttwist_begin\t" << getTwistBegin() << "\n";
01562         output_stream <<"\t\t\tradius_offset\t" << getRadiusOffset() << "\n";
01563         output_stream <<"\t\t\ttaper_x\t" << getTaperX() << "\n";
01564         output_stream <<"\t\t\ttaper_y\t" << getTaperY() << "\n";
01565         output_stream <<"\t\t\trevolutions\t" << getRevolutions() << "\n";
01566         output_stream <<"\t\t\tskew\t" << getSkew() << "\n";
01567 
01568         output_stream << "\t\t}\n";
01569         return TRUE;
01570 }
01571 
01572 LLSD LLPathParams::asLLSD() const
01573 {
01574         LLSD sd = LLSD();
01575         sd["curve"] = getCurveType();
01576         sd["begin"] = getBegin();
01577         sd["end"] = getEnd();
01578         sd["scale_x"] = getScaleX();
01579         sd["scale_y"] = getScaleY();
01580         sd["shear_x"] = getShearX();
01581         sd["shear_y"] = getShearY();
01582         sd["twist"] = getTwist();
01583         sd["twist_begin"] = getTwistBegin();
01584         sd["radius_offset"] = getRadiusOffset();
01585         sd["taper_x"] = getTaperX();
01586         sd["taper_y"] = getTaperY();
01587         sd["revolutions"] = getRevolutions();
01588         sd["skew"] = getSkew();
01589 
01590         return sd;
01591 }
01592 
01593 bool LLPathParams::fromLLSD(LLSD& sd)
01594 {
01595         setCurveType(sd["curve"].asInteger());
01596         setBegin((F32)sd["begin"].asReal());
01597         setEnd((F32)sd["end"].asReal());
01598         setScaleX((F32)sd["scale_x"].asReal());
01599         setScaleY((F32)sd["scale_y"].asReal());
01600         setShearX((F32)sd["shear_x"].asReal());
01601         setShearY((F32)sd["shear_y"].asReal());
01602         setTwist((F32)sd["twist"].asReal());
01603         setTwistBegin((F32)sd["twist_begin"].asReal());
01604         setRadiusOffset((F32)sd["radius_offset"].asReal());
01605         setTaperX((F32)sd["taper_x"].asReal());
01606         setTaperY((F32)sd["taper_y"].asReal());
01607         setRevolutions((F32)sd["revolutions"].asReal());
01608         setSkew((F32)sd["skew"].asReal());
01609         return true;
01610 }
01611 
01612 void LLPathParams::copyParams(const LLPathParams &params)
01613 {
01614         setCurveType(params.getCurveType());
01615         setBegin(params.getBegin());
01616         setEnd(params.getEnd());
01617         setScale(params.getScaleX(), params.getScaleY() );
01618         setShear(params.getShearX(), params.getShearY() );
01619         setTwist(params.getTwist());
01620         setTwistBegin(params.getTwistBegin());
01621         setRadiusOffset(params.getRadiusOffset());
01622         setTaper( params.getTaperX(), params.getTaperY() );
01623         setRevolutions(params.getRevolutions());
01624         setSkew(params.getSkew());
01625 }
01626 
01627 LLProfile::~LLProfile()
01628 {
01629         
01630 }
01631 
01632 
01633 S32 LLVolume::sNumMeshPoints = 0;
01634 
01635 LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL generate_single_face, const BOOL is_unique)
01636         : mParams(params)
01637 {
01638         LLMemType m1(LLMemType::MTYPE_VOLUME);
01639         
01640         mUnique = is_unique;
01641         mFaceMask = 0x0;
01642         mDetail = detail;
01643         mSculptLevel = -2;
01644         
01645         // set defaults
01646         if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
01647         {
01648                 mPathp = new LLDynamicPath();
01649         }
01650         else
01651         {
01652                 mPathp = new LLPath();
01653         }
01654         mProfilep = new LLProfile();
01655 
01656         mGenerateSingleFace = generate_single_face;
01657 
01658         generate();
01659         if (mParams.getSculptID().isNull())
01660         {
01661                 createVolumeFaces();
01662         }
01663 }
01664 
01665 void LLVolume::resizePath(S32 length)
01666 {
01667         mPathp->resizePath(length);
01668         mVolumeFaces.clear();
01669 }
01670 
01671 void LLVolume::regen()
01672 {
01673         generate();
01674         createVolumeFaces();
01675 }
01676 
01677 void LLVolume::genBinormals(S32 face)
01678 {
01679         mVolumeFaces[face].createBinormals();
01680 }
01681 
01682 LLVolume::~LLVolume()
01683 {
01684         sNumMeshPoints -= mMesh.size();
01685         delete mPathp;
01686         delete mProfilep;
01687         mPathp = NULL;
01688         mProfilep = NULL;
01689         mVolumeFaces.clear();
01690 }
01691 
01692 BOOL LLVolume::generate()
01693 {
01694         LLMemType m1(LLMemType::MTYPE_VOLUME);
01695         llassert_always(mProfilep);
01696         
01697         //Added 10.03.05 Dave Parks
01698         // Split is a parameter to LLProfile::generate that tesselates edges on the profile 
01699         // to prevent lighting and texture interpolation errors on triangles that are 
01700         // stretched due to twisting or scaling on the path.  
01701         S32 split = (S32) ((mDetail)*0.66f);
01702         
01703         if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_LINE &&
01704                 (mParams.getPathParams().getScale().mV[0] != 1.0f ||
01705                  mParams.getPathParams().getScale().mV[1] != 1.0f) &&
01706                 (mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_SQUARE ||
01707                  mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_ISOTRI ||
01708                  mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_EQUALTRI ||
01709                  mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_RIGHTTRI))
01710         {
01711                 split = 0;
01712         }
01713                  
01714         mLODScaleBias.setVec(0.5f, 0.5f, 0.5f);
01715         
01716         F32 profile_detail = mDetail;
01717         F32 path_detail = mDetail;
01718         
01719         U8 path_type = mParams.getPathParams().getCurveType();
01720         U8 profile_type = mParams.getProfileParams().getCurveType();
01721         
01722         if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE)
01723         { //cylinders don't care about Z-Axis
01724                 mLODScaleBias.setVec(0.6f, 0.6f, 0.0f);
01725         }
01726         else if (path_type == LL_PCODE_PATH_CIRCLE) 
01727         {       
01728                 mLODScaleBias.setVec(0.6f, 0.6f, 0.6f);
01729         }
01730         
01731         BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split);
01732         BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split);
01733 
01734         if (regenPath || regenProf ) 
01735         {
01736                 sNumMeshPoints -= mMesh.size();
01737                 mMesh.resize(mProfilep->mProfile.size() * mPathp->mPath.size());
01738                 sNumMeshPoints += mMesh.size();
01739 
01740                 S32 sizeS = mPathp->mPath.size();
01741                 S32 sizeT = mProfilep->mProfile.size();
01742 
01743                 //generate vertex positions
01744 
01745                 // Run along the path.
01746                 for (S32 s = 0; s < sizeS; ++s)
01747                 {
01748                         LLVector2  scale = mPathp->mPath[s].mScale;
01749                         LLQuaternion rot = mPathp->mPath[s].mRot;
01750 
01751                         // Run along the profile.
01752                         for (S32 t = 0; t < sizeT; ++t)
01753                         {
01754                                 S32 m = s*sizeT + t;
01755                                 Point& pt = mMesh[m];
01756                                 
01757                                 pt.mPos.mV[0] = mProfilep->mProfile[t].mV[0] * scale.mV[0];
01758                                 pt.mPos.mV[1] = mProfilep->mProfile[t].mV[1] * scale.mV[1];
01759                                 pt.mPos.mV[2] = 0.0f;
01760                                 pt.mPos       = pt.mPos * rot;
01761                                 pt.mPos      += mPathp->mPath[s].mPos;
01762                         }
01763                 }
01764 
01765                 for (std::vector<LLProfile::Face>::iterator iter = mProfilep->mFaces.begin();
01766                          iter != mProfilep->mFaces.end(); ++iter)
01767                 {
01768                         LLFaceID id = iter->mFaceID;
01769                         mFaceMask |= id;
01770                 }
01771                 
01772                 return TRUE;
01773         }
01774         return FALSE;
01775 }
01776 
01777 
01778 void LLVolume::createVolumeFaces()
01779 {
01780         LLMemType m1(LLMemType::MTYPE_VOLUME);
01781 
01782         if (mGenerateSingleFace)
01783         {
01784                 // do nothing
01785         }
01786         else
01787         {
01788                 S32 num_faces = getNumFaces();
01789                 BOOL partial_build = TRUE;
01790                 if (num_faces != mVolumeFaces.size())
01791                 {
01792                         partial_build = FALSE;
01793                         mVolumeFaces.resize(num_faces);
01794                 }
01795                 // Initialize volume faces with parameter data
01796                 for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++)
01797                 {
01798                         LLVolumeFace& vf = mVolumeFaces[i];
01799                         LLProfile::Face& face = mProfilep->mFaces[i];
01800                         vf.mBeginS = face.mIndex;
01801                         vf.mNumS = face.mCount;
01802                         vf.mBeginT = 0;
01803                         vf.mNumT= getPath().mPath.size();
01804                         vf.mID = i;
01805 
01806                         // Set the type mask bits correctly
01807                         if (mParams.getProfileParams().getHollow() > 0)
01808                         {
01809                                 vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK;
01810                         }
01811                         if (mProfilep->isOpen())
01812                         {
01813                                 vf.mTypeMask |= LLVolumeFace::OPEN_MASK;
01814                         }
01815                         if (face.mCap)
01816                         {
01817                                 vf.mTypeMask |= LLVolumeFace::CAP_MASK;
01818                                 if (face.mFaceID == LL_FACE_PATH_BEGIN)
01819                                 {
01820                                         vf.mTypeMask |= LLVolumeFace::TOP_MASK;
01821                                 }
01822                                 else
01823                                 {
01824                                         llassert(face.mFaceID == LL_FACE_PATH_END);
01825                                         vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK;
01826                                 }
01827                         }
01828                         else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END))
01829                         {
01830                                 vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK;
01831                         }
01832                         else
01833                         {
01834                                 vf.mTypeMask |= LLVolumeFace::SIDE_MASK;
01835                                 if (face.mFlat)
01836                                 {
01837                                         vf.mTypeMask |= LLVolumeFace::FLAT_MASK;
01838                                 }
01839                                 if (face.mFaceID & LL_FACE_INNER_SIDE)
01840                                 {
01841                                         vf.mTypeMask |= LLVolumeFace::INNER_MASK;
01842                                         if (face.mFlat && vf.mNumS > 2)
01843                                         { //flat inner faces have to copy vert normals
01844                                                 vf.mNumS = vf.mNumS*2;
01845                                         }
01846                                 }
01847                                 else
01848                                 {
01849                                         vf.mTypeMask |= LLVolumeFace::OUTER_MASK;
01850                                 }
01851                         }
01852                 }
01853 
01854                 for (face_list_t::iterator iter = mVolumeFaces.begin();
01855                          iter != mVolumeFaces.end(); ++iter)
01856                 {
01857                         (*iter).create(this, partial_build);
01858                 }
01859         }
01860 }
01861 
01862 
01863 inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b)
01864 {
01865         // maps RGB values to vector values [0..255] -> [-0.5..0.5]
01866         LLVector3 value;
01867         value.mV[VX] = r / 255.f - 0.5f;
01868         value.mV[VY] = g / 255.f - 0.5f;
01869         value.mV[VZ] = b / 255.f - 0.5f;
01870 
01871         return value;
01872 }
01873 
01874 inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
01875 {
01876         U32 index = (x + y * sculpt_width) * sculpt_components;
01877         return index;
01878 }
01879 
01880 
01881 inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
01882 {
01883         U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width);
01884         U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height);
01885 
01886         return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
01887 }
01888 
01889 
01890 inline LLVector3 sculpt_index_to_vector(U32 index, const U8* sculpt_data)
01891 {
01892         LLVector3 v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]);
01893 
01894         return v;
01895 }
01896 
01897 inline LLVector3 sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
01898 {
01899         U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components);
01900 
01901         return sculpt_index_to_vector(index, sculpt_data);
01902 }
01903 
01904 inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
01905 {
01906         U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
01907 
01908         return sculpt_index_to_vector(index, sculpt_data);
01909 }
01910 
01911 
01912 F32 LLVolume::sculptGetSurfaceArea(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
01913 {
01914         // test to see if image has enough variation to create non-degenerate geometry
01915 
01916         S32 sizeS = mPathp->mPath.size();
01917         S32 sizeT = mProfilep->mProfile.size();
01918 
01919         F32 area = 0;
01920         
01921         if ((sculpt_width != 0) &&
01922                 (sculpt_height != 0) &&
01923                 (sculpt_components != 0) &&
01924                 (sculpt_data != NULL))
01925         {
01926                 for (S32 s = 0; s < sizeS - 1; s++)
01927                 {
01928                         for (S32 t = 0; t < sizeT - 1; t++)
01929                         {
01930                                 // convert image data to vectors
01931                                 LLVector3 p1 = sculpt_st_to_vector(s, t, sizeS, sizeT, sculpt_width, sculpt_height, sculpt_components, sculpt_data);
01932                                 LLVector3 p2 = sculpt_st_to_vector(s+1, t, sizeS, sizeT, sculpt_width, sculpt_height, sculpt_components, sculpt_data);
01933                                 LLVector3 p3 = sculpt_st_to_vector(s, t+1, sizeS, sizeT, sculpt_width, sculpt_height, sculpt_components, sculpt_data);
01934 
01935                                 // compute the area of the parallelogram by taking the length of the cross product:
01936                                 // (parallegram is an approximation of two triangles)
01937                                 LLVector3 cross = (p1 - p2) % (p1 - p3);
01938                                 area += cross.magVec();
01939                         }
01940                 }
01941         }
01942 
01943         return area;
01944 }
01945 
01946 // create placeholder shape
01947 void LLVolume::sculptGeneratePlaceholder()
01948 {
01949         LLMemType m1(LLMemType::MTYPE_VOLUME);
01950         
01951         S32 sizeS = mPathp->mPath.size();
01952         S32 sizeT = mProfilep->mProfile.size();
01953         
01954         S32 line = 0;
01955 
01956         // for now, this is a sphere.
01957         for (S32 s = 0; s < sizeS; s++)
01958         {
01959                 for (S32 t = 0; t < sizeT; t++)
01960                 {
01961                         S32 i = t + line;
01962                         Point& pt = mMesh[i];
01963 
01964                         
01965                         F32 u = (F32)s/(sizeS-1);
01966                         F32 v = (F32)t/(sizeT-1);
01967 
01968                         const F32 RADIUS = (F32) 0.3;
01969                                         
01970                         pt.mPos.mV[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS);
01971                         pt.mPos.mV[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS);
01972                         pt.mPos.mV[2] = (F32)(cos(F_PI * v) * RADIUS);
01973 
01974                 }
01975                 line += sizeT;
01976         }
01977 }
01978 
01979 // create the vertices from the map
01980 void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type)
01981 {
01982         LLMemType m1(LLMemType::MTYPE_VOLUME);
01983         
01984         S32 sizeS = mPathp->mPath.size();
01985         S32 sizeT = mProfilep->mProfile.size();
01986         
01987         S32 line = 0;
01988         for (S32 s = 0; s < sizeS; s++)
01989         {
01990                 // Run along the profile.
01991                 for (S32 t = 0; t < sizeT; t++)
01992                 {
01993                         S32 i = t + line;
01994                         Point& pt = mMesh[i];
01995 
01996                         U32 x = (U32) ((F32)t/(sizeT-1) * (F32) sculpt_width);
01997                         U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height);
01998 
01999                         if (y == 0)  // top row stitching
02000                         {
02001                                 // pinch?
02002                                 if (sculpt_type == LL_SCULPT_TYPE_SPHERE)
02003                                 {
02004                                         x = sculpt_width / 2;
02005                                 }
02006                         }
02007 
02008                         if (y == sculpt_height)  // bottom row stitching
02009                         {
02010                                 // wrap?
02011                                 if (sculpt_type == LL_SCULPT_TYPE_TORUS)
02012                                 {
02013                                         y = 0;
02014                                 }
02015                                 else
02016                                 {
02017                                         y = sculpt_height - 1;
02018                                 }
02019 
02020                                 // pinch?
02021                                 if (sculpt_type == LL_SCULPT_TYPE_SPHERE)
02022                                 {
02023                                         x = sculpt_width / 2;
02024                                 }
02025                         }
02026 
02027                         if (x == sculpt_width)   // side stitching
02028                         {
02029                                 // wrap?
02030                                 if ((sculpt_type == LL_SCULPT_TYPE_SPHERE) ||
02031                                         (sculpt_type == LL_SCULPT_TYPE_TORUS) ||
02032                                         (sculpt_type == LL_SCULPT_TYPE_CYLINDER))
02033                                 {
02034                                         x = 0;
02035                                 }
02036                                         
02037                                 else
02038                                 {
02039                                         x = sculpt_width - 1;
02040                                 }
02041                         }
02042 
02043                         pt.mPos = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data);
02044                 }
02045                 line += sizeT;
02046         }
02047 }
02048 
02049 
02050 // sculpt replaces generate() for sculpted surfaces
02051 void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level)
02052 {
02053         LLMemType m1(LLMemType::MTYPE_VOLUME);
02054     U8 sculpt_type = mParams.getSculptType();
02055 
02056         BOOL data_is_empty = FALSE;
02057 
02058         if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL)
02059         {
02060                 sculpt_level = -1;
02061                 data_is_empty = TRUE;
02062         }
02063 
02064         mPathp->generate(mParams.getPathParams(), mDetail, 0, TRUE);
02065         mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, TRUE);
02066 
02067         S32 sizeS = mPathp->mPath.size();
02068         S32 sizeT = mProfilep->mProfile.size();
02069 
02070         // weird crash bug - DEV-11158 - trying to collect more data:
02071         if ((sizeS == 0) || (sizeT == 0))
02072         {
02073                 llwarns << "sculpt bad mesh size " << sizeS << " " << sizeT << llendl;
02074         }
02075         
02076         sNumMeshPoints -= mMesh.size();
02077         mMesh.resize(sizeS * sizeT);
02078         sNumMeshPoints += mMesh.size();
02079         
02080         if (!data_is_empty && sculptGetSurfaceArea(sculpt_width, sculpt_height, sculpt_components, sculpt_data) < SCULPT_MIN_AREA)
02081                 data_is_empty = TRUE;
02082 
02083         //generate vertex positions
02084         if (data_is_empty) // if empty, make a placeholder mesh
02085         {
02086                 sculptGeneratePlaceholder();
02087         }       
02088         else
02089         {
02090                 sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type);
02091         }
02092 
02093         for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++)
02094         {
02095                 mFaceMask |= mProfilep->mFaces[i].mFaceID;
02096         }
02097 
02098         mSculptLevel = sculpt_level;
02099 
02100         // Delete any existing faces so that they get regenerated
02101         mVolumeFaces.clear();
02102         
02103         createVolumeFaces();
02104 }
02105 
02106 
02107 
02108 
02109 BOOL LLVolume::isCap(S32 face)
02110 {
02111         return mProfilep->mFaces[face].mCap; 
02112 }
02113 
02114 BOOL LLVolume::isFlat(S32 face)
02115 {
02116         return mProfilep->mFaces[face].mFlat;
02117 }
02118 
02119 
02120 bool LLVolumeParams::operator==(const LLVolumeParams &params) const
02121 {
02122         return ( (getPathParams() == params.getPathParams()) &&
02123                          (getProfileParams() == params.getProfileParams()) &&
02124                          (mSculptID == params.mSculptID) &&
02125                          (mSculptType == params.mSculptType) );
02126 }
02127 
02128 bool LLVolumeParams::operator!=(const LLVolumeParams &params) const
02129 {
02130         return ( (getPathParams() != params.getPathParams()) ||
02131                          (getProfileParams() != params.getProfileParams()) ||
02132                          (mSculptID != params.mSculptID) ||
02133                          (mSculptType != params.mSculptType) );
02134 }
02135 
02136 bool LLVolumeParams::operator<(const LLVolumeParams &params) const
02137 {
02138         if( getPathParams() != params.getPathParams() )
02139         {
02140                 return getPathParams() < params.getPathParams();
02141         }
02142         
02143         if (getProfileParams() != params.getProfileParams())
02144         {
02145                 return getProfileParams() < params.getProfileParams();
02146         }
02147         
02148         if (mSculptID != params.mSculptID)
02149         {
02150                 return mSculptID < params.mSculptID;
02151         }
02152 
02153 
02154         return mSculptType < params.mSculptType;
02155 
02156 
02157 }
02158 
02159 void LLVolumeParams::copyParams(const LLVolumeParams &params)
02160 {
02161         LLMemType m1(LLMemType::MTYPE_VOLUME);
02162         mProfileParams.copyParams(params.mProfileParams);
02163         mPathParams.copyParams(params.mPathParams);
02164         mSculptID = params.getSculptID();
02165         mSculptType = params.getSculptType();
02166 }
02167 
02168 // Less restricitve approx 0 for volumes
02169 const F32 APPROXIMATELY_ZERO = 0.001f;
02170 bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO)
02171 {
02172         return (f >= -tolerance) && (f <= tolerance);
02173 }
02174 
02175 // return true if in range (or nearly so)
02176 static bool limit_range(F32& v, F32 min, F32 max, F32 tolerance = APPROXIMATELY_ZERO)
02177 {
02178         F32 min_delta = v - min;
02179         if (min_delta < 0.f)
02180         {
02181                 v = min;
02182                 if (!approx_zero(min_delta, tolerance))
02183                         return false;
02184         }
02185         F32 max_delta = max - v;
02186         if (max_delta < 0.f)
02187         {
02188                 v = max;
02189                 if (!approx_zero(max_delta, tolerance))
02190                         return false;
02191         }
02192         return true;
02193 }
02194 
02195 bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e)
02196 {
02197         bool valid = true;
02198 
02199         // First, clamp to valid ranges.
02200         F32 begin = b;
02201         valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA);
02202 
02203         F32 end = e;
02204         if (end >= .0149f && end < MIN_CUT_DELTA) end = MIN_CUT_DELTA; // eliminate warning for common rounding error
02205         valid &= limit_range(end, MIN_CUT_DELTA, 1.f);
02206 
02207         valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f);
02208 
02209         // Now set them.
02210         mProfileParams.setBegin(begin);
02211         mProfileParams.setEnd(end);
02212 
02213         return valid;
02214 }
02215 
02216 bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e)
02217 {
02218         bool valid = true;
02219 
02220         // First, clamp to valid ranges.
02221         F32 begin = b;
02222         valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA);
02223 
02224         F32 end = e;
02225         valid &= limit_range(end, MIN_CUT_DELTA, 1.f);
02226 
02227         valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f);
02228 
02229         // Now set them.
02230         mPathParams.setBegin(begin);
02231         mPathParams.setEnd(end);
02232 
02233         return valid;
02234 }                       
02235 
02236 bool LLVolumeParams::setHollow(const F32 h)
02237 {
02238         // Validate the hollow based on path and profile.
02239         U8 profile      = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
02240         U8 hole_type    = mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK;
02241         
02242         F32 max_hollow = HOLLOW_MAX;
02243 
02244         // Only square holes have trouble.
02245         if (LL_PCODE_HOLE_SQUARE == hole_type)
02246         {
02247                 switch(profile)
02248                 {
02249                 case LL_PCODE_PROFILE_CIRCLE:
02250                 case LL_PCODE_PROFILE_CIRCLE_HALF:
02251                 case LL_PCODE_PROFILE_EQUALTRI:
02252                         max_hollow = HOLLOW_MAX_SQUARE;
02253                 }
02254         }
02255 
02256         F32 hollow = h;
02257         bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow);
02258         mProfileParams.setHollow(hollow); 
02259 
02260         return valid;
02261 }       
02262 
02263 bool LLVolumeParams::setTwistBegin(const F32 b)
02264 {
02265         F32 twist_begin = b;
02266         bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX);
02267         mPathParams.setTwistBegin(twist_begin);
02268         return valid;
02269 }
02270 
02271 bool LLVolumeParams::setTwistEnd(const F32 e)
02272 {       
02273         F32 twist_end = e;
02274         bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX);
02275         mPathParams.setTwistEnd(twist_end);
02276         return valid;
02277 }
02278 
02279 bool LLVolumeParams::setRatio(const F32 x, const F32 y)
02280 {
02281         F32 min_x = RATIO_MIN;
02282         F32 max_x = RATIO_MAX;
02283         F32 min_y = RATIO_MIN;
02284         F32 max_y = RATIO_MAX;
02285         // If this is a circular path (and not a sphere) then 'ratio' is actually hole size.
02286         U8 path_type    = mPathParams.getCurveType();
02287         U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
02288         if ( LL_PCODE_PATH_CIRCLE == path_type &&
02289                  LL_PCODE_PROFILE_CIRCLE_HALF != profile_type)
02290         {
02291                 // Holes are more restricted...
02292                 min_x = HOLE_X_MIN;
02293                 max_x = HOLE_X_MAX;
02294                 min_y = HOLE_Y_MIN;
02295                 max_y = HOLE_Y_MAX;
02296         }
02297 
02298         F32 ratio_x = x;
02299         bool valid = limit_range(ratio_x, min_x, max_x);
02300         F32 ratio_y = y;
02301         valid &= limit_range(ratio_y, min_y, max_y);
02302 
02303         mPathParams.setScale(ratio_x, ratio_y);
02304 
02305         return valid;
02306 }
02307 
02308 bool LLVolumeParams::setShear(const F32 x, const F32 y)
02309 {
02310         F32 shear_x = x;
02311         bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX);
02312         F32 shear_y = y;
02313         valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX);
02314         mPathParams.setShear(shear_x, shear_y);
02315         return valid;
02316 }
02317 
02318 bool LLVolumeParams::setTaperX(const F32 v)
02319 {
02320         F32 taper = v;
02321         bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX);
02322         mPathParams.setTaperX(taper);
02323         return valid;
02324 }
02325 
02326 bool LLVolumeParams::setTaperY(const F32 v)
02327 {
02328         F32 taper = v;
02329         bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX);
02330         mPathParams.setTaperY(taper);
02331         return valid;
02332 }
02333 
02334 bool LLVolumeParams::setRevolutions(const F32 r)
02335 {
02336         F32 revolutions = r;
02337         bool valid = limit_range(revolutions, REV_MIN, REV_MAX);
02338         mPathParams.setRevolutions(revolutions);
02339         return valid;
02340 }
02341 
02342 bool LLVolumeParams::setRadiusOffset(const F32 offset)
02343 {
02344         bool valid = true;
02345 
02346         // If this is a sphere, just set it to 0 and get out.
02347         U8 path_type    = mPathParams.getCurveType();
02348         U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
02349         if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ||
02350                 LL_PCODE_PATH_CIRCLE != path_type )
02351         {
02352                 mPathParams.setRadiusOffset(0.f);
02353                 return true;
02354         }
02355 
02356         // Limit radius offset, based on taper and hole size y.
02357         F32 radius_offset       = offset;
02358         F32 taper_y             = getTaperY();
02359         F32 radius_mag          = fabs(radius_offset);
02360         F32 hole_y_mag          = fabs(getRatioY());
02361         F32 taper_y_mag         = fabs(taper_y);
02362         // Check to see if the taper effects us.
02363         if ( (radius_offset > 0.f && taper_y < 0.f) ||
02364                         (radius_offset < 0.f && taper_y > 0.f) )
02365         {
02366                 // The taper does not help increase the radius offset range.
02367                 taper_y_mag = 0.f;
02368         }
02369         F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag);
02370 
02371         // Enforce the maximum magnitude.
02372         F32 delta = max_radius_mag - radius_mag;
02373         if (delta < 0.f)
02374         {
02375                 // Check radius offset sign.
02376                 if (radius_offset < 0.f)
02377                 {
02378                         radius_offset = -max_radius_mag;
02379                 }
02380                 else
02381                 {
02382                         radius_offset = max_radius_mag;
02383                 }
02384                 valid = approx_zero(delta, .1f);
02385         }
02386 
02387         mPathParams.setRadiusOffset(radius_offset);
02388         return valid;
02389 }
02390 
02391 bool LLVolumeParams::setSkew(const F32 skew_value)
02392 {
02393         bool valid = true;
02394 
02395         // Check the skew value against the revolutions.
02396         F32 skew                = llclamp(skew_value, SKEW_MIN, SKEW_MAX);
02397         F32 skew_mag    = fabs(skew);
02398         F32 revolutions = getRevolutions();
02399         F32 scale_x             = getRatioX();
02400         F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f);
02401         // Discontinuity; A revolution of 1 allows skews below 0.5.
02402         if ( fabs(revolutions - 1.0f) < 0.001)
02403                 min_skew_mag = 0.0f;
02404 
02405         // Clip skew.
02406         F32 delta = skew_mag - min_skew_mag;
02407         if (delta < 0.f)
02408         {
02409                 // Check skew sign.
02410                 if (skew < 0.0f)
02411                 {
02412                         skew = -min_skew_mag;
02413                 }
02414                 else 
02415                 {
02416                         skew = min_skew_mag;
02417                 }
02418                 valid = approx_zero(delta, .01f);
02419         }
02420 
02421         mPathParams.setSkew(skew);
02422         return valid;
02423 }
02424 
02425 bool LLVolumeParams::setSculptID(const LLUUID sculpt_id, U8 sculpt_type)
02426 {
02427         mSculptID = sculpt_id;
02428         mSculptType = sculpt_type;
02429         return true;
02430 }
02431 
02432 bool LLVolumeParams::setType(U8 profile, U8 path)
02433 {
02434         bool result = true;
02435         // First, check profile and path for validity.
02436         U8 profile_type = profile & LL_PCODE_PROFILE_MASK;
02437         U8 hole_type    = (profile & LL_PCODE_HOLE_MASK) >> 4;
02438         U8 path_type    = path >> 4;
02439 
02440         if (profile_type > LL_PCODE_PROFILE_MAX)
02441         {
02442                 // Bad profile.  Make it square.
02443                 profile = LL_PCODE_PROFILE_SQUARE;
02444                 result = false;
02445                 llwarns << "LLVolumeParams::setType changing bad profile type (" << profile_type
02446                                 << ") to be LL_PCODE_PROFILE_SQUARE" << llendl;
02447         }
02448         else if (hole_type > LL_PCODE_HOLE_MAX)
02449         {
02450                 // Bad hole.  Make it the same.
02451                 profile = profile_type;
02452                 result = false;
02453                 llwarns << "LLVolumeParams::setType changing bad hole type (" << hole_type
02454                                 << ") to be LL_PCODE_HOLE_SAME" << llendl;
02455         }
02456 
02457         if (path_type < LL_PCODE_PATH_MIN ||
02458                 path_type > LL_PCODE_PATH_MAX)
02459         {
02460                 // Bad path.  Make it linear.
02461                 result = false;
02462                 llwarns << "LLVolumeParams::setType changing bad path (" << path
02463                                 << ") to be LL_PCODE_PATH_LINE" << llendl;
02464                 path = LL_PCODE_PATH_LINE;
02465         }
02466 
02467         mProfileParams.setCurveType(profile);
02468         mPathParams.setCurveType(path);
02469         return result;
02470 }
02471 
02472 // static 
02473 bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow,
02474                 U8 path_curve, F32 path_begin, F32 path_end,
02475                 F32 scx, F32 scy, F32 shx, F32 shy,
02476                 F32 twistend, F32 twistbegin, F32 radiusoffset,
02477                 F32 tx, F32 ty, F32 revolutions, F32 skew)
02478 {
02479         LLVolumeParams test_params;
02480         if (!test_params.setType                (prof_curve, path_curve))
02481         {
02482                 return false;
02483         }
02484         if (!test_params.setBeginAndEndS        (prof_begin, prof_end))
02485         {
02486                 return false;
02487         }
02488         if (!test_params.setBeginAndEndT        (path_begin, path_end))
02489         {
02490                 return false;
02491         }
02492         if (!test_params.setHollow              (hollow))
02493         {
02494                 return false;
02495         }
02496         if (!test_params.setTwistBegin          (twistbegin))
02497         {
02498                 return false;
02499         }
02500         if (!test_params.setTwistEnd            (twistend))
02501         {
02502                 return false;
02503         }
02504         if (!test_params.setRatio               (scx, scy))
02505         {
02506                 return false;
02507         }
02508         if (!test_params.setShear               (shx, shy))
02509         {
02510                 return false;
02511         }
02512         if (!test_params.setTaper               (tx, ty))
02513         {
02514                 return false;
02515         }
02516         if (!test_params.setRevolutions         (revolutions))
02517         {
02518                 return false;
02519         }
02520         if (!test_params.setRadiusOffset        (radiusoffset))
02521         {
02522                 return false;
02523         }
02524         if (!test_params.setSkew                (skew))
02525         {
02526                 return false;
02527         }
02528         return true;
02529 }
02530 
02531 S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
02532 {
02533         LLMemType m1(LLMemType::MTYPE_VOLUME);
02534         
02535         S32 expected_num_triangle_indices = getNumTriangleIndices();
02536         if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES)
02537         {
02538                 // we don't allow LLVolumes with this many vertices
02539                 llwarns << "Couldn't allocate triangle indices" << llendl;
02540                 num_indices = 0;
02541                 return NULL;
02542         }
02543 
02544         S32* index = new S32[expected_num_triangle_indices];
02545         S32 count = 0;
02546 
02547         // Let's do this totally diffently, as we don't care about faces...
02548         // Counter-clockwise triangles are forward facing...
02549 
02550         BOOL open = getProfile().isOpen();
02551         BOOL hollow = (mParams.getProfileParams().getHollow() > 0);
02552         BOOL path_open = getPath().isOpen();
02553         S32 size_s, size_s_out, size_t;
02554         S32 s, t, i;
02555         size_s = getProfile().getTotal();
02556         size_s_out = getProfile().getTotalOut();
02557         size_t = getPath().mPath.size();
02558 
02559         // NOTE -- if the construction of the triangles below ever changes
02560         // then getNumTriangleIndices() method may also have to be updated.
02561 
02562         if (open)               /* Flawfinder: ignore */
02563         {
02564                 if (hollow)
02565                 {
02566                         // Open hollow -- much like the closed solid, except we 
02567                         // we need to stitch up the gap between s=0 and s=size_s-1
02568 
02569                         for (t = 0; t < size_t - 1; t++)
02570                         {
02571                                 // The outer face, first cut, and inner face
02572                                 for (s = 0; s < size_s - 1; s++)
02573                                 {
02574                                         i  = s + t*size_s;
02575                                         index[count++]  = i;                            // x,y
02576                                         index[count++]  = i + 1;                        // x+1,y
02577                                         index[count++]  = i + size_s;           // x,y+1
02578         
02579                                         index[count++]  = i + size_s;           // x,y+1
02580                                         index[count++]  = i + 1;                        // x+1,y
02581                                         index[count++]  = i + size_s + 1;       // x+1,y+1
02582                                 }
02583 
02584                                 // The other cut face
02585                                 index[count++]  = s + t*size_s;         // x,y
02586                                 index[count++]  = 0 + t*size_s;         // x+1,y
02587                                 index[count++]  = s + (t+1)*size_s;     // x,y+1
02588         
02589                                 index[count++]  = s + (t+1)*size_s;     // x,y+1
02590                                 index[count++]  = 0 + t*size_s;         // x+1,y
02591                                 index[count++]  = 0 + (t+1)*size_s;     // x+1,y+1
02592                         }
02593 
02594                         // Do the top and bottom caps, if necessary
02595                         if (path_open)
02596                         {
02597                                 // Top cap
02598                                 S32 pt1 = 0;
02599                                 S32 pt2 = size_s-1;
02600                                 S32 i   = (size_t - 1)*size_s;
02601 
02602                                 while (pt2 - pt1 > 1)
02603                                 {
02604                                         // Use the profile points instead of the mesh, since you want
02605                                         // the un-transformed profile distances.
02606                                         LLVector3 p1 = getProfile().mProfile[pt1];
02607                                         LLVector3 p2 = getProfile().mProfile[pt2];
02608                                         LLVector3 pa = getProfile().mProfile[pt1+1];
02609                                         LLVector3 pb = getProfile().mProfile[pt2-1];
02610 
02611                                         p1.mV[VZ] = 0.f;
02612                                         p2.mV[VZ] = 0.f;
02613                                         pa.mV[VZ] = 0.f;
02614                                         pb.mV[VZ] = 0.f;
02615 
02616                                         // Use area of triangle to determine backfacing
02617                                         F32 area_1a2, area_1ba, area_21b, area_2ab;
02618                                         area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
02619                                                                 (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
02620                                                                 (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
02621 
02622                                         area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
02623                                                                 (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
02624                                                                 (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
02625 
02626                                         area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
02627                                                                 (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
02628                                                                 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
02629 
02630                                         area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
02631                                                                 (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
02632                                                                 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
02633 
02634                                         BOOL use_tri1a2 = TRUE;
02635                                         BOOL tri_1a2 = TRUE;
02636                                         BOOL tri_21b = TRUE;
02637 
02638                                         if (area_1a2 < 0)
02639                                         {
02640                                                 tri_1a2 = FALSE;
02641                                         }
02642                                         if (area_2ab < 0)
02643                                         {
02644                                                 // Can't use, because it contains point b
02645                                                 tri_1a2 = FALSE;
02646                                         }
02647                                         if (area_21b < 0)
02648                                         {
02649                                                 tri_21b = FALSE;
02650                                         }
02651                                         if (area_1ba < 0)
02652                                         {
02653                                                 // Can't use, because it contains point b
02654                                                 tri_21b = FALSE;
02655                                         }
02656 
02657                                         if (!tri_1a2)
02658                                         {
02659                                                 use_tri1a2 = FALSE;
02660                                         }
02661                                         else if (!tri_21b)
02662                                         {
02663                                                 use_tri1a2 = TRUE;
02664                                         }
02665                                         else
02666                                         {
02667                                                 LLVector3 d1 = p1 - pa;
02668                                                 LLVector3 d2 = p2 - pb;
02669 
02670                                                 if (d1.magVecSquared() < d2.magVecSquared())
02671                                                 {
02672                                                         use_tri1a2 = TRUE;
02673                                                 }
02674                                                 else
02675                                                 {
02676                                                         use_tri1a2 = FALSE;
02677                                                 }
02678                                         }
02679 
02680                                         if (use_tri1a2)
02681                                         {
02682                                                 index[count++] = pt1 + i;
02683                                                 index[count++] = pt1 + 1 + i;
02684                                                 index[count++] = pt2 + i;
02685                                                 pt1++;
02686                                         }
02687                                         else
02688                                         {
02689                                                 index[count++] = pt1 + i;
02690                                                 index[count++] = pt2 - 1 + i;
02691                                                 index[count++] = pt2 + i;
02692                                                 pt2--;
02693                                         }
02694                                 }
02695 
02696                                 // Bottom cap
02697                                 pt1          = 0;
02698                                 pt2          = size_s-1;
02699                                 while (pt2 - pt1 > 1)
02700                                 {
02701                                         // Use the profile points instead of the mesh, since you want
02702                                         // the un-transformed profile distances.
02703                                         LLVector3 p1 = getProfile().mProfile[pt1];
02704                                         LLVector3 p2 = getProfile().mProfile[pt2];
02705                                         LLVector3 pa = getProfile().mProfile[pt1+1];
02706                                         LLVector3 pb = getProfile().mProfile[pt2-1];
02707 
02708                                         p1.mV[VZ] = 0.f;
02709                                         p2.mV[VZ] = 0.f;
02710                                         pa.mV[VZ] = 0.f;
02711                                         pb.mV[VZ] = 0.f;
02712 
02713                                         // Use area of triangle to determine backfacing
02714                                         F32 area_1a2, area_1ba, area_21b, area_2ab;
02715                                         area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
02716                                                                 (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
02717                                                                 (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
02718 
02719                                         area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
02720                                                                 (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
02721                                                                 (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
02722 
02723                                         area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
02724                                                                 (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
02725                                                                 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
02726 
02727                                         area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
02728                                                                 (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
02729                                                                 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
02730 
02731                                         BOOL use_tri1a2 = TRUE;
02732                                         BOOL tri_1a2 = TRUE;
02733                                         BOOL tri_21b = TRUE;
02734 
02735                                         if (area_1a2 < 0)
02736                                         {
02737                                                 tri_1a2 = FALSE;
02738                                         }
02739                                         if (area_2ab < 0)
02740                                         {
02741                                                 // Can't use, because it contains point b
02742                                                 tri_1a2 = FALSE;
02743                                         }
02744                                         if (area_21b < 0)
02745                                         {
02746                                                 tri_21b = FALSE;
02747                                         }
02748                                         if (area_1ba < 0)
02749                                         {
02750                                                 // Can't use, because it contains point b
02751                                                 tri_21b = FALSE;
02752                                         }
02753 
02754                                         if (!tri_1a2)
02755                                         {
02756                                                 use_tri1a2 = FALSE;
02757                                         }
02758                                         else if (!tri_21b)
02759                                         {
02760                                                 use_tri1a2 = TRUE;
02761                                         }
02762                                         else
02763                                         {
02764                                                 LLVector3 d1 = p1 - pa;
02765                                                 LLVector3 d2 = p2 - pb;
02766 
02767                                                 if (d1.magVecSquared() < d2.magVecSquared())
02768                                                 {
02769                                                         use_tri1a2 = TRUE;
02770                                                 }
02771                                                 else
02772                                                 {
02773                                                         use_tri1a2 = FALSE;
02774                                                 }
02775                                         }
02776 
02777                                         if (use_tri1a2)
02778                                         {
02779                                                 index[count++] = pt1;
02780                                                 index[count++] = pt2;
02781                                                 index[count++] = pt1 + 1;
02782                                                 pt1++;
02783                                         }
02784                                         else
02785                                         {
02786                                                 index[count++] = pt1;
02787                                                 index[count++] = pt2;
02788                                                 index[count++] = pt2 - 1;
02789                                                 pt2--;
02790                                         }
02791                                 }
02792                         }
02793                 }
02794                 else
02795                 {
02796                         // Open solid
02797 
02798                         for (t = 0; t < size_t - 1; t++)
02799                         {
02800                                 // Outer face + 1 cut face
02801                                 for (s = 0; s < size_s - 1; s++)
02802                                 {
02803                                         i  = s + t*size_s;
02804 
02805                                         index[count++]  = i;                            // x,y
02806                                         index[count++]  = i + 1;                        // x+1,y
02807                                         index[count++]  = i + size_s;           // x,y+1
02808 
02809                                         index[count++]  = i + size_s;           // x,y+1
02810                                         index[count++]  = i + 1;                        // x+1,y
02811                                         index[count++]  = i + size_s + 1;       // x+1,y+1
02812                                 }
02813 
02814                                 // The other cut face
02815                                 index[count++] = (size_s - 1) + (t*size_s);             // x,y
02816                                 index[count++] = 0 + t*size_s;                                  // x+1,y
02817                                 index[count++] = (size_s - 1) + (t+1)*size_s;   // x,y+1
02818 
02819                                 index[count++] = (size_s - 1) + (t+1)*size_s;   // x,y+1
02820                                 index[count++] = 0 + (t*size_s);                                // x+1,y
02821                                 index[count++] = 0 + (t+1)*size_s;                              // x+1,y+1
02822                         }
02823 
02824                         // Do the top and bottom caps, if necessary
02825                         if (path_open)
02826                         {
02827                                 for (s = 0; s < size_s - 2; s++)
02828                                 {
02829                                         index[count++] = s+1;
02830                                         index[count++] = s;
02831                                         index[count++] = size_s - 1;
02832                                 }
02833 
02834                                 // We've got a top cap
02835                                 S32 offset = (size_t - 1)*size_s;
02836                                 for (s = 0; s < size_s - 2; s++)
02837                                 {
02838                                         // Inverted ordering from bottom cap.
02839                                         index[count++] = offset + size_s - 1;
02840                                         index[count++] = offset + s;
02841                                         index[count++] = offset + s + 1;
02842                                 }
02843                         }
02844                 }
02845         }
02846         else if (hollow)
02847         {
02848                 // Closed hollow
02849                 // Outer face
02850                 
02851                 for (t = 0; t < size_t - 1; t++)
02852                 {
02853                         for (s = 0; s < size_s_out - 1; s++)
02854                         {
02855                                 i  = s + t*size_s;
02856 
02857                                 index[count++]  = i;                            // x,y
02858                                 index[count++]  = i + 1;                        // x+1,y
02859                                 index[count++]  = i + size_s;           // x,y+1
02860 
02861                                 index[count++]  = i + size_s;           // x,y+1
02862                                 index[count++]  = i + 1;                        // x+1,y
02863                                 index[count++]  = i + 1 + size_s;       // x+1,y+1
02864                         }
02865                 }
02866 
02867                 // Inner face
02868                 // Invert facing from outer face
02869                 for (t = 0; t < size_t - 1; t++)
02870                 {
02871                         for (s = size_s_out; s < size_s - 1; s++)
02872                         {
02873                                 i  = s + t*size_s;
02874 
02875                                 index[count++]  = i;                            // x,y
02876                                 index[count++]  = i + 1;                        // x+1,y
02877                                 index[count++]  = i + size_s;           // x,y+1
02878 
02879                                 index[count++]  = i + size_s;           // x,y+1
02880                                 index[count++]  = i + 1;                        // x+1,y
02881                                 index[count++]  = i + 1 + size_s;       // x+1,y+1
02882                         }
02883                 }
02884 
02885                 // Do the top and bottom caps, if necessary
02886                 if (path_open)
02887                 {
02888                         // Top cap
02889                         S32 pt1 = 0;
02890                         S32 pt2 = size_s-1;
02891                         S32 i   = (size_t - 1)*size_s;
02892 
02893                         while (pt2 - pt1 > 1)
02894                         {
02895                                 // Use the profile points instead of the mesh, since you want
02896                                 // the un-transformed profile distances.
02897                                 LLVector3 p1 = getProfile().mProfile[pt1];
02898                                 LLVector3 p2 = getProfile().mProfile[pt2];
02899                                 LLVector3 pa = getProfile().mProfile[pt1+1];
02900                                 LLVector3 pb = getProfile().mProfile[pt2-1];
02901 
02902                                 p1.mV[VZ] = 0.f;
02903                                 p2.mV[VZ] = 0.f;
02904                                 pa.mV[VZ] = 0.f;
02905                                 pb.mV[VZ] = 0.f;
02906 
02907                                 // Use area of triangle to determine backfacing
02908                                 F32 area_1a2, area_1ba, area_21b, area_2ab;
02909                                 area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
02910                                                         (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
02911                                                         (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
02912 
02913                                 area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
02914                                                         (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
02915                                                         (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
02916 
02917                                 area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
02918                                                         (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
02919                                                         (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
02920 
02921                                 area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
02922                                                         (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
02923                                                         (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
02924 
02925                                 BOOL use_tri1a2 = TRUE;
02926                                 BOOL tri_1a2 = TRUE;
02927                                 BOOL tri_21b = TRUE;
02928 
02929                                 if (area_1a2 < 0)
02930                                 {
02931                                         tri_1a2 = FALSE;
02932                                 }
02933                                 if (area_2ab < 0)
02934                                 {
02935                                         // Can't use, because it contains point b
02936                                         tri_1a2 = FALSE;
02937                                 }
02938                                 if (area_21b < 0)
02939                                 {
02940                                         tri_21b = FALSE;
02941                                 }
02942                                 if (area_1ba < 0)
02943                                 {
02944                                         // Can't use, because it contains point b
02945                                         tri_21b = FALSE;
02946                                 }
02947 
02948                                 if (!tri_1a2)
02949                                 {
02950                                         use_tri1a2 = FALSE;
02951                                 }
02952                                 else if (!tri_21b)
02953                                 {
02954                                         use_tri1a2 = TRUE;
02955                                 }
02956                                 else
02957                                 {
02958                                         LLVector3 d1 = p1 - pa;
02959                                         LLVector3 d2 = p2 - pb;
02960 
02961                                         if (d1.magVecSquared() < d2.magVecSquared())
02962                                         {
02963                                                 use_tri1a2 = TRUE;
02964                                         }
02965                                         else
02966                                         {
02967                                                 use_tri1a2 = FALSE;
02968                                         }
02969                                 }
02970 
02971                                 if (use_tri1a2)
02972                                 {
02973                                         index[count++] = pt1 + i;
02974                                         index[count++] = pt1 + 1 + i;
02975                                         index[count++] = pt2 + i;
02976                                         pt1++;
02977                                 }
02978                                 else
02979                                 {
02980                                         index[count++] = pt1 + i;
02981                                         index[count++] = pt2 - 1 + i;
02982                                         index[count++] = pt2 + i;
02983                                         pt2--;
02984                                 }
02985                         }
02986 
02987                         // Bottom cap
02988                         pt1          = 0;
02989                         pt2          = size_s-1;
02990                         while (pt2 - pt1 > 1)
02991                         {
02992                                 // Use the profile points instead of the mesh, since you want
02993                                 // the un-transformed profile distances.
02994                                 LLVector3 p1 = getProfile().mProfile[pt1];
02995                                 LLVector3 p2 = getProfile().mProfile[pt2];
02996                                 LLVector3 pa = getProfile().mProfile[pt1+1];
02997                                 LLVector3 pb = getProfile().mProfile[pt2-1];
02998 
02999                                 p1.mV[VZ] = 0.f;
03000                                 p2.mV[VZ] = 0.f;
03001                                 pa.mV[VZ] = 0.f;
03002                                 pb.mV[VZ] = 0.f;
03003 
03004                                 // Use area of triangle to determine backfacing
03005                                 F32 area_1a2, area_1ba, area_21b, area_2ab;
03006                                 area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
03007                                                         (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
03008                                                         (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
03009 
03010                                 area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
03011                                                         (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
03012                                                         (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
03013 
03014                                 area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
03015                                                         (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
03016                                                         (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
03017 
03018                                 area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
03019                                                         (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
03020                                                         (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
03021 
03022                                 BOOL use_tri1a2 = TRUE;
03023                                 BOOL tri_1a2 = TRUE;
03024                                 BOOL tri_21b = TRUE;
03025 
03026                                 if (area_1a2 < 0)
03027                                 {
03028                                         tri_1a2 = FALSE;
03029                                 }
03030                                 if (area_2ab < 0)
03031                                 {
03032                                         // Can't use, because it contains point b
03033                                         tri_1a2 = FALSE;
03034                                 }
03035                                 if (area_21b < 0)
03036                                 {
03037                                         tri_21b = FALSE;
03038                                 }
03039                                 if (area_1ba < 0)
03040                                 {
03041                                         // Can't use, because it contains point b
03042                                         tri_21b = FALSE;
03043                                 }
03044 
03045                                 if (!tri_1a2)
03046                                 {
03047                                         use_tri1a2 = FALSE;
03048                                 }
03049                                 else if (!tri_21b)
03050                                 {
03051                                         use_tri1a2 = TRUE;
03052                                 }
03053                                 else
03054                                 {
03055                                         LLVector3 d1 = p1 - pa;
03056                                         LLVector3 d2 = p2 - pb;
03057 
03058                                         if (d1.magVecSquared() < d2.magVecSquared())
03059                                         {
03060                                                 use_tri1a2 = TRUE;
03061                                         }
03062                                         else
03063                                         {
03064                                                 use_tri1a2 = FALSE;
03065                                         }
03066                                 }
03067 
03068                                 if (use_tri1a2)
03069                                 {
03070                                         index[count++] = pt1;
03071                                         index[count++] = pt2;
03072                                         index[count++] = pt1 + 1;
03073                                         pt1++;
03074                                 }
03075                                 else
03076                                 {
03077                                         index[count++] = pt1;
03078                                         index[count++] = pt2;
03079                                         index[count++] = pt2 - 1;
03080                                         pt2--;
03081                                 }
03082                         }
03083                 }               
03084         }
03085         else
03086         {
03087                 // Closed solid.  Easy case.
03088                 for (t = 0; t < size_t - 1; t++)
03089                 {
03090                         for (s = 0; s < size_s - 1; s++)
03091                         {
03092                                 // Should wrap properly, but for now...
03093                                 i  = s + t*size_s;
03094 
03095                                 index[count++]  = i;                            // x,y
03096                                 index[count++]  = i + 1;                        // x+1,y
03097                                 index[count++]  = i + size_s;           // x,y+1
03098 
03099                                 index[count++]  = i + size_s;           // x,y+1
03100                                 index[count++]  = i + 1;                        // x+1,y
03101                                 index[count++]  = i + size_s + 1;       // x+1,y+1
03102                         }
03103                 }
03104 
03105                 // Do the top and bottom caps, if necessary
03106                 if (path_open)
03107                 {
03108                         // bottom cap
03109                         for (s = 1; s < size_s - 2; s++)
03110                         {
03111                                 index[count++] = s+1;
03112                                 index[count++] = s;
03113                                 index[count++] = 0;
03114                         }
03115 
03116                         // top cap
03117                         S32 offset = (size_t - 1)*size_s;
03118                         for (s = 1; s < size_s - 2; s++)
03119                         {
03120                                 // Inverted ordering from bottom cap.
03121                                 index[count++] = offset;
03122                                 index[count++] = offset + s;
03123                                 index[count++] = offset + s + 1;
03124                         }
03125                 }
03126         }
03127 
03128 #ifdef LL_DEBUG
03129         // assert that we computed the correct number of indices
03130         if (count != expected_num_triangle_indices )
03131         {
03132                 llerrs << "bad index count prediciton:"
03133                         << "  expected=" << expected_num_triangle_indices 
03134                         << " actual=" << count << llendl;
03135         }
03136 #endif
03137 
03138 #if 0
03139         // verify that each index does not point beyond the size of the mesh
03140         S32 num_vertices = mMesh.size();
03141         for (i = 0; i < count; i+=3)
03142         {
03143                 llinfos << index[i] << ":" << index[i+1] << ":" << index[i+2] << llendl;
03144                 llassert(index[i] < num_vertices);
03145                 llassert(index[i+1] < num_vertices);
03146                 llassert(index[i+2] < num_vertices);
03147         }
03148 #endif
03149 
03150         num_indices = count;
03151         return index;
03152 }
03153 
03154 S32 LLVolume::getNumTriangleIndices() const
03155 {
03156         BOOL profile_open = getProfile().isOpen();
03157         BOOL hollow = (mParams.getProfileParams().getHollow() > 0);
03158         BOOL path_open = getPath().isOpen();
03159 
03160         S32 size_s, size_s_out, size_t;
03161         size_s = getProfile().getTotal();
03162         size_s_out = getProfile().getTotalOut();
03163         size_t = getPath().mPath.size();
03164 
03165         S32 count = 0;
03166         if (profile_open)               /* Flawfinder: ignore */
03167         {
03168                 if (hollow)
03169                 {
03170                         // Open hollow -- much like the closed solid, except we 
03171                         // we need to stitch up the gap between s=0 and s=size_s-1
03172                         count = (size_t - 1) * (((size_s -1) * 6) + 6);
03173                 }
03174                 else
03175                 {
03176                         count = (size_t - 1) * (((size_s -1) * 6) + 6); 
03177                 }
03178         }
03179         else if (hollow)
03180         {
03181                 // Closed hollow
03182                 // Outer face
03183                 count = (size_t - 1) * (size_s_out - 1) * 6;
03184 
03185                 // Inner face
03186                 count += (size_t - 1) * ((size_s - 1) - size_s_out) * 6;
03187         }
03188         else
03189         {
03190                 // Closed solid.  Easy case.
03191                 count = (size_t - 1) * (size_s - 1) * 6;
03192         }
03193 
03194         if (path_open)
03195         {
03196                 S32 cap_triangle_count = size_s - 3;
03197                 if ( profile_open
03198                         || hollow )
03199                 {
03200                         cap_triangle_count = size_s - 2;
03201                 }
03202                 if ( cap_triangle_count > 0 )
03203                 {
03204                         // top and bottom caps
03205                         count += cap_triangle_count * 2 * 3;
03206                 }
03207         }
03208         return count;
03209 }
03210 
03211 //-----------------------------------------------------------------------------
03212 // generateSilhouetteVertices()
03213 //-----------------------------------------------------------------------------
03214 void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
03215                                                                                   std::vector<LLVector3> &normals,
03216                                                                                   std::vector<S32> &segments,
03217                                                                                   const LLVector3& obj_cam_vec,
03218                                                                                   const LLMatrix4& mat,
03219                                                                                   const LLMatrix3& norm_mat)
03220 {
03221         LLMemType m1(LLMemType::MTYPE_VOLUME);
03222         
03223         vertices.clear();
03224         normals.clear();
03225         segments.clear();
03226 
03227         //for each face
03228         for (face_list_t::iterator iter = mVolumeFaces.begin();
03229                  iter != mVolumeFaces.end(); ++iter)
03230         {
03231                 const LLVolumeFace& face = *iter;
03232         
03233                 if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) {
03234         
03235                 }
03236                 else {
03237 
03238                         //==============================================
03239                         //DEBUG draw edge map instead of silhouette edge
03240                         //==============================================
03241 
03242 #if DEBUG_SILHOUETTE_EDGE_MAP
03243 
03244                         //for each triangle
03245                         U32 count = face.mIndices.size();
03246                         for (U32 j = 0; j < count/3; j++) {
03247                                 //get vertices
03248                                 S32 v1 = face.mIndices[j*3+0];
03249                                 S32 v2 = face.mIndices[j*3+1];
03250                                 S32 v3 = face.mIndices[j*3+2];
03251 
03252                                 //get current face center
03253                                 LLVector3 cCenter = (face.mVertices[v1].mPosition + 
03254                                                                         face.mVertices[v2].mPosition + 
03255                                                                         face.mVertices[v3].mPosition) / 3.0f;
03256 
03257                                 //for each edge
03258                                 for (S32 k = 0; k < 3; k++) {
03259                     S32 nIndex = face.mEdge[j*3+k];
03260                                         if (nIndex <= -1) {
03261                                                 continue;
03262                                         }
03263 
03264                                         if (nIndex >= (S32) count/3) {
03265                                                 continue;
03266                                         }
03267                                         //get neighbor vertices
03268                                         v1 = face.mIndices[nIndex*3+0];
03269                                         v2 = face.mIndices[nIndex*3+1];
03270                                         v3 = face.mIndices[nIndex*3+2];
03271 
03272                                         //get neighbor face center
03273                                         LLVector3 nCenter = (face.mVertices[v1].mPosition + 
03274                                                                         face.mVertices[v2].mPosition + 
03275                                                                         face.mVertices[v3].mPosition) / 3.0f;
03276 
03277                                         //draw line
03278                                         vertices.push_back(cCenter);
03279                                         vertices.push_back(nCenter);
03280                                         normals.push_back(LLVector3(1,1,1));
03281                                         normals.push_back(LLVector3(1,1,1));
03282                                         segments.push_back(vertices.size());
03283                                 }
03284                         }
03285                 
03286                         continue;
03287 
03288                         //==============================================
03289                         //DEBUG
03290                         //==============================================
03291 
03292                         //==============================================
03293                         //DEBUG draw normals instead of silhouette edge
03294                         //==============================================
03295 #elif DEBUG_SILHOUETTE_NORMALS
03296 
03297                         //for each vertex
03298                         for (U32 j = 0; j < face.mVertices.size(); j++) {
03299                                 vertices.push_back(face.mVertices[j].mPosition);
03300                                 vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mNormal*0.1f);
03301                                 normals.push_back(LLVector3(0,0,1));
03302                                 normals.push_back(LLVector3(0,0,1));
03303                                 segments.push_back(vertices.size());
03304 #if DEBUG_SILHOUETTE_BINORMALS
03305                                 vertices.push_back(face.mVertices[j].mPosition);
03306                                 vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mBinormal*0.1f);
03307                                 normals.push_back(LLVector3(0,0,1));
03308                                 normals.push_back(LLVector3(0,0,1));
03309                                 segments.push_back(vertices.size());
03310 #endif
03311                         }
03312                                                 
03313                         continue;
03314 #else
03315                         //==============================================
03316                         //DEBUG
03317                         //==============================================
03318 
03319                         static const U8 AWAY = 0x01,
03320                                                         TOWARDS = 0x02;
03321 
03322                         //for each triangle
03323                         std::vector<U8> fFacing;
03324                         vector_append(fFacing, face.mIndices.size()/3);
03325                         for (U32 j = 0; j < face.mIndices.size()/3; j++) 
03326                         {
03327                                 //approximate normal
03328                                 S32 v1 = face.mIndices[j*3+0];
03329                                 S32 v2 = face.mIndices[j*3+1];
03330                                 S32 v3 = face.mIndices[j*3+2];
03331 
03332                                 LLVector3 norm = (face.mVertices[v1].mPosition - face.mVertices[v2].mPosition) % 
03333                                         (face.mVertices[v2].mPosition - face.mVertices[v3].mPosition);
03334                                 
03335                                 if (norm.magVecSquared() < 0.00000001f) 
03336                                 {
03337                                         fFacing[j] = AWAY | TOWARDS;
03338                                 }
03339                                 else 
03340                                 {
03341                                         //get view vector
03342                                         LLVector3 view = (obj_cam_vec-face.mVertices[v1].mPosition);
03343                                         bool away = view * norm > 0.0f; 
03344                                         if (away) 
03345                                         {
03346                                                 fFacing[j] = AWAY;
03347                                         }
03348                                         else 
03349                                         {
03350                                                 fFacing[j] = TOWARDS;
03351                                         }
03352                                 }
03353                         }
03354                         
03355                         //for each triangle
03356                         for (U32 j = 0; j < face.mIndices.size()/3; j++) 
03357                         {
03358                                 if (fFacing[j] == (AWAY | TOWARDS)) 
03359                                 { //this is a degenerate triangle
03360                                         //take neighbor facing (degenerate faces get facing of one of their neighbors)
03361                                         // *FIX IF NEEDED:  this does not deal with neighboring degenerate faces
03362                                         for (S32 k = 0; k < 3; k++) 
03363                                         {
03364                                                 S32 index = face.mEdge[j*3+k];
03365                                                 if (index != -1) 
03366                                                 {
03367                                                         fFacing[j] = fFacing[index];
03368                                                         break;
03369                                                 }
03370                                         }
03371                                         continue; //skip degenerate face
03372                                 }
03373 
03374                                 //for each edge
03375                                 for (S32 k = 0; k < 3; k++) {
03376                                         S32 index = face.mEdge[j*3+k];
03377                                         if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) {
03378                                                 //our neighbor is degenerate, make him face our direction
03379                                                 fFacing[face.mEdge[j*3+k]] = fFacing[j];
03380                                                 continue;
03381                                         }
03382 
03383                                         if (index == -1 ||              //edge has no neighbor, MUST be a silhouette edge
03384                                                 (fFacing[index] & fFacing[j]) == 0) {   //we found a silhouette edge
03385 
03386                                                 S32 v1 = face.mIndices[j*3+k];
03387                                                 S32 v2 = face.mIndices[j*3+((k+1)%3)];
03388                                                 
03389                                                 vertices.push_back(face.mVertices[v1].mPosition*mat);
03390                                                 LLVector3 norm1 = face.mVertices[v1].mNormal * norm_mat;
03391                                                 norm1.normVec();
03392                                                 normals.push_back(norm1);
03393 
03394                                                 vertices.push_back(face.mVertices[v2].mPosition*mat);
03395                                                 LLVector3 norm2 = face.mVertices[v2].mNormal * norm_mat;
03396                                                 norm2.normVec();
03397                                                 normals.push_back(norm2);
03398 
03399                                                 segments.push_back(vertices.size());
03400                                         }
03401                                 }               
03402                         }
03403 #endif
03404                 }
03405         }
03406 }
03407 
03408 S32 LLVolume::lineSegmentIntersect(const LLVector3& start, LLVector3& end) const
03409 {
03410         S32 ret = -1;
03411         
03412         LLVector3 vec = end - start;
03413         
03414         for (S32 i = 0; i < getNumFaces(); i++)
03415         {
03416                 const LLVolumeFace& face = getVolumeFace(i);
03417 
03418                 for (U32 j = 0; j < face.mIndices.size()/3; j++) 
03419                 {
03420                         //approximate normal
03421                         S32 v1 = face.mIndices[j*3+0];
03422                         S32 v2 = face.mIndices[j*3+1];
03423                         S32 v3 = face.mIndices[j*3+2];
03424 
03425                         LLVector3 norm = (face.mVertices[v2].mPosition - face.mVertices[v1].mPosition) % 
03426                                 (face.mVertices[v3].mPosition - face.mVertices[v2].mPosition);
03427                         
03428                         if (norm.magVecSquared() >= 0.00000001f) 
03429                         {
03430                                 //get view vector
03431                                 //LLVector3 view = (start-face.mVertices[v1].mPosition);
03432                                 //if (view * norm < 0.0f)
03433                                 {
03434                                         if (LLTriangleLineSegmentIntersect( face.mVertices[v1].mPosition,
03435                                                                                                                 face.mVertices[v2].mPosition,
03436                                                                                                                 face.mVertices[v3].mPosition,
03437                                                                                                                 end,
03438                                                                                                                 vec))
03439                                         {
03440                                                 vec = end-start;
03441                                                 ret = (S32) i;
03442                                         }
03443                                 }
03444                         }
03445                 }               
03446         }
03447         
03448         return ret;
03449 }
03450 
03451 class LLVertexIndexPair
03452 {
03453 public:
03454         LLVertexIndexPair(const LLVector3 &vertex, const S32 index);
03455 
03456         LLVector3 mVertex;
03457         S32     mIndex;
03458 };
03459 
03460 LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index)
03461 {
03462         mVertex = vertex;
03463         mIndex = index;
03464 }
03465 
03466 const F32 VERTEX_SLOP = 0.00001f;
03467 const F32 VERTEX_SLOP_SQRD = VERTEX_SLOP * VERTEX_SLOP;
03468 
03469 struct lessVertex
03470 {
03471         bool operator()(const LLVertexIndexPair *a, const LLVertexIndexPair *b)
03472         {
03473                 const F32 slop = VERTEX_SLOP;
03474 
03475                 if (a->mVertex.mV[0] + slop < b->mVertex.mV[0])
03476                 {
03477                         return TRUE;
03478                 }
03479                 else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0])
03480                 {
03481                         return FALSE;
03482                 }
03483                 
03484                 if (a->mVertex.mV[1] + slop < b->mVertex.mV[1])
03485                 {
03486                         return TRUE;
03487                 }
03488                 else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1])
03489                 {
03490                         return FALSE;
03491                 }
03492                 
03493                 if (a->mVertex.mV[2] + slop < b->mVertex.mV[2])
03494                 {
03495                         return TRUE;
03496                 }
03497                 else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2])
03498                 {
03499                         return FALSE;
03500                 }
03501                 
03502                 return FALSE;
03503         }
03504 };
03505 
03506 struct lessTriangle
03507 {
03508         bool operator()(const S32 *a, const S32 *b)
03509         {
03510                 if (*a < *b)
03511                 {
03512                         return TRUE;
03513                 }
03514                 else if (*a > *b)
03515                 {
03516                         return FALSE;
03517                 }
03518 
03519                 if (*(a+1) < *(b+1))
03520                 {
03521                         return TRUE;
03522                 }
03523                 else if (*(a+1) > *(b+1))
03524                 {
03525                         return FALSE;
03526                 }
03527 
03528                 if (*(a+2) < *(b+2))
03529                 {
03530                         return TRUE;
03531                 }
03532                 else if (*(a+2) > *(b+2))
03533                 {
03534                         return FALSE;
03535                 }
03536 
03537                 return FALSE;
03538         }
03539 };
03540 
03541 BOOL equalTriangle(const S32 *a, const S32 *b)
03542 {
03543         if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2)))
03544         {
03545                 return TRUE;
03546         }
03547         return FALSE;
03548 }
03549 
03550 BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices,
03551                                                                         const std::vector<Point>& input_vertices,
03552                                                                         const S32 num_input_triangles,
03553                                                                         S32 *input_triangles,
03554                                                                         S32 &num_output_vertices,
03555                                                                         LLVector3 **output_vertices,
03556                                                                         S32 &num_output_triangles,
03557                                                                         S32 **output_triangles)
03558 {
03559         LLMemType m1(LLMemType::MTYPE_VOLUME);
03560         
03561         /* Testing: avoid any cleanup
03562         static BOOL skip_cleanup = TRUE;
03563         if ( skip_cleanup )
03564         {
03565                 num_output_vertices = num_input_vertices;
03566                 num_output_triangles = num_input_triangles;
03567 
03568                 *output_vertices = new LLVector3[num_input_vertices];
03569                 for (S32 index = 0; index < num_input_vertices; index++)
03570                 {
03571                         (*output_vertices)[index] = input_vertices[index].mPos;
03572                 }
03573 
03574                 *output_triangles = new S32[num_input_triangles*3];
03575                 memcpy(*output_triangles, input_triangles, 3*num_input_triangles*sizeof(S32));          // Flawfinder: ignore
03576                 return TRUE;
03577         }
03578         */
03579 
03580         // Here's how we do this:
03581         // Create a structure which contains the original vertex index and the
03582         // LLVector3 data.
03583         // "Sort" the data by the vectors
03584         // Create an array the size of the old vertex list, with a mapping of
03585         // old indices to new indices.
03586         // Go through triangles, shift so the lowest index is first
03587         // Sort triangles by first index
03588         // Remove duplicate triangles
03589         // Allocate and pack new triangle data.
03590 
03591         //LLTimer cleanupTimer;
03592         //llinfos << "In vertices: " << num_input_vertices << llendl;
03593         //llinfos << "In triangles: " << num_input_triangles << llendl;
03594 
03595         S32 i;
03596         typedef std::multiset<LLVertexIndexPair*, lessVertex> vertex_set_t;
03597         vertex_set_t vertex_list;
03598 
03599         LLVertexIndexPair *pairp = NULL;
03600         for (i = 0; i < num_input_vertices; i++)
03601         {
03602                 LLVertexIndexPair *new_pairp = new LLVertexIndexPair(input_vertices[i].mPos, i);
03603                 vertex_list.insert(new_pairp);
03604         }
03605 
03606         // Generate the vertex mapping and the list of vertices without
03607         // duplicates.  This will crash if there are no vertices.
03608         S32 *vertex_mapping = new S32[num_input_vertices];
03609         LLVector3 *new_vertices = new LLVector3[num_input_vertices];
03610         LLVertexIndexPair *prev_pairp = NULL;
03611 
03612         S32 new_num_vertices;
03613 
03614         new_num_vertices = 0;
03615         for (vertex_set_t::iterator iter = vertex_list.begin(),
03616                          end = vertex_list.end();
03617                  iter != end; iter++)
03618         {
03619                 pairp = *iter;
03620                 if (!prev_pairp || ((pairp->mVertex - prev_pairp->mVertex).magVecSquared() >= VERTEX_SLOP_SQRD))        
03621                 {
03622                         new_vertices[new_num_vertices] = pairp->mVertex;
03623                         //llinfos << "Added vertex " << new_num_vertices << " : " << pairp->mVertex << llendl;
03624                         new_num_vertices++;
03625                         // Update the previous
03626                         prev_pairp = pairp;
03627                 }
03628                 else
03629                 {
03630                         //llinfos << "Removed duplicate vertex " << pairp->mVertex << ", distance magVecSquared() is " << (pairp->mVertex - prev_pairp->mVertex).magVecSquared() << llendl;
03631                 }
03632                 vertex_mapping[pairp->mIndex] = new_num_vertices - 1;
03633         }
03634 
03635         // Iterate through triangles and remove degenerates, re-ordering vertices
03636         // along the way.
03637         S32 *new_triangles = new S32[num_input_triangles * 3];
03638         S32 new_num_triangles = 0;
03639 
03640         for (i = 0; i < num_input_triangles; i++)
03641         {
03642                 S32 v1 = i*3;
03643                 S32 v2 = v1 + 1;
03644                 S32 v3 = v1 + 2;
03645 
03646                 //llinfos << "Checking triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;
03647                 input_triangles[v1] = vertex_mapping[input_triangles[v1]];
03648                 input_triangles[v2] = vertex_mapping[input_triangles[v2]];
03649                 input_triangles[v3] = vertex_mapping[input_triangles[v3]];
03650 
03651                 if ((input_triangles[v1] == input_triangles[v2])
03652                         || (input_triangles[v1] == input_triangles[v3])
03653                         || (input_triangles[v2] == input_triangles[v3]))
03654                 {
03655                         //llinfos << "Removing degenerate triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;
03656                         // Degenerate triangle, skip
03657                         continue;
03658                 }
03659 
03660                 if (input_triangles[v1] < input_triangles[v2])
03661                 {
03662                         if (input_triangles[v1] < input_triangles[v3])
03663                         {
03664                                 // (0 < 1) && (0 < 2)
03665                                 new_triangles[new_num_triangles*3] = input_triangles[v1];
03666                                 new_triangles[new_num_triangles*3+1] = input_triangles[v2];
03667                                 new_triangles[new_num_triangles*3+2] = input_triangles[v3];
03668                         }
03669                         else
03670                         {
03671                                 // (0 < 1) && (2 < 0)
03672                                 new_triangles[new_num_triangles*3] = input_triangles[v3];
03673                                 new_triangles[new_num_triangles*3+1] = input_triangles[v1];
03674                                 new_triangles[new_num_triangles*3+2] = input_triangles[v2];
03675                         }
03676                 }
03677                 else if (input_triangles[v2] < input_triangles[v3])
03678                 {
03679                         // (1 < 0) && (1 < 2)
03680                         new_triangles[new_num_triangles*3] = input_triangles[v2];
03681                         new_triangles[new_num_triangles*3+1] = input_triangles[v3];
03682                         new_triangles[new_num_triangles*3+2] = input_triangles[v1];
03683                 }
03684                 else
03685                 {
03686                         // (1 < 0) && (2 < 1)
03687                         new_triangles[new_num_triangles*3] = input_triangles[v3];
03688                         new_triangles[new_num_triangles*3+1] = input_triangles[v1];
03689                         new_triangles[new_num_triangles*3+2] = input_triangles[v2];
03690                 }
03691                 new_num_triangles++;
03692         }
03693 
03694         if (new_num_triangles == 0)
03695         {
03696                 llwarns << "Created volume object with 0 faces." << llendl;
03697                 delete[] new_triangles;
03698                 delete[] vertex_mapping;
03699                 delete[] new_vertices;
03700                 return FALSE;
03701         }
03702 
03703         typedef std::set<S32*, lessTriangle> triangle_set_t;
03704         triangle_set_t triangle_list;
03705 
03706         for (i = 0; i < new_num_triangles; i++)
03707         {
03708                 triangle_list.insert(&new_triangles[i*3]);
03709         }
03710 
03711         // Sort through the triangle list, and delete duplicates
03712 
03713         S32 *prevp = NULL;
03714         S32 *curp = NULL;
03715 
03716         S32 *sorted_tris = new S32[new_num_triangles*3];
03717         S32 cur_tri = 0;
03718         for (triangle_set_t::iterator iter = triangle_list.begin(),
03719                          end = triangle_list.end();
03720                  iter != end; iter++)
03721         {
03722                 curp = *iter;
03723                 if (!prevp || !equalTriangle(prevp, curp))
03724                 {
03725                         //llinfos << "Added triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl;
03726                         sorted_tris[cur_tri*3] = *curp;
03727                         sorted_tris[cur_tri*3+1] = *(curp+1);
03728                         sorted_tris[cur_tri*3+2] = *(curp+2);
03729                         cur_tri++;
03730                         prevp = curp;
03731                 }
03732                 else
03733                 {
03734                         //llinfos << "Skipped triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl;
03735                 }
03736         }
03737 
03738         *output_vertices = new LLVector3[new_num_vertices];
03739         num_output_vertices = new_num_vertices;
03740         for (i = 0; i < new_num_vertices; i++)
03741         {
03742                 (*output_vertices)[i] = new_vertices[i];
03743         }
03744 
03745         *output_triangles = new S32[cur_tri*3];
03746         num_output_triangles = cur_tri;
03747         memcpy(*output_triangles, sorted_tris, 3*cur_tri*sizeof(S32));          /* Flawfinder: ignore */
03748 
03749         /*
03750         llinfos << "Out vertices: " << num_output_vertices << llendl;
03751         llinfos << "Out triangles: " << num_output_triangles << llendl;
03752         for (i = 0; i < num_output_vertices; i++)
03753         {
03754                 llinfos << i << ":" << (*output_vertices)[i] << llendl;
03755         }
03756         for (i = 0; i < num_output_triangles; i++)
03757         {
03758                 llinfos << i << ":" << (*output_triangles)[i*3] << ":" << (*output_triangles)[i*3+1] << ":" << (*output_triangles)[i*3+2] << llendl;
03759         }
03760         */
03761 
03762         //llinfos << "Out vertices: " << num_output_vertices << llendl;
03763         //llinfos << "Out triangles: " << num_output_triangles << llendl;
03764         delete[] vertex_mapping;
03765         vertex_mapping = NULL;
03766         delete[] new_vertices;
03767         new_vertices = NULL;
03768         delete[] new_triangles;
03769         new_triangles = NULL;
03770         delete[] sorted_tris;
03771         sorted_tris = NULL;
03772         triangle_list.clear();
03773         std::for_each(vertex_list.begin(), vertex_list.end(), DeletePointer());
03774         vertex_list.clear();
03775         
03776         return TRUE;
03777 }
03778 
03779 
03780 BOOL LLVolumeParams::importFile(LLFILE *fp)
03781 {
03782         LLMemType m1(LLMemType::MTYPE_VOLUME);
03783         
03784         //llinfos << "importing volume" << llendl;
03785         const S32 BUFSIZE = 16384;
03786         char buffer[BUFSIZE];   /* Flawfinder: ignore */
03787         // *NOTE: changing the size or type of this buffer will require
03788         // changing the sscanf below.
03789         char keyword[256];      /* Flawfinder: ignore */
03790         keyword[0] = 0;
03791 
03792         while (!feof(fp))
03793         {
03794                 if (fgets(buffer, BUFSIZE, fp) == NULL)
03795                 {
03796                         buffer[0] = '\0';
03797                 }
03798                 
03799                 sscanf(buffer, " %255s", keyword);      /* Flawfinder: ignore */
03800                 if (!strcmp("{", keyword))
03801                 {
03802                         continue;
03803                 }
03804                 if (!strcmp("}",keyword))
03805                 {
03806                         break;
03807                 }
03808                 else if (!strcmp("profile", keyword))
03809                 {
03810                         mProfileParams.importFile(fp);
03811                 }
03812                 else if (!strcmp("path",keyword))
03813                 {
03814                         mPathParams.importFile(fp);
03815                 }
03816                 else
03817                 {
03818                         llwarns << "unknown keyword " << keyword << " in volume import" << llendl;
03819                 }
03820         }
03821 
03822         return TRUE;
03823 }
03824 
03825 BOOL LLVolumeParams::exportFile(LLFILE *fp) const
03826 {
03827         fprintf(fp,"\tshape 0\n");
03828         fprintf(fp,"\t{\n");
03829         mPathParams.exportFile(fp);
03830         mProfileParams.exportFile(fp);
03831         fprintf(fp, "\t}\n");
03832         return TRUE;
03833 }
03834 
03835 
03836 BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream)
03837 {
03838         LLMemType m1(LLMemType::MTYPE_VOLUME);
03839         
03840         //llinfos << "importing volume" << llendl;
03841         const S32 BUFSIZE = 16384;
03842         // *NOTE: changing the size or type of this buffer will require
03843         // changing the sscanf below.
03844         char buffer[BUFSIZE];           /* Flawfinder: ignore */
03845         char keyword[256];              /* Flawfinder: ignore */
03846         keyword[0] = 0;
03847 
03848         while (input_stream.good())
03849         {
03850                 input_stream.getline(buffer, BUFSIZE);
03851                 sscanf(buffer, " %255s", keyword);
03852                 if (!strcmp("{", keyword))
03853                 {
03854                         continue;
03855                 }
03856                 if (!strcmp("}",keyword))
03857                 {
03858                         break;
03859                 }
03860                 else if (!strcmp("profile", keyword))
03861                 {
03862                         mProfileParams.importLegacyStream(input_stream);
03863                 }
03864                 else if (!strcmp("path",keyword))
03865                 {
03866                         mPathParams.importLegacyStream(input_stream);
03867                 }
03868                 else
03869                 {
03870                         llwarns << "unknown keyword " << keyword << " in volume import" << llendl;
03871                 }
03872         }
03873 
03874         return TRUE;
03875 }
03876 
03877 BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const
03878 {
03879         LLMemType m1(LLMemType::MTYPE_VOLUME);
03880         
03881         output_stream <<"\tshape 0\n";
03882         output_stream <<"\t{\n";
03883         mPathParams.exportLegacyStream(output_stream);
03884         mProfileParams.exportLegacyStream(output_stream);
03885         output_stream << "\t}\n";
03886         return TRUE;
03887 }
03888 
03889 LLSD LLVolumeParams::asLLSD() const
03890 {
03891         LLSD sd = LLSD();
03892         sd["path"] = mPathParams;
03893         sd["profile"] = mProfileParams;
03894         return sd;
03895 }
03896 
03897 bool LLVolumeParams::fromLLSD(LLSD& sd)
03898 {
03899         mPathParams.fromLLSD(sd["path"]);
03900         mProfileParams.fromLLSD(sd["profile"]);
03901         return true;
03902 }
03903 
03904 void LLVolumeParams::reduceS(F32 begin, F32 end)
03905 {
03906         begin = llclampf(begin);
03907         end = llclampf(end);
03908         if (begin > end)
03909         {
03910                 F32 temp = begin;
03911                 begin = end;
03912                 end = temp;
03913         }
03914         F32 a = mProfileParams.getBegin();
03915         F32 b = mProfileParams.getEnd();
03916         mProfileParams.setBegin(a + begin * (b - a));
03917         mProfileParams.setEnd(a + end * (b - a));
03918 }
03919 
03920 void LLVolumeParams::reduceT(F32 begin, F32 end)
03921 {
03922         begin = llclampf(begin);
03923         end = llclampf(end);
03924         if (begin > end)
03925         {
03926                 F32 temp = begin;
03927                 begin = end;
03928                 end = temp;
03929         }
03930         F32 a = mPathParams.getBegin();
03931         F32 b = mPathParams.getEnd();
03932         mPathParams.setBegin(a + begin * (b - a));
03933         mPathParams.setEnd(a + end * (b - a));
03934 }
03935 
03936 const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f;   // 1/8 unity
03937 const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f;   // 1/9 unity
03938 
03939 // returns TRUE if the shape can be approximated with a convex shape 
03940 // for collison purposes
03941 BOOL LLVolumeParams::isConvex() const
03942 {
03943         F32 path_length = mPathParams.getEnd() - mPathParams.getBegin();
03944         F32 hollow = mProfileParams.getHollow();
03945          
03946         U8 path_type = mPathParams.getCurveType();
03947         if ( path_length > MIN_CONCAVE_PATH_WEDGE
03948                 && ( mPathParams.getTwist() != mPathParams.getTwistBegin()
03949                      || (hollow > 0.f 
03950                                  && LL_PCODE_PATH_LINE != path_type) ) )
03951         {
03952                 // twist along a "not too short" path is concave
03953                 return FALSE;
03954         }
03955 
03956         F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin();
03957         BOOL same_hole = hollow == 0.f 
03958                                          || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME;
03959 
03960         F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE;
03961         U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
03962         if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )
03963         {
03964                 // it is a sphere and spheres get twice the minimum profile wedge
03965                 min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE;
03966         }
03967 
03968         BOOL convex_profile = ( ( profile_length == 1.f
03969                                                      || profile_length <= 0.5f )
03970                                                    && hollow == 0.f )                                           // trivially convex
03971                                                   || ( profile_length <= min_profile_wedge
03972                                                           && same_hole );                                               // effectvely convex (even when hollow)
03973 
03974         if (!convex_profile)
03975         {
03976                 // profile is concave
03977                 return FALSE;
03978         }
03979 
03980         if ( LL_PCODE_PATH_LINE == path_type )
03981         {
03982                 // straight paths with convex profile
03983                 return TRUE;
03984         }
03985 
03986         BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f);
03987         if (concave_path)
03988         {
03989                 return FALSE;
03990         }
03991 
03992         // we're left with spheres, toroids and tubes
03993         if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )
03994         {
03995                 // at this stage all spheres must be convex
03996                 return TRUE;
03997         }
03998 
03999         // it's a toroid or tube                
04000         if ( path_length <= MIN_CONCAVE_PATH_WEDGE )
04001         {
04002                 // effectively convex
04003                 return TRUE;
04004         }
04005 
04006         return FALSE;
04007 }
04008 
04009 // debug
04010 void LLVolumeParams::setCube()
04011 {
04012         mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE);
04013         mProfileParams.setBegin(0.f);
04014         mProfileParams.setEnd(1.f);
04015         mProfileParams.setHollow(0.f);
04016 
04017         mPathParams.setBegin(0.f);
04018         mPathParams.setEnd(1.f);
04019         mPathParams.setScale(1.f, 1.f);
04020         mPathParams.setShear(0.f, 0.f);
04021         mPathParams.setCurveType(LL_PCODE_PATH_LINE);
04022         mPathParams.setTwistBegin(0.f);
04023         mPathParams.setTwistEnd(0.f);
04024         mPathParams.setRadiusOffset(0.f);
04025         mPathParams.setTaper(0.f, 0.f);
04026         mPathParams.setRevolutions(0.f);
04027         mPathParams.setSkew(0.f);
04028 }
04029 
04030 LLFaceID LLVolume::generateFaceMask()
04031 {
04032         LLFaceID new_mask = 0x0000;
04033 
04034         switch(mParams.getProfileParams().getCurveType() & LL_PCODE_PROFILE_MASK)
04035         {
04036         case LL_PCODE_PROFILE_CIRCLE:
04037         case LL_PCODE_PROFILE_CIRCLE_HALF:
04038                 new_mask |= LL_FACE_OUTER_SIDE_0;
04039                 break;
04040         case LL_PCODE_PROFILE_SQUARE:
04041                 {
04042                         for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 4.f); side < llceil(mParams.getProfileParams().getEnd() * 4.f); side++)
04043                         {
04044                                 new_mask |= LL_FACE_OUTER_SIDE_0 << side;
04045                         }
04046                 }
04047                 break;
04048         case LL_PCODE_PROFILE_ISOTRI:
04049         case LL_PCODE_PROFILE_EQUALTRI:
04050         case LL_PCODE_PROFILE_RIGHTTRI:
04051                 {
04052                         for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 3.f); side < llceil(mParams.getProfileParams().getEnd() * 3.f); side++)
04053                         {
04054                                 new_mask |= LL_FACE_OUTER_SIDE_0 << side;
04055                         }
04056                 }
04057                 break;
04058         default:
04059                 llerrs << "Unknown profile!" << llendl
04060                 break;
04061         }
04062 
04063         // handle hollow objects
04064         if (mParams.getProfileParams().getHollow() > 0)
04065         {
04066                 new_mask |= LL_FACE_INNER_SIDE;
04067         }
04068 
04069         // handle open profile curves
04070         if (mProfilep->isOpen())
04071         {
04072                 new_mask |= LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END;
04073         }
04074 
04075         // handle open path curves
04076         if (mPathp->isOpen())
04077         {
04078                 new_mask |= LL_FACE_PATH_BEGIN | LL_FACE_PATH_END;
04079         }
04080 
04081         return new_mask;
04082 }
04083 
04084 BOOL LLVolume::isFaceMaskValid(LLFaceID face_mask)
04085 {
04086         LLFaceID test_mask = 0;
04087         for(S32 i = 0; i < getNumFaces(); i++)
04088         {
04089                 test_mask |= mProfilep->mFaces[i].mFaceID;
04090         }
04091 
04092         return test_mask == face_mask;
04093 }
04094 
04095 BOOL LLVolume::isConvex() const
04096 {
04097         // mParams.isConvex() may return FALSE even though the final
04098         // geometry is actually convex due to LOD approximations.
04099         // TODO -- provide LLPath and LLProfile with isConvex() methods
04100         // that correctly determine convexity. -- Leviathan
04101         return mParams.isConvex();
04102 }
04103 
04104 
04105 std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params)
04106 {
04107         s << "{type=" << (U32) profile_params.mCurveType;
04108         s << ", begin=" << profile_params.mBegin;
04109         s << ", end=" << profile_params.mEnd;
04110         s << ", hollow=" << profile_params.mHollow;
04111         s << "}";
04112         return s;
04113 }
04114 
04115 
04116 std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params)
04117 {
04118         s << "{type=" << (U32) path_params.mCurveType;
04119         s << ", begin=" << path_params.mBegin;
04120         s << ", end=" << path_params.mEnd;
04121         s << ", twist=" << path_params.mTwistEnd;
04122         s << ", scale=" << path_params.mScale;
04123         s << ", shear=" << path_params.mShear;
04124         s << ", twist_begin=" << path_params.mTwistBegin;
04125         s << ", radius_offset=" << path_params.mRadiusOffset;
04126         s << ", taper=" << path_params.mTaper;
04127         s << ", revolutions=" << path_params.mRevolutions;
04128         s << ", skew=" << path_params.mSkew;
04129         s << "}";
04130         return s;
04131 }
04132 
04133 
04134 std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params)
04135 {
04136         s << "{profileparams = " << volume_params.mProfileParams;
04137         s << ", pathparams = " << volume_params.mPathParams;
04138         s << "}";
04139         return s;
04140 }
04141 
04142 
04143 std::ostream& operator<<(std::ostream &s, const LLProfile &profile)
04144 {
04145         s << " {open=" << (U32) profile.mOpen;
04146         s << ", dirty=" << profile.mDirty;
04147         s << ", totalout=" << profile.mTotalOut;
04148         s << ", total=" << profile.mTotal;
04149         s << "}";
04150         return s;
04151 }
04152 
04153 
04154 std::ostream& operator<<(std::ostream &s, const LLPath &path)
04155 {
04156         s << "{open=" << (U32) path.mOpen;
04157         s << ", dirty=" << path.mDirty;
04158         s << ", step=" << path.mStep;
04159         s << ", total=" << path.mTotal;
04160         s << "}";
04161         return s;
04162 }
04163 
04164 std::ostream& operator<<(std::ostream &s, const LLVolume &volume)
04165 {
04166         s << "{params = " << volume.getParams();
04167         s << ", path = " << *volume.mPathp;
04168         s << ", profile = " << *volume.mProfilep;
04169         s << "}";
04170         return s;
04171 }
04172 
04173 
04174 std::ostream& operator<<(std::ostream &s, const LLVolume *volumep)
04175 {
04176         s << "{params = " << volumep->getParams();
04177         s << ", path = " << *(volumep->mPathp);
04178         s << ", profile = " << *(volumep->mProfilep);
04179         s << "}";
04180         return s;
04181 }
04182 
04183 
04184 BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
04185 {
04186         if (mTypeMask & CAP_MASK)
04187         {
04188                 return createCap(volume, partial_build);
04189         }
04190         else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK))
04191         {
04192                 return createSide(volume, partial_build);
04193         }
04194         else
04195         {
04196                 llerrs << "Unknown/uninitialized face type!" << llendl;
04197                 return FALSE;
04198         }
04199 }
04200 
04201 void    LerpPlanarVertex(LLVolumeFace::VertexData& v0,
04202                                    LLVolumeFace::VertexData& v1,
04203                                    LLVolumeFace::VertexData& v2,
04204                                    LLVolumeFace::VertexData& vout,
04205                                    F32  coef01,
04206                                    F32  coef02)
04207 {
04208         vout.mPosition = v0.mPosition + ((v1.mPosition-v0.mPosition)*coef01)+((v2.mPosition-v0.mPosition)*coef02);
04209         vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02);
04210         vout.mNormal = v0.mNormal;
04211         vout.mBinormal = v0.mBinormal;
04212 }
04213 
04214 BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
04215 {
04216         LLMemType m1(LLMemType::MTYPE_VOLUME);
04217         
04218         const std::vector<LLVolume::Point>& mesh = volume->getMesh();
04219         const std::vector<LLVector3>& profile = volume->getProfile().mProfile;
04220         S32 max_s = volume->getProfile().getTotal();
04221         S32 max_t = volume->getPath().mPath.size();
04222 
04223         // S32 i;
04224         S32 num_vertices = 0, num_indices = 0;
04225         S32     grid_size = (profile.size()-1)/4;
04226         S32     quad_count = (grid_size * grid_size);
04227 
04228         num_vertices = (grid_size+1)*(grid_size+1);
04229         num_indices = quad_count * 4;
04230 
04231         LLVector3& min = mExtents[0];
04232         LLVector3& max = mExtents[1];
04233 
04234         S32 offset = 0;
04235         if (mTypeMask & TOP_MASK)
04236                 offset = (max_t-1) * max_s;
04237         else
04238                 offset = mBeginS;
04239 
04240         VertexData      corners[4];
04241         VertexData baseVert;
04242         for(int t = 0; t < 4; t++){
04243                 corners[t].mPosition = mesh[offset + (grid_size*t)].mPos;
04244                 corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f;
04245                 corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1];
04246         }
04247         baseVert.mNormal = 
04248                 ((corners[1].mPosition-corners[0].mPosition) % 
04249                 (corners[2].mPosition-corners[1].mPosition));
04250         baseVert.mNormal.normVec();
04251         if(!(mTypeMask & TOP_MASK)){
04252                 baseVert.mNormal *= -1.0f;
04253         }else{
04254                 //Swap the UVs on the U(X) axis for top face
04255                 LLVector2 swap;
04256                 swap = corners[0].mTexCoord;
04257                 corners[0].mTexCoord=corners[3].mTexCoord;
04258                 corners[3].mTexCoord=swap;
04259                 swap = corners[1].mTexCoord;
04260                 corners[1].mTexCoord=corners[2].mTexCoord;
04261                 corners[2].mTexCoord=swap;
04262         }
04263         baseVert.mBinormal = calc_binormal_from_triangle( 
04264                 corners[0].mPosition, corners[0].mTexCoord,
04265                 corners[1].mPosition, corners[1].mTexCoord,
04266                 corners[2].mPosition, corners[2].mTexCoord);
04267         for(int t = 0; t < 4; t++){
04268                 corners[t].mBinormal = baseVert.mBinormal;
04269                 corners[t].mNormal = baseVert.mNormal;
04270         }
04271         mHasBinormals = TRUE;
04272 
04273         if (partial_build)
04274         {
04275                 mVertices.clear();
04276         }
04277 
04278         S32     vtop = mVertices.size();
04279         for(int gx = 0;gx<grid_size+1;gx++){
04280                 for(int gy = 0;gy<grid_size+1;gy++){
04281                         VertexData newVert;
04282                         LerpPlanarVertex(
04283                                 corners[0],
04284                                 corners[1],
04285                                 corners[3],
04286                                 newVert,
04287                                 (F32)gx/(F32)grid_size,
04288                                 (F32)gy/(F32)grid_size);
04289                         mVertices.push_back(newVert);
04290 
04291                         if (gx == 0 && gy == 0)
04292                         {
04293                                 min = max = newVert.mPosition;
04294                         }
04295                         else
04296                         {
04297                                 update_min_max(min,max,newVert.mPosition);
04298                         }
04299                 }
04300         }
04301         
04302         mCenter = (min + max) * 0.5f;
04303 
04304         if (!partial_build)
04305         {
04306                 int idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0};
04307                 for(int gx = 0;gx<grid_size;gx++){
04308                         for(int gy = 0;gy<grid_size;gy++){
04309                                 if (mTypeMask & TOP_MASK){
04310                                         for(int i=5;i>=0;i--)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
04311                                 }else{
04312                                         for(int i=0;i<6;i++)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
04313                                 }
04314                         }
04315                 }
04316         }
04317                 
04318         return TRUE;
04319 }
04320 
04321 
04322 BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
04323 {
04324         LLMemType m1(LLMemType::MTYPE_VOLUME);
04325         
04326         if (!(mTypeMask & HOLLOW_MASK) && 
04327                 !(mTypeMask & OPEN_MASK) && 
04328                 ((volume->getParams().getPathParams().getBegin()==0.0f)&&
04329                 (volume->getParams().getPathParams().getEnd()==1.0f))&&
04330                 (volume->getParams().getProfileParams().getCurveType()==LL_PCODE_PROFILE_SQUARE &&
04331                  volume->getParams().getPathParams().getCurveType()==LL_PCODE_PATH_LINE)        
04332                 ){
04333                 return createUnCutCubeCap(volume, partial_build);
04334         }
04335 
04336         S32 num_vertices = 0, num_indices = 0;
04337 
04338         const std::vector<LLVolume::Point>& mesh = volume->getMesh();
04339         const std::vector<LLVector3>& profile = volume->getProfile().mProfile;
04340 
04341         // All types of caps have the same number of vertices and indices
04342         num_vertices = profile.size();
04343         num_indices = (profile.size() - 2)*3;
04344 
04345         mVertices.resize(num_vertices);
04346 
04347         if (!partial_build)
04348         {
04349                 mIndices.resize(num_indices);
04350         }
04351 
04352         S32 max_s = volume->getProfile().getTotal();
04353         S32 max_t = volume->getPath().mPath.size();
04354 
04355         mCenter.clearVec();
04356 
04357         S32 offset = 0;
04358         if (mTypeMask & TOP_MASK)
04359         {
04360                 offset = (max_t-1) * max_s;
04361         }
04362         else
04363         {
04364                 offset = mBeginS;
04365         }
04366 
04367         // Figure out the normal, assume all caps are flat faces.
04368         // Cross product to get normals.
04369         
04370         LLVector2 cuv;
04371         LLVector2 min_uv, max_uv;
04372 
04373         LLVector3& min = mExtents[0];
04374         LLVector3& max = mExtents[1];
04375 
04376         // Copy the vertices into the array
04377         for (S32 i = 0; i < num_vertices; i++)
04378         {
04379                 if (mTypeMask & TOP_MASK)
04380                 {
04381                         mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f;
04382                         mVertices[i].mTexCoord.mV[1] = profile[i].mV[1]+0.5f;
04383                 }
04384                 else
04385                 {
04386                         // Mirror for underside.
04387                         mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f;
04388                         mVertices[i].mTexCoord.mV[1] = 0.5f - profile[i].mV[1];
04389                 }
04390 
04391                 mVertices[i].mPosition = mesh[i + offset].mPos;
04392                 
04393                 if (i == 0)
04394                 {
04395                         min = max = mVertices[i].mPosition;
04396                         min_uv = max_uv = mVertices[i].mTexCoord;
04397                 }
04398                 else
04399                 {
04400                         update_min_max(min,max, mVertices[i].mPosition);
04401                         update_min_max(min_uv, max_uv, mVertices[i].mTexCoord);
04402                 }
04403         }
04404 
04405         mCenter = (min+max)*0.5f;
04406         cuv = (min_uv + max_uv)*0.5f;
04407 
04408         LLVector3 binormal = calc_binormal_from_triangle( 
04409                 mCenter, cuv,
04410                 mVertices[0].mPosition, mVertices[0].mTexCoord,
04411                 mVertices[1].mPosition, mVertices[1].mTexCoord);
04412         binormal.normVec();
04413 
04414         LLVector3 d0;
04415         LLVector3 d1;
04416         LLVector3 normal;
04417 
04418         d0 = mCenter-mVertices[0].mPosition;
04419         d1 = mCenter-mVertices[1].mPosition;
04420 
04421         normal = (mTypeMask & TOP_MASK) ? (d0%d1) : (d1%d0);
04422         normal.normVec();
04423 
04424         VertexData vd;
04425         vd.mPosition = mCenter;
04426         vd.mNormal = normal;
04427         vd.mBinormal = binormal;
04428         vd.mTexCoord = cuv;
04429         
04430         if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
04431         {
04432                 mVertices.push_back(vd);
04433                 num_vertices++;
04434                 if (!partial_build)
04435                 {
04436                         vector_append(mIndices, 3);
04437                 }
04438         }
04439                 
04440         
04441         for (S32 i = 0; i < num_vertices; i++)
04442         {
04443                 mVertices[i].mBinormal = binormal;
04444                 mVertices[i].mNormal = normal;
04445         }
04446 
04447         mHasBinormals = TRUE;
04448 
04449         if (partial_build)
04450         {
04451                 return TRUE;
04452         }
04453 
04454         if (mTypeMask & HOLLOW_MASK)
04455         {
04456                 if (mTypeMask & TOP_MASK)
04457                 {
04458                         // HOLLOW TOP
04459                         // Does it matter if it's open or closed? - djs
04460 
04461                         S32 pt1 = 0, pt2 = num_vertices - 1;
04462                         S32 i = 0;
04463                         while (pt2 - pt1 > 1)
04464                         {
04465                                 // Use the profile points instead of the mesh, since you want
04466                                 // the un-transformed profile distances.
04467                                 LLVector3 p1 = profile[pt1];
04468                                 LLVector3 p2 = profile[pt2];
04469                                 LLVector3 pa = profile[pt1+1];
04470                                 LLVector3 pb = profile[pt2-1];
04471 
04472                                 p1.mV[VZ] = 0.f;
04473                                 p2.mV[VZ] = 0.f;
04474                                 pa.mV[VZ] = 0.f;
04475                                 pb.mV[VZ] = 0.f;
04476 
04477                                 // Use area of triangle to determine backfacing
04478                                 F32 area_1a2, area_1ba, area_21b, area_2ab;
04479                                 area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
04480                                                         (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
04481                                                         (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
04482 
04483                                 area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
04484                                                         (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
04485                                                         (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
04486 
04487                                 area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
04488                                                         (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
04489                                                         (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
04490 
04491                                 area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
04492                                                         (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
04493                                                         (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
04494 
04495                                 BOOL use_tri1a2 = TRUE;
04496                                 BOOL tri_1a2 = TRUE;
04497                                 BOOL tri_21b = TRUE;
04498 
04499                                 if (area_1a2 < 0)
04500                                 {
04501                                         tri_1a2 = FALSE;
04502                                 }
04503                                 if (area_2ab < 0)
04504                                 {
04505                                         // Can't use, because it contains point b
04506                                         tri_1a2 = FALSE;
04507                                 }
04508                                 if (area_21b < 0)
04509                                 {
04510                                         tri_21b = FALSE;
04511                                 }
04512                                 if (area_1ba < 0)
04513                                 {
04514                                         // Can't use, because it contains point b
04515                                         tri_21b = FALSE;
04516                                 }
04517 
04518                                 if (!tri_1a2)
04519                                 {
04520                                         use_tri1a2 = FALSE;
04521                                 }
04522                                 else if (!tri_21b)
04523                                 {
04524                                         use_tri1a2 = TRUE;
04525                                 }
04526                                 else
04527                                 {
04528                                         LLVector3 d1 = p1 - pa;
04529                                         LLVector3 d2 = p2 - pb;
04530 
04531                                         if (d1.magVecSquared() < d2.magVecSquared())
04532                                         {
04533                                                 use_tri1a2 = TRUE;
04534                                         }
04535                                         else
04536                                         {
04537                                                 use_tri1a2 = FALSE;
04538                                         }
04539                                 }
04540 
04541                                 if (use_tri1a2)
04542                                 {
04543                                         mIndices[i++] = pt1;
04544                                         mIndices[i++] = pt1 + 1;
04545                                         mIndices[i++] = pt2;
04546                                         pt1++;
04547                                 }
04548                                 else
04549                                 {
04550                                         mIndices[i++] = pt1;
04551                                         mIndices[i++] = pt2 - 1;
04552                                         mIndices[i++] = pt2;
04553                                         pt2--;
04554                                 }
04555                         }
04556                 }
04557                 else
04558                 {
04559                         // HOLLOW BOTTOM
04560                         // Does it matter if it's open or closed? - djs
04561 
04562                         llassert(mTypeMask & BOTTOM_MASK);
04563                         S32 pt1 = 0, pt2 = num_vertices - 1;
04564 
04565                         S32 i = 0;
04566                         while (pt2 - pt1 > 1)
04567                         {
04568                                 // Use the profile points instead of the mesh, since you want
04569                                 // the un-transformed profile distances.
04570                                 LLVector3 p1 = profile[pt1];
04571                                 LLVector3 p2 = profile[pt2];
04572                                 LLVector3 pa = profile[pt1+1];
04573                                 LLVector3 pb = profile[pt2-1];
04574 
04575                                 p1.mV[VZ] = 0.f;
04576                                 p2.mV[VZ] = 0.f;
04577                                 pa.mV[VZ] = 0.f;
04578                                 pb.mV[VZ] = 0.f;
04579 
04580                                 // Use area of triangle to determine backfacing
04581                                 F32 area_1a2, area_1ba, area_21b, area_2ab;
04582                                 area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
04583                                                         (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
04584                                                         (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
04585 
04586                                 area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
04587                                                         (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
04588                                                         (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
04589 
04590                                 area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
04591                                                         (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
04592                                                         (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
04593 
04594                                 area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
04595                                                         (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
04596                                                         (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
04597 
04598                                 BOOL use_tri1a2 = TRUE;
04599                                 BOOL tri_1a2 = TRUE;
04600                                 BOOL tri_21b = TRUE;
04601 
04602                                 if (area_1a2 < 0)
04603                                 {
04604                                         tri_1a2 = FALSE;
04605                                 }
04606                                 if (area_2ab < 0)
04607                                 {
04608                                         // Can't use, because it contains point b
04609                                         tri_1a2 = FALSE;
04610                                 }
04611                                 if (area_21b < 0)
04612                                 {
04613                                         tri_21b = FALSE;
04614                                 }
04615                                 if (area_1ba < 0)
04616                                 {
04617                                         // Can't use, because it contains point b
04618                                         tri_21b = FALSE;
04619                                 }
04620 
04621                                 if (!tri_1a2)
04622                                 {
04623                                         use_tri1a2 = FALSE;
04624                                 }
04625                                 else if (!tri_21b)
04626                                 {
04627                                         use_tri1a2 = TRUE;
04628                                 }
04629                                 else
04630                                 {
04631                                         LLVector3 d1 = p1 - pa;
04632                                         LLVector3 d2 = p2 - pb;
04633 
04634                                         if (d1.magVecSquared() < d2.magVecSquared())
04635                                         {
04636                                                 use_tri1a2 = TRUE;
04637                                         }
04638                                         else
04639                                         {
04640                                                 use_tri1a2 = FALSE;
04641                                         }
04642                                 }
04643 
04644                                 // Flipped backfacing from top
04645                                 if (use_tri1a2)
04646                                 {
04647                                         mIndices[i++] = pt1;
04648                                         mIndices[i++] = pt2;
04649                                         mIndices[i++] = pt1 + 1;
04650                                         pt1++;
04651                                 }
04652                                 else
04653                                 {
04654                                         mIndices[i++] = pt1;
04655                                         mIndices[i++] = pt2;
04656                                         mIndices[i++] = pt2 - 1;
04657                                         pt2--;
04658                                 }
04659                         }
04660                 }
04661         }
04662         else
04663         {
04664                 // Not hollow, generate the triangle fan.
04665                 if (mTypeMask & TOP_MASK)
04666                 {
04667                         if (mTypeMask & OPEN_MASK)
04668                         {
04669                                 // SOLID OPEN TOP
04670                                 // Generate indices
04671                                 // This is a tri-fan, so we reuse the same first point for all triangles.
04672                                 for (S32 i = 0; i < (num_vertices - 2); i++)
04673                                 {
04674                                         mIndices[3*i] = num_vertices - 1;
04675                                         mIndices[3*i+1] = i;
04676                                         mIndices[3*i+2] = i + 1;
04677                                 }
04678                         }
04679                         else
04680                         {
04681                                 // SOLID CLOSED TOP
04682                                 for (S32 i = 0; i < (num_vertices - 2); i++)
04683                                 {                               
04684                                         //MSMSM fix these caps but only for the un-cut case
04685                                         mIndices[3*i] = num_vertices - 1;
04686                                         mIndices[3*i+1] = i;
04687                                         mIndices[3*i+2] = i + 1;
04688                                 }
04689                         }
04690                 }
04691                 else
04692                 {
04693                         if (mTypeMask & OPEN_MASK)
04694                         {
04695                                 // SOLID OPEN BOTTOM
04696                                 // Generate indices
04697                                 // This is a tri-fan, so we reuse the same first point for all triangles.
04698                                 for (S32 i = 0; i < (num_vertices - 2); i++)
04699                                 {
04700                                         mIndices[3*i] = num_vertices - 1;
04701                                         mIndices[3*i+1] = i + 1;
04702                                         mIndices[3*i+2] = i;
04703                                 }
04704                         }
04705                         else
04706                         {
04707                                 // SOLID CLOSED BOTTOM
04708                                 for (S32 i = 0; i < (num_vertices - 2); i++)
04709                                 {
04710                                         //MSMSM fix these caps but only for the un-cut case
04711                                         mIndices[3*i] = num_vertices - 1;
04712                                         mIndices[3*i+1] = i + 1;
04713                                         mIndices[3*i+2] = i;
04714                                 }
04715                         }
04716                 }
04717         }
04718         return TRUE;
04719 }
04720 
04721 void LLVolumeFace::createBinormals()
04722 {
04723         LLMemType m1(LLMemType::MTYPE_VOLUME);
04724         
04725         if (!mHasBinormals)
04726         {
04727                 //generate binormals
04728                 for (U32 i = 0; i < mIndices.size()/3; i++) 
04729                 {       //for each triangle
04730                         const VertexData& v0 = mVertices[mIndices[i*3+0]];
04731                         const VertexData& v1 = mVertices[mIndices[i*3+1]];
04732                         const VertexData& v2 = mVertices[mIndices[i*3+2]];
04733                                                 
04734                         //calculate binormal
04735                         LLVector3 binorm = calc_binormal_from_triangle(v0.mPosition, v0.mTexCoord,
04736                                                                                                                         v1.mPosition, v1.mTexCoord,
04737                                                                                                                         v2.mPosition, v2.mTexCoord);
04738 
04739                         for (U32 j = 0; j < 3; j++) 
04740                         { //add triangle normal to vertices
04741                                 mVertices[mIndices[i*3+j]].mBinormal += binorm; // * (weight_sum - d[j])/weight_sum;
04742                         }
04743 
04744                         //even out quad contributions
04745                         if (i % 2 == 0) 
04746                         {
04747                                 mVertices[mIndices[i*3+2]].mBinormal += binorm;
04748                         }
04749                         else 
04750                         {
04751                                 mVertices[mIndices[i*3+1]].mBinormal += binorm;
04752                         }
04753                 }
04754 
04755                 //normalize binormals
04756                 for (U32 i = 0; i < mVertices.size(); i++) 
04757                 {
04758                         mVertices[i].mBinormal.normVec();
04759                         mVertices[i].mNormal.normVec();
04760                 }
04761 
04762                 mHasBinormals = TRUE;
04763         }
04764 }
04765 
04766 BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
04767 {
04768         LLMemType m1(LLMemType::MTYPE_VOLUME);
04769         
04770         BOOL flat = mTypeMask & FLAT_MASK;
04771         S32 num_vertices, num_indices;
04772 
04773         const std::vector<LLVolume::Point>& mesh = volume->getMesh();
04774         const std::vector<LLVector3>& profile = volume->getProfile().mProfile;
04775         const std::vector<LLPath::PathPt>& path_data = volume->getPath().mPath;
04776 
04777         S32 max_s = volume->getProfile().getTotal();
04778 
04779         S32 s, t, i;
04780         F32 ss, tt;
04781 
04782         num_vertices = mNumS*mNumT;
04783         num_indices = (mNumS-1)*(mNumT-1)*6;
04784 
04785         mVertices.resize(num_vertices);
04786 
04787         if (!partial_build)
04788         {
04789                 mIndices.resize(num_indices);
04790                 mEdge.resize(num_indices);
04791         }
04792 
04793         LLVector3& face_min = mExtents[0];
04794         LLVector3& face_max = mExtents[1];
04795 
04796         mCenter.clearVec();
04797 
04798         S32 begin_stex = llfloor( profile[mBeginS].mV[2] );
04799         S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS;
04800 
04801         S32 cur_vertex = 0;
04802         // Copy the vertices into the array
04803         for (t = mBeginT; t < mBeginT + mNumT; t++)
04804         {
04805                 tt = path_data[t].mTexT;
04806                 for (s = 0; s < num_s; s++)
04807                 {
04808                         if (mTypeMask & END_MASK)
04809                         {
04810                                 if (s)
04811                                 {
04812                                         ss = 1.f;
04813                                 }
04814                                 else
04815                                 {
04816                                         ss = 0.f;
04817                                 }
04818                         }
04819                         else
04820                         {
04821                                 // Get s value for tex-coord.
04822                                 if (!flat)
04823                                 {
04824                                         ss = profile[mBeginS + s].mV[2];
04825                                 }
04826                                 else
04827                                 {
04828                                         ss = profile[mBeginS + s].mV[2] - begin_stex;
04829                                 }
04830                         }
04831 
04832                         // Check to see if this triangle wraps around the array.
04833                         if (mBeginS + s >= max_s)
04834                         {
04835                                 // We're wrapping
04836                                 i = mBeginS + s + max_s*(t-1);
04837                         }
04838                         else
04839                         {
04840                                 i = mBeginS + s + max_s*t;
04841                         }
04842 
04843                         mVertices[cur_vertex].mPosition = mesh[i].mPos;
04844                         mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
04845                 
04846                         mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
04847                         mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
04848                         
04849                         if (cur_vertex == 0)
04850                         {
04851                                 face_min = face_max = mesh[i].mPos;
04852                         }
04853                         else
04854                         {
04855                                 update_min_max(face_min, face_max, mesh[i].mPos);
04856                         }
04857 
04858                         cur_vertex++;
04859 
04860                         if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0)
04861                         {
04862                                 mVertices[cur_vertex].mPosition = mesh[i].mPos;
04863                                 mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
04864                         
04865                                 mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
04866                                 mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
04867                                 cur_vertex++;
04868                         }
04869                 }
04870                 
04871                 if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2)
04872                 {
04873                         if (mTypeMask & OPEN_MASK)
04874                         {
04875                                 s = num_s-1;
04876                         }
04877                         else
04878                         {
04879                                 s = 0;
04880                         }
04881 
04882                         i = mBeginS + s + max_s*t;
04883                         ss = profile[mBeginS + s].mV[2] - begin_stex;
04884                         mVertices[cur_vertex].mPosition = mesh[i].mPos;
04885                         mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
04886                 
04887                         mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
04888                         mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
04889 
04890                         update_min_max(face_min,face_max,mesh[i].mPos);
04891 
04892                         cur_vertex++;
04893                 }
04894         }
04895         
04896         mCenter = (face_min + face_max) * 0.5f;
04897 
04898         S32 cur_index = 0;
04899         S32 cur_edge = 0;
04900         BOOL flat_face = mTypeMask & FLAT_MASK;
04901 
04902         if (!partial_build)
04903         {
04904                 // Now we generate the indices.
04905                 for (t = 0; t < (mNumT-1); t++)
04906                 {
04907                         for (s = 0; s < (mNumS-1); s++)
04908                         {       
04909                                 mIndices[cur_index++] = s   + mNumS*t;                  //bottom left
04910                                 mIndices[cur_index++] = s+1 + mNumS*(t+1);              //top right
04911                                 mIndices[cur_index++] = s   + mNumS*(t+1);              //top left
04912                                 mIndices[cur_index++] = s   + mNumS*t;                  //bottom left
04913                                 mIndices[cur_index++] = s+1 + mNumS*t;                  //bottom right
04914                                 mIndices[cur_index++] = s+1 + mNumS*(t+1);              //top right
04915 
04916                                 mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1;                                                //bottom left/top right neighbor face 
04917                                 if (t < mNumT-2) {                                                                                              //top right/top left neighbor face 
04918                                         mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
04919                                 }
04920                                 else if (mNumT <= 3 || volume->getPath().isOpen() == TRUE) { //no neighbor
04921                                         mEdge[cur_edge++] = -1;
04922                                 }
04923                                 else { //wrap on T
04924                                         mEdge[cur_edge++] = s*2+1;
04925                                 }
04926                                 if (s > 0) {                                                                                                    //top left/bottom left neighbor face
04927                                         mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1;
04928                                 }
04929                                 else if (flat_face ||  volume->getProfile().isOpen() == TRUE) { //no neighbor
04930                                         mEdge[cur_edge++] = -1;
04931                                 }
04932                                 else {  //wrap on S
04933                                         mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1;
04934                                 }
04935                                 
04936                                 if (t > 0) {                                                                                                    //bottom left/bottom right neighbor face
04937                                         mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2;
04938                                 }
04939                                 else if (mNumT <= 3 || volume->getPath().isOpen() == TRUE) { //no neighbor
04940                                         mEdge[cur_edge++] = -1;
04941                                 }
04942                                 else { //wrap on T
04943                                         mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2;
04944                                 }
04945                                 if (s < mNumS-2) {                                                                                              //bottom right/top right neighbor face
04946                                         mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2;
04947                                 }
04948                                 else if (flat_face || volume->getProfile().isOpen() == TRUE) { //no neighbor
04949                                         mEdge[cur_edge++] = -1;
04950                                 }
04951                                 else { //wrap on S
04952                                         mEdge[cur_edge++] = (mNumS-1)*2*t;
04953                                 }
04954                                 mEdge[cur_edge++] = (mNumS-1)*2*t+s*2;                                                  //top right/bottom left neighbor face   
04955                         }
04956                 }
04957         }
04958 
04959         //generate normals 
04960         for (U32 i = 0; i < mIndices.size()/3; i++) //for each triangle
04961         {
04962                 const S32 i0 = mIndices[i*3+0];
04963                 const S32 i1 = mIndices[i*3+1];
04964                 const S32 i2 = mIndices[i*3+2];
04965                 const VertexData& v0 = mVertices[i0];
04966                 const VertexData& v1 = mVertices[i1];
04967                 const VertexData& v2 = mVertices[i2];
04968                                         
04969                 //calculate triangle normal
04970                 LLVector3 norm = (v0.mPosition-v1.mPosition) % (v0.mPosition-v2.mPosition);
04971 
04972                 for (U32 j = 0; j < 3; j++) 
04973                 { //add triangle normal to vertices
04974                         const S32 idx = mIndices[i*3+j];
04975                         mVertices[idx].mNormal += norm; // * (weight_sum - d[j])/weight_sum;
04976                 }
04977 
04978                 //even out quad contributions
04979                 if ((i & 1) == 0) 
04980                 {
04981                         mVertices[i2].mNormal += norm;
04982                 }
04983                 else 
04984                 {
04985                         mVertices[i1].mNormal += norm;
04986                 }
04987         }
04988         
04989         // adjust normals based on wrapping and stitching
04990         
04991         BOOL s_bottom_converges = ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f);
04992         BOOL s_top_converges = ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 0.000001f);
04993         U8 sculpt_type = volume->getParams().getSculptType();
04994 
04995         if (sculpt_type == LL_SCULPT_TYPE_NONE)  // logic for non-sculpt volumes
04996         {
04997                 if (volume->getPath().isOpen() == FALSE)
04998                 { //wrap normals on T
04999                         for (S32 i = 0; i < mNumS; i++)
05000                         {
05001                                 LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal;
05002                                 mVertices[i].mNormal = norm;
05003                                 mVertices[mNumS*(mNumT-1)+i].mNormal = norm;
05004                         }
05005                 }
05006 
05007                 if ((volume->getProfile().isOpen() == FALSE) && !(s_bottom_converges))
05008                 { //wrap normals on S
05009                         for (S32 i = 0; i < mNumT; i++)
05010                         {
05011                                 LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
05012                                 mVertices[mNumS * i].mNormal = norm;
05013                                 mVertices[mNumS * i+mNumS-1].mNormal = norm;
05014                         }
05015                 }
05016         
05017                 if (volume->getPathType() == LL_PCODE_PATH_CIRCLE &&
05018                         ((volume->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF))
05019                 {
05020                         if (s_bottom_converges)
05021                         { //all lower S have same normal
05022                                 for (S32 i = 0; i < mNumT; i++)
05023                                 {
05024                                         mVertices[mNumS*i].mNormal = LLVector3(1,0,0);
05025                                 }
05026                         }
05027 
05028                         if (s_top_converges)
05029                         { //all upper S have same normal
05030                                 for (S32 i = 0; i < mNumT; i++)
05031                                 {
05032                                         mVertices[mNumS*i+mNumS-1].mNormal = LLVector3(-1,0,0);
05033                                 }
05034                         }
05035                 }
05036         }
05037         
05038         else  // logic for sculpt volumes
05039         {
05040                 BOOL average_poles = FALSE;
05041                 BOOL wrap_s = FALSE;
05042                 BOOL wrap_t = FALSE;
05043 
05044                 if (sculpt_type == LL_SCULPT_TYPE_SPHERE)
05045                         average_poles = TRUE;
05046 
05047                 if ((sculpt_type == LL_SCULPT_TYPE_SPHERE) ||
05048                         (sculpt_type == LL_SCULPT_TYPE_TORUS) ||
05049                         (sculpt_type == LL_SCULPT_TYPE_CYLINDER))
05050                         wrap_s = TRUE;
05051 
05052                 if (sculpt_type == LL_SCULPT_TYPE_TORUS)
05053                         wrap_t = TRUE;
05054                         
05055                 
05056                 if (average_poles)
05057                 {
05058                         // average normals for north pole
05059                 
05060                         LLVector3 average(0.0, 0.0, 0.0);
05061                         for (S32 i = 0; i < mNumS; i++)
05062                         {
05063                                 average += mVertices[i].mNormal;
05064                         }
05065 
05066                         // set average
05067                         for (S32 i = 0; i < mNumS; i++)
05068                         {
05069                                 mVertices[i].mNormal = average;
05070                         }
05071 
05072                         // average normals for south pole
05073                 
05074                         average = LLVector3(0.0, 0.0, 0.0);
05075                         for (S32 i = 0; i < mNumS; i++)
05076                         {
05077                                 average += mVertices[i + mNumS * (mNumT - 1)].mNormal;
05078                         }
05079 
05080                         // set average
05081                         for (S32 i = 0; i < mNumS; i++)
05082                         {
05083                                 mVertices[i + mNumS * (mNumT - 1)].mNormal = average;
05084                         }
05085 
05086                 }
05087 
05088                 
05089                 if (wrap_s)
05090                 {
05091                         for (S32 i = 0; i < mNumT; i++)
05092                         {
05093                                 LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
05094                                 mVertices[mNumS * i].mNormal = norm;
05095                                 mVertices[mNumS * i+mNumS-1].mNormal = norm;
05096                         }
05097                 }
05098 
05099 
05100                 
05101                 if (wrap_t)
05102                 {
05103                         for (S32 i = 0; i < mNumS; i++)
05104                         {
05105                                 LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal;
05106                                 mVertices[i].mNormal = norm;
05107                                 mVertices[mNumS*(mNumT-1)+i].mNormal = norm;
05108                         }
05109                         
05110                 }
05111 
05112         }
05113 
05114         return TRUE;
05115 }
05116 
05117 // Finds binormal based on three vertices with texture coordinates.
05118 // Fills in dummy values if the triangle has degenerate texture coordinates.
05119 LLVector3 calc_binormal_from_triangle( 
05120         const LLVector3& pos0,
05121         const LLVector2& tex0,
05122         const LLVector3& pos1,
05123         const LLVector2& tex1,
05124         const LLVector3& pos2,
05125         const LLVector2& tex2)
05126 {
05127         LLVector3 rx0( pos0.mV[VX], tex0.mV[VX], tex0.mV[VY] );
05128         LLVector3 rx1( pos1.mV[VX], tex1.mV[VX], tex1.mV[VY] );
05129         LLVector3 rx2( pos2.mV[VX], tex2.mV[VX], tex2.mV[VY] );
05130         
05131         LLVector3 ry0( pos0.mV[VY], tex0.mV[VX], tex0.mV[VY] );
05132         LLVector3 ry1( pos1.mV[VY], tex1.mV[VX], tex1.mV[VY] );
05133         LLVector3 ry2( pos2.mV[VY], tex2.mV[VX], tex2.mV[VY] );
05134 
05135         LLVector3 rz0( pos0.mV[VZ], tex0.mV[VX], tex0.mV[VY] );
05136         LLVector3 rz1( pos1.mV[VZ], tex1.mV[VX], tex1.mV[VY] );
05137         LLVector3 rz2( pos2.mV[VZ], tex2.mV[VX], tex2.mV[VY] );
05138         
05139         LLVector3 r0 = (rx0 - rx1) % (rx0 - rx2);
05140         LLVector3 r1 = (ry0 - ry1) % (ry0 - ry2);
05141         LLVector3 r2 = (rz0 - rz1) % (rz0 - rz2);
05142 
05143         if( r0.mV[VX] && r1.mV[VX] && r2.mV[VX] )
05144         {
05145                 LLVector3 binormal(
05146                                 -r0.mV[VZ] / r0.mV[VX],
05147                                 -r1.mV[VZ] / r1.mV[VX],
05148                                 -r2.mV[VZ] / r2.mV[VX]);
05149                 // binormal.normVec();
05150                 return binormal;
05151         }
05152         else
05153         {
05154                 return LLVector3( 0, 1 , 0 );
05155         }
05156 }

Generated on Fri May 16 08:32:17 2008 for SecondLife by  doxygen 1.5.5