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