PageRenderTime 64ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llmath/llvolume.cpp

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