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

Generated on Thu Jul 1 06:09:41 2010 for Second Life Viewer by  doxygen 1.4.7