llvolume.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:130k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llvolume.cpp
  3.  *
  4.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  5.  * 
  6.  * Copyright (c) 2002-2010, Linden Research, Inc.
  7.  * 
  8.  * Second Life Viewer Source Code
  9.  * The source code in this file ("Source Code") is provided by Linden Lab
  10.  * to you under the terms of the GNU General Public License, version 2.0
  11.  * ("GPL"), unless you have obtained a separate licensing agreement
  12.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  13.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  14.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  15.  * 
  16.  * There are special exceptions to the terms and conditions of the GPL as
  17.  * it is applied to this Source Code. View the full text of the exception
  18.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  19.  * online at
  20.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  21.  * 
  22.  * By copying, modifying or distributing this software, you acknowledge
  23.  * that you have read and understood your obligations described above,
  24.  * and agree to abide by those obligations.
  25.  * 
  26.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  27.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  28.  * COMPLETENESS OR PERFORMANCE.
  29.  * $/LicenseInfo$
  30.  */
  31. #include "linden_common.h"
  32. #include "llmath.h"
  33. #include <set>
  34. #include "llerror.h"
  35. #include "llmemtype.h"
  36. #include "llvolumemgr.h"
  37. #include "v2math.h"
  38. #include "v3math.h"
  39. #include "v4math.h"
  40. #include "m4math.h"
  41. #include "m3math.h"
  42. #include "lldarray.h"
  43. #include "llvolume.h"
  44. #include "llstl.h"
  45. #define DEBUG_SILHOUETTE_BINORMALS 0
  46. #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
  47. #define DEBUG_SILHOUETTE_EDGE_MAP 0 // DaveP: Use this to display edge map using the silhouette
  48. const F32 CUT_MIN = 0.f;
  49. const F32 CUT_MAX = 1.f;
  50. const F32 MIN_CUT_DELTA = 0.02f;
  51. const F32 HOLLOW_MIN = 0.f;
  52. const F32 HOLLOW_MAX = 0.95f;
  53. const F32 HOLLOW_MAX_SQUARE = 0.7f;
  54. const F32 TWIST_MIN = -1.f;
  55. const F32 TWIST_MAX =  1.f;
  56. const F32 RATIO_MIN = 0.f;
  57. const F32 RATIO_MAX = 2.f; // Tom Y: Inverted sense here: 0 = top taper, 2 = bottom taper
  58. const F32 HOLE_X_MIN= 0.05f;
  59. const F32 HOLE_X_MAX= 1.0f;
  60. const F32 HOLE_Y_MIN= 0.05f;
  61. const F32 HOLE_Y_MAX= 0.5f;
  62. const F32 SHEAR_MIN = -0.5f;
  63. const F32 SHEAR_MAX =  0.5f;
  64. const F32 REV_MIN = 1.f;
  65. const F32 REV_MAX = 4.f;
  66. const F32 TAPER_MIN = -1.f;
  67. const F32 TAPER_MAX =  1.f;
  68. const F32 SKEW_MIN = -0.95f;
  69. const F32 SKEW_MAX =  0.95f;
  70. const F32 SCULPT_MIN_AREA = 0.002f;
  71. const S32 SCULPT_MIN_AREA_DETAIL = 1;
  72. BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
  73. {    
  74. LLVector3 test = (pt2-pt1)%(pt3-pt2);
  75. //answer
  76. if(test * norm < 0) 
  77. {
  78. return FALSE;
  79. }
  80. else 
  81. {
  82. return TRUE;
  83. }
  84. BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size)
  85. {
  86. float fAWdU[3];
  87. LLVector3 dir;
  88. LLVector3 diff;
  89. for (U32 i = 0; i < 3; i++)
  90. {
  91. dir.mV[i] = 0.5f * (end.mV[i] - start.mV[i]);
  92. diff.mV[i] = (0.5f * (end.mV[i] + start.mV[i])) - center.mV[i];
  93. fAWdU[i] = fabsf(dir.mV[i]);
  94. if(fabsf(diff.mV[i])>size.mV[i] + fAWdU[i]) return false;
  95. }
  96. float f;
  97. f = dir.mV[1] * diff.mV[2] - dir.mV[2] * diff.mV[1];    if(fabsf(f)>size.mV[1]*fAWdU[2] + size.mV[2]*fAWdU[1])  return false;
  98. f = dir.mV[2] * diff.mV[0] - dir.mV[0] * diff.mV[2];    if(fabsf(f)>size.mV[0]*fAWdU[2] + size.mV[2]*fAWdU[0])  return false;
  99. f = dir.mV[0] * diff.mV[1] - dir.mV[1] * diff.mV[0];    if(fabsf(f)>size.mV[0]*fAWdU[1] + size.mV[1]*fAWdU[0])  return false;
  100. return true;
  101. }
  102. // intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir.
  103. // returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b,
  104. // and returns the intersection point along dir in intersection_t.
  105. // Moller-Trumbore algorithm
  106. BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
  107. F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided)
  108. {
  109. F32 u, v, t;
  110. /* find vectors for two edges sharing vert0 */
  111. LLVector3 edge1 = vert1 - vert0;
  112. LLVector3 edge2 = vert2 - vert0;;
  113. /* begin calculating determinant - also used to calculate U parameter */
  114. LLVector3 pvec = dir % edge2;
  115. /* if determinant is near zero, ray lies in plane of triangle */
  116. F32 det = edge1 * pvec;
  117. if (!two_sided)
  118. {
  119. if (det < F_APPROXIMATELY_ZERO)
  120. {
  121. return FALSE;
  122. }
  123. /* calculate distance from vert0 to ray origin */
  124. LLVector3 tvec = orig - vert0;
  125. /* calculate U parameter and test bounds */
  126. u = tvec * pvec;
  127. if (u < 0.f || u > det)
  128. {
  129. return FALSE;
  130. }
  131. /* prepare to test V parameter */
  132. LLVector3 qvec = tvec % edge1;
  133. /* calculate V parameter and test bounds */
  134. v = dir * qvec;
  135. if (v < 0.f || u + v > det)
  136. {
  137. return FALSE;
  138. }
  139. /* calculate t, scale parameters, ray intersects triangle */
  140. t = edge2 * qvec;
  141. F32 inv_det = 1.0 / det;
  142. t *= inv_det;
  143. u *= inv_det;
  144. v *= inv_det;
  145. }
  146. else // two sided
  147. {
  148. if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
  149. {
  150. return FALSE;
  151. }
  152. F32 inv_det = 1.0 / det;
  153. /* calculate distance from vert0 to ray origin */
  154. LLVector3 tvec = orig - vert0;
  155. /* calculate U parameter and test bounds */
  156. u = (tvec * pvec) * inv_det;
  157. if (u < 0.f || u > 1.f)
  158. {
  159. return FALSE;
  160. }
  161. /* prepare to test V parameter */
  162. LLVector3 qvec = tvec - edge1;
  163. /* calculate V parameter and test bounds */
  164. v = (dir * qvec) * inv_det;
  165. if (v < 0.f || u + v > 1.f)
  166. {
  167. return FALSE;
  168. }
  169. /* calculate t, ray intersects triangle */
  170. t = (edge2 * qvec) * inv_det;
  171. }
  172. if (intersection_a != NULL)
  173. *intersection_a = u;
  174. if (intersection_b != NULL)
  175. *intersection_b = v;
  176. if (intersection_t != NULL)
  177. *intersection_t = t;
  178. return TRUE;
  179. //-------------------------------------------------------------------
  180. // statics
  181. //-------------------------------------------------------------------
  182. //----------------------------------------------------
  183. LLProfile::Face* LLProfile::addCap(S16 faceID)
  184. {
  185. LLMemType m1(LLMemType::MTYPE_VOLUME);
  186. Face *face   = vector_append(mFaces, 1);
  187. face->mIndex = 0;
  188. face->mCount = mTotal;
  189. face->mScaleU= 1.0f;
  190. face->mCap   = TRUE;
  191. face->mFaceID = faceID;
  192. return face;
  193. }
  194. LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BOOL flat)
  195. {
  196. LLMemType m1(LLMemType::MTYPE_VOLUME);
  197. Face *face   = vector_append(mFaces, 1);
  198. face->mIndex = i;
  199. face->mCount = count;
  200. face->mScaleU= scaleU;
  201. face->mFlat = flat;
  202. face->mCap   = FALSE;
  203. face->mFaceID = faceID;
  204. return face;
  205. }
  206. // What is the bevel parameter used for? - DJS 04/05/02
  207. // Bevel parameter is currently unused but presumedly would support
  208. // filleted and chamfered corners
  209. void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split)
  210. {
  211. LLMemType m1(LLMemType::MTYPE_VOLUME);
  212. // Generate an n-sided "circular" path.
  213. // 0 is (1,0), and we go counter-clockwise along a circular path from there.
  214. const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f };
  215. F32 scale = 0.5f;
  216. F32 t, t_step, t_first, t_fraction, ang, ang_step;
  217. LLVector3 pt1,pt2;
  218. F32 begin  = params.getBegin();
  219. F32 end    = params.getEnd();
  220. t_step = 1.0f / sides;
  221. ang_step = 2.0f*F_PI*t_step*ang_scale;
  222. // Scale to have size "match" scale.  Compensates to get object to generally fill bounding box.
  223. S32 total_sides = llround(sides / ang_scale); // Total number of sides all around
  224. if (total_sides < 8)
  225. {
  226. scale = tableScale[total_sides];
  227. }
  228. t_first = floor(begin * sides) / (F32)sides;
  229. // pt1 is the first point on the fractional face.
  230. // Starting t and ang values for the first face
  231. t = t_first;
  232. ang = 2.0f*F_PI*(t*ang_scale + offset);
  233. pt1.setVec(cos(ang)*scale,sin(ang)*scale, t);
  234. // Increment to the next point.
  235. // pt2 is the end point on the fractional face
  236. t += t_step;
  237. ang += ang_step;
  238. pt2.setVec(cos(ang)*scale,sin(ang)*scale,t);
  239. t_fraction = (begin - t_first)*sides;
  240. // Only use if it's not almost exactly on an edge.
  241. if (t_fraction < 0.9999f)
  242. {
  243. LLVector3 new_pt = lerp(pt1, pt2, t_fraction);
  244. mProfile.push_back(new_pt);
  245. }
  246. // There's lots of potential here for floating point error to generate unneeded extra points - DJS 04/05/02
  247. while (t < end)
  248. {
  249. // Iterate through all the integer steps of t.
  250. pt1.setVec(cos(ang)*scale,sin(ang)*scale,t);
  251. if (mProfile.size() > 0) {
  252. LLVector3 p = mProfile[mProfile.size()-1];
  253. for (S32 i = 0; i < split && mProfile.size() > 0; i++) {
  254. mProfile.push_back(p+(pt1-p) * 1.0f/(float)(split+1) * (float)(i+1));
  255. }
  256. }
  257. mProfile.push_back(pt1);
  258. t += t_step;
  259. ang += ang_step;
  260. }
  261. t_fraction = (end - (t - t_step))*sides;
  262. // pt1 is the first point on the fractional face
  263. // pt2 is the end point on the fractional face
  264. pt2.setVec(cos(ang)*scale,sin(ang)*scale,t);
  265. // Find the fraction that we need to add to the end point.
  266. t_fraction = (end - (t - t_step))*sides;
  267. if (t_fraction > 0.0001f)
  268. {
  269. LLVector3 new_pt = lerp(pt1, pt2, t_fraction);
  270. if (mProfile.size() > 0) {
  271. LLVector3 p = mProfile[mProfile.size()-1];
  272. for (S32 i = 0; i < split && mProfile.size() > 0; i++) {
  273. mProfile.push_back(p+(new_pt-p) * 1.0f/(float)(split+1) * (float)(i+1));
  274. }
  275. }
  276. mProfile.push_back(new_pt);
  277. }
  278. // If we're sliced, the profile is open.
  279. if ((end - begin)*ang_scale < 0.99f)
  280. {
  281. if ((end - begin)*ang_scale > 0.5f)
  282. {
  283. mConcave = TRUE;
  284. }
  285. else
  286. {
  287. mConcave = FALSE;
  288. }
  289. mOpen = TRUE;
  290. if (params.getHollow() <= 0)
  291. {
  292. // put center point if not hollow.
  293. mProfile.push_back(LLVector3(0,0,0));
  294. }
  295. }
  296. else
  297. {
  298. // The profile isn't open.
  299. mOpen = FALSE;
  300. mConcave = FALSE;
  301. }
  302. mTotal = mProfile.size();
  303. }
  304. void LLProfile::genNormals(const LLProfileParams& params)
  305. {
  306. S32 count = mProfile.size();
  307. S32 outer_count;
  308. if (mTotalOut)
  309. {
  310. outer_count = mTotalOut;
  311. }
  312. else
  313. {
  314. outer_count = mTotal / 2;
  315. }
  316. mEdgeNormals.resize(count * 2);
  317. mEdgeCenters.resize(count * 2);
  318. mNormals.resize(count);
  319. LLVector2 pt0,pt1;
  320. BOOL hollow = (params.getHollow() > 0);
  321. S32 i0, i1, i2, i3, i4;
  322. // Parametrically generate normal
  323. for (i2 = 0; i2 < count; i2++)
  324. {
  325. mNormals[i2].mV[0] = mProfile[i2].mV[0];
  326. mNormals[i2].mV[1] = mProfile[i2].mV[1];
  327. if (hollow && (i2 >= outer_count))
  328. {
  329. mNormals[i2] *= -1.f;
  330. }
  331. if (mNormals[i2].magVec() < 0.001)
  332. {
  333. // Special case for point at center, get adjacent points.
  334. i1 = (i2 - 1) >= 0 ? i2 - 1 : count - 1;
  335. i0 = (i1 - 1) >= 0 ? i1 - 1 : count - 1;
  336. i3 = (i2 + 1) < count ? i2 + 1 : 0;
  337. i4 = (i3 + 1) < count ? i3 + 1 : 0;
  338. pt0.setVec(mProfile[i1].mV[VX] + mProfile[i1].mV[VX] - mProfile[i0].mV[VX], 
  339. mProfile[i1].mV[VY] + mProfile[i1].mV[VY] - mProfile[i0].mV[VY]);
  340. pt1.setVec(mProfile[i3].mV[VX] + mProfile[i3].mV[VX] - mProfile[i4].mV[VX], 
  341. mProfile[i3].mV[VY] + mProfile[i3].mV[VY] - mProfile[i4].mV[VY]);
  342. mNormals[i2] = pt0 + pt1;
  343. mNormals[i2] *= 0.5f;
  344. }
  345. mNormals[i2].normVec();
  346. }
  347. S32 num_normal_sets = isConcave() ? 2 : 1;
  348. for (S32 normal_set = 0; normal_set < num_normal_sets; normal_set++)
  349. {
  350. S32 point_num;
  351. for (point_num = 0; point_num < mTotal; point_num++)
  352. {
  353. LLVector3 point_1 = mProfile[point_num];
  354. point_1.mV[VZ] = 0.f;
  355. LLVector3 point_2;
  356. if (isConcave() && normal_set == 0 && point_num == (mTotal - 1) / 2)
  357. {
  358. point_2 = mProfile[mTotal - 1];
  359. }
  360. else if (isConcave() && normal_set == 1 && point_num == mTotal - 1)
  361. {
  362. point_2 = mProfile[(mTotal - 1) / 2];
  363. }
  364. else
  365. {
  366. LLVector3 delta_pos;
  367. S32 neighbor_point = (point_num + 1) % mTotal;
  368. while(delta_pos.magVecSquared() < 0.01f * 0.01f)
  369. {
  370. point_2 = mProfile[neighbor_point];
  371. delta_pos = point_2 - point_1;
  372. neighbor_point = (neighbor_point + 1) % mTotal;
  373. if (neighbor_point == point_num)
  374. {
  375. break;
  376. }
  377. }
  378. }
  379. point_2.mV[VZ] = 0.f;
  380. LLVector3 face_normal = (point_2 - point_1) % LLVector3::z_axis;
  381. face_normal.normVec();
  382. mEdgeNormals[normal_set * count + point_num] = face_normal;
  383. mEdgeCenters[normal_set * count + point_num] = lerp(point_1, point_2, 0.5f);
  384. }
  385. }
  386. }
  387. // Hollow is percent of the original bounding box, not of this particular
  388. // profile's geometry.  Thus, a swept triangle needs lower hollow values than
  389. // a swept square.
  390. LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split)
  391. {
  392. // Note that addHole will NOT work for non-"circular" profiles, if we ever decide to use them.
  393. // Total add has number of vertices on outside.
  394. mTotalOut = mTotal;
  395. // Why is the "bevel" parameter -1? DJS 04/05/02
  396. genNGon(params, llfloor(sides),offset,-1, ang_scale, split);
  397. Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat);
  398. std::vector<LLVector3> pt;
  399. pt.resize(mTotal) ;
  400. for (S32 i=mTotalOut;i<mTotal;i++)
  401. {
  402. pt[i] = mProfile[i] * box_hollow;
  403. }
  404. S32 j=mTotal-1;
  405. for (S32 i=mTotalOut;i<mTotal;i++)
  406. {
  407. mProfile[i] = pt[j--];
  408. }
  409. for (S32 i=0;i<(S32)mFaces.size();i++) 
  410. {
  411. if (mFaces[i].mCap)
  412. {
  413. mFaces[i].mCount *= 2;
  414. }
  415. }
  416. return face;
  417. }
  418. BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split,
  419.  BOOL is_sculpted, S32 sculpt_size)
  420. {
  421. LLMemType m1(LLMemType::MTYPE_VOLUME);
  422. if ((!mDirty) && (!is_sculpted))
  423. {
  424. return FALSE;
  425. }
  426. mDirty = FALSE;
  427. if (detail < MIN_LOD)
  428. {
  429. llinfos << "Generating profile with LOD < MIN_LOD.  CLAMPING" << llendl;
  430. detail = MIN_LOD;
  431. }
  432. mProfile.clear();
  433. mFaces.clear();
  434. // Generate the face data
  435. S32 i;
  436. F32 begin = params.getBegin();
  437. F32 end = params.getEnd();
  438. F32 hollow = params.getHollow();
  439. // Quick validation to eliminate some server crashes.
  440. if (begin > end - 0.01f)
  441. {
  442. llwarns << "LLProfile::generate() assertion failed (begin >= end)" << llendl;
  443. return FALSE;
  444. }
  445. S32 face_num = 0;
  446. switch (params.getCurveType() & LL_PCODE_PROFILE_MASK)
  447. {
  448. case LL_PCODE_PROFILE_SQUARE:
  449. {
  450. genNGon(params, 4,-0.375, 0, 1, split);
  451. if (path_open)
  452. {
  453. addCap (LL_FACE_PATH_BEGIN);
  454. }
  455. for (i = llfloor(begin * 4.f); i < llfloor(end * 4.f + .999f); i++)
  456. {
  457. addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE);
  458. }
  459. for (i = 0; i <(S32) mProfile.size(); i++)
  460. {
  461. // Scale by 4 to generate proper tex coords.
  462. mProfile[i].mV[2] *= 4.f;
  463. }
  464. if (hollow)
  465. {
  466. switch (params.getCurveType() & LL_PCODE_HOLE_MASK)
  467. {
  468. case LL_PCODE_HOLE_TRIANGLE:
  469. // This offset is not correct, but we can't change it now... DK 11/17/04
  470.    addHole(params, TRUE, 3, -0.375f, hollow, 1.f, split);
  471. break;
  472. case LL_PCODE_HOLE_CIRCLE:
  473. // TODO: Compute actual detail levels for cubes
  474.    addHole(params, FALSE, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f);
  475. break;
  476. case LL_PCODE_HOLE_SAME:
  477. case LL_PCODE_HOLE_SQUARE:
  478. default:
  479. addHole(params, TRUE, 4, -0.375f, hollow, 1.f, split);
  480. break;
  481. }
  482. }
  483. if (path_open) {
  484. mFaces[0].mCount = mTotal;
  485. }
  486. }
  487. break;
  488. case  LL_PCODE_PROFILE_ISOTRI:
  489. case  LL_PCODE_PROFILE_RIGHTTRI:
  490. case  LL_PCODE_PROFILE_EQUALTRI:
  491. {
  492. genNGon(params, 3,0, 0, 1, split);
  493. for (i = 0; i <(S32) mProfile.size(); i++)
  494. {
  495. // Scale by 3 to generate proper tex coords.
  496. mProfile[i].mV[2] *= 3.f;
  497. }
  498. if (path_open)
  499. {
  500. addCap(LL_FACE_PATH_BEGIN);
  501. }
  502. for (i = llfloor(begin * 3.f); i < llfloor(end * 3.f + .999f); i++)
  503. {
  504. addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE);
  505. }
  506. if (hollow)
  507. {
  508. // Swept triangles need smaller hollowness values,
  509. // because the triangle doesn't fill the bounding box.
  510. F32 triangle_hollow = hollow / 2.f;
  511. switch (params.getCurveType() & LL_PCODE_HOLE_MASK)
  512. {
  513. case LL_PCODE_HOLE_CIRCLE:
  514. // TODO: Actually generate level of detail for triangles
  515. addHole(params, FALSE, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f);
  516. break;
  517. case LL_PCODE_HOLE_SQUARE:
  518. addHole(params, TRUE, 4, 0, triangle_hollow, 1.f, split);
  519. break;
  520. case LL_PCODE_HOLE_SAME:
  521. case LL_PCODE_HOLE_TRIANGLE:
  522. default:
  523. addHole(params, TRUE, 3, 0, triangle_hollow, 1.f, split);
  524. break;
  525. }
  526. }
  527. }
  528. break;
  529. case LL_PCODE_PROFILE_CIRCLE:
  530. {
  531. // If this has a square hollow, we should adjust the
  532. // number of faces a bit so that the geometry lines up.
  533. U8 hole_type=0;
  534. F32 circle_detail = MIN_DETAIL_FACES * detail;
  535. if (hollow)
  536. {
  537. hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK;
  538. if (hole_type == LL_PCODE_HOLE_SQUARE)
  539. {
  540. // Snap to the next multiple of four sides,
  541. // so that corners line up.
  542. circle_detail = llceil(circle_detail / 4.0f) * 4.0f;
  543. }
  544. }
  545. S32 sides = (S32)circle_detail;
  546. if (is_sculpted)
  547. sides = sculpt_size;
  548. genNGon(params, sides);
  549. if (path_open)
  550. {
  551. addCap (LL_FACE_PATH_BEGIN);
  552. }
  553. if (mOpen && !hollow)
  554. {
  555. addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE);
  556. }
  557. else
  558. {
  559. addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE);
  560. }
  561. if (hollow)
  562. {
  563. switch (hole_type)
  564. {
  565. case LL_PCODE_HOLE_SQUARE:
  566. addHole(params, TRUE, 4, 0, hollow, 1.f, split);
  567. break;
  568. case LL_PCODE_HOLE_TRIANGLE:
  569. addHole(params, TRUE, 3, 0, hollow, 1.f, split);
  570. break;
  571. case LL_PCODE_HOLE_CIRCLE:
  572. case LL_PCODE_HOLE_SAME:
  573. default:
  574. addHole(params, FALSE, circle_detail, 0, hollow, 1.f);
  575. break;
  576. }
  577. }
  578. }
  579. break;
  580. case LL_PCODE_PROFILE_CIRCLE_HALF:
  581. {
  582. // If this has a square hollow, we should adjust the
  583. // number of faces a bit so that the geometry lines up.
  584. U8 hole_type=0;
  585. // Number of faces is cut in half because it's only a half-circle.
  586. F32 circle_detail = MIN_DETAIL_FACES * detail * 0.5f;
  587. if (hollow)
  588. {
  589. hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK;
  590. if (hole_type == LL_PCODE_HOLE_SQUARE)
  591. {
  592. // Snap to the next multiple of four sides (div 2),
  593. // so that corners line up.
  594. circle_detail = llceil(circle_detail / 2.0f) * 2.0f;
  595. }
  596. }
  597. genNGon(params, llfloor(circle_detail), 0.5f, 0.f, 0.5f);
  598. if (path_open)
  599. {
  600. addCap(LL_FACE_PATH_BEGIN);
  601. }
  602. if (mOpen && !params.getHollow())
  603. {
  604. addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE);
  605. }
  606. else
  607. {
  608. addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE);
  609. }
  610. if (hollow)
  611. {
  612. switch (hole_type)
  613. {
  614. case LL_PCODE_HOLE_SQUARE:
  615. addHole(params, TRUE, 2, 0.5f, hollow, 0.5f, split);
  616. break;
  617. case LL_PCODE_HOLE_TRIANGLE:
  618. addHole(params, TRUE, 3,  0.5f, hollow, 0.5f, split);
  619. break;
  620. case LL_PCODE_HOLE_CIRCLE:
  621. case LL_PCODE_HOLE_SAME:
  622. default:
  623. addHole(params, FALSE, circle_detail,  0.5f, hollow, 0.5f);
  624. break;
  625. }
  626. }
  627. // Special case for openness of sphere
  628. if ((params.getEnd() - params.getBegin()) < 1.f)
  629. {
  630. mOpen = TRUE;
  631. }
  632. else if (!hollow)
  633. {
  634. mOpen = FALSE;
  635. mProfile.push_back(mProfile[0]);
  636. mTotal++;
  637. }
  638. }
  639. break;
  640. default:
  641.     llerrs << "Unknown profile: getCurveType()=" << params.getCurveType() << llendl;
  642. break;
  643. };
  644. if (path_open)
  645. {
  646. addCap(LL_FACE_PATH_END); // bottom
  647. }
  648. if ( mOpen) // interior edge caps
  649. {
  650. addFace(mTotal-1, 2,0.5,LL_FACE_PROFILE_BEGIN, TRUE); 
  651. if (hollow)
  652. {
  653. addFace(mTotalOut-1, 2,0.5,LL_FACE_PROFILE_END, TRUE);
  654. }
  655. else
  656. {
  657. addFace(mTotal-2, 2,0.5,LL_FACE_PROFILE_END, TRUE);
  658. }
  659. }
  660. //genNormals(params);
  661. return TRUE;
  662. }
  663. BOOL LLProfileParams::importFile(LLFILE *fp)
  664. {
  665. LLMemType m1(LLMemType::MTYPE_VOLUME);
  666. const S32 BUFSIZE = 16384;
  667. char buffer[BUFSIZE]; /* Flawfinder: ignore */
  668. // *NOTE: changing the size or type of these buffers will require
  669. // changing the sscanf below.
  670. char keyword[256]; /* Flawfinder: ignore */
  671. char valuestr[256]; /* Flawfinder: ignore */
  672. keyword[0] = 0;
  673. valuestr[0] = 0;
  674. F32 tempF32;
  675. U32 tempU32;
  676. while (!feof(fp))
  677. {
  678. if (fgets(buffer, BUFSIZE, fp) == NULL)
  679. {
  680. buffer[0] = '';
  681. }
  682. sscanf( /* Flawfinder: ignore */
  683. buffer,
  684. " %255s %255s",
  685. keyword, valuestr);
  686. if (!strcmp("{", keyword))
  687. {
  688. continue;
  689. }
  690. if (!strcmp("}",keyword))
  691. {
  692. break;
  693. }
  694. else if (!strcmp("curve", keyword))
  695. {
  696. sscanf(valuestr,"%d",&tempU32);
  697. setCurveType((U8) tempU32);
  698. }
  699. else if (!strcmp("begin",keyword))
  700. {
  701. sscanf(valuestr,"%g",&tempF32);
  702. setBegin(tempF32);
  703. }
  704. else if (!strcmp("end",keyword))
  705. {
  706. sscanf(valuestr,"%g",&tempF32);
  707. setEnd(tempF32);
  708. }
  709. else if (!strcmp("hollow",keyword))
  710. {
  711. sscanf(valuestr,"%g",&tempF32);
  712. setHollow(tempF32);
  713. }
  714. else
  715. {
  716. llwarns << "unknown keyword " << keyword << " in profile import" << llendl;
  717. }
  718. }
  719. return TRUE;
  720. }
  721. BOOL LLProfileParams::exportFile(LLFILE *fp) const
  722. {
  723. fprintf(fp,"ttprofile 0n");
  724. fprintf(fp,"tt{n");
  725. fprintf(fp,"tttcurvet%dn", getCurveType());
  726. fprintf(fp,"tttbegint%gn", getBegin());
  727. fprintf(fp,"tttendt%gn", getEnd());
  728. fprintf(fp,"ttthollowt%gn", getHollow());
  729. fprintf(fp, "tt}n");
  730. return TRUE;
  731. }
  732. BOOL LLProfileParams::importLegacyStream(std::istream& input_stream)
  733. {
  734. LLMemType m1(LLMemType::MTYPE_VOLUME);
  735. const S32 BUFSIZE = 16384;
  736. char buffer[BUFSIZE]; /* Flawfinder: ignore */
  737. // *NOTE: changing the size or type of these buffers will require
  738. // changing the sscanf below.
  739. char keyword[256]; /* Flawfinder: ignore */
  740. char valuestr[256]; /* Flawfinder: ignore */
  741. keyword[0] = 0;
  742. valuestr[0] = 0;
  743. F32 tempF32;
  744. U32 tempU32;
  745. while (input_stream.good())
  746. {
  747. input_stream.getline(buffer, BUFSIZE);
  748. sscanf( /* Flawfinder: ignore */
  749. buffer,
  750. " %255s %255s",
  751. keyword,
  752. valuestr);
  753. if (!strcmp("{", keyword))
  754. {
  755. continue;
  756. }
  757. if (!strcmp("}",keyword))
  758. {
  759. break;
  760. }
  761. else if (!strcmp("curve", keyword))
  762. {
  763. sscanf(valuestr,"%d",&tempU32);
  764. setCurveType((U8) tempU32);
  765. }
  766. else if (!strcmp("begin",keyword))
  767. {
  768. sscanf(valuestr,"%g",&tempF32);
  769. setBegin(tempF32);
  770. }
  771. else if (!strcmp("end",keyword))
  772. {
  773. sscanf(valuestr,"%g",&tempF32);
  774. setEnd(tempF32);
  775. }
  776. else if (!strcmp("hollow",keyword))
  777. {
  778. sscanf(valuestr,"%g",&tempF32);
  779. setHollow(tempF32);
  780. }
  781. else
  782. {
  783.   llwarns << "unknown keyword " << keyword << " in profile import" << llendl;
  784. }
  785. }
  786. return TRUE;
  787. }
  788. BOOL LLProfileParams::exportLegacyStream(std::ostream& output_stream) const
  789. {
  790. output_stream <<"ttprofile 0n";
  791. output_stream <<"tt{n";
  792. output_stream <<"tttcurvet" << (S32) getCurveType() << "n";
  793. output_stream <<"tttbegint" << getBegin() << "n";
  794. output_stream <<"tttendt" << getEnd() << "n";
  795. output_stream <<"ttthollowt" << getHollow() << "n";
  796. output_stream << "tt}n";
  797. return TRUE;
  798. }
  799. LLSD LLProfileParams::asLLSD() const
  800. {
  801. LLSD sd;
  802. sd["curve"] = getCurveType();
  803. sd["begin"] = getBegin();
  804. sd["end"] = getEnd();
  805. sd["hollow"] = getHollow();
  806. return sd;
  807. }
  808. bool LLProfileParams::fromLLSD(LLSD& sd)
  809. {
  810. setCurveType(sd["curve"].asInteger());
  811. setBegin((F32)sd["begin"].asReal());
  812. setEnd((F32)sd["end"].asReal());
  813. setHollow((F32)sd["hollow"].asReal());
  814. return true;
  815. }
  816. void LLProfileParams::copyParams(const LLProfileParams &params)
  817. {
  818. LLMemType m1(LLMemType::MTYPE_VOLUME);
  819. setCurveType(params.getCurveType());
  820. setBegin(params.getBegin());
  821. setEnd(params.getEnd());
  822. setHollow(params.getHollow());
  823. }
  824. LLPath::~LLPath()
  825. {
  826. }
  827. void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale)
  828. {
  829. // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane.
  830. const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f };
  831. F32 revolutions = params.getRevolutions();
  832. F32 skew = params.getSkew();
  833. F32 skew_mag = fabs(skew);
  834. F32 hole_x = params.getScaleX() * (1.0f - skew_mag);
  835. F32 hole_y = params.getScaleY();
  836. // Calculate taper begin/end for x,y (Negative means taper the beginning)
  837. F32 taper_x_begin = 1.0f;
  838. F32 taper_x_end = 1.0f - params.getTaperX();
  839. F32 taper_y_begin = 1.0f;
  840. F32 taper_y_end = 1.0f - params.getTaperY();
  841. if ( taper_x_end > 1.0f )
  842. {
  843. // Flip tapering.
  844. taper_x_begin = 2.0f - taper_x_end;
  845. taper_x_end = 1.0f;
  846. }
  847. if ( taper_y_end > 1.0f )
  848. {
  849. // Flip tapering.
  850. taper_y_begin = 2.0f - taper_y_end;
  851. taper_y_end = 1.0f;
  852. }
  853. // For spheres, the radius is usually zero.
  854. F32 radius_start = 0.5f;
  855. if (sides < 8)
  856. {
  857. radius_start = tableScale[sides];
  858. }
  859. // Scale the radius to take the hole size into account.
  860. radius_start *= 1.0f - hole_y;
  861. // Now check the radius offset to calculate the start,end radius.  (Negative means
  862. // decrease the start radius instead).
  863. F32 radius_end    = radius_start;
  864. F32 radius_offset = params.getRadiusOffset();
  865. if (radius_offset < 0.f)
  866. {
  867. radius_start *= 1.f + radius_offset;
  868. }
  869. else
  870. {
  871. radius_end   *= 1.f - radius_offset;
  872. }
  873. // Is the path NOT a closed loop?
  874. mOpen = ( (params.getEnd()*end_scale - params.getBegin() < 1.0f) ||
  875.       (skew_mag > 0.001f) ||
  876.   (fabs(taper_x_end - taper_x_begin) > 0.001f) ||
  877.   (fabs(taper_y_end - taper_y_begin) > 0.001f) ||
  878.   (fabs(radius_end - radius_start) > 0.001f) );
  879. F32 ang, c, s;
  880. LLQuaternion twist, qang;
  881. PathPt *pt;
  882. LLVector3 path_axis (1.f, 0.f, 0.f);
  883. //LLVector3 twist_axis(0.f, 0.f, 1.f);
  884. F32 twist_begin = params.getTwistBegin() * twist_scale;
  885. F32 twist_end = params.getTwist() * twist_scale;
  886. // We run through this once before the main loop, to make sure
  887. // the path begins at the correct cut.
  888. F32 step= 1.0f / sides;
  889. F32 t = params.getBegin();
  890. pt = vector_append(mPath, 1);
  891. ang = 2.0f*F_PI*revolutions * t;
  892. s = sin(ang)*lerp(radius_start, radius_end, t);
  893. c = cos(ang)*lerp(radius_start, radius_end, t);
  894. pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s)
  895.   + lerp(-skew ,skew, t) * 0.5f,
  896. c + lerp(0,params.getShear().mV[1],s), 
  897. s);
  898. pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
  899. pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
  900. pt->mTexT  = t;
  901. // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
  902. twist.setQuat  (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
  903. // Rotate the point around the circle's center.
  904. qang.setQuat   (ang,path_axis);
  905. pt->mRot   = twist * qang;
  906. t+=step;
  907. // Snap to a quantized parameter, so that cut does not
  908. // affect most sample points.
  909. t = ((S32)(t * sides)) / (F32)sides;
  910. // Run through the non-cut dependent points.
  911. while (t < params.getEnd())
  912. {
  913. pt = vector_append(mPath, 1);
  914. ang = 2.0f*F_PI*revolutions * t;
  915. c   = cos(ang)*lerp(radius_start, radius_end, t);
  916. s   = sin(ang)*lerp(radius_start, radius_end, t);
  917. pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s)
  918.       + lerp(-skew ,skew, t) * 0.5f,
  919. c + lerp(0,params.getShear().mV[1],s), 
  920. s);
  921. pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
  922. pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
  923. pt->mTexT  = t;
  924. // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
  925. twist.setQuat  (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
  926. // Rotate the point around the circle's center.
  927. qang.setQuat   (ang,path_axis);
  928. pt->mRot = twist * qang;
  929. t+=step;
  930. }
  931. // Make one final pass for the end cut.
  932. t = params.getEnd();
  933. pt = vector_append(mPath, 1);
  934. ang = 2.0f*F_PI*revolutions * t;
  935. c   = cos(ang)*lerp(radius_start, radius_end, t);
  936. s   = sin(ang)*lerp(radius_start, radius_end, t);
  937. pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s)
  938.   + lerp(-skew ,skew, t) * 0.5f,
  939. c + lerp(0,params.getShear().mV[1],s), 
  940. s);
  941. pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
  942. pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
  943. pt->mTexT  = t;
  944. // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
  945. twist.setQuat  (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
  946. // Rotate the point around the circle's center.
  947. qang.setQuat   (ang,path_axis);
  948. pt->mRot   = twist * qang;
  949. mTotal = mPath.size();
  950. }
  951. const LLVector2 LLPathParams::getBeginScale() const
  952. {
  953. LLVector2 begin_scale(1.f, 1.f);
  954. if (getScaleX() > 1)
  955. {
  956. begin_scale.mV[0] = 2-getScaleX();
  957. }
  958. if (getScaleY() > 1)
  959. {
  960. begin_scale.mV[1] = 2-getScaleY();
  961. }
  962. return begin_scale;
  963. }
  964. const LLVector2 LLPathParams::getEndScale() const
  965. {
  966. LLVector2 end_scale(1.f, 1.f);
  967. if (getScaleX() < 1)
  968. {
  969. end_scale.mV[0] = getScaleX();
  970. }
  971. if (getScaleY() < 1)
  972. {
  973. end_scale.mV[1] = getScaleY();
  974. }
  975. return end_scale;
  976. }
  977. BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split,
  978.   BOOL is_sculpted, S32 sculpt_size)
  979. {
  980. LLMemType m1(LLMemType::MTYPE_VOLUME);
  981. if ((!mDirty) && (!is_sculpted))
  982. {
  983. return FALSE;
  984. }
  985. if (detail < MIN_LOD)
  986. {
  987. llinfos << "Generating path with LOD < MIN!  Clamping to 1" << llendl;
  988. detail = MIN_LOD;
  989. }
  990. mDirty = FALSE;
  991. S32 np = 2; // hardcode for line
  992. mPath.clear();
  993. mOpen = TRUE;
  994. // Is this 0xf0 mask really necessary?  DK 03/02/05
  995. switch (params.getCurveType() & 0xf0)
  996. {
  997. default:
  998. case LL_PCODE_PATH_LINE:
  999. {
  1000. // Take the begin/end twist into account for detail.
  1001. np    = llfloor(fabs(params.getTwistBegin() - params.getTwist()) * 3.5f * (detail-0.5f)) + 2;
  1002. if (np < split+2)
  1003. {
  1004. np = split+2;
  1005. }
  1006. mStep = 1.0f / (np-1);
  1007. mPath.resize(np);
  1008. LLVector2 start_scale = params.getBeginScale();
  1009. LLVector2 end_scale = params.getEndScale();
  1010. for (S32 i=0;i<np;i++)
  1011. {
  1012. F32 t = lerp(params.getBegin(),params.getEnd(),(F32)i * mStep);
  1013. mPath[i].mPos.setVec(lerp(0,params.getShear().mV[0],t),
  1014.  lerp(0,params.getShear().mV[1],t),
  1015.  t - 0.5f);
  1016. mPath[i].mRot.setQuat(lerp(F_PI * params.getTwistBegin(),F_PI * params.getTwist(),t),0,0,1);
  1017. mPath[i].mScale.mV[0] = lerp(start_scale.mV[0],end_scale.mV[0],t);
  1018. mPath[i].mScale.mV[1] = lerp(start_scale.mV[1],end_scale.mV[1],t);
  1019. mPath[i].mTexT        = t;
  1020. }
  1021. }
  1022. break;
  1023. case LL_PCODE_PATH_CIRCLE:
  1024. {
  1025. // Increase the detail as the revolutions and twist increase.
  1026. F32 twist_mag = fabs(params.getTwistBegin() - params.getTwist());
  1027. S32 sides = (S32)llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * params.getRevolutions());
  1028. if (is_sculpted)
  1029. sides = sculpt_size;
  1030. genNGon(params, sides);
  1031. }
  1032. break;
  1033. case LL_PCODE_PATH_CIRCLE2:
  1034. {
  1035. if (params.getEnd() - params.getBegin() >= 0.99f &&
  1036. params.getScaleX() >= .99f)
  1037. {
  1038. mOpen = FALSE;
  1039. }
  1040. //genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f);
  1041. genNGon(params, llfloor(MIN_DETAIL_FACES * detail));
  1042. F32 t     = 0.f;
  1043. F32 tStep = 1.0f / mPath.size();
  1044. F32 toggle = 0.5f;
  1045. for (S32 i=0;i<(S32)mPath.size();i++)
  1046. {
  1047. mPath[i].mPos.mV[0] = toggle;
  1048. if (toggle == 0.5f)
  1049. toggle = -0.5f;
  1050. else
  1051. toggle = 0.5f;
  1052. t += tStep;
  1053. }
  1054. }
  1055. break;
  1056. case LL_PCODE_PATH_TEST:
  1057. np     = 5;
  1058. mStep = 1.0f / (np-1);
  1059. mPath.resize(np);
  1060. for (S32 i=0;i<np;i++)
  1061. {
  1062. F32 t = (F32)i * mStep;
  1063. mPath[i].mPos.setVec(0,
  1064. lerp(0,   -sin(F_PI*params.getTwist()*t)*0.5f,t),
  1065. lerp(-0.5, cos(F_PI*params.getTwist()*t)*0.5f,t));
  1066. mPath[i].mScale.mV[0] = lerp(1,params.getScale().mV[0],t);
  1067. mPath[i].mScale.mV[1] = lerp(1,params.getScale().mV[1],t);
  1068. mPath[i].mTexT  = t;
  1069. mPath[i].mRot.setQuat(F_PI * params.getTwist() * t,1,0,0);
  1070. }
  1071. break;
  1072. };
  1073. if (params.getTwist() != params.getTwistBegin()) mOpen = TRUE;
  1074. //if ((int(fabsf(params.getTwist() - params.getTwistBegin())*100))%100 != 0) {
  1075. // mOpen = TRUE;
  1076. //}
  1077. return TRUE;
  1078. }
  1079. BOOL LLDynamicPath::generate(const LLPathParams& params, F32 detail, S32 split,
  1080.  BOOL is_sculpted, S32 sculpt_size)
  1081. {
  1082. LLMemType m1(LLMemType::MTYPE_VOLUME);
  1083. mOpen = TRUE; // Draw end caps
  1084. if (getPathLength() == 0)
  1085. {
  1086. // Path hasn't been generated yet.
  1087. // Some algorithms later assume at least TWO path points.
  1088. resizePath(2);
  1089. for (U32 i = 0; i < 2; i++)
  1090. {
  1091. mPath[i].mPos.setVec(0, 0, 0);
  1092. mPath[i].mRot.setQuat(0, 0, 0);
  1093. mPath[i].mScale.setVec(1, 1);
  1094. mPath[i].mTexT = 0;
  1095. }
  1096. }
  1097. return TRUE;
  1098. }
  1099. BOOL LLPathParams::importFile(LLFILE *fp)
  1100. {
  1101. LLMemType m1(LLMemType::MTYPE_VOLUME);
  1102. const S32 BUFSIZE = 16384;
  1103. char buffer[BUFSIZE]; /* Flawfinder: ignore */
  1104. // *NOTE: changing the size or type of these buffers will require
  1105. // changing the sscanf below.
  1106. char keyword[256]; /* Flawfinder: ignore */
  1107. char valuestr[256]; /* Flawfinder: ignore */
  1108. keyword[0] = 0;
  1109. valuestr[0] = 0;
  1110. F32 tempF32;
  1111. F32 x, y;
  1112. U32 tempU32;
  1113. while (!feof(fp))
  1114. {
  1115. if (fgets(buffer, BUFSIZE, fp) == NULL)
  1116. {
  1117. buffer[0] = '';
  1118. }
  1119. sscanf( /* Flawfinder: ignore */
  1120. buffer,
  1121. " %255s %255s",
  1122. keyword, valuestr);
  1123. if (!strcmp("{", keyword))
  1124. {
  1125. continue;
  1126. }
  1127. if (!strcmp("}",keyword))
  1128. {
  1129. break;
  1130. }
  1131. else if (!strcmp("curve", keyword))
  1132. {
  1133. sscanf(valuestr,"%d",&tempU32);
  1134. setCurveType((U8) tempU32);
  1135. }
  1136. else if (!strcmp("begin",keyword))
  1137. {
  1138. sscanf(valuestr,"%g",&tempF32);
  1139. setBegin(tempF32);
  1140. }
  1141. else if (!strcmp("end",keyword))
  1142. {
  1143. sscanf(valuestr,"%g",&tempF32);
  1144. setEnd(tempF32);
  1145. }
  1146. else if (!strcmp("scale",keyword))
  1147. {
  1148. // Legacy for one dimensional scale per path
  1149. sscanf(valuestr,"%g",&tempF32);
  1150. setScale(tempF32, tempF32);
  1151. }
  1152. else if (!strcmp("scale_x", keyword))
  1153. {
  1154. sscanf(valuestr, "%g", &x);
  1155. setScaleX(x);
  1156. }
  1157. else if (!strcmp("scale_y", keyword))
  1158. {
  1159. sscanf(valuestr, "%g", &y);
  1160. setScaleY(y);
  1161. }
  1162. else if (!strcmp("shear_x", keyword))
  1163. {
  1164. sscanf(valuestr, "%g", &x);
  1165. setShearX(x);
  1166. }
  1167. else if (!strcmp("shear_y", keyword))
  1168. {
  1169. sscanf(valuestr, "%g", &y);
  1170. setShearY(y);
  1171. }
  1172. else if (!strcmp("twist",keyword))
  1173. {
  1174. sscanf(valuestr,"%g",&tempF32);
  1175. setTwist(tempF32);
  1176. }
  1177. else if (!strcmp("twist_begin", keyword))
  1178. {
  1179. sscanf(valuestr, "%g", &y);
  1180. setTwistBegin(y);
  1181. }
  1182. else if (!strcmp("radius_offset", keyword))
  1183. {
  1184. sscanf(valuestr, "%g", &y);
  1185. setRadiusOffset(y);
  1186. }
  1187. else if (!strcmp("taper_x", keyword))
  1188. {
  1189. sscanf(valuestr, "%g", &y);
  1190. setTaperX(y);
  1191. }
  1192. else if (!strcmp("taper_y", keyword))
  1193. {
  1194. sscanf(valuestr, "%g", &y);
  1195. setTaperY(y);
  1196. }
  1197. else if (!strcmp("revolutions", keyword))
  1198. {
  1199. sscanf(valuestr, "%g", &y);
  1200. setRevolutions(y);
  1201. }
  1202. else if (!strcmp("skew", keyword))
  1203. {
  1204. sscanf(valuestr, "%g", &y);
  1205. setSkew(y);
  1206. }
  1207. else
  1208. {
  1209. llwarns << "unknown keyword " << " in path import" << llendl;
  1210. }
  1211. }
  1212. return TRUE;
  1213. }
  1214. BOOL LLPathParams::exportFile(LLFILE *fp) const
  1215. {
  1216. fprintf(fp, "ttpath 0n");
  1217. fprintf(fp, "tt{n");
  1218. fprintf(fp, "tttcurvet%dn", getCurveType());
  1219. fprintf(fp, "tttbegint%gn", getBegin());
  1220. fprintf(fp, "tttendt%gn", getEnd());
  1221. fprintf(fp, "tttscale_xt%gn", getScaleX() );
  1222. fprintf(fp, "tttscale_yt%gn", getScaleY() );
  1223. fprintf(fp, "tttshear_xt%gn", getShearX() );
  1224. fprintf(fp, "tttshear_yt%gn", getShearY() );
  1225. fprintf(fp,"ttttwistt%gn", getTwist());
  1226. fprintf(fp,"ttttwist_begint%gn", getTwistBegin());
  1227. fprintf(fp,"tttradius_offsett%gn", getRadiusOffset());
  1228. fprintf(fp,"ttttaper_xt%gn", getTaperX());
  1229. fprintf(fp,"ttttaper_yt%gn", getTaperY());
  1230. fprintf(fp,"tttrevolutionst%gn", getRevolutions());
  1231. fprintf(fp,"tttskewt%gn", getSkew());
  1232. fprintf(fp, "tt}n");
  1233. return TRUE;
  1234. }
  1235. BOOL LLPathParams::importLegacyStream(std::istream& input_stream)
  1236. {
  1237. LLMemType m1(LLMemType::MTYPE_VOLUME);
  1238. const S32 BUFSIZE = 16384;
  1239. char buffer[BUFSIZE]; /* Flawfinder: ignore */
  1240. // *NOTE: changing the size or type of these buffers will require
  1241. // changing the sscanf below.
  1242. char keyword[256]; /* Flawfinder: ignore */
  1243. char valuestr[256]; /* Flawfinder: ignore */
  1244. keyword[0] = 0;
  1245. valuestr[0] = 0;
  1246. F32 tempF32;
  1247. F32 x, y;
  1248. U32 tempU32;
  1249. while (input_stream.good())
  1250. {
  1251. input_stream.getline(buffer, BUFSIZE);
  1252. sscanf( /* Flawfinder: ignore */
  1253. buffer,
  1254. " %255s %255s",
  1255. keyword, valuestr);
  1256. if (!strcmp("{", keyword))
  1257. {
  1258. continue;
  1259. }
  1260. if (!strcmp("}",keyword))
  1261. {
  1262. break;
  1263. }
  1264. else if (!strcmp("curve", keyword))
  1265. {
  1266. sscanf(valuestr,"%d",&tempU32);
  1267. setCurveType((U8) tempU32);
  1268. }
  1269. else if (!strcmp("begin",keyword))
  1270. {
  1271. sscanf(valuestr,"%g",&tempF32);
  1272. setBegin(tempF32);
  1273. }
  1274. else if (!strcmp("end",keyword))
  1275. {
  1276. sscanf(valuestr,"%g",&tempF32);
  1277. setEnd(tempF32);
  1278. }
  1279. else if (!strcmp("scale",keyword))
  1280. {
  1281. // Legacy for one dimensional scale per path
  1282. sscanf(valuestr,"%g",&tempF32);
  1283. setScale(tempF32, tempF32);
  1284. }
  1285. else if (!strcmp("scale_x", keyword))
  1286. {
  1287. sscanf(valuestr, "%g", &x);
  1288. setScaleX(x);
  1289. }
  1290. else if (!strcmp("scale_y", keyword))
  1291. {
  1292. sscanf(valuestr, "%g", &y);
  1293. setScaleY(y);
  1294. }
  1295. else if (!strcmp("shear_x", keyword))
  1296. {
  1297. sscanf(valuestr, "%g", &x);
  1298. setShearX(x);
  1299. }
  1300. else if (!strcmp("shear_y", keyword))
  1301. {
  1302. sscanf(valuestr, "%g", &y);
  1303. setShearY(y);
  1304. }
  1305. else if (!strcmp("twist",keyword))
  1306. {
  1307. sscanf(valuestr,"%g",&tempF32);
  1308. setTwist(tempF32);
  1309. }
  1310. else if (!strcmp("twist_begin", keyword))
  1311. {
  1312. sscanf(valuestr, "%g", &y);
  1313. setTwistBegin(y);
  1314. }
  1315. else if (!strcmp("radius_offset", keyword))
  1316. {
  1317. sscanf(valuestr, "%g", &y);
  1318. setRadiusOffset(y);
  1319. }
  1320. else if (!strcmp("taper_x", keyword))
  1321. {
  1322. sscanf(valuestr, "%g", &y);
  1323. setTaperX(y);
  1324. }
  1325. else if (!strcmp("taper_y", keyword))
  1326. {
  1327. sscanf(valuestr, "%g", &y);
  1328. setTaperY(y);
  1329. }
  1330. else if (!strcmp("revolutions", keyword))
  1331. {
  1332. sscanf(valuestr, "%g", &y);
  1333. setRevolutions(y);
  1334. }
  1335. else if (!strcmp("skew", keyword))
  1336. {
  1337. sscanf(valuestr, "%g", &y);
  1338. setSkew(y);
  1339. }
  1340. else
  1341. {
  1342. llwarns << "unknown keyword " << " in path import" << llendl;
  1343. }
  1344. }
  1345. return TRUE;
  1346. }
  1347. BOOL LLPathParams::exportLegacyStream(std::ostream& output_stream) const
  1348. {
  1349. output_stream << "ttpath 0n";
  1350. output_stream << "tt{n";
  1351. output_stream << "tttcurvet" << (S32) getCurveType() << "n";
  1352. output_stream << "tttbegint" << getBegin() << "n";
  1353. output_stream << "tttendt" << getEnd() << "n";
  1354. output_stream << "tttscale_xt" << getScaleX()  << "n";
  1355. output_stream << "tttscale_yt" << getScaleY()  << "n";
  1356. output_stream << "tttshear_xt" << getShearX()  << "n";
  1357. output_stream << "tttshear_yt" << getShearY()  << "n";
  1358. output_stream <<"ttttwistt" << getTwist() << "n";
  1359. output_stream <<"ttttwist_begint" << getTwistBegin() << "n";
  1360. output_stream <<"tttradius_offsett" << getRadiusOffset() << "n";
  1361. output_stream <<"ttttaper_xt" << getTaperX() << "n";
  1362. output_stream <<"ttttaper_yt" << getTaperY() << "n";
  1363. output_stream <<"tttrevolutionst" << getRevolutions() << "n";
  1364. output_stream <<"tttskewt" << getSkew() << "n";
  1365. output_stream << "tt}n";
  1366. return TRUE;
  1367. }
  1368. LLSD LLPathParams::asLLSD() const
  1369. {
  1370. LLSD sd = LLSD();
  1371. sd["curve"] = getCurveType();
  1372. sd["begin"] = getBegin();
  1373. sd["end"] = getEnd();
  1374. sd["scale_x"] = getScaleX();
  1375. sd["scale_y"] = getScaleY();
  1376. sd["shear_x"] = getShearX();
  1377. sd["shear_y"] = getShearY();
  1378. sd["twist"] = getTwist();
  1379. sd["twist_begin"] = getTwistBegin();
  1380. sd["radius_offset"] = getRadiusOffset();
  1381. sd["taper_x"] = getTaperX();
  1382. sd["taper_y"] = getTaperY();
  1383. sd["revolutions"] = getRevolutions();
  1384. sd["skew"] = getSkew();
  1385. return sd;
  1386. }
  1387. bool LLPathParams::fromLLSD(LLSD& sd)
  1388. {
  1389. setCurveType(sd["curve"].asInteger());
  1390. setBegin((F32)sd["begin"].asReal());
  1391. setEnd((F32)sd["end"].asReal());
  1392. setScaleX((F32)sd["scale_x"].asReal());
  1393. setScaleY((F32)sd["scale_y"].asReal());
  1394. setShearX((F32)sd["shear_x"].asReal());
  1395. setShearY((F32)sd["shear_y"].asReal());
  1396. setTwist((F32)sd["twist"].asReal());
  1397. setTwistBegin((F32)sd["twist_begin"].asReal());
  1398. setRadiusOffset((F32)sd["radius_offset"].asReal());
  1399. setTaperX((F32)sd["taper_x"].asReal());
  1400. setTaperY((F32)sd["taper_y"].asReal());
  1401. setRevolutions((F32)sd["revolutions"].asReal());
  1402. setSkew((F32)sd["skew"].asReal());
  1403. return true;
  1404. }
  1405. void LLPathParams::copyParams(const LLPathParams &params)
  1406. {
  1407. setCurveType(params.getCurveType());
  1408. setBegin(params.getBegin());
  1409. setEnd(params.getEnd());
  1410. setScale(params.getScaleX(), params.getScaleY() );
  1411. setShear(params.getShearX(), params.getShearY() );
  1412. setTwist(params.getTwist());
  1413. setTwistBegin(params.getTwistBegin());
  1414. setRadiusOffset(params.getRadiusOffset());
  1415. setTaper( params.getTaperX(), params.getTaperY() );
  1416. setRevolutions(params.getRevolutions());
  1417. setSkew(params.getSkew());
  1418. }
  1419. S32 profile_delete_lock = 1 ; 
  1420. LLProfile::~LLProfile()
  1421. {
  1422. if(profile_delete_lock)
  1423. {
  1424. llerrs << "LLProfile should not be deleted here!" << llendl ;
  1425. }
  1426. }
  1427. S32 LLVolume::sNumMeshPoints = 0;
  1428. LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL generate_single_face, const BOOL is_unique)
  1429. : mParams(params)
  1430. {
  1431. LLMemType m1(LLMemType::MTYPE_VOLUME);
  1432. mUnique = is_unique;
  1433. mFaceMask = 0x0;
  1434. mDetail = detail;
  1435. mSculptLevel = -2;
  1436. // set defaults
  1437. if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
  1438. {
  1439. mPathp = new LLDynamicPath();
  1440. }
  1441. else
  1442. {
  1443. mPathp = new LLPath();
  1444. }
  1445. mProfilep = new LLProfile();
  1446. mGenerateSingleFace = generate_single_face;
  1447. generate();
  1448. if (mParams.getSculptID().isNull())
  1449. {
  1450. createVolumeFaces();
  1451. }
  1452. }
  1453. void LLVolume::resizePath(S32 length)
  1454. {
  1455. mPathp->resizePath(length);
  1456. mVolumeFaces.clear();
  1457. }
  1458. void LLVolume::regen()
  1459. {
  1460. generate();
  1461. createVolumeFaces();
  1462. }
  1463. void LLVolume::genBinormals(S32 face)
  1464. {
  1465. mVolumeFaces[face].createBinormals();
  1466. }
  1467. LLVolume::~LLVolume()
  1468. {
  1469. sNumMeshPoints -= mMesh.size();
  1470. delete mPathp;
  1471. profile_delete_lock = 0 ;
  1472. delete mProfilep;
  1473. profile_delete_lock = 1 ;
  1474. mPathp = NULL;
  1475. mProfilep = NULL;
  1476. mVolumeFaces.clear();
  1477. }
  1478. BOOL LLVolume::generate()
  1479. {
  1480. LLMemType m1(LLMemType::MTYPE_VOLUME);
  1481. llassert_always(mProfilep);
  1482. //Added 10.03.05 Dave Parks
  1483. // Split is a parameter to LLProfile::generate that tesselates edges on the profile 
  1484. // to prevent lighting and texture interpolation errors on triangles that are 
  1485. // stretched due to twisting or scaling on the path.  
  1486. S32 split = (S32) ((mDetail)*0.66f);
  1487. if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_LINE &&
  1488. (mParams.getPathParams().getScale().mV[0] != 1.0f ||
  1489.  mParams.getPathParams().getScale().mV[1] != 1.0f) &&
  1490. (mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_SQUARE ||
  1491.  mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_ISOTRI ||
  1492.  mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_EQUALTRI ||
  1493.  mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_RIGHTTRI))
  1494. {
  1495. split = 0;
  1496. }
  1497.  
  1498. mLODScaleBias.setVec(0.5f, 0.5f, 0.5f);
  1499. F32 profile_detail = mDetail;
  1500. F32 path_detail = mDetail;
  1501. U8 path_type = mParams.getPathParams().getCurveType();
  1502. U8 profile_type = mParams.getProfileParams().getCurveType();
  1503. if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE)
  1504. { //cylinders don't care about Z-Axis
  1505. mLODScaleBias.setVec(0.6f, 0.6f, 0.0f);
  1506. }
  1507. else if (path_type == LL_PCODE_PATH_CIRCLE) 
  1508. {
  1509. mLODScaleBias.setVec(0.6f, 0.6f, 0.6f);
  1510. }
  1511. //********************************************************************
  1512. //debug info, to be removed
  1513. if((U32)(mPathp->mPath.size() * mProfilep->mProfile.size()) > (1u << 20))
  1514. {
  1515. llinfos << "sizeS: " << mPathp->mPath.size() << " sizeT: " << mProfilep->mProfile.size() << llendl ;
  1516. llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ;
  1517. llinfos << mParams << llendl ;
  1518. llinfos << "more info to check if mProfilep is deleted or not." << llendl ;
  1519. llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ;
  1520. llerrs << "LLVolume corrupted!" << llendl ;
  1521. }
  1522. //********************************************************************
  1523. BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split);
  1524. BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split);
  1525. if (regenPath || regenProf ) 
  1526. {
  1527. S32 sizeS = mPathp->mPath.size();
  1528. S32 sizeT = mProfilep->mProfile.size();
  1529. //********************************************************************
  1530. //debug info, to be removed
  1531. if((U32)(sizeS * sizeT) > (1u << 20))
  1532. {
  1533. llinfos << "regenPath: " << (S32)regenPath << " regenProf: " << (S32)regenProf << llendl ;
  1534. llinfos << "sizeS: " << sizeS << " sizeT: " << sizeT << llendl ;
  1535. llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ;
  1536. llinfos << mParams << llendl ;
  1537. llinfos << "more info to check if mProfilep is deleted or not." << llendl ;
  1538. llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ;
  1539. llerrs << "LLVolume corrupted!" << llendl ;
  1540. }
  1541. //********************************************************************
  1542. sNumMeshPoints -= mMesh.size();
  1543. mMesh.resize(sizeT * sizeS);
  1544. sNumMeshPoints += mMesh.size();
  1545. //generate vertex positions
  1546. // Run along the path.
  1547. for (S32 s = 0; s < sizeS; ++s)
  1548. {
  1549. LLVector2  scale = mPathp->mPath[s].mScale;
  1550. LLQuaternion rot = mPathp->mPath[s].mRot;
  1551. // Run along the profile.
  1552. for (S32 t = 0; t < sizeT; ++t)
  1553. {
  1554. S32 m = s*sizeT + t;
  1555. Point& pt = mMesh[m];
  1556. pt.mPos.mV[0] = mProfilep->mProfile[t].mV[0] * scale.mV[0];
  1557. pt.mPos.mV[1] = mProfilep->mProfile[t].mV[1] * scale.mV[1];
  1558. pt.mPos.mV[2] = 0.0f;
  1559. pt.mPos       = pt.mPos * rot;
  1560. pt.mPos      += mPathp->mPath[s].mPos;
  1561. }
  1562. }
  1563. for (std::vector<LLProfile::Face>::iterator iter = mProfilep->mFaces.begin();
  1564.  iter != mProfilep->mFaces.end(); ++iter)
  1565. {
  1566. LLFaceID id = iter->mFaceID;
  1567. mFaceMask |= id;
  1568. }
  1569. return TRUE;
  1570. }
  1571. return FALSE;
  1572. }
  1573. void LLVolume::createVolumeFaces()
  1574. {
  1575. LLMemType m1(LLMemType::MTYPE_VOLUME);
  1576. if (mGenerateSingleFace)
  1577. {
  1578. // do nothing
  1579. }
  1580. else
  1581. {
  1582. S32 num_faces = getNumFaces();
  1583. BOOL partial_build = TRUE;
  1584. if (num_faces != mVolumeFaces.size())
  1585. {
  1586. partial_build = FALSE;
  1587. mVolumeFaces.resize(num_faces);
  1588. }
  1589. // Initialize volume faces with parameter data
  1590. for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++)
  1591. {
  1592. LLVolumeFace& vf = mVolumeFaces[i];
  1593. LLProfile::Face& face = mProfilep->mFaces[i];
  1594. vf.mBeginS = face.mIndex;
  1595. vf.mNumS = face.mCount;
  1596. vf.mBeginT = 0;
  1597. vf.mNumT= getPath().mPath.size();
  1598. vf.mID = i;
  1599. // Set the type mask bits correctly
  1600. if (mParams.getProfileParams().getHollow() > 0)
  1601. {
  1602. vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK;
  1603. }
  1604. if (mProfilep->isOpen())
  1605. {
  1606. vf.mTypeMask |= LLVolumeFace::OPEN_MASK;
  1607. }
  1608. if (face.mCap)
  1609. {
  1610. vf.mTypeMask |= LLVolumeFace::CAP_MASK;
  1611. if (face.mFaceID == LL_FACE_PATH_BEGIN)
  1612. {
  1613. vf.mTypeMask |= LLVolumeFace::TOP_MASK;
  1614. }
  1615. else
  1616. {
  1617. llassert(face.mFaceID == LL_FACE_PATH_END);
  1618. vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK;
  1619. }
  1620. }
  1621. else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END))
  1622. {
  1623. vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK;
  1624. }
  1625. else
  1626. {
  1627. vf.mTypeMask |= LLVolumeFace::SIDE_MASK;
  1628. if (face.mFlat)
  1629. {
  1630. vf.mTypeMask |= LLVolumeFace::FLAT_MASK;
  1631. }
  1632. if (face.mFaceID & LL_FACE_INNER_SIDE)
  1633. {
  1634. vf.mTypeMask |= LLVolumeFace::INNER_MASK;
  1635. if (face.mFlat && vf.mNumS > 2)
  1636. { //flat inner faces have to copy vert normals
  1637. vf.mNumS = vf.mNumS*2;
  1638. }
  1639. }
  1640. else
  1641. {
  1642. vf.mTypeMask |= LLVolumeFace::OUTER_MASK;
  1643. }
  1644. }
  1645. }
  1646. for (face_list_t::iterator iter = mVolumeFaces.begin();
  1647.  iter != mVolumeFaces.end(); ++iter)
  1648. {
  1649. (*iter).create(this, partial_build);
  1650. }
  1651. }
  1652. }
  1653. inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b)
  1654. {
  1655. // maps RGB values to vector values [0..255] -> [-0.5..0.5]
  1656. LLVector3 value;
  1657. value.mV[VX] = r / 255.f - 0.5f;
  1658. value.mV[VY] = g / 255.f - 0.5f;
  1659. value.mV[VZ] = b / 255.f - 0.5f;
  1660. return value;
  1661. }
  1662. inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
  1663. {
  1664. U32 index = (x + y * sculpt_width) * sculpt_components;
  1665. return index;
  1666. }
  1667. inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
  1668. {
  1669. U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width);
  1670. U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height);
  1671. return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
  1672. }
  1673. inline LLVector3 sculpt_index_to_vector(U32 index, const U8* sculpt_data)
  1674. {
  1675. LLVector3 v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]);
  1676. return v;
  1677. }
  1678. inline LLVector3 sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
  1679. {
  1680. U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components);
  1681. return sculpt_index_to_vector(index, sculpt_data);
  1682. }
  1683. inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
  1684. {
  1685. U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
  1686. return sculpt_index_to_vector(index, sculpt_data);
  1687. }
  1688. F32 LLVolume::sculptGetSurfaceArea()
  1689. {
  1690. // test to see if image has enough variation to create non-degenerate geometry
  1691. F32 area = 0;
  1692. S32 sizeS = mPathp->mPath.size();
  1693. S32 sizeT = mProfilep->mProfile.size();
  1694. for (S32 s = 0; s < sizeS-1; s++)
  1695. {
  1696. for (S32 t = 0; t < sizeT-1; t++)
  1697. {
  1698. // get four corners of quad
  1699. LLVector3 p1 = mMesh[(s  )*sizeT + (t  )].mPos;
  1700. LLVector3 p2 = mMesh[(s+1)*sizeT + (t  )].mPos;
  1701. LLVector3 p3 = mMesh[(s  )*sizeT + (t+1)].mPos;
  1702. LLVector3 p4 = mMesh[(s+1)*sizeT + (t+1)].mPos;
  1703. // compute the area of the quad by taking the length of the cross product of the two triangles
  1704. LLVector3 cross1 = (p1 - p2) % (p1 - p3);
  1705. LLVector3 cross2 = (p4 - p2) % (p4 - p3);
  1706. area += (cross1.magVec() + cross2.magVec()) / 2.0;
  1707. }
  1708. }
  1709. return area;
  1710. }
  1711. // create placeholder shape
  1712. void LLVolume::sculptGeneratePlaceholder()
  1713. {
  1714. LLMemType m1(LLMemType::MTYPE_VOLUME);
  1715. S32 sizeS = mPathp->mPath.size();
  1716. S32 sizeT = mProfilep->mProfile.size();
  1717. S32 line = 0;
  1718. // for now, this is a sphere.
  1719. for (S32 s = 0; s < sizeS; s++)
  1720. {
  1721. for (S32 t = 0; t < sizeT; t++)
  1722. {
  1723. S32 i = t + line;
  1724. Point& pt = mMesh[i];
  1725. F32 u = (F32)s/(sizeS-1);
  1726. F32 v = (F32)t/(sizeT-1);
  1727. const F32 RADIUS = (F32) 0.3;
  1728. pt.mPos.mV[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS);
  1729. pt.mPos.mV[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS);
  1730. pt.mPos.mV[2] = (F32)(cos(F_PI * v) * RADIUS);
  1731. }
  1732. line += sizeT;
  1733. }
  1734. }
  1735. // create the vertices from the map
  1736. void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type)
  1737. {
  1738. U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK;
  1739. BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT;
  1740. BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR;
  1741. BOOL reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror);  // XOR
  1742. LLMemType m1(LLMemType::MTYPE_VOLUME);
  1743. S32 sizeS = mPathp->mPath.size();
  1744. S32 sizeT = mProfilep->mProfile.size();
  1745. S32 line = 0;
  1746. for (S32 s = 0; s < sizeS; s++)
  1747. {
  1748. // Run along the profile.
  1749. for (S32 t = 0; t < sizeT; t++)
  1750. {
  1751. S32 i = t + line;
  1752. Point& pt = mMesh[i];
  1753. S32 reversed_t = t;
  1754. if (reverse_horizontal)
  1755. {
  1756. reversed_t = sizeT - t - 1;
  1757. }
  1758. U32 x = (U32) ((F32)reversed_t/(sizeT-1) * (F32) sculpt_width);
  1759. U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height);
  1760. if (y == 0)  // top row stitching
  1761. {
  1762. // pinch?
  1763. if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE)
  1764. {
  1765. x = sculpt_width / 2;
  1766. }
  1767. }
  1768. if (y == sculpt_height)  // bottom row stitching
  1769. {
  1770. // wrap?
  1771. if (sculpt_stitching == LL_SCULPT_TYPE_TORUS)
  1772. {
  1773. y = 0;
  1774. }
  1775. else
  1776. {
  1777. y = sculpt_height - 1;
  1778. }
  1779. // pinch?
  1780. if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE)
  1781. {
  1782. x = sculpt_width / 2;
  1783. }
  1784. }
  1785. if (x == sculpt_width)   // side stitching
  1786. {
  1787. // wrap?
  1788. if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) ||
  1789. (sculpt_stitching == LL_SCULPT_TYPE_TORUS) ||
  1790. (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER))
  1791. {
  1792. x = 0;
  1793. }
  1794. else
  1795. {
  1796. x = sculpt_width - 1;
  1797. }
  1798. }
  1799. pt.mPos = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data);
  1800. if (sculpt_mirror)
  1801. {
  1802. pt.mPos.mV[VX] *= -1.f;
  1803. }
  1804. }
  1805. line += sizeT;
  1806. }
  1807. }
  1808. const S32 SCULPT_REZ_1 = 6;  // changed from 4 to 6 - 6 looks round whereas 4 looks square
  1809. const S32 SCULPT_REZ_2 = 8;
  1810. const S32 SCULPT_REZ_3 = 16;
  1811. const S32 SCULPT_REZ_4 = 32;
  1812. S32 sculpt_sides(F32 detail)
  1813. {
  1814. // detail is usually one of: 1, 1.5, 2.5, 4.0.
  1815. if (detail <= 1.0)
  1816. {
  1817. return SCULPT_REZ_1;
  1818. }
  1819. if (detail <= 2.0)
  1820. {
  1821. return SCULPT_REZ_2;
  1822. }
  1823. if (detail <= 3.0)
  1824. {
  1825. return SCULPT_REZ_3;
  1826. }
  1827. else
  1828. {
  1829. return SCULPT_REZ_4;
  1830. }
  1831. }
  1832. // determine the number of vertices in both s and t direction for this sculpt
  1833. void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t)
  1834. {
  1835. // this code has the following properties:
  1836. // 1) the aspect ratio of the mesh is as close as possible to the ratio of the map
  1837. //    while still using all available verts
  1838. // 2) the mesh cannot have more verts than is allowed by LOD
  1839. // 3) the mesh cannot have more verts than is allowed by the map
  1840. S32 max_vertices_lod = (S32)pow((double)sculpt_sides(detail), 2.0);
  1841. S32 max_vertices_map = width * height / 4;
  1842. S32 vertices;
  1843. if (max_vertices_map > 0)
  1844. vertices = llmin(max_vertices_lod, max_vertices_map);
  1845. else
  1846. vertices = max_vertices_lod;
  1847. F32 ratio;
  1848. if ((width == 0) || (height == 0))
  1849. ratio = 1.f;
  1850. else
  1851. ratio = (F32) width / (F32) height;
  1852. s = (S32)fsqrtf(((F32)vertices / ratio));
  1853. s = llmax(s, 4);              // no degenerate sizes, please
  1854. t = vertices / s;
  1855. t = llmax(t, 4);              // no degenerate sizes, please
  1856. s = vertices / t;
  1857. }
  1858. // sculpt replaces generate() for sculpted surfaces
  1859. void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level)
  1860. {
  1861. LLMemType m1(LLMemType::MTYPE_VOLUME);
  1862.     U8 sculpt_type = mParams.getSculptType();
  1863. BOOL data_is_empty = FALSE;
  1864. if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL)
  1865. {
  1866. sculpt_level = -1;
  1867. data_is_empty = TRUE;
  1868. }
  1869. S32 requested_sizeS = 0;
  1870. S32 requested_sizeT = 0;
  1871. sculpt_calc_mesh_resolution(sculpt_width, sculpt_height, sculpt_type, mDetail, requested_sizeS, requested_sizeT);
  1872. mPathp->generate(mParams.getPathParams(), mDetail, 0, TRUE, requested_sizeS);
  1873. mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, TRUE, requested_sizeT);
  1874. S32 sizeS = mPathp->mPath.size();         // we requested a specific size, now see what we really got
  1875. S32 sizeT = mProfilep->mProfile.size();   // we requested a specific size, now see what we really got
  1876. // weird crash bug - DEV-11158 - trying to collect more data:
  1877. if ((sizeS == 0) || (sizeT == 0))
  1878. {
  1879. llwarns << "sculpt bad mesh size " << sizeS << " " << sizeT << llendl;
  1880. }
  1881. sNumMeshPoints -= mMesh.size();
  1882. mMesh.resize(sizeS * sizeT);
  1883. sNumMeshPoints += mMesh.size();
  1884. //generate vertex positions
  1885. if (!data_is_empty)
  1886. {
  1887. sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type);
  1888. // don't test lowest LOD to support legacy content DEV-33670
  1889. if (mDetail > SCULPT_MIN_AREA_DETAIL)
  1890. {
  1891. if (sculptGetSurfaceArea() < SCULPT_MIN_AREA)
  1892. {
  1893. data_is_empty = TRUE;
  1894. }
  1895. }
  1896. }
  1897. if (data_is_empty)
  1898. {
  1899. sculptGeneratePlaceholder();
  1900. }
  1901. for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++)
  1902. {
  1903. mFaceMask |= mProfilep->mFaces[i].mFaceID;
  1904. }
  1905. mSculptLevel = sculpt_level;
  1906. // Delete any existing faces so that they get regenerated
  1907. mVolumeFaces.clear();
  1908. createVolumeFaces();
  1909. }
  1910. BOOL LLVolume::isCap(S32 face)
  1911. {
  1912. return mProfilep->mFaces[face].mCap; 
  1913. }
  1914. BOOL LLVolume::isFlat(S32 face)
  1915. {
  1916. return mProfilep->mFaces[face].mFlat;
  1917. }
  1918. bool LLVolumeParams::operator==(const LLVolumeParams &params) const
  1919. {
  1920. return ( (getPathParams() == params.getPathParams()) &&
  1921.  (getProfileParams() == params.getProfileParams()) &&
  1922.  (mSculptID == params.mSculptID) &&
  1923.  (mSculptType == params.mSculptType) );
  1924. }
  1925. bool LLVolumeParams::operator!=(const LLVolumeParams &params) const
  1926. {
  1927. return ( (getPathParams() != params.getPathParams()) ||
  1928.  (getProfileParams() != params.getProfileParams()) ||
  1929.  (mSculptID != params.mSculptID) ||
  1930.  (mSculptType != params.mSculptType) );
  1931. }
  1932. bool LLVolumeParams::operator<(const LLVolumeParams &params) const
  1933. {
  1934. if( getPathParams() != params.getPathParams() )
  1935. {
  1936. return getPathParams() < params.getPathParams();
  1937. }
  1938. if (getProfileParams() != params.getProfileParams())
  1939. {
  1940. return getProfileParams() < params.getProfileParams();
  1941. }
  1942. if (mSculptID != params.mSculptID)
  1943. {
  1944. return mSculptID < params.mSculptID;
  1945. }
  1946. return mSculptType < params.mSculptType;
  1947. }
  1948. void LLVolumeParams::copyParams(const LLVolumeParams &params)
  1949. {
  1950. LLMemType m1(LLMemType::MTYPE_VOLUME);
  1951. mProfileParams.copyParams(params.mProfileParams);
  1952. mPathParams.copyParams(params.mPathParams);
  1953. mSculptID = params.getSculptID();
  1954. mSculptType = params.getSculptType();
  1955. }
  1956. // Less restricitve approx 0 for volumes
  1957. const F32 APPROXIMATELY_ZERO = 0.001f;
  1958. bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO)
  1959. {
  1960. return (f >= -tolerance) && (f <= tolerance);
  1961. }
  1962. // return true if in range (or nearly so)
  1963. static bool limit_range(F32& v, F32 min, F32 max, F32 tolerance = APPROXIMATELY_ZERO)
  1964. {
  1965. F32 min_delta = v - min;
  1966. if (min_delta < 0.f)
  1967. {
  1968. v = min;
  1969. if (!approx_zero(min_delta, tolerance))
  1970. return false;
  1971. }
  1972. F32 max_delta = max - v;
  1973. if (max_delta < 0.f)
  1974. {
  1975. v = max;
  1976. if (!approx_zero(max_delta, tolerance))
  1977. return false;
  1978. }
  1979. return true;
  1980. }
  1981. bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e)
  1982. {
  1983. bool valid = true;
  1984. // First, clamp to valid ranges.
  1985. F32 begin = b;
  1986. valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA);
  1987. F32 end = e;
  1988. if (end >= .0149f && end < MIN_CUT_DELTA) end = MIN_CUT_DELTA; // eliminate warning for common rounding error
  1989. valid &= limit_range(end, MIN_CUT_DELTA, 1.f);
  1990. valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f);
  1991. // Now set them.
  1992. mProfileParams.setBegin(begin);
  1993. mProfileParams.setEnd(end);
  1994. return valid;
  1995. }
  1996. bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e)
  1997. {
  1998. bool valid = true;
  1999. // First, clamp to valid ranges.
  2000. F32 begin = b;
  2001. valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA);
  2002. F32 end = e;
  2003. valid &= limit_range(end, MIN_CUT_DELTA, 1.f);
  2004. valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f);
  2005. // Now set them.
  2006. mPathParams.setBegin(begin);
  2007. mPathParams.setEnd(end);
  2008. return valid;
  2009. }
  2010. bool LLVolumeParams::setHollow(const F32 h)
  2011. {
  2012. // Validate the hollow based on path and profile.
  2013. U8 profile  = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
  2014. U8 hole_type  = mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK;
  2015. F32 max_hollow = HOLLOW_MAX;
  2016. // Only square holes have trouble.
  2017. if (LL_PCODE_HOLE_SQUARE == hole_type)
  2018. {
  2019. switch(profile)
  2020. {
  2021. case LL_PCODE_PROFILE_CIRCLE:
  2022. case LL_PCODE_PROFILE_CIRCLE_HALF:
  2023. case LL_PCODE_PROFILE_EQUALTRI:
  2024. max_hollow = HOLLOW_MAX_SQUARE;
  2025. }
  2026. }
  2027. F32 hollow = h;
  2028. bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow);
  2029. mProfileParams.setHollow(hollow); 
  2030. return valid;
  2031. }
  2032. bool LLVolumeParams::setTwistBegin(const F32 b)
  2033. {
  2034. F32 twist_begin = b;
  2035. bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX);
  2036. mPathParams.setTwistBegin(twist_begin);
  2037. return valid;
  2038. }
  2039. bool LLVolumeParams::setTwistEnd(const F32 e)
  2040. {
  2041. F32 twist_end = e;
  2042. bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX);
  2043. mPathParams.setTwistEnd(twist_end);
  2044. return valid;
  2045. }
  2046. bool LLVolumeParams::setRatio(const F32 x, const F32 y)
  2047. {
  2048. F32 min_x = RATIO_MIN;
  2049. F32 max_x = RATIO_MAX;
  2050. F32 min_y = RATIO_MIN;
  2051. F32 max_y = RATIO_MAX;
  2052. // If this is a circular path (and not a sphere) then 'ratio' is actually hole size.
  2053. U8 path_type  = mPathParams.getCurveType();
  2054. U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
  2055. if ( LL_PCODE_PATH_CIRCLE == path_type &&
  2056.  LL_PCODE_PROFILE_CIRCLE_HALF != profile_type)
  2057. {
  2058. // Holes are more restricted...
  2059. min_x = HOLE_X_MIN;
  2060. max_x = HOLE_X_MAX;
  2061. min_y = HOLE_Y_MIN;
  2062. max_y = HOLE_Y_MAX;
  2063. }
  2064. F32 ratio_x = x;
  2065. bool valid = limit_range(ratio_x, min_x, max_x);
  2066. F32 ratio_y = y;
  2067. valid &= limit_range(ratio_y, min_y, max_y);
  2068. mPathParams.setScale(ratio_x, ratio_y);
  2069. return valid;
  2070. }
  2071. bool LLVolumeParams::setShear(const F32 x, const F32 y)
  2072. {
  2073. F32 shear_x = x;
  2074. bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX);
  2075. F32 shear_y = y;
  2076. valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX);
  2077. mPathParams.setShear(shear_x, shear_y);
  2078. return valid;
  2079. }
  2080. bool LLVolumeParams::setTaperX(const F32 v)
  2081. {
  2082. F32 taper = v;
  2083. bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX);
  2084. mPathParams.setTaperX(taper);
  2085. return valid;
  2086. }
  2087. bool LLVolumeParams::setTaperY(const F32 v)
  2088. {
  2089. F32 taper = v;
  2090. bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX);
  2091. mPathParams.setTaperY(taper);
  2092. return valid;
  2093. }
  2094. bool LLVolumeParams::setRevolutions(const F32 r)
  2095. {
  2096. F32 revolutions = r;
  2097. bool valid = limit_range(revolutions, REV_MIN, REV_MAX);
  2098. mPathParams.setRevolutions(revolutions);
  2099. return valid;
  2100. }
  2101. bool LLVolumeParams::setRadiusOffset(const F32 offset)
  2102. {
  2103. bool valid = true;
  2104. // If this is a sphere, just set it to 0 and get out.
  2105. U8 path_type  = mPathParams.getCurveType();
  2106. U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
  2107. if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ||
  2108. LL_PCODE_PATH_CIRCLE != path_type )
  2109. {
  2110. mPathParams.setRadiusOffset(0.f);
  2111. return true;
  2112. }
  2113. // Limit radius offset, based on taper and hole size y.
  2114. F32 radius_offset = offset;
  2115. F32 taper_y     = getTaperY();
  2116. F32 radius_mag = fabs(radius_offset);
  2117. F32 hole_y_mag  = fabs(getRatioY());
  2118. F32 taper_y_mag = fabs(taper_y);
  2119. // Check to see if the taper effects us.
  2120. if ( (radius_offset > 0.f && taper_y < 0.f) ||
  2121. (radius_offset < 0.f && taper_y > 0.f) )
  2122. {
  2123. // The taper does not help increase the radius offset range.
  2124. taper_y_mag = 0.f;
  2125. }
  2126. F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag);
  2127. // Enforce the maximum magnitude.
  2128. F32 delta = max_radius_mag - radius_mag;
  2129. if (delta < 0.f)
  2130. {
  2131. // Check radius offset sign.
  2132. if (radius_offset < 0.f)
  2133. {
  2134. radius_offset = -max_radius_mag;
  2135. }
  2136. else
  2137. {
  2138. radius_offset = max_radius_mag;
  2139. }
  2140. valid = approx_zero(delta, .1f);
  2141. }
  2142. mPathParams.setRadiusOffset(radius_offset);
  2143. return valid;
  2144. }
  2145. bool LLVolumeParams::setSkew(const F32 skew_value)
  2146. {
  2147. bool valid = true;
  2148. // Check the skew value against the revolutions.
  2149. F32 skew = llclamp(skew_value, SKEW_MIN, SKEW_MAX);
  2150. F32 skew_mag = fabs(skew);
  2151. F32 revolutions = getRevolutions();
  2152. F32 scale_x = getRatioX();
  2153. F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f);
  2154. // Discontinuity; A revolution of 1 allows skews below 0.5.
  2155. if ( fabs(revolutions - 1.0f) < 0.001)
  2156. min_skew_mag = 0.0f;
  2157. // Clip skew.
  2158. F32 delta = skew_mag - min_skew_mag;
  2159. if (delta < 0.f)
  2160. {
  2161. // Check skew sign.
  2162. if (skew < 0.0f)
  2163. {
  2164. skew = -min_skew_mag;
  2165. }
  2166. else 
  2167. {
  2168. skew = min_skew_mag;
  2169. }
  2170. valid = approx_zero(delta, .01f);
  2171. }
  2172. mPathParams.setSkew(skew);
  2173. return valid;
  2174. }
  2175. bool LLVolumeParams::setSculptID(const LLUUID sculpt_id, U8 sculpt_type)
  2176. {
  2177. mSculptID = sculpt_id;
  2178. mSculptType = sculpt_type;
  2179. return true;
  2180. }
  2181. bool LLVolumeParams::setType(U8 profile, U8 path)
  2182. {
  2183. bool result = true;
  2184. // First, check profile and path for validity.
  2185. U8 profile_type = profile & LL_PCODE_PROFILE_MASK;
  2186. U8 hole_type  = (profile & LL_PCODE_HOLE_MASK) >> 4;
  2187. U8 path_type = path >> 4;
  2188. if (profile_type > LL_PCODE_PROFILE_MAX)
  2189. {
  2190. // Bad profile.  Make it square.
  2191. profile = LL_PCODE_PROFILE_SQUARE;
  2192. result = false;
  2193. llwarns << "LLVolumeParams::setType changing bad profile type (" << profile_type
  2194.   << ") to be LL_PCODE_PROFILE_SQUARE" << llendl;
  2195. }
  2196. else if (hole_type > LL_PCODE_HOLE_MAX)
  2197. {
  2198. // Bad hole.  Make it the same.
  2199. profile = profile_type;
  2200. result = false;
  2201. llwarns << "LLVolumeParams::setType changing bad hole type (" << hole_type
  2202.   << ") to be LL_PCODE_HOLE_SAME" << llendl;
  2203. }
  2204. if (path_type < LL_PCODE_PATH_MIN ||
  2205. path_type > LL_PCODE_PATH_MAX)
  2206. {
  2207. // Bad path.  Make it linear.
  2208. result = false;
  2209. llwarns << "LLVolumeParams::setType changing bad path (" << path
  2210.   << ") to be LL_PCODE_PATH_LINE" << llendl;
  2211. path = LL_PCODE_PATH_LINE;
  2212. }
  2213. mProfileParams.setCurveType(profile);
  2214. mPathParams.setCurveType(path);
  2215. return result;
  2216. }
  2217. // static 
  2218. bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow,
  2219. U8 path_curve, F32 path_begin, F32 path_end,
  2220. F32 scx, F32 scy, F32 shx, F32 shy,
  2221. F32 twistend, F32 twistbegin, F32 radiusoffset,
  2222. F32 tx, F32 ty, F32 revolutions, F32 skew)
  2223. {
  2224. LLVolumeParams test_params;
  2225. if (!test_params.setType (prof_curve, path_curve))
  2226. {
  2227.      return false;
  2228. }
  2229. if (!test_params.setBeginAndEndS (prof_begin, prof_end))
  2230. {
  2231.      return false;
  2232. }
  2233. if (!test_params.setBeginAndEndT (path_begin, path_end))
  2234. {
  2235.      return false;
  2236. }
  2237. if (!test_params.setHollow (hollow))
  2238. {
  2239.      return false;
  2240. }
  2241. if (!test_params.setTwistBegin (twistbegin))
  2242. {
  2243.      return false;
  2244. }
  2245. if (!test_params.setTwistEnd (twistend))
  2246. {
  2247.      return false;
  2248. }
  2249. if (!test_params.setRatio (scx, scy))
  2250. {
  2251.      return false;
  2252. }
  2253. if (!test_params.setShear (shx, shy))
  2254. {
  2255.      return false;
  2256. }
  2257. if (!test_params.setTaper (tx, ty))
  2258. {
  2259.      return false;
  2260. }
  2261. if (!test_params.setRevolutions (revolutions))
  2262. {
  2263.      return false;
  2264. }
  2265. if (!test_params.setRadiusOffset (radiusoffset))
  2266. {
  2267.      return false;
  2268. }
  2269. if (!test_params.setSkew (skew))
  2270. {
  2271.      return false;
  2272. }
  2273. return true;
  2274. }
  2275. S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
  2276. {
  2277. LLMemType m1(LLMemType::MTYPE_VOLUME);
  2278. S32 expected_num_triangle_indices = getNumTriangleIndices();
  2279. if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES)