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