diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmath/llvolume.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llmath/llvolume.cpp')
-rw-r--r-- | linden/indra/llmath/llvolume.cpp | 4576 |
1 files changed, 4576 insertions, 0 deletions
diff --git a/linden/indra/llmath/llvolume.cpp b/linden/indra/llmath/llvolume.cpp new file mode 100644 index 0000000..14d4cdf --- /dev/null +++ b/linden/indra/llmath/llvolume.cpp | |||
@@ -0,0 +1,4576 @@ | |||
1 | /** | ||
2 | * @file llvolume.cpp | ||
3 | * | ||
4 | * Copyright (c) 2002-2007, Linden Research, Inc. | ||
5 | * | ||
6 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
7 | * to you under the terms of the GNU General Public License, version 2.0 | ||
8 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
9 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
10 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
11 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
12 | * | ||
13 | * There are special exceptions to the terms and conditions of the GPL as | ||
14 | * it is applied to this Source Code. View the full text of the exception | ||
15 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
16 | * online at http://secondlife.com/developers/opensource/flossexception | ||
17 | * | ||
18 | * By copying, modifying or distributing this software, you acknowledge | ||
19 | * that you have read and understood your obligations described above, | ||
20 | * and agree to abide by those obligations. | ||
21 | * | ||
22 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
23 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
24 | * COMPLETENESS OR PERFORMANCE. | ||
25 | */ | ||
26 | |||
27 | #include "linden_common.h" | ||
28 | #include "llmath.h" | ||
29 | |||
30 | #include <set> | ||
31 | |||
32 | #include "llerror.h" | ||
33 | |||
34 | #include "llvolumemgr.h" | ||
35 | #include "v2math.h" | ||
36 | #include "v3math.h" | ||
37 | #include "v4math.h" | ||
38 | #include "m4math.h" | ||
39 | #include "m3math.h" | ||
40 | #include "lldarray.h" | ||
41 | #include "llvolume.h" | ||
42 | #include "llstl.h" | ||
43 | |||
44 | #define DEBUG_SILHOUETTE_BINORMALS 0 | ||
45 | #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette | ||
46 | #define DEBUG_SILHOUETTE_EDGE_MAP 0 // DaveP: Use this to display edge map using the silhouette | ||
47 | |||
48 | const F32 CUT_MIN = 0.f; | ||
49 | const F32 CUT_MAX = 1.f; | ||
50 | const F32 MIN_CUT_DELTA = 0.02f; | ||
51 | |||
52 | const F32 HOLLOW_MIN = 0.f; | ||
53 | const F32 HOLLOW_MAX = 0.95f; | ||
54 | const F32 HOLLOW_MAX_SQUARE = 0.7f; | ||
55 | |||
56 | const F32 TWIST_MIN = -1.f; | ||
57 | const F32 TWIST_MAX = 1.f; | ||
58 | |||
59 | const F32 RATIO_MIN = 0.f; | ||
60 | const F32 RATIO_MAX = 2.f; // Tom Y: Inverted sense here: 0 = top taper, 2 = bottom taper | ||
61 | |||
62 | const F32 HOLE_X_MIN= 0.05f; | ||
63 | const F32 HOLE_X_MAX= 1.0f; | ||
64 | |||
65 | const F32 HOLE_Y_MIN= 0.05f; | ||
66 | const F32 HOLE_Y_MAX= 0.5f; | ||
67 | |||
68 | const F32 SHEAR_MIN = -0.5f; | ||
69 | const F32 SHEAR_MAX = 0.5f; | ||
70 | |||
71 | const F32 REV_MIN = 1.f; | ||
72 | const F32 REV_MAX = 4.f; | ||
73 | |||
74 | const F32 TAPER_MIN = -1.f; | ||
75 | const F32 TAPER_MAX = 1.f; | ||
76 | |||
77 | const F32 SKEW_MIN = -0.95f; | ||
78 | const F32 SKEW_MAX = 0.95f; | ||
79 | |||
80 | BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) | ||
81 | { | ||
82 | LLVector3 test = (pt2-pt1)%(pt3-pt2); | ||
83 | |||
84 | //answer | ||
85 | if(test * norm < 0) | ||
86 | { | ||
87 | return FALSE; | ||
88 | } | ||
89 | else | ||
90 | { | ||
91 | return TRUE; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | // intersect test between triangle pt1,pt2,pt3 and line from linept to linept+vect | ||
96 | //returns TRUE if intersecting and moves linept to the point of intersection | ||
97 | BOOL LLTriangleLineSegmentIntersect( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, LLVector3& linept, const LLVector3& vect) | ||
98 | { | ||
99 | LLVector3 V1 = pt2-pt1; | ||
100 | LLVector3 V2 = pt3-pt2; | ||
101 | |||
102 | LLVector3 norm = V1 % V2; | ||
103 | |||
104 | F32 dotprod = norm * vect; | ||
105 | |||
106 | if(dotprod < 0) | ||
107 | { | ||
108 | //Find point of intersect to triangle plane. | ||
109 | //find t to intersect point | ||
110 | F32 t = -(norm * (linept-pt1))/dotprod; | ||
111 | |||
112 | // if ds is neg line started past triangle so can't hit triangle. | ||
113 | if (t > 0) | ||
114 | { | ||
115 | return FALSE; | ||
116 | } | ||
117 | |||
118 | LLVector3 pt_int = linept + (vect*t); | ||
119 | |||
120 | if(check_same_clock_dir(pt1, pt2, pt_int, norm)) | ||
121 | { | ||
122 | if(check_same_clock_dir(pt2, pt3, pt_int, norm)) | ||
123 | { | ||
124 | if(check_same_clock_dir(pt3, pt1, pt_int, norm)) | ||
125 | { | ||
126 | // answer in pt_int is insde triangle | ||
127 | linept.setVec(pt_int); | ||
128 | return TRUE; | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | return FALSE; | ||
135 | } | ||
136 | |||
137 | |||
138 | //------------------------------------------------------------------- | ||
139 | // statics | ||
140 | //------------------------------------------------------------------- | ||
141 | |||
142 | |||
143 | //---------------------------------------------------- | ||
144 | |||
145 | LLProfile::Face* LLProfile::addCap(S16 faceID) | ||
146 | { | ||
147 | Face *face = vector_append(mFaces, 1); | ||
148 | |||
149 | face->mIndex = 0; | ||
150 | face->mCount = mTotal; | ||
151 | face->mScaleU= 1.0f; | ||
152 | face->mCap = TRUE; | ||
153 | face->mFaceID = faceID; | ||
154 | return face; | ||
155 | } | ||
156 | |||
157 | LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BOOL flat) | ||
158 | { | ||
159 | Face *face = vector_append(mFaces, 1); | ||
160 | |||
161 | face->mIndex = i; | ||
162 | face->mCount = count; | ||
163 | face->mScaleU= scaleU; | ||
164 | |||
165 | face->mFlat = flat; | ||
166 | face->mCap = FALSE; | ||
167 | face->mFaceID = faceID; | ||
168 | return face; | ||
169 | } | ||
170 | |||
171 | // What is the bevel parameter used for? - DJS 04/05/02 | ||
172 | // Bevel parameter is currently unused but presumedly would support | ||
173 | // filleted and chamfered corners | ||
174 | void LLProfile::genNGon(S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split) | ||
175 | { | ||
176 | // Generate an n-sided "circular" path. | ||
177 | // 0 is (1,0), and we go counter-clockwise along a circular path from there. | ||
178 | const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; | ||
179 | F32 scale = 0.5f; | ||
180 | F32 t, t_step, t_first, t_fraction, ang, ang_step; | ||
181 | LLVector3 pt1,pt2; | ||
182 | |||
183 | mMaxX = 0.f; | ||
184 | mMinX = 0.f; | ||
185 | |||
186 | F32 begin = mParams.getBegin(); | ||
187 | F32 end = mParams.getEnd(); | ||
188 | |||
189 | t_step = 1.0f / sides; | ||
190 | ang_step = 2.0f*F_PI*t_step*ang_scale; | ||
191 | |||
192 | // Scale to have size "match" scale. Compensates to get object to generally fill bounding box. | ||
193 | |||
194 | S32 total_sides = llround(sides / ang_scale); // Total number of sides all around | ||
195 | |||
196 | if (total_sides < 8) | ||
197 | { | ||
198 | scale = tableScale[total_sides]; | ||
199 | } | ||
200 | |||
201 | t_first = floor(begin * sides) / (F32)sides; | ||
202 | |||
203 | // pt1 is the first point on the fractional face. | ||
204 | // Starting t and ang values for the first face | ||
205 | t = t_first; | ||
206 | ang = 2.0f*F_PI*(t*ang_scale + offset); | ||
207 | pt1.setVec(cos(ang)*scale,sin(ang)*scale, t); | ||
208 | |||
209 | // Increment to the next point. | ||
210 | // pt2 is the end point on the fractional face | ||
211 | t += t_step; | ||
212 | ang += ang_step; | ||
213 | pt2.setVec(cos(ang)*scale,sin(ang)*scale,t); | ||
214 | |||
215 | t_fraction = (begin - t_first)*sides; | ||
216 | |||
217 | // Only use if it's not almost exactly on an edge. | ||
218 | if (t_fraction < 0.99f) | ||
219 | { | ||
220 | LLVector3 new_pt = lerp(pt1, pt2, t_fraction); | ||
221 | F32 pt_x = new_pt.mV[VX]; | ||
222 | if (pt_x < mMinX) | ||
223 | { | ||
224 | mMinX = pt_x; | ||
225 | } | ||
226 | else if (pt_x > mMaxX) | ||
227 | { | ||
228 | mMaxX = pt_x; | ||
229 | } | ||
230 | mProfile.push_back(new_pt); | ||
231 | } | ||
232 | |||
233 | // There's lots of potential here for floating point error to generate unneeded extra points - DJS 04/05/02 | ||
234 | while (t < end) | ||
235 | { | ||
236 | // Iterate through all the integer steps of t. | ||
237 | pt1.setVec(cos(ang)*scale,sin(ang)*scale,t); | ||
238 | |||
239 | F32 pt_x = pt1.mV[VX]; | ||
240 | if (pt_x < mMinX) | ||
241 | { | ||
242 | mMinX = pt_x; | ||
243 | } | ||
244 | else if (pt_x > mMaxX) | ||
245 | { | ||
246 | mMaxX = pt_x; | ||
247 | } | ||
248 | |||
249 | if (mProfile.size() > 0) { | ||
250 | LLVector3 p = mProfile[mProfile.size()-1]; | ||
251 | for (S32 i = 0; i < split && mProfile.size() > 0; i++) { | ||
252 | mProfile.push_back(p+(pt1-p) * 1.0f/(float)(split+1) * (float)(i+1)); | ||
253 | } | ||
254 | } | ||
255 | mProfile.push_back(pt1); | ||
256 | |||
257 | t += t_step; | ||
258 | ang += ang_step; | ||
259 | } | ||
260 | |||
261 | t_fraction = (end - (t - t_step))*sides; | ||
262 | |||
263 | // pt1 is the first point on the fractional face | ||
264 | // pt2 is the end point on the fractional face | ||
265 | pt2.setVec(cos(ang)*scale,sin(ang)*scale,t); | ||
266 | |||
267 | // Find the fraction that we need to add to the end point. | ||
268 | t_fraction = (end - (t - t_step))*sides; | ||
269 | if (t_fraction > 0.01f) | ||
270 | { | ||
271 | LLVector3 new_pt = lerp(pt1, pt2, t_fraction); | ||
272 | F32 pt_x = new_pt.mV[VX]; | ||
273 | if (pt_x < mMinX) | ||
274 | { | ||
275 | mMinX = pt_x; | ||
276 | } | ||
277 | else if (pt_x > mMaxX) | ||
278 | { | ||
279 | mMaxX = pt_x; | ||
280 | } | ||
281 | |||
282 | if (mProfile.size() > 0) { | ||
283 | LLVector3 p = mProfile[mProfile.size()-1]; | ||
284 | for (S32 i = 0; i < split && mProfile.size() > 0; i++) { | ||
285 | mProfile.push_back(p+(new_pt-p) * 1.0f/(float)(split+1) * (float)(i+1)); | ||
286 | } | ||
287 | } | ||
288 | mProfile.push_back(new_pt); | ||
289 | } | ||
290 | |||
291 | // If we're sliced, the profile is open. | ||
292 | if ((end - begin)*ang_scale < 0.99f) | ||
293 | { | ||
294 | if ((end - begin)*ang_scale > 0.5f) | ||
295 | { | ||
296 | mConcave = TRUE; | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | mConcave = FALSE; | ||
301 | } | ||
302 | mOpen = TRUE; | ||
303 | if (!isHollow()) | ||
304 | { | ||
305 | // put center point if not hollow. | ||
306 | mProfile.push_back(LLVector3(0,0,0)); | ||
307 | } | ||
308 | } | ||
309 | else | ||
310 | { | ||
311 | // The profile isn't open. | ||
312 | mOpen = FALSE; | ||
313 | mConcave = FALSE; | ||
314 | } | ||
315 | |||
316 | mTotal = mProfile.size(); | ||
317 | } | ||
318 | |||
319 | void LLProfile::genNormals() | ||
320 | { | ||
321 | S32 count = mProfile.size(); | ||
322 | |||
323 | S32 outer_count; | ||
324 | if (mTotalOut) | ||
325 | { | ||
326 | outer_count = mTotalOut; | ||
327 | } | ||
328 | else | ||
329 | { | ||
330 | outer_count = mTotal / 2; | ||
331 | } | ||
332 | |||
333 | mEdgeNormals.resize(count * 2); | ||
334 | mEdgeCenters.resize(count * 2); | ||
335 | mNormals.resize(count); | ||
336 | |||
337 | LLVector2 pt0,pt1; | ||
338 | |||
339 | BOOL hollow; | ||
340 | hollow = isHollow(); | ||
341 | |||
342 | S32 i0, i1, i2, i3, i4; | ||
343 | |||
344 | // Parametrically generate normal | ||
345 | for (i2 = 0; i2 < count; i2++) | ||
346 | { | ||
347 | mNormals[i2].mV[0] = mProfile[i2].mV[0]; | ||
348 | mNormals[i2].mV[1] = mProfile[i2].mV[1]; | ||
349 | if (hollow && (i2 >= outer_count)) | ||
350 | { | ||
351 | mNormals[i2] *= -1.f; | ||
352 | } | ||
353 | if (mNormals[i2].magVec() < 0.001) | ||
354 | { | ||
355 | // Special case for point at center, get adjacent points. | ||
356 | i1 = (i2 - 1) >= 0 ? i2 - 1 : count - 1; | ||
357 | i0 = (i1 - 1) >= 0 ? i1 - 1 : count - 1; | ||
358 | i3 = (i2 + 1) < count ? i2 + 1 : 0; | ||
359 | i4 = (i3 + 1) < count ? i3 + 1 : 0; | ||
360 | |||
361 | pt0.setVec(mProfile[i1].mV[VX] + mProfile[i1].mV[VX] - mProfile[i0].mV[VX], | ||
362 | mProfile[i1].mV[VY] + mProfile[i1].mV[VY] - mProfile[i0].mV[VY]); | ||
363 | pt1.setVec(mProfile[i3].mV[VX] + mProfile[i3].mV[VX] - mProfile[i4].mV[VX], | ||
364 | mProfile[i3].mV[VY] + mProfile[i3].mV[VY] - mProfile[i4].mV[VY]); | ||
365 | |||
366 | mNormals[i2] = pt0 + pt1; | ||
367 | mNormals[i2] *= 0.5f; | ||
368 | } | ||
369 | mNormals[i2].normVec(); | ||
370 | } | ||
371 | |||
372 | S32 num_normal_sets = isConcave() ? 2 : 1; | ||
373 | for (S32 normal_set = 0; normal_set < num_normal_sets; normal_set++) | ||
374 | { | ||
375 | S32 point_num; | ||
376 | for (point_num = 0; point_num < mTotal; point_num++) | ||
377 | { | ||
378 | LLVector3 point_1 = mProfile[point_num]; | ||
379 | point_1.mV[VZ] = 0.f; | ||
380 | |||
381 | LLVector3 point_2; | ||
382 | |||
383 | if (isConcave() && normal_set == 0 && point_num == (mTotal - 1) / 2) | ||
384 | { | ||
385 | point_2 = mProfile[mTotal - 1]; | ||
386 | } | ||
387 | else if (isConcave() && normal_set == 1 && point_num == mTotal - 1) | ||
388 | { | ||
389 | point_2 = mProfile[(mTotal - 1) / 2]; | ||
390 | } | ||
391 | else | ||
392 | { | ||
393 | LLVector3 delta_pos; | ||
394 | S32 neighbor_point = (point_num + 1) % mTotal; | ||
395 | while(delta_pos.magVecSquared() < 0.01f * 0.01f) | ||
396 | { | ||
397 | point_2 = mProfile[neighbor_point]; | ||
398 | delta_pos = point_2 - point_1; | ||
399 | neighbor_point = (neighbor_point + 1) % mTotal; | ||
400 | if (neighbor_point == point_num) | ||
401 | { | ||
402 | break; | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | |||
407 | point_2.mV[VZ] = 0.f; | ||
408 | LLVector3 face_normal = (point_2 - point_1) % LLVector3::z_axis; | ||
409 | face_normal.normVec(); | ||
410 | mEdgeNormals[normal_set * count + point_num] = face_normal; | ||
411 | mEdgeCenters[normal_set * count + point_num] = lerp(point_1, point_2, 0.5f); | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | |||
416 | |||
417 | // Hollow is percent of the original bounding box, not of this particular | ||
418 | // profile's geometry. Thus, a swept triangle needs lower hollow values than | ||
419 | // a swept square. | ||
420 | LLProfile::Face* LLProfile::addHole(BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split) | ||
421 | { | ||
422 | // Note that addHole will NOT work for non-"circular" profiles, if we ever decide to use them. | ||
423 | |||
424 | // Total add has number of vertices on outside. | ||
425 | mTotalOut = mTotal; | ||
426 | |||
427 | // Why is the "bevel" parameter -1? DJS 04/05/02 | ||
428 | genNGon(llfloor(sides),offset,-1, ang_scale, split); | ||
429 | |||
430 | Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat); | ||
431 | |||
432 | LLVector3 pt[128]; | ||
433 | |||
434 | for (S32 i=mTotalOut;i<mTotal;i++) | ||
435 | { | ||
436 | pt[i] = mProfile[i] * box_hollow; | ||
437 | } | ||
438 | |||
439 | S32 j=mTotal-1; | ||
440 | for (S32 i=mTotalOut;i<mTotal;i++) | ||
441 | { | ||
442 | mProfile[i] = pt[j--]; | ||
443 | } | ||
444 | |||
445 | for (S32 i=0;i<(S32)mFaces.size();i++) | ||
446 | { | ||
447 | if (mFaces[i].mCap) | ||
448 | { | ||
449 | mFaces[i].mCount *= 2; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | return face; | ||
454 | } | ||
455 | |||
456 | BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split) | ||
457 | { | ||
458 | if (!mDirty) | ||
459 | { | ||
460 | return FALSE; | ||
461 | } | ||
462 | mDirty = FALSE; | ||
463 | |||
464 | if (detail < MIN_LOD) | ||
465 | { | ||
466 | llinfos << "Generating profile with LOD < MIN_LOD. CLAMPING" << llendl; | ||
467 | detail = MIN_LOD; | ||
468 | } | ||
469 | |||
470 | mProfile.clear(); | ||
471 | mFaces.clear(); | ||
472 | |||
473 | // Generate the face data | ||
474 | S32 i; | ||
475 | F32 begin = mParams.getBegin(); | ||
476 | F32 end = mParams.getEnd(); | ||
477 | F32 hollow = mParams.getHollow(); | ||
478 | |||
479 | // Quick validation to eliminate some server crashes. | ||
480 | if (begin > end - 0.01f) | ||
481 | { | ||
482 | llwarns << "LLProfile::generate() assertion failed (begin >= end)" << llendl; | ||
483 | return FALSE; | ||
484 | } | ||
485 | |||
486 | S32 face_num = 0; | ||
487 | |||
488 | switch (mParams.getCurveType() & LL_PCODE_PROFILE_MASK) | ||
489 | { | ||
490 | case LL_PCODE_PROFILE_SQUARE: | ||
491 | { | ||
492 | genNGon(4,-0.375, 0, 1, split); | ||
493 | if (path_open) | ||
494 | { | ||
495 | addCap (LL_FACE_PATH_BEGIN); | ||
496 | } | ||
497 | |||
498 | for (i = llfloor(begin * 4.f); i < llfloor(end * 4.f + .999f); i++) | ||
499 | { | ||
500 | addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE); | ||
501 | } | ||
502 | |||
503 | for (i = 0; i <(S32) mProfile.size(); i++) | ||
504 | { | ||
505 | // Scale by 4 to generate proper tex coords. | ||
506 | mProfile[i].mV[2] *= 4.f; | ||
507 | } | ||
508 | |||
509 | if (hollow) | ||
510 | { | ||
511 | switch (mParams.getCurveType() & LL_PCODE_HOLE_MASK) | ||
512 | { | ||
513 | case LL_PCODE_HOLE_TRIANGLE: | ||
514 | // This offset is not correct, but we can't change it now... DK 11/17/04 | ||
515 | addHole(TRUE, 3, -0.375f, hollow, 1.f, split); | ||
516 | break; | ||
517 | case LL_PCODE_HOLE_CIRCLE: | ||
518 | // TODO: Compute actual detail levels for cubes | ||
519 | addHole(FALSE, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f); | ||
520 | break; | ||
521 | case LL_PCODE_HOLE_SAME: | ||
522 | case LL_PCODE_HOLE_SQUARE: | ||
523 | default: | ||
524 | addHole(TRUE, 4, -0.375f, hollow, 1.f, split); | ||
525 | break; | ||
526 | } | ||
527 | } | ||
528 | |||
529 | if (path_open) { | ||
530 | mFaces[0].mCount = mTotal; | ||
531 | } | ||
532 | } | ||
533 | break; | ||
534 | case LL_PCODE_PROFILE_ISOTRI: | ||
535 | case LL_PCODE_PROFILE_RIGHTTRI: | ||
536 | case LL_PCODE_PROFILE_EQUALTRI: | ||
537 | { | ||
538 | genNGon(3,0, 0, 1, split); | ||
539 | for (i = 0; i <(S32) mProfile.size(); i++) | ||
540 | { | ||
541 | // Scale by 3 to generate proper tex coords. | ||
542 | mProfile[i].mV[2] *= 3.f; | ||
543 | } | ||
544 | |||
545 | if (path_open) | ||
546 | { | ||
547 | addCap(LL_FACE_PATH_BEGIN); | ||
548 | } | ||
549 | |||
550 | for (i = llfloor(begin * 3.f); i < llfloor(end * 3.f + .999f); i++) | ||
551 | { | ||
552 | addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE); | ||
553 | } | ||
554 | if (hollow) | ||
555 | { | ||
556 | // Swept triangles need smaller hollowness values, | ||
557 | // because the triangle doesn't fill the bounding box. | ||
558 | F32 triangle_hollow = hollow / 2.f; | ||
559 | |||
560 | switch (mParams.getCurveType() & LL_PCODE_HOLE_MASK) | ||
561 | { | ||
562 | case LL_PCODE_HOLE_CIRCLE: | ||
563 | // TODO: Actually generate level of detail for triangles | ||
564 | addHole(FALSE, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f); | ||
565 | break; | ||
566 | case LL_PCODE_HOLE_SQUARE: | ||
567 | addHole(TRUE, 4, 0, triangle_hollow, 1.f, split); | ||
568 | break; | ||
569 | case LL_PCODE_HOLE_SAME: | ||
570 | case LL_PCODE_HOLE_TRIANGLE: | ||
571 | default: | ||
572 | addHole(TRUE, 3, 0, triangle_hollow, 1.f, split); | ||
573 | break; | ||
574 | } | ||
575 | } | ||
576 | } | ||
577 | break; | ||
578 | case LL_PCODE_PROFILE_CIRCLE: | ||
579 | { | ||
580 | // If this has a square hollow, we should adjust the | ||
581 | // number of faces a bit so that the geometry lines up. | ||
582 | U8 hole_type=0; | ||
583 | F32 circle_detail = MIN_DETAIL_FACES * detail; | ||
584 | if (hollow) | ||
585 | { | ||
586 | hole_type = mParams.getCurveType() & LL_PCODE_HOLE_MASK; | ||
587 | if (hole_type == LL_PCODE_HOLE_SQUARE) | ||
588 | { | ||
589 | // Snap to the next multiple of four sides, | ||
590 | // so that corners line up. | ||
591 | circle_detail = llceil(circle_detail / 4.0f) * 4.0f; | ||
592 | } | ||
593 | } | ||
594 | |||
595 | //llinfos << "(CIRCLE) detail: " << detail << "; genNGon(" | ||
596 | // << llfloor(circle_detail) << ")" << llendl; | ||
597 | genNGon(llfloor(circle_detail)); | ||
598 | if (path_open) | ||
599 | { | ||
600 | addCap (LL_FACE_PATH_BEGIN); | ||
601 | } | ||
602 | |||
603 | if (mOpen && !hollow) | ||
604 | { | ||
605 | addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE); | ||
606 | } | ||
607 | else | ||
608 | { | ||
609 | addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE); | ||
610 | } | ||
611 | |||
612 | if (hollow) | ||
613 | { | ||
614 | switch (hole_type) | ||
615 | { | ||
616 | case LL_PCODE_HOLE_SQUARE: | ||
617 | addHole(TRUE, 4, 0, hollow, 1.f, split); | ||
618 | break; | ||
619 | case LL_PCODE_HOLE_TRIANGLE: | ||
620 | addHole(TRUE, 3, 0, hollow, 1.f, split); | ||
621 | break; | ||
622 | case LL_PCODE_HOLE_CIRCLE: | ||
623 | case LL_PCODE_HOLE_SAME: | ||
624 | default: | ||
625 | addHole(FALSE, circle_detail, 0, hollow, 1.f); | ||
626 | break; | ||
627 | } | ||
628 | } | ||
629 | } | ||
630 | break; | ||
631 | case LL_PCODE_PROFILE_CIRCLE_HALF: | ||
632 | { | ||
633 | // If this has a square hollow, we should adjust the | ||
634 | // number of faces a bit so that the geometry lines up. | ||
635 | U8 hole_type=0; | ||
636 | // Number of faces is cut in half because it's only a half-circle. | ||
637 | F32 circle_detail = MIN_DETAIL_FACES * detail * 0.5f; | ||
638 | if (hollow) | ||
639 | { | ||
640 | hole_type = mParams.getCurveType() & LL_PCODE_HOLE_MASK; | ||
641 | if (hole_type == LL_PCODE_HOLE_SQUARE) | ||
642 | { | ||
643 | // Snap to the next multiple of four sides (div 2), | ||
644 | // so that corners line up. | ||
645 | circle_detail = llceil(circle_detail / 2.0f) * 2.0f; | ||
646 | } | ||
647 | } | ||
648 | genNGon(llfloor(circle_detail), 0.5f, 0.f, 0.5f); | ||
649 | if (path_open) | ||
650 | { | ||
651 | addCap(LL_FACE_PATH_BEGIN); | ||
652 | } | ||
653 | if (mOpen && !mParams.getHollow()) | ||
654 | { | ||
655 | addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE); | ||
656 | } | ||
657 | else | ||
658 | { | ||
659 | addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE); | ||
660 | } | ||
661 | |||
662 | if (hollow) | ||
663 | { | ||
664 | switch (hole_type) | ||
665 | { | ||
666 | case LL_PCODE_HOLE_SQUARE: | ||
667 | addHole(TRUE, 2, 0.5f, hollow, 0.5f, split); | ||
668 | break; | ||
669 | case LL_PCODE_HOLE_TRIANGLE: | ||
670 | addHole(TRUE, 3, 0.5f, hollow, 0.5f, split); | ||
671 | break; | ||
672 | case LL_PCODE_HOLE_CIRCLE: | ||
673 | case LL_PCODE_HOLE_SAME: | ||
674 | default: | ||
675 | addHole(FALSE, circle_detail, 0.5f, hollow, 0.5f); | ||
676 | break; | ||
677 | } | ||
678 | } | ||
679 | |||
680 | // Special case for openness of sphere | ||
681 | if ((mParams.getEnd() - mParams.getBegin()) < 1.f) | ||
682 | { | ||
683 | mOpen = TRUE; | ||
684 | } | ||
685 | else if (!hollow) | ||
686 | { | ||
687 | mOpen = FALSE; | ||
688 | mProfile.push_back(mProfile[0]); | ||
689 | mTotal++; | ||
690 | } | ||
691 | } | ||
692 | break; | ||
693 | default: | ||
694 | llerrs << "Unknown profile: getCurveType()=" << mParams.getCurveType() << llendl; | ||
695 | break; | ||
696 | }; | ||
697 | |||
698 | if (path_open) | ||
699 | { | ||
700 | addCap(LL_FACE_PATH_END); // bottom | ||
701 | } | ||
702 | |||
703 | if ( mOpen) // interior edge caps | ||
704 | { | ||
705 | addFace(mTotal-1, 2,0.5,LL_FACE_PROFILE_BEGIN, TRUE); | ||
706 | |||
707 | if (hollow) | ||
708 | { | ||
709 | addFace(mTotalOut-1, 2,0.5,LL_FACE_PROFILE_END, TRUE); | ||
710 | } | ||
711 | else | ||
712 | { | ||
713 | addFace(mTotal-2, 2,0.5,LL_FACE_PROFILE_END, TRUE); | ||
714 | } | ||
715 | } | ||
716 | |||
717 | //genNormals(); | ||
718 | |||
719 | return TRUE; | ||
720 | } | ||
721 | |||
722 | |||
723 | |||
724 | BOOL LLProfileParams::importFile(FILE *fp) | ||
725 | { | ||
726 | const S32 BUFSIZE = 16384; | ||
727 | char buffer[BUFSIZE]; | ||
728 | char keyword[256]; | ||
729 | char valuestr[256]; | ||
730 | keyword[0] = 0; | ||
731 | valuestr[0] = 0; | ||
732 | F32 tempF32; | ||
733 | U32 tempU32; | ||
734 | |||
735 | while (!feof(fp)) | ||
736 | { | ||
737 | fgets(buffer, BUFSIZE, fp); | ||
738 | sscanf(buffer, " %s %s", keyword, valuestr); | ||
739 | if (!keyword) | ||
740 | { | ||
741 | continue; | ||
742 | } | ||
743 | if (!strcmp("{", keyword)) | ||
744 | { | ||
745 | continue; | ||
746 | } | ||
747 | if (!strcmp("}",keyword)) | ||
748 | { | ||
749 | break; | ||
750 | } | ||
751 | else if (!strcmp("curve", keyword)) | ||
752 | { | ||
753 | sscanf(valuestr,"%d",&tempU32); | ||
754 | setCurveType((U8) tempU32); | ||
755 | } | ||
756 | else if (!strcmp("begin",keyword)) | ||
757 | { | ||
758 | sscanf(valuestr,"%g",&tempF32); | ||
759 | setBegin(tempF32); | ||
760 | } | ||
761 | else if (!strcmp("end",keyword)) | ||
762 | { | ||
763 | sscanf(valuestr,"%g",&tempF32); | ||
764 | setEnd(tempF32); | ||
765 | } | ||
766 | else if (!strcmp("hollow",keyword)) | ||
767 | { | ||
768 | sscanf(valuestr,"%g",&tempF32); | ||
769 | setHollow(tempF32); | ||
770 | } | ||
771 | else | ||
772 | { | ||
773 | llwarns << "unknown keyword " << keyword << " in profile import" << llendl; | ||
774 | } | ||
775 | } | ||
776 | |||
777 | return TRUE; | ||
778 | } | ||
779 | |||
780 | |||
781 | BOOL LLProfileParams::exportFile(FILE *fp) const | ||
782 | { | ||
783 | fprintf(fp,"\t\tprofile 0\n"); | ||
784 | fprintf(fp,"\t\t{\n"); | ||
785 | fprintf(fp,"\t\t\tcurve\t%d\n", getCurveType()); | ||
786 | fprintf(fp,"\t\t\tbegin\t%g\n", getBegin()); | ||
787 | fprintf(fp,"\t\t\tend\t%g\n", getEnd()); | ||
788 | fprintf(fp,"\t\t\thollow\t%g\n", getHollow()); | ||
789 | fprintf(fp, "\t\t}\n"); | ||
790 | return TRUE; | ||
791 | } | ||
792 | |||
793 | |||
794 | BOOL LLProfileParams::importLegacyStream(std::istream& input_stream) | ||
795 | { | ||
796 | const S32 BUFSIZE = 16384; | ||
797 | char buffer[BUFSIZE]; | ||
798 | char keyword[256]; | ||
799 | char valuestr[256]; | ||
800 | keyword[0] = 0; | ||
801 | valuestr[0] = 0; | ||
802 | F32 tempF32; | ||
803 | U32 tempU32; | ||
804 | |||
805 | while (input_stream.good()) | ||
806 | { | ||
807 | input_stream.getline(buffer, BUFSIZE); | ||
808 | sscanf(buffer, " %s %s", keyword, valuestr); | ||
809 | if (!keyword) | ||
810 | { | ||
811 | continue; | ||
812 | } | ||
813 | if (!strcmp("{", keyword)) | ||
814 | { | ||
815 | continue; | ||
816 | } | ||
817 | if (!strcmp("}",keyword)) | ||
818 | { | ||
819 | break; | ||
820 | } | ||
821 | else if (!strcmp("curve", keyword)) | ||
822 | { | ||
823 | sscanf(valuestr,"%d",&tempU32); | ||
824 | setCurveType((U8) tempU32); | ||
825 | } | ||
826 | else if (!strcmp("begin",keyword)) | ||
827 | { | ||
828 | sscanf(valuestr,"%g",&tempF32); | ||
829 | setBegin(tempF32); | ||
830 | } | ||
831 | else if (!strcmp("end",keyword)) | ||
832 | { | ||
833 | sscanf(valuestr,"%g",&tempF32); | ||
834 | setEnd(tempF32); | ||
835 | } | ||
836 | else if (!strcmp("hollow",keyword)) | ||
837 | { | ||
838 | sscanf(valuestr,"%g",&tempF32); | ||
839 | setHollow(tempF32); | ||
840 | } | ||
841 | else | ||
842 | { | ||
843 | llwarns << "unknown keyword " << keyword << " in profile import" << llendl; | ||
844 | } | ||
845 | } | ||
846 | |||
847 | return TRUE; | ||
848 | } | ||
849 | |||
850 | |||
851 | BOOL LLProfileParams::exportLegacyStream(std::ostream& output_stream) const | ||
852 | { | ||
853 | output_stream <<"\t\tprofile 0\n"; | ||
854 | output_stream <<"\t\t{\n"; | ||
855 | output_stream <<"\t\t\tcurve\t" << (S32) getCurveType() << "\n"; | ||
856 | output_stream <<"\t\t\tbegin\t" << getBegin() << "\n"; | ||
857 | output_stream <<"\t\t\tend\t" << getEnd() << "\n"; | ||
858 | output_stream <<"\t\t\thollow\t" << getHollow() << "\n"; | ||
859 | output_stream << "\t\t}\n"; | ||
860 | return TRUE; | ||
861 | } | ||
862 | |||
863 | LLSD LLProfileParams::asLLSD() const | ||
864 | { | ||
865 | LLSD sd; | ||
866 | |||
867 | sd["curve"] = getCurveType(); | ||
868 | sd["begin"] = getBegin(); | ||
869 | sd["end"] = getEnd(); | ||
870 | sd["hollow"] = getHollow(); | ||
871 | return sd; | ||
872 | } | ||
873 | |||
874 | bool LLProfileParams::fromLLSD(LLSD& sd) | ||
875 | { | ||
876 | setCurveType(sd["curve"].asInteger()); | ||
877 | setBegin((F32)sd["begin"].asReal()); | ||
878 | setEnd((F32)sd["end"].asReal()); | ||
879 | setHollow((F32)sd["hollow"].asReal()); | ||
880 | return true; | ||
881 | } | ||
882 | |||
883 | void LLProfileParams::copyParams(const LLProfileParams ¶ms) | ||
884 | { | ||
885 | setCurveType(params.getCurveType()); | ||
886 | setBegin(params.getBegin()); | ||
887 | setEnd(params.getEnd()); | ||
888 | setHollow(params.getHollow()); | ||
889 | } | ||
890 | |||
891 | |||
892 | LLPath::~LLPath() | ||
893 | { | ||
894 | } | ||
895 | |||
896 | void LLPath::genNGon(S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) | ||
897 | { | ||
898 | // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane. | ||
899 | const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; | ||
900 | |||
901 | F32 revolutions = mParams.getRevolutions(); | ||
902 | F32 skew = mParams.getSkew(); | ||
903 | F32 skew_mag = fabs(skew); | ||
904 | F32 hole_x = mParams.getScaleX() * (1.0f - skew_mag); | ||
905 | F32 hole_y = mParams.getScaleY(); | ||
906 | |||
907 | // Calculate taper begin/end for x,y (Negative means taper the beginning) | ||
908 | F32 taper_x_begin = 1.0f; | ||
909 | F32 taper_x_end = 1.0f - mParams.getTaperX(); | ||
910 | F32 taper_y_begin = 1.0f; | ||
911 | F32 taper_y_end = 1.0f - mParams.getTaperY(); | ||
912 | |||
913 | if ( taper_x_end > 1.0f ) | ||
914 | { | ||
915 | // Flip tapering. | ||
916 | taper_x_begin = 2.0f - taper_x_end; | ||
917 | taper_x_end = 1.0f; | ||
918 | } | ||
919 | if ( taper_y_end > 1.0f ) | ||
920 | { | ||
921 | // Flip tapering. | ||
922 | taper_y_begin = 2.0f - taper_y_end; | ||
923 | taper_y_end = 1.0f; | ||
924 | } | ||
925 | |||
926 | // For spheres, the radius is usually zero. | ||
927 | F32 radius_start = 0.5f; | ||
928 | if (sides < 8) | ||
929 | { | ||
930 | radius_start = tableScale[sides]; | ||
931 | } | ||
932 | |||
933 | // Scale the radius to take the hole size into account. | ||
934 | radius_start *= 1.0f - hole_y; | ||
935 | |||
936 | // Now check the radius offset to calculate the start,end radius. (Negative means | ||
937 | // decrease the start radius instead). | ||
938 | F32 radius_end = radius_start; | ||
939 | F32 radius_offset = mParams.getRadiusOffset(); | ||
940 | if (radius_offset < 0.f) | ||
941 | { | ||
942 | radius_start *= 1.f + radius_offset; | ||
943 | } | ||
944 | else | ||
945 | { | ||
946 | radius_end *= 1.f - radius_offset; | ||
947 | } | ||
948 | |||
949 | // Is the path NOT a closed loop? | ||
950 | mOpen = ( (mParams.getEnd()*end_scale - mParams.getBegin() < 1.0f) || | ||
951 | (skew_mag > 0.001f) || | ||
952 | (fabs(taper_x_end - taper_x_begin) > 0.001f) || | ||
953 | (fabs(taper_y_end - taper_y_begin) > 0.001f) || | ||
954 | (fabs(radius_end - radius_start) > 0.001f) ); | ||
955 | |||
956 | F32 ang, c, s; | ||
957 | LLQuaternion twist, qang; | ||
958 | PathPt *pt; | ||
959 | LLVector3 path_axis (1.f, 0.f, 0.f); | ||
960 | //LLVector3 twist_axis(0.f, 0.f, 1.f); | ||
961 | F32 twist_begin = mParams.getTwistBegin() * twist_scale; | ||
962 | F32 twist_end = mParams.getTwist() * twist_scale; | ||
963 | |||
964 | // We run through this once before the main loop, to make sure | ||
965 | // the path begins at the correct cut. | ||
966 | F32 step= 1.0f / sides; | ||
967 | F32 t = mParams.getBegin(); | ||
968 | pt = vector_append(mPath, 1); | ||
969 | ang = 2.0f*F_PI*revolutions * t; | ||
970 | s = sin(ang)*lerp(radius_start, radius_end, t); | ||
971 | c = cos(ang)*lerp(radius_start, radius_end, t); | ||
972 | |||
973 | |||
974 | pt->mPos.setVec(0 + lerp(0,mParams.getShear().mV[0],s) | ||
975 | + lerp(-skew ,skew, t) * 0.5f, | ||
976 | c + lerp(0,mParams.getShear().mV[1],s), | ||
977 | s); | ||
978 | pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); | ||
979 | pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); | ||
980 | pt->mTexT = t; | ||
981 | |||
982 | // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 | ||
983 | twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); | ||
984 | // Rotate the point around the circle's center. | ||
985 | qang.setQuat (ang,path_axis); | ||
986 | pt->mRot = twist * qang; | ||
987 | |||
988 | t+=step; | ||
989 | |||
990 | // Snap to a quantized parameter, so that cut does not | ||
991 | // affect most sample points. | ||
992 | t = ((S32)(t * sides)) / (F32)sides; | ||
993 | |||
994 | // Run through the non-cut dependent points. | ||
995 | while (t < mParams.getEnd()) | ||
996 | { | ||
997 | pt = vector_append(mPath, 1); | ||
998 | |||
999 | ang = 2.0f*F_PI*revolutions * t; | ||
1000 | c = cos(ang)*lerp(radius_start, radius_end, t); | ||
1001 | s = sin(ang)*lerp(radius_start, radius_end, t); | ||
1002 | |||
1003 | pt->mPos.setVec(0 + lerp(0,mParams.getShear().mV[0],s) | ||
1004 | + lerp(-skew ,skew, t) * 0.5f, | ||
1005 | c + lerp(0,mParams.getShear().mV[1],s), | ||
1006 | s); | ||
1007 | |||
1008 | pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); | ||
1009 | pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); | ||
1010 | pt->mTexT = t; | ||
1011 | |||
1012 | // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 | ||
1013 | twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); | ||
1014 | // Rotate the point around the circle's center. | ||
1015 | qang.setQuat (ang,path_axis); | ||
1016 | pt->mRot = twist * qang; | ||
1017 | |||
1018 | t+=step; | ||
1019 | } | ||
1020 | |||
1021 | // Make one final pass for the end cut. | ||
1022 | t = mParams.getEnd(); | ||
1023 | pt = vector_append(mPath, 1); | ||
1024 | ang = 2.0f*F_PI*revolutions * t; | ||
1025 | c = cos(ang)*lerp(radius_start, radius_end, t); | ||
1026 | s = sin(ang)*lerp(radius_start, radius_end, t); | ||
1027 | |||
1028 | pt->mPos.setVec(0 + lerp(0,mParams.getShear().mV[0],s) | ||
1029 | + lerp(-skew ,skew, t) * 0.5f, | ||
1030 | c + lerp(0,mParams.getShear().mV[1],s), | ||
1031 | s); | ||
1032 | pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); | ||
1033 | pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); | ||
1034 | pt->mTexT = t; | ||
1035 | |||
1036 | // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 | ||
1037 | twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); | ||
1038 | // Rotate the point around the circle's center. | ||
1039 | qang.setQuat (ang,path_axis); | ||
1040 | pt->mRot = twist * qang; | ||
1041 | |||
1042 | mTotal = mPath.size(); | ||
1043 | } | ||
1044 | |||
1045 | const LLVector2 LLPathParams::getBeginScale() const | ||
1046 | { | ||
1047 | LLVector2 begin_scale(1.f, 1.f); | ||
1048 | if (getScaleX() > 1) | ||
1049 | { | ||
1050 | begin_scale.mV[0] = 2-getScaleX(); | ||
1051 | } | ||
1052 | if (getScaleY() > 1) | ||
1053 | { | ||
1054 | begin_scale.mV[1] = 2-getScaleY(); | ||
1055 | } | ||
1056 | return begin_scale; | ||
1057 | } | ||
1058 | |||
1059 | const LLVector2 LLPathParams::getEndScale() const | ||
1060 | { | ||
1061 | LLVector2 end_scale(1.f, 1.f); | ||
1062 | if (getScaleX() < 1) | ||
1063 | { | ||
1064 | end_scale.mV[0] = getScaleX(); | ||
1065 | } | ||
1066 | if (getScaleY() < 1) | ||
1067 | { | ||
1068 | end_scale.mV[1] = getScaleY(); | ||
1069 | } | ||
1070 | return end_scale; | ||
1071 | } | ||
1072 | |||
1073 | BOOL LLPath::generate(F32 detail, S32 split) | ||
1074 | { | ||
1075 | if (!mDirty) | ||
1076 | { | ||
1077 | return FALSE; | ||
1078 | } | ||
1079 | |||
1080 | if (detail < MIN_LOD) | ||
1081 | { | ||
1082 | llinfos << "Generating path with LOD < MIN! Clamping to 1" << llendl; | ||
1083 | detail = MIN_LOD; | ||
1084 | } | ||
1085 | |||
1086 | mDirty = FALSE; | ||
1087 | S32 np = 2; // hardcode for line | ||
1088 | |||
1089 | mPath.clear(); | ||
1090 | mOpen = TRUE; | ||
1091 | |||
1092 | // Is this 0xf0 mask really necessary? DK 03/02/05 | ||
1093 | switch (mParams.getCurveType() & 0xf0) | ||
1094 | { | ||
1095 | default: | ||
1096 | case LL_PCODE_PATH_LINE: | ||
1097 | { | ||
1098 | // Take the begin/end twist into account for detail. | ||
1099 | np = llfloor(fabs(mParams.getTwistBegin() - mParams.getTwist()) * 3.5f * (detail-0.5f)) + 2; | ||
1100 | if (np < split+2) | ||
1101 | { | ||
1102 | np = split+2; | ||
1103 | } | ||
1104 | |||
1105 | mStep = 1.0f / (np-1); | ||
1106 | |||
1107 | mPath.resize(np); | ||
1108 | |||
1109 | LLVector2 start_scale = mParams.getBeginScale(); | ||
1110 | LLVector2 end_scale = mParams.getEndScale(); | ||
1111 | |||
1112 | for (S32 i=0;i<np;i++) | ||
1113 | { | ||
1114 | F32 t = lerp(mParams.getBegin(),mParams.getEnd(),(F32)i * mStep); | ||
1115 | mPath[i].mPos.setVec(lerp(0,mParams.getShear().mV[0],t), | ||
1116 | lerp(0,mParams.getShear().mV[1],t), | ||
1117 | t - 0.5f); | ||
1118 | mPath[i].mRot.setQuat(lerp(F_PI * mParams.getTwistBegin(),F_PI * mParams.getTwist(),t),0,0,1); | ||
1119 | mPath[i].mScale.mV[0] = lerp(start_scale.mV[0],end_scale.mV[0],t); | ||
1120 | mPath[i].mScale.mV[1] = lerp(start_scale.mV[1],end_scale.mV[1],t); | ||
1121 | mPath[i].mTexT = t; | ||
1122 | } | ||
1123 | } | ||
1124 | break; | ||
1125 | |||
1126 | case LL_PCODE_PATH_CIRCLE: | ||
1127 | { | ||
1128 | // Increase the detail as the revolutions and twist increase. | ||
1129 | F32 twist_mag = fabs(mParams.getTwistBegin() - mParams.getTwist()); | ||
1130 | genNGon(llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * mParams.getRevolutions())); | ||
1131 | } | ||
1132 | break; | ||
1133 | |||
1134 | case LL_PCODE_PATH_CIRCLE2: | ||
1135 | { | ||
1136 | if (mParams.getEnd() - mParams.getBegin() >= 0.99f && | ||
1137 | mParams.getScaleX() >= .99f) | ||
1138 | { | ||
1139 | mOpen = FALSE; | ||
1140 | } | ||
1141 | |||
1142 | //genNGon(llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f); | ||
1143 | genNGon(llfloor(MIN_DETAIL_FACES * detail)); | ||
1144 | |||
1145 | F32 t = 0.f; | ||
1146 | F32 tStep = 1.0f / mPath.size(); | ||
1147 | |||
1148 | F32 toggle = 0.5f; | ||
1149 | for (S32 i=0;i<(S32)mPath.size();i++) | ||
1150 | { | ||
1151 | mPath[i].mPos.mV[0] = toggle; | ||
1152 | if (toggle == 0.5f) | ||
1153 | toggle = -0.5f; | ||
1154 | else | ||
1155 | toggle = 0.5f; | ||
1156 | t += tStep; | ||
1157 | } | ||
1158 | } | ||
1159 | |||
1160 | break; | ||
1161 | |||
1162 | case LL_PCODE_PATH_TEST: | ||
1163 | |||
1164 | np = 5; | ||
1165 | mStep = 1.0f / (np-1); | ||
1166 | |||
1167 | mPath.resize(np); | ||
1168 | |||
1169 | for (S32 i=0;i<np;i++) | ||
1170 | { | ||
1171 | F32 t = (F32)i * mStep; | ||
1172 | mPath[i].mPos.setVec(0, | ||
1173 | lerp(0, -sin(F_PI*mParams.getTwist()*t)*0.5f,t), | ||
1174 | lerp(-0.5, cos(F_PI*mParams.getTwist()*t)*0.5f,t)); | ||
1175 | mPath[i].mScale.mV[0] = lerp(1,mParams.getScale().mV[0],t); | ||
1176 | mPath[i].mScale.mV[1] = lerp(1,mParams.getScale().mV[1],t); | ||
1177 | mPath[i].mTexT = t; | ||
1178 | mPath[i].mRot.setQuat(F_PI * mParams.getTwist() * t,1,0,0); | ||
1179 | } | ||
1180 | |||
1181 | break; | ||
1182 | }; | ||
1183 | |||
1184 | if (mParams.getTwist() != mParams.getTwistBegin()) mOpen = TRUE; | ||
1185 | |||
1186 | //if ((int(fabsf(mParams.getTwist() - mParams.getTwistBegin())*100))%100 != 0) { | ||
1187 | // mOpen = TRUE; | ||
1188 | //} | ||
1189 | |||
1190 | return TRUE; | ||
1191 | } | ||
1192 | |||
1193 | BOOL LLDynamicPath::generate(F32 detail, S32 split) | ||
1194 | { | ||
1195 | mOpen = TRUE; // Draw end caps | ||
1196 | if (getPathLength() == 0) | ||
1197 | { | ||
1198 | // Path hasn't been generated yet. | ||
1199 | // Some algorithms later assume at least TWO path points. | ||
1200 | resizePath(2); | ||
1201 | for (U32 i = 0; i < 2; i++) | ||
1202 | { | ||
1203 | mPath[i].mPos.setVec(0, 0, 0); | ||
1204 | mPath[i].mRot.setQuat(0, 0, 0); | ||
1205 | mPath[i].mScale.setVec(1, 1); | ||
1206 | mPath[i].mTexT = 0; | ||
1207 | } | ||
1208 | } | ||
1209 | |||
1210 | return TRUE; | ||
1211 | } | ||
1212 | |||
1213 | |||
1214 | BOOL LLPathParams::importFile(FILE *fp) | ||
1215 | { | ||
1216 | const S32 BUFSIZE = 16384; | ||
1217 | char buffer[BUFSIZE]; | ||
1218 | char keyword[256]; | ||
1219 | char valuestr[256]; | ||
1220 | keyword[0] = 0; | ||
1221 | valuestr[0] = 0; | ||
1222 | |||
1223 | F32 tempF32; | ||
1224 | F32 x, y; | ||
1225 | U32 tempU32; | ||
1226 | |||
1227 | while (!feof(fp)) | ||
1228 | { | ||
1229 | fgets(buffer, BUFSIZE, fp); | ||
1230 | sscanf(buffer, " %s %s", keyword, valuestr); | ||
1231 | if (!keyword) | ||
1232 | { | ||
1233 | continue; | ||
1234 | } | ||
1235 | if (!strcmp("{", keyword)) | ||
1236 | { | ||
1237 | continue; | ||
1238 | } | ||
1239 | if (!strcmp("}",keyword)) | ||
1240 | { | ||
1241 | break; | ||
1242 | } | ||
1243 | else if (!strcmp("curve", keyword)) | ||
1244 | { | ||
1245 | sscanf(valuestr,"%d",&tempU32); | ||
1246 | setCurveType((U8) tempU32); | ||
1247 | } | ||
1248 | else if (!strcmp("begin",keyword)) | ||
1249 | { | ||
1250 | sscanf(valuestr,"%g",&tempF32); | ||
1251 | setBegin(tempF32); | ||
1252 | } | ||
1253 | else if (!strcmp("end",keyword)) | ||
1254 | { | ||
1255 | sscanf(valuestr,"%g",&tempF32); | ||
1256 | setEnd(tempF32); | ||
1257 | } | ||
1258 | else if (!strcmp("scale",keyword)) | ||
1259 | { | ||
1260 | // Legacy for one dimensional scale per path | ||
1261 | sscanf(valuestr,"%g",&tempF32); | ||
1262 | setScale(tempF32, tempF32); | ||
1263 | } | ||
1264 | else if (!strcmp("scale_x", keyword)) | ||
1265 | { | ||
1266 | sscanf(valuestr, "%g", &x); | ||
1267 | setScaleX(x); | ||
1268 | } | ||
1269 | else if (!strcmp("scale_y", keyword)) | ||
1270 | { | ||
1271 | sscanf(valuestr, "%g", &y); | ||
1272 | setScaleY(y); | ||
1273 | } | ||
1274 | else if (!strcmp("shear_x", keyword)) | ||
1275 | { | ||
1276 | sscanf(valuestr, "%g", &x); | ||
1277 | setShearX(x); | ||
1278 | } | ||
1279 | else if (!strcmp("shear_y", keyword)) | ||
1280 | { | ||
1281 | sscanf(valuestr, "%g", &y); | ||
1282 | setShearY(y); | ||
1283 | } | ||
1284 | else if (!strcmp("twist",keyword)) | ||
1285 | { | ||
1286 | sscanf(valuestr,"%g",&tempF32); | ||
1287 | setTwist(tempF32); | ||
1288 | } | ||
1289 | else if (!strcmp("twist_begin", keyword)) | ||
1290 | { | ||
1291 | sscanf(valuestr, "%g", &y); | ||
1292 | setTwistBegin(y); | ||
1293 | } | ||
1294 | else if (!strcmp("radius_offset", keyword)) | ||
1295 | { | ||
1296 | sscanf(valuestr, "%g", &y); | ||
1297 | setRadiusOffset(y); | ||
1298 | } | ||
1299 | else if (!strcmp("taper_x", keyword)) | ||
1300 | { | ||
1301 | sscanf(valuestr, "%g", &y); | ||
1302 | setTaperX(y); | ||
1303 | } | ||
1304 | else if (!strcmp("taper_y", keyword)) | ||
1305 | { | ||
1306 | sscanf(valuestr, "%g", &y); | ||
1307 | setTaperY(y); | ||
1308 | } | ||
1309 | else if (!strcmp("revolutions", keyword)) | ||
1310 | { | ||
1311 | sscanf(valuestr, "%g", &y); | ||
1312 | setRevolutions(y); | ||
1313 | } | ||
1314 | else if (!strcmp("skew", keyword)) | ||
1315 | { | ||
1316 | sscanf(valuestr, "%g", &y); | ||
1317 | setSkew(y); | ||
1318 | } | ||
1319 | else | ||
1320 | { | ||
1321 | llwarns << "unknown keyword " << " in path import" << llendl; | ||
1322 | } | ||
1323 | } | ||
1324 | return TRUE; | ||
1325 | } | ||
1326 | |||
1327 | |||
1328 | BOOL LLPathParams::exportFile(FILE *fp) const | ||
1329 | { | ||
1330 | fprintf(fp, "\t\tpath 0\n"); | ||
1331 | fprintf(fp, "\t\t{\n"); | ||
1332 | fprintf(fp, "\t\t\tcurve\t%d\n", getCurveType()); | ||
1333 | fprintf(fp, "\t\t\tbegin\t%g\n", getBegin()); | ||
1334 | fprintf(fp, "\t\t\tend\t%g\n", getEnd()); | ||
1335 | fprintf(fp, "\t\t\tscale_x\t%g\n", getScaleX() ); | ||
1336 | fprintf(fp, "\t\t\tscale_y\t%g\n", getScaleY() ); | ||
1337 | fprintf(fp, "\t\t\tshear_x\t%g\n", getShearX() ); | ||
1338 | fprintf(fp, "\t\t\tshear_y\t%g\n", getShearY() ); | ||
1339 | fprintf(fp,"\t\t\ttwist\t%g\n", getTwist()); | ||
1340 | |||
1341 | fprintf(fp,"\t\t\ttwist_begin\t%g\n", getTwistBegin()); | ||
1342 | fprintf(fp,"\t\t\tradius_offset\t%g\n", getRadiusOffset()); | ||
1343 | fprintf(fp,"\t\t\ttaper_x\t%g\n", getTaperX()); | ||
1344 | fprintf(fp,"\t\t\ttaper_y\t%g\n", getTaperY()); | ||
1345 | fprintf(fp,"\t\t\trevolutions\t%g\n", getRevolutions()); | ||
1346 | fprintf(fp,"\t\t\tskew\t%g\n", getSkew()); | ||
1347 | |||
1348 | fprintf(fp, "\t\t}\n"); | ||
1349 | return TRUE; | ||
1350 | } | ||
1351 | |||
1352 | |||
1353 | BOOL LLPathParams::importLegacyStream(std::istream& input_stream) | ||
1354 | { | ||
1355 | const S32 BUFSIZE = 16384; | ||
1356 | char buffer[BUFSIZE]; | ||
1357 | char keyword[256]; | ||
1358 | char valuestr[256]; | ||
1359 | keyword[0] = 0; | ||
1360 | valuestr[0] = 0; | ||
1361 | |||
1362 | F32 tempF32; | ||
1363 | F32 x, y; | ||
1364 | U32 tempU32; | ||
1365 | |||
1366 | while (input_stream.good()) | ||
1367 | { | ||
1368 | input_stream.getline(buffer, BUFSIZE); | ||
1369 | sscanf(buffer, " %s %s", keyword, valuestr); | ||
1370 | if (!keyword) | ||
1371 | { | ||
1372 | continue; | ||
1373 | } | ||
1374 | if (!strcmp("{", keyword)) | ||
1375 | { | ||
1376 | continue; | ||
1377 | } | ||
1378 | if (!strcmp("}",keyword)) | ||
1379 | { | ||
1380 | break; | ||
1381 | } | ||
1382 | else if (!strcmp("curve", keyword)) | ||
1383 | { | ||
1384 | sscanf(valuestr,"%d",&tempU32); | ||
1385 | setCurveType((U8) tempU32); | ||
1386 | } | ||
1387 | else if (!strcmp("begin",keyword)) | ||
1388 | { | ||
1389 | sscanf(valuestr,"%g",&tempF32); | ||
1390 | setBegin(tempF32); | ||
1391 | } | ||
1392 | else if (!strcmp("end",keyword)) | ||
1393 | { | ||
1394 | sscanf(valuestr,"%g",&tempF32); | ||
1395 | setEnd(tempF32); | ||
1396 | } | ||
1397 | else if (!strcmp("scale",keyword)) | ||
1398 | { | ||
1399 | // Legacy for one dimensional scale per path | ||
1400 | sscanf(valuestr,"%g",&tempF32); | ||
1401 | setScale(tempF32, tempF32); | ||
1402 | } | ||
1403 | else if (!strcmp("scale_x", keyword)) | ||
1404 | { | ||
1405 | sscanf(valuestr, "%g", &x); | ||
1406 | setScaleX(x); | ||
1407 | } | ||
1408 | else if (!strcmp("scale_y", keyword)) | ||
1409 | { | ||
1410 | sscanf(valuestr, "%g", &y); | ||
1411 | setScaleY(y); | ||
1412 | } | ||
1413 | else if (!strcmp("shear_x", keyword)) | ||
1414 | { | ||
1415 | sscanf(valuestr, "%g", &x); | ||
1416 | setShearX(x); | ||
1417 | } | ||
1418 | else if (!strcmp("shear_y", keyword)) | ||
1419 | { | ||
1420 | sscanf(valuestr, "%g", &y); | ||
1421 | setShearY(y); | ||
1422 | } | ||
1423 | else if (!strcmp("twist",keyword)) | ||
1424 | { | ||
1425 | sscanf(valuestr,"%g",&tempF32); | ||
1426 | setTwist(tempF32); | ||
1427 | } | ||
1428 | else if (!strcmp("twist_begin", keyword)) | ||
1429 | { | ||
1430 | sscanf(valuestr, "%g", &y); | ||
1431 | setTwistBegin(y); | ||
1432 | } | ||
1433 | else if (!strcmp("radius_offset", keyword)) | ||
1434 | { | ||
1435 | sscanf(valuestr, "%g", &y); | ||
1436 | setRadiusOffset(y); | ||
1437 | } | ||
1438 | else if (!strcmp("taper_x", keyword)) | ||
1439 | { | ||
1440 | sscanf(valuestr, "%g", &y); | ||
1441 | setTaperX(y); | ||
1442 | } | ||
1443 | else if (!strcmp("taper_y", keyword)) | ||
1444 | { | ||
1445 | sscanf(valuestr, "%g", &y); | ||
1446 | setTaperY(y); | ||
1447 | } | ||
1448 | else if (!strcmp("revolutions", keyword)) | ||
1449 | { | ||
1450 | sscanf(valuestr, "%g", &y); | ||
1451 | setRevolutions(y); | ||
1452 | } | ||
1453 | else if (!strcmp("skew", keyword)) | ||
1454 | { | ||
1455 | sscanf(valuestr, "%g", &y); | ||
1456 | setSkew(y); | ||
1457 | } | ||
1458 | else | ||
1459 | { | ||
1460 | llwarns << "unknown keyword " << " in path import" << llendl; | ||
1461 | } | ||
1462 | } | ||
1463 | return TRUE; | ||
1464 | } | ||
1465 | |||
1466 | |||
1467 | BOOL LLPathParams::exportLegacyStream(std::ostream& output_stream) const | ||
1468 | { | ||
1469 | output_stream << "\t\tpath 0\n"; | ||
1470 | output_stream << "\t\t{\n"; | ||
1471 | output_stream << "\t\t\tcurve\t" << (S32) getCurveType() << "\n"; | ||
1472 | output_stream << "\t\t\tbegin\t" << getBegin() << "\n"; | ||
1473 | output_stream << "\t\t\tend\t" << getEnd() << "\n"; | ||
1474 | output_stream << "\t\t\tscale_x\t" << getScaleX() << "\n"; | ||
1475 | output_stream << "\t\t\tscale_y\t" << getScaleY() << "\n"; | ||
1476 | output_stream << "\t\t\tshear_x\t" << getShearX() << "\n"; | ||
1477 | output_stream << "\t\t\tshear_y\t" << getShearY() << "\n"; | ||
1478 | output_stream <<"\t\t\ttwist\t" << getTwist() << "\n"; | ||
1479 | |||
1480 | output_stream <<"\t\t\ttwist_begin\t" << getTwistBegin() << "\n"; | ||
1481 | output_stream <<"\t\t\tradius_offset\t" << getRadiusOffset() << "\n"; | ||
1482 | output_stream <<"\t\t\ttaper_x\t" << getTaperX() << "\n"; | ||
1483 | output_stream <<"\t\t\ttaper_y\t" << getTaperY() << "\n"; | ||
1484 | output_stream <<"\t\t\trevolutions\t" << getRevolutions() << "\n"; | ||
1485 | output_stream <<"\t\t\tskew\t" << getSkew() << "\n"; | ||
1486 | |||
1487 | output_stream << "\t\t}\n"; | ||
1488 | return TRUE; | ||
1489 | } | ||
1490 | |||
1491 | LLSD LLPathParams::asLLSD() const | ||
1492 | { | ||
1493 | LLSD sd = LLSD(); | ||
1494 | sd["curve"] = getCurveType(); | ||
1495 | sd["begin"] = getBegin(); | ||
1496 | sd["end"] = getEnd(); | ||
1497 | sd["scale_x"] = getScaleX(); | ||
1498 | sd["scale_y"] = getScaleY(); | ||
1499 | sd["shear_x"] = getShearX(); | ||
1500 | sd["shear_y"] = getShearY(); | ||
1501 | sd["twist"] = getTwist(); | ||
1502 | sd["twist_begin"] = getTwistBegin(); | ||
1503 | sd["radius_offset"] = getRadiusOffset(); | ||
1504 | sd["taper_x"] = getTaperX(); | ||
1505 | sd["taper_y"] = getTaperY(); | ||
1506 | sd["revolutions"] = getRevolutions(); | ||
1507 | sd["skew"] = getSkew(); | ||
1508 | |||
1509 | return sd; | ||
1510 | } | ||
1511 | |||
1512 | bool LLPathParams::fromLLSD(LLSD& sd) | ||
1513 | { | ||
1514 | setCurveType(sd["curve"].asInteger()); | ||
1515 | setBegin((F32)sd["begin"].asReal()); | ||
1516 | setEnd((F32)sd["end"].asReal()); | ||
1517 | setScaleX((F32)sd["scale_x"].asReal()); | ||
1518 | setScaleY((F32)sd["scale_y"].asReal()); | ||
1519 | setShearX((F32)sd["shear_x"].asReal()); | ||
1520 | setShearY((F32)sd["shear_y"].asReal()); | ||
1521 | setTwist((F32)sd["twist"].asReal()); | ||
1522 | setTwistBegin((F32)sd["twist_begin"].asReal()); | ||
1523 | setRadiusOffset((F32)sd["radius_offset"].asReal()); | ||
1524 | setTaperX((F32)sd["taper_x"].asReal()); | ||
1525 | setTaperY((F32)sd["taper_y"].asReal()); | ||
1526 | setRevolutions((F32)sd["revolutions"].asReal()); | ||
1527 | setSkew((F32)sd["skew"].asReal()); | ||
1528 | return true; | ||
1529 | } | ||
1530 | |||
1531 | void LLPathParams::copyParams(const LLPathParams ¶ms) | ||
1532 | { | ||
1533 | setCurveType(params.getCurveType()); | ||
1534 | setBegin(params.getBegin()); | ||
1535 | setEnd(params.getEnd()); | ||
1536 | setScale(params.getScaleX(), params.getScaleY() ); | ||
1537 | setShear(params.getShearX(), params.getShearY() ); | ||
1538 | setTwist(params.getTwist()); | ||
1539 | setTwistBegin(params.getTwistBegin()); | ||
1540 | setRadiusOffset(params.getRadiusOffset()); | ||
1541 | setTaper( params.getTaperX(), params.getTaperY() ); | ||
1542 | setRevolutions(params.getRevolutions()); | ||
1543 | setSkew(params.getSkew()); | ||
1544 | } | ||
1545 | |||
1546 | LLProfile::~LLProfile() | ||
1547 | { | ||
1548 | |||
1549 | } | ||
1550 | |||
1551 | |||
1552 | S32 LLVolume::mNumMeshPoints = 0; | ||
1553 | |||
1554 | LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL generate_single_face, const BOOL is_unique) : mParams(params) | ||
1555 | { | ||
1556 | mUnique = is_unique; | ||
1557 | mFaceMask = 0x0; | ||
1558 | mDetail = detail; | ||
1559 | // set defaults | ||
1560 | if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) | ||
1561 | { | ||
1562 | mPathp = new LLDynamicPath(mParams.getPathParams()); | ||
1563 | } | ||
1564 | else | ||
1565 | { | ||
1566 | mPathp = new LLPath(mParams.getPathParams()); | ||
1567 | } | ||
1568 | mProfilep = new LLProfile(mParams.getProfileParams()); | ||
1569 | |||
1570 | mNumVolumeFaces = 0; | ||
1571 | mVolumeFaces = NULL; | ||
1572 | mGenerateSingleFace = generate_single_face; | ||
1573 | |||
1574 | generate(); | ||
1575 | createVolumeFaces(); | ||
1576 | } | ||
1577 | |||
1578 | void LLVolume::regen() | ||
1579 | { | ||
1580 | generate(); | ||
1581 | createVolumeFaces(); | ||
1582 | } | ||
1583 | |||
1584 | LLVolume::~LLVolume() | ||
1585 | { | ||
1586 | mNumMeshPoints -= mMesh.size(); | ||
1587 | delete mPathp; | ||
1588 | delete mProfilep; | ||
1589 | delete[] mVolumeFaces; | ||
1590 | |||
1591 | mPathp = NULL; | ||
1592 | mProfilep = NULL; | ||
1593 | mVolumeFaces = NULL; | ||
1594 | } | ||
1595 | |||
1596 | BOOL LLVolume::generate() | ||
1597 | { | ||
1598 | //Added 10.03.05 Dave Parks | ||
1599 | // Split is a parameter to LLProfile::generate that tesselates edges on the profile | ||
1600 | // to prevent lighting and texture interpolation errors on triangles that are | ||
1601 | // stretched due to twisting or scaling on the path. | ||
1602 | S32 split = (S32) ((mDetail)*0.66f); | ||
1603 | |||
1604 | if (mPathp->mParams.getCurveType() == LL_PCODE_PATH_LINE && | ||
1605 | (mPathp->mParams.getScale().mV[0] != 1.0f || | ||
1606 | mPathp->mParams.getScale().mV[1] != 1.0f) && | ||
1607 | (mProfilep->mParams.getCurveType() == LL_PCODE_PROFILE_SQUARE || | ||
1608 | mProfilep->mParams.getCurveType() == LL_PCODE_PROFILE_ISOTRI || | ||
1609 | mProfilep->mParams.getCurveType() == LL_PCODE_PROFILE_EQUALTRI || | ||
1610 | mProfilep->mParams.getCurveType() == LL_PCODE_PROFILE_RIGHTTRI)) | ||
1611 | { | ||
1612 | split = 0; | ||
1613 | } | ||
1614 | |||
1615 | mLODScaleBias.setVec(0.5f, 0.5f, 0.5f); | ||
1616 | |||
1617 | F32 profile_detail = mDetail; | ||
1618 | F32 path_detail = mDetail; | ||
1619 | |||
1620 | U8 path_type = mPathp->mParams.getCurveType(); | ||
1621 | U8 profile_type = mProfilep->mParams.getCurveType(); | ||
1622 | |||
1623 | if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) | ||
1624 | { //cylinders don't care about Z-Axis | ||
1625 | mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); | ||
1626 | } | ||
1627 | else if (path_type == LL_PCODE_PATH_CIRCLE) | ||
1628 | { | ||
1629 | mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); | ||
1630 | } | ||
1631 | |||
1632 | BOOL regenPath = mPathp->generate(path_detail, split); | ||
1633 | BOOL regenProf = mProfilep->generate(mPathp->isOpen(),profile_detail, split); | ||
1634 | |||
1635 | if (regenPath || regenProf ) | ||
1636 | { | ||
1637 | mNumMeshPoints -= mMesh.size(); | ||
1638 | mMesh.resize(mProfilep->mProfile.size() * mPathp->mPath.size()); | ||
1639 | mNumMeshPoints += mMesh.size(); | ||
1640 | |||
1641 | S32 s = 0, t=0; | ||
1642 | S32 sizeS = mPathp->mPath.size(); | ||
1643 | S32 sizeT = mProfilep->mProfile.size(); | ||
1644 | S32 line = 0; | ||
1645 | |||
1646 | //generate vertex positions | ||
1647 | |||
1648 | // Run along the path. | ||
1649 | while (s < sizeS) | ||
1650 | { | ||
1651 | LLVector2 scale = mPathp->mPath[s].mScale; | ||
1652 | LLQuaternion rot = mPathp->mPath[s].mRot; | ||
1653 | |||
1654 | t = 0; | ||
1655 | // Run along the profile. | ||
1656 | while (t < sizeT) | ||
1657 | { | ||
1658 | S32 i = t + line; | ||
1659 | Point& pt = mMesh[i]; | ||
1660 | |||
1661 | pt.mPos.mV[0] = mProfilep->mProfile[t].mV[0] * scale.mV[0]; | ||
1662 | pt.mPos.mV[1] = mProfilep->mProfile[t].mV[1] * scale.mV[1]; | ||
1663 | pt.mPos.mV[2] = 0.0f; | ||
1664 | pt.mPos = pt.mPos * rot; | ||
1665 | pt.mPos += mPathp->mPath[s].mPos; | ||
1666 | t++; | ||
1667 | } | ||
1668 | line += sizeT; | ||
1669 | s++; | ||
1670 | } | ||
1671 | |||
1672 | for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++) | ||
1673 | { | ||
1674 | mFaceMask |= mProfilep->mFaces[i].mFaceID; | ||
1675 | } | ||
1676 | return TRUE; | ||
1677 | } | ||
1678 | return FALSE; | ||
1679 | } | ||
1680 | |||
1681 | |||
1682 | void LLVolume::createVolumeFaces() | ||
1683 | { | ||
1684 | S32 i; | ||
1685 | |||
1686 | if (mVolumeFaces != NULL) | ||
1687 | { | ||
1688 | delete[] mVolumeFaces; | ||
1689 | mVolumeFaces = NULL; | ||
1690 | } | ||
1691 | |||
1692 | if (mGenerateSingleFace) | ||
1693 | { | ||
1694 | mNumVolumeFaces = 0; | ||
1695 | } | ||
1696 | else | ||
1697 | { | ||
1698 | S32 num_faces = getNumFaces(); | ||
1699 | mNumVolumeFaces = num_faces; | ||
1700 | mVolumeFaces = new LLVolumeFace[num_faces]; | ||
1701 | // Initialize volume faces with parameter data | ||
1702 | for (i = 0; i < num_faces; i++) | ||
1703 | { | ||
1704 | LLVolumeFace &vf = mVolumeFaces[i]; | ||
1705 | LLProfile::Face &face = mProfilep->mFaces[i]; | ||
1706 | vf.mVolumep = this; | ||
1707 | vf.mBeginS = face.mIndex; | ||
1708 | vf.mNumS = face.mCount; | ||
1709 | vf.mBeginT = 0; | ||
1710 | vf.mNumT= getPath().mPath.size(); | ||
1711 | vf.mID = i; | ||
1712 | |||
1713 | // Set the type mask bits correctly | ||
1714 | if (mProfilep->isHollow()) | ||
1715 | { | ||
1716 | vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK; | ||
1717 | } | ||
1718 | if (mProfilep->isOpen()) | ||
1719 | { | ||
1720 | vf.mTypeMask |= LLVolumeFace::OPEN_MASK; | ||
1721 | } | ||
1722 | if (face.mCap) | ||
1723 | { | ||
1724 | vf.mTypeMask |= LLVolumeFace::CAP_MASK; | ||
1725 | if (face.mFaceID == LL_FACE_PATH_BEGIN) | ||
1726 | { | ||
1727 | vf.mTypeMask |= LLVolumeFace::TOP_MASK; | ||
1728 | } | ||
1729 | else | ||
1730 | { | ||
1731 | llassert(face.mFaceID == LL_FACE_PATH_END); | ||
1732 | vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK; | ||
1733 | } | ||
1734 | } | ||
1735 | else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END)) | ||
1736 | { | ||
1737 | vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK; | ||
1738 | } | ||
1739 | else | ||
1740 | { | ||
1741 | vf.mTypeMask |= LLVolumeFace::SIDE_MASK; | ||
1742 | if (face.mFlat) | ||
1743 | { | ||
1744 | vf.mTypeMask |= LLVolumeFace::FLAT_MASK; | ||
1745 | } | ||
1746 | if (face.mFaceID & LL_FACE_INNER_SIDE) | ||
1747 | { | ||
1748 | vf.mTypeMask |= LLVolumeFace::INNER_MASK; | ||
1749 | if (face.mFlat && vf.mNumS > 2) | ||
1750 | { //flat inner faces have to copy vert normals | ||
1751 | vf.mNumS = vf.mNumS*2; | ||
1752 | } | ||
1753 | } | ||
1754 | else | ||
1755 | { | ||
1756 | vf.mTypeMask |= LLVolumeFace::OUTER_MASK; | ||
1757 | } | ||
1758 | } | ||
1759 | } | ||
1760 | |||
1761 | for (i = 0; i < mNumVolumeFaces; i++) | ||
1762 | { | ||
1763 | mVolumeFaces[i].create(); | ||
1764 | } | ||
1765 | } | ||
1766 | |||
1767 | mBounds[1] = LLVector3(0,0,0); | ||
1768 | mBounds[0] = LLVector3(512,512,512); | ||
1769 | } | ||
1770 | |||
1771 | |||
1772 | BOOL LLVolume::isCap(S32 face) | ||
1773 | { | ||
1774 | return mProfilep->mFaces[face].mCap; | ||
1775 | } | ||
1776 | |||
1777 | BOOL LLVolume::isFlat(S32 face) | ||
1778 | { | ||
1779 | return mProfilep->mFaces[face].mFlat; | ||
1780 | } | ||
1781 | |||
1782 | |||
1783 | bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const | ||
1784 | { | ||
1785 | return (getPathParams() == params.getPathParams()) && | ||
1786 | (getProfileParams() == params.getProfileParams()); | ||
1787 | } | ||
1788 | |||
1789 | bool LLVolumeParams::operator!=(const LLVolumeParams ¶ms) const | ||
1790 | { | ||
1791 | return (getPathParams() != params.getPathParams()) || | ||
1792 | (getProfileParams() != params.getProfileParams()); | ||
1793 | } | ||
1794 | |||
1795 | bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const | ||
1796 | { | ||
1797 | if( getPathParams() != params.getPathParams() ) | ||
1798 | { | ||
1799 | return getPathParams() < params.getPathParams(); | ||
1800 | } | ||
1801 | else | ||
1802 | { | ||
1803 | return getProfileParams() < params.getProfileParams(); | ||
1804 | } | ||
1805 | } | ||
1806 | |||
1807 | void LLVolumeParams::copyParams(const LLVolumeParams ¶ms) | ||
1808 | { | ||
1809 | mProfileParams.copyParams(params.mProfileParams); | ||
1810 | mPathParams.copyParams(params.mPathParams); | ||
1811 | } | ||
1812 | |||
1813 | // return true if in range (or nearly so) | ||
1814 | static bool limit_range(F32& v, F32 min, F32 max) | ||
1815 | { | ||
1816 | F32 min_delta = v - min; | ||
1817 | if (min_delta < 0.f) | ||
1818 | { | ||
1819 | v = min; | ||
1820 | if (!is_approx_zero(min_delta)) | ||
1821 | return false; | ||
1822 | } | ||
1823 | F32 max_delta = max - v; | ||
1824 | if (max_delta < 0.f) | ||
1825 | { | ||
1826 | v = max; | ||
1827 | if (!is_approx_zero(max_delta)) | ||
1828 | return false; | ||
1829 | } | ||
1830 | return true; | ||
1831 | } | ||
1832 | |||
1833 | bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e) | ||
1834 | { | ||
1835 | bool valid = true; | ||
1836 | |||
1837 | // First, clamp to valid ranges. | ||
1838 | F32 begin = b; | ||
1839 | valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); | ||
1840 | |||
1841 | F32 end = e; | ||
1842 | valid &= limit_range(end, MIN_CUT_DELTA, 1.f); | ||
1843 | |||
1844 | valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA); | ||
1845 | |||
1846 | // Now set them. | ||
1847 | mProfileParams.setBegin(begin); | ||
1848 | mProfileParams.setEnd(end); | ||
1849 | |||
1850 | return valid; | ||
1851 | } | ||
1852 | |||
1853 | bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e) | ||
1854 | { | ||
1855 | bool valid = true; | ||
1856 | |||
1857 | // First, clamp to valid ranges. | ||
1858 | F32 begin = b; | ||
1859 | valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); | ||
1860 | |||
1861 | F32 end = e; | ||
1862 | valid &= limit_range(end, MIN_CUT_DELTA, 1.f); | ||
1863 | |||
1864 | valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA); | ||
1865 | |||
1866 | // Now set them. | ||
1867 | mPathParams.setBegin(begin); | ||
1868 | mPathParams.setEnd(end); | ||
1869 | |||
1870 | return valid; | ||
1871 | } | ||
1872 | |||
1873 | bool LLVolumeParams::setHollow(const F32 h) | ||
1874 | { | ||
1875 | // Validate the hollow based on path and profile. | ||
1876 | U8 profile = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; | ||
1877 | U8 hole_type = mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK; | ||
1878 | |||
1879 | F32 max_hollow = HOLLOW_MAX; | ||
1880 | |||
1881 | // Only square holes have trouble. | ||
1882 | if (LL_PCODE_HOLE_SQUARE == hole_type) | ||
1883 | { | ||
1884 | switch(profile) | ||
1885 | { | ||
1886 | case LL_PCODE_PROFILE_CIRCLE: | ||
1887 | case LL_PCODE_PROFILE_CIRCLE_HALF: | ||
1888 | case LL_PCODE_PROFILE_EQUALTRI: | ||
1889 | max_hollow = HOLLOW_MAX_SQUARE; | ||
1890 | } | ||
1891 | } | ||
1892 | |||
1893 | F32 hollow = h; | ||
1894 | bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow); | ||
1895 | mProfileParams.setHollow(hollow); | ||
1896 | |||
1897 | return valid; | ||
1898 | } | ||
1899 | |||
1900 | bool LLVolumeParams::setTwistBegin(const F32 b) | ||
1901 | { | ||
1902 | F32 twist_begin = b; | ||
1903 | bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX); | ||
1904 | mPathParams.setTwistBegin(twist_begin); | ||
1905 | return valid; | ||
1906 | } | ||
1907 | |||
1908 | bool LLVolumeParams::setTwistEnd(const F32 e) | ||
1909 | { | ||
1910 | F32 twist_end = e; | ||
1911 | bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX); | ||
1912 | mPathParams.setTwistEnd(twist_end); | ||
1913 | return valid; | ||
1914 | } | ||
1915 | |||
1916 | bool LLVolumeParams::setRatio(const F32 x, const F32 y) | ||
1917 | { | ||
1918 | F32 min_x = RATIO_MIN; | ||
1919 | F32 max_x = RATIO_MAX; | ||
1920 | F32 min_y = RATIO_MIN; | ||
1921 | F32 max_y = RATIO_MAX; | ||
1922 | // If this is a circular path (and not a sphere) then 'ratio' is actually hole size. | ||
1923 | U8 path_type = mPathParams.getCurveType(); | ||
1924 | U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; | ||
1925 | if ( LL_PCODE_PATH_CIRCLE == path_type && | ||
1926 | LL_PCODE_PROFILE_CIRCLE_HALF != profile_type) | ||
1927 | { | ||
1928 | // Holes are more restricted... | ||
1929 | min_x = HOLE_X_MIN; | ||
1930 | max_x = HOLE_X_MAX; | ||
1931 | min_y = HOLE_Y_MIN; | ||
1932 | max_y = HOLE_Y_MAX; | ||
1933 | } | ||
1934 | |||
1935 | F32 ratio_x = x; | ||
1936 | bool valid = limit_range(ratio_x, min_x, max_x); | ||
1937 | F32 ratio_y = y; | ||
1938 | valid &= limit_range(ratio_y, min_y, max_y); | ||
1939 | |||
1940 | mPathParams.setScale(ratio_x, ratio_y); | ||
1941 | |||
1942 | return valid; | ||
1943 | } | ||
1944 | |||
1945 | bool LLVolumeParams::setShear(const F32 x, const F32 y) | ||
1946 | { | ||
1947 | F32 shear_x = x; | ||
1948 | bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX); | ||
1949 | F32 shear_y = y; | ||
1950 | valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX); | ||
1951 | mPathParams.setShear(shear_x, shear_y); | ||
1952 | return valid; | ||
1953 | } | ||
1954 | |||
1955 | bool LLVolumeParams::setTaperX(const F32 v) | ||
1956 | { | ||
1957 | F32 taper = v; | ||
1958 | bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); | ||
1959 | mPathParams.setTaperX(taper); | ||
1960 | return valid; | ||
1961 | } | ||
1962 | |||
1963 | bool LLVolumeParams::setTaperY(const F32 v) | ||
1964 | { | ||
1965 | F32 taper = v; | ||
1966 | bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); | ||
1967 | mPathParams.setTaperY(taper); | ||
1968 | return valid; | ||
1969 | } | ||
1970 | |||
1971 | bool LLVolumeParams::setRevolutions(const F32 r) | ||
1972 | { | ||
1973 | F32 revolutions = r; | ||
1974 | bool valid = limit_range(revolutions, REV_MIN, REV_MAX); | ||
1975 | mPathParams.setRevolutions(revolutions); | ||
1976 | return valid; | ||
1977 | } | ||
1978 | |||
1979 | bool LLVolumeParams::setRadiusOffset(const F32 offset) | ||
1980 | { | ||
1981 | bool valid = true; | ||
1982 | |||
1983 | // If this is a sphere, just set it to 0 and get out. | ||
1984 | U8 path_type = mPathParams.getCurveType(); | ||
1985 | U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; | ||
1986 | if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type || | ||
1987 | LL_PCODE_PATH_CIRCLE != path_type ) | ||
1988 | { | ||
1989 | mPathParams.setRadiusOffset(0.f); | ||
1990 | return true; | ||
1991 | } | ||
1992 | |||
1993 | // Limit radius offset, based on taper and hole size y. | ||
1994 | F32 radius_offset = offset; | ||
1995 | F32 taper_y = getTaperY(); | ||
1996 | F32 radius_mag = fabs(radius_offset); | ||
1997 | F32 hole_y_mag = fabs(getRatioY()); | ||
1998 | F32 taper_y_mag = fabs(taper_y); | ||
1999 | // Check to see if the taper effects us. | ||
2000 | if ( (radius_offset > 0.f && taper_y < 0.f) || | ||
2001 | (radius_offset < 0.f && taper_y > 0.f) ) | ||
2002 | { | ||
2003 | // The taper does not help increase the radius offset range. | ||
2004 | taper_y_mag = 0.f; | ||
2005 | } | ||
2006 | F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); | ||
2007 | |||
2008 | // Enforce the maximum magnitude. | ||
2009 | F32 delta = max_radius_mag - radius_mag; | ||
2010 | if (delta < 0.f) | ||
2011 | { | ||
2012 | // Check radius offset sign. | ||
2013 | if (radius_offset < 0.f) | ||
2014 | { | ||
2015 | radius_offset = -max_radius_mag; | ||
2016 | } | ||
2017 | else | ||
2018 | { | ||
2019 | radius_offset = max_radius_mag; | ||
2020 | } | ||
2021 | valid = is_approx_zero(delta); | ||
2022 | } | ||
2023 | |||
2024 | mPathParams.setRadiusOffset(radius_offset); | ||
2025 | return valid; | ||
2026 | } | ||
2027 | |||
2028 | bool LLVolumeParams::setSkew(const F32 skew_value) | ||
2029 | { | ||
2030 | bool valid = true; | ||
2031 | |||
2032 | // Check the skew value against the revolutions. | ||
2033 | F32 skew = llclamp(skew_value, SKEW_MIN, SKEW_MAX); | ||
2034 | F32 skew_mag = fabs(skew); | ||
2035 | F32 revolutions = getRevolutions(); | ||
2036 | F32 scale_x = getRatioX(); | ||
2037 | F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); | ||
2038 | // Discontinuity; A revolution of 1 allows skews below 0.5. | ||
2039 | if ( fabs(revolutions - 1.0f) < 0.001) | ||
2040 | min_skew_mag = 0.0f; | ||
2041 | |||
2042 | // Clip skew. | ||
2043 | F32 delta = skew_mag - min_skew_mag; | ||
2044 | if (delta < 0.f) | ||
2045 | { | ||
2046 | // Check skew sign. | ||
2047 | if (skew < 0.0f) | ||
2048 | { | ||
2049 | skew = -min_skew_mag; | ||
2050 | } | ||
2051 | else | ||
2052 | { | ||
2053 | skew = min_skew_mag; | ||
2054 | } | ||
2055 | valid = is_approx_zero(delta); | ||
2056 | } | ||
2057 | |||
2058 | mPathParams.setSkew(skew); | ||
2059 | return valid; | ||
2060 | } | ||
2061 | |||
2062 | bool LLVolumeParams::setType(U8 profile, U8 path) | ||
2063 | { | ||
2064 | bool result = true; | ||
2065 | // First, check profile and path for validity. | ||
2066 | U8 profile_type = profile & LL_PCODE_PROFILE_MASK; | ||
2067 | U8 hole_type = (profile & LL_PCODE_HOLE_MASK) >> 4; | ||
2068 | U8 path_type = path >> 4; | ||
2069 | |||
2070 | if (profile_type > LL_PCODE_PROFILE_MAX) | ||
2071 | { | ||
2072 | // Bad profile. Make it square. | ||
2073 | profile = LL_PCODE_PROFILE_SQUARE; | ||
2074 | result = false; | ||
2075 | llwarns << "LLVolumeParams::setType changing bad profile type (" << profile_type | ||
2076 | << ") to be LL_PCODE_PROFILE_SQUARE" << llendl; | ||
2077 | } | ||
2078 | else if (hole_type > LL_PCODE_HOLE_MAX) | ||
2079 | { | ||
2080 | // Bad hole. Make it the same. | ||
2081 | profile = profile_type; | ||
2082 | result = false; | ||
2083 | llwarns << "LLVolumeParams::setType changing bad hole type (" << hole_type | ||
2084 | << ") to be LL_PCODE_HOLE_SAME" << llendl; | ||
2085 | } | ||
2086 | |||
2087 | if (path_type < LL_PCODE_PATH_MIN || | ||
2088 | path_type > LL_PCODE_PATH_MAX) | ||
2089 | { | ||
2090 | // Bad path. Make it linear. | ||
2091 | result = false; | ||
2092 | llwarns << "LLVolumeParams::setType changing bad path (" << path | ||
2093 | << ") to be LL_PCODE_PATH_LINE" << llendl; | ||
2094 | path = LL_PCODE_PATH_LINE; | ||
2095 | } | ||
2096 | |||
2097 | mProfileParams.setCurveType(profile); | ||
2098 | mPathParams.setCurveType(path); | ||
2099 | return result; | ||
2100 | } | ||
2101 | |||
2102 | // static | ||
2103 | bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow, | ||
2104 | U8 path_curve, F32 path_begin, F32 path_end, | ||
2105 | F32 scx, F32 scy, F32 shx, F32 shy, | ||
2106 | F32 twistend, F32 twistbegin, F32 radiusoffset, | ||
2107 | F32 tx, F32 ty, F32 revolutions, F32 skew) | ||
2108 | { | ||
2109 | LLVolumeParams test_params; | ||
2110 | if (!test_params.setType (prof_curve, path_curve)) | ||
2111 | { | ||
2112 | return false; | ||
2113 | } | ||
2114 | if (!test_params.setBeginAndEndS (prof_begin, prof_end)) | ||
2115 | { | ||
2116 | return false; | ||
2117 | } | ||
2118 | if (!test_params.setBeginAndEndT (path_begin, path_end)) | ||
2119 | { | ||
2120 | return false; | ||
2121 | } | ||
2122 | if (!test_params.setHollow (hollow)) | ||
2123 | { | ||
2124 | return false; | ||
2125 | } | ||
2126 | if (!test_params.setTwistBegin (twistbegin)) | ||
2127 | { | ||
2128 | return false; | ||
2129 | } | ||
2130 | if (!test_params.setTwistEnd (twistend)) | ||
2131 | { | ||
2132 | return false; | ||
2133 | } | ||
2134 | if (!test_params.setRatio (scx, scy)) | ||
2135 | { | ||
2136 | return false; | ||
2137 | } | ||
2138 | if (!test_params.setShear (shx, shy)) | ||
2139 | { | ||
2140 | return false; | ||
2141 | } | ||
2142 | if (!test_params.setTaper (tx, ty)) | ||
2143 | { | ||
2144 | return false; | ||
2145 | } | ||
2146 | if (!test_params.setRevolutions (revolutions)) | ||
2147 | { | ||
2148 | return false; | ||
2149 | } | ||
2150 | if (!test_params.setRadiusOffset (radiusoffset)) | ||
2151 | { | ||
2152 | return false; | ||
2153 | } | ||
2154 | if (!test_params.setSkew (skew)) | ||
2155 | { | ||
2156 | return false; | ||
2157 | } | ||
2158 | return true; | ||
2159 | } | ||
2160 | |||
2161 | #define MAX_INDEX 10000 | ||
2162 | S32 *LLVolume::getTriangleIndices(U32 &num_indices) const | ||
2163 | { | ||
2164 | S32 index[MAX_INDEX]; | ||
2165 | S32 count = 0; | ||
2166 | S32 *indices = NULL; | ||
2167 | |||
2168 | // Let's do this totally diffently, as we don't care about faces... | ||
2169 | // Counter-clockwise triangles are forward facing... | ||
2170 | |||
2171 | BOOL open = getProfile().isOpen(); | ||
2172 | BOOL hollow = getProfile().isHollow(); | ||
2173 | BOOL path_open = getPath().isOpen(); | ||
2174 | S32 size_s, size_s_out, size_t; | ||
2175 | S32 s, t, i; | ||
2176 | size_s = getProfile().getTotal(); | ||
2177 | size_s_out = getProfile().getTotalOut(); | ||
2178 | size_t = getPath().mPath.size(); | ||
2179 | |||
2180 | if (open) | ||
2181 | { | ||
2182 | if (hollow) | ||
2183 | { | ||
2184 | // Open hollow -- much like the closed solid, except we | ||
2185 | // we need to stitch up the gap between s=0 and s=size_s-1 | ||
2186 | |||
2187 | if ( (size_t - 1) * (((size_s -1) * 6) + 6) >= MAX_INDEX) | ||
2188 | goto noindices; | ||
2189 | |||
2190 | for (t = 0; t < size_t - 1; t++) | ||
2191 | { | ||
2192 | // The outer face, first cut, and inner face | ||
2193 | for (s = 0; s < size_s - 1; s++) | ||
2194 | { | ||
2195 | i = s + t*size_s; | ||
2196 | index[count++] = i; // x,y | ||
2197 | index[count++] = i + 1; // x+1,y | ||
2198 | index[count++] = i + size_s; // x,y+1 | ||
2199 | |||
2200 | index[count++] = i + size_s; // x,y+1 | ||
2201 | index[count++] = i + 1; // x+1,y | ||
2202 | index[count++] = i + size_s + 1; // x+1,y+1 | ||
2203 | } | ||
2204 | |||
2205 | // The other cut face | ||
2206 | index[count++] = s + t*size_s; // x,y | ||
2207 | index[count++] = 0 + t*size_s; // x+1,y | ||
2208 | index[count++] = s + (t+1)*size_s; // x,y+1 | ||
2209 | |||
2210 | index[count++] = s + (t+1)*size_s; // x,y+1 | ||
2211 | index[count++] = 0 + t*size_s; // x+1,y | ||
2212 | index[count++] = 0 + (t+1)*size_s; // x+1,y+1 | ||
2213 | } | ||
2214 | |||
2215 | // Do the top and bottom caps, if necessary | ||
2216 | if (path_open) | ||
2217 | { | ||
2218 | // Top cap | ||
2219 | S32 pt1 = 0; | ||
2220 | S32 pt2 = size_s-1; | ||
2221 | S32 i = (size_t - 1)*size_s; | ||
2222 | |||
2223 | while (pt2 - pt1 > 1) | ||
2224 | { | ||
2225 | // Use the profile points instead of the mesh, since you want | ||
2226 | // the un-transformed profile distances. | ||
2227 | LLVector3 p1 = getProfile().mProfile[pt1]; | ||
2228 | LLVector3 p2 = getProfile().mProfile[pt2]; | ||
2229 | LLVector3 pa = getProfile().mProfile[pt1+1]; | ||
2230 | LLVector3 pb = getProfile().mProfile[pt2-1]; | ||
2231 | |||
2232 | p1.mV[VZ] = 0.f; | ||
2233 | p2.mV[VZ] = 0.f; | ||
2234 | pa.mV[VZ] = 0.f; | ||
2235 | pb.mV[VZ] = 0.f; | ||
2236 | |||
2237 | // Use area of triangle to determine backfacing | ||
2238 | F32 area_1a2, area_1ba, area_21b, area_2ab; | ||
2239 | area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + | ||
2240 | (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + | ||
2241 | (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); | ||
2242 | |||
2243 | area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + | ||
2244 | (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + | ||
2245 | (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); | ||
2246 | |||
2247 | area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + | ||
2248 | (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + | ||
2249 | (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); | ||
2250 | |||
2251 | area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + | ||
2252 | (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + | ||
2253 | (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); | ||
2254 | |||
2255 | BOOL use_tri1a2 = TRUE; | ||
2256 | BOOL tri_1a2 = TRUE; | ||
2257 | BOOL tri_21b = TRUE; | ||
2258 | |||
2259 | if (area_1a2 < 0) | ||
2260 | { | ||
2261 | tri_1a2 = FALSE; | ||
2262 | } | ||
2263 | if (area_2ab < 0) | ||
2264 | { | ||
2265 | // Can't use, because it contains point b | ||
2266 | tri_1a2 = FALSE; | ||
2267 | } | ||
2268 | if (area_21b < 0) | ||
2269 | { | ||
2270 | tri_21b = FALSE; | ||
2271 | } | ||
2272 | if (area_1ba < 0) | ||
2273 | { | ||
2274 | // Can't use, because it contains point b | ||
2275 | tri_21b = FALSE; | ||
2276 | } | ||
2277 | |||
2278 | if (!tri_1a2) | ||
2279 | { | ||
2280 | use_tri1a2 = FALSE; | ||
2281 | } | ||
2282 | else if (!tri_21b) | ||
2283 | { | ||
2284 | use_tri1a2 = TRUE; | ||
2285 | } | ||
2286 | else | ||
2287 | { | ||
2288 | LLVector3 d1 = p1 - pa; | ||
2289 | LLVector3 d2 = p2 - pb; | ||
2290 | |||
2291 | if (d1.magVecSquared() < d2.magVecSquared()) | ||
2292 | { | ||
2293 | use_tri1a2 = TRUE; | ||
2294 | } | ||
2295 | else | ||
2296 | { | ||
2297 | use_tri1a2 = FALSE; | ||
2298 | } | ||
2299 | } | ||
2300 | |||
2301 | if (use_tri1a2) | ||
2302 | { | ||
2303 | if (count + 3 >= MAX_INDEX) | ||
2304 | goto noindices; | ||
2305 | index[count++] = pt1 + i; | ||
2306 | index[count++] = pt1 + 1 + i; | ||
2307 | index[count++] = pt2 + i; | ||
2308 | pt1++; | ||
2309 | } | ||
2310 | else | ||
2311 | { | ||
2312 | if (count + 3 >= MAX_INDEX) | ||
2313 | goto noindices; | ||
2314 | index[count++] = pt1 + i; | ||
2315 | index[count++] = pt2 - 1 + i; | ||
2316 | index[count++] = pt2 + i; | ||
2317 | pt2--; | ||
2318 | } | ||
2319 | } | ||
2320 | |||
2321 | // Bottom cap | ||
2322 | pt1 = 0; | ||
2323 | pt2 = size_s-1; | ||
2324 | while (pt2 - pt1 > 1) | ||
2325 | { | ||
2326 | // Use the profile points instead of the mesh, since you want | ||
2327 | // the un-transformed profile distances. | ||
2328 | LLVector3 p1 = getProfile().mProfile[pt1]; | ||
2329 | LLVector3 p2 = getProfile().mProfile[pt2]; | ||
2330 | LLVector3 pa = getProfile().mProfile[pt1+1]; | ||
2331 | LLVector3 pb = getProfile().mProfile[pt2-1]; | ||
2332 | |||
2333 | p1.mV[VZ] = 0.f; | ||
2334 | p2.mV[VZ] = 0.f; | ||
2335 | pa.mV[VZ] = 0.f; | ||
2336 | pb.mV[VZ] = 0.f; | ||
2337 | |||
2338 | // Use area of triangle to determine backfacing | ||
2339 | F32 area_1a2, area_1ba, area_21b, area_2ab; | ||
2340 | area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + | ||
2341 | (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + | ||
2342 | (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); | ||
2343 | |||
2344 | area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + | ||
2345 | (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + | ||
2346 | (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); | ||
2347 | |||
2348 | area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + | ||
2349 | (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + | ||
2350 | (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); | ||
2351 | |||
2352 | area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + | ||
2353 | (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + | ||
2354 | (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); | ||
2355 | |||
2356 | BOOL use_tri1a2 = TRUE; | ||
2357 | BOOL tri_1a2 = TRUE; | ||
2358 | BOOL tri_21b = TRUE; | ||
2359 | |||
2360 | if (area_1a2 < 0) | ||
2361 | { | ||
2362 | tri_1a2 = FALSE; | ||
2363 | } | ||
2364 | if (area_2ab < 0) | ||
2365 | { | ||
2366 | // Can't use, because it contains point b | ||
2367 | tri_1a2 = FALSE; | ||
2368 | } | ||
2369 | if (area_21b < 0) | ||
2370 | { | ||
2371 | tri_21b = FALSE; | ||
2372 | } | ||
2373 | if (area_1ba < 0) | ||
2374 | { | ||
2375 | // Can't use, because it contains point b | ||
2376 | tri_21b = FALSE; | ||
2377 | } | ||
2378 | |||
2379 | if (!tri_1a2) | ||
2380 | { | ||
2381 | use_tri1a2 = FALSE; | ||
2382 | } | ||
2383 | else if (!tri_21b) | ||
2384 | { | ||
2385 | use_tri1a2 = TRUE; | ||
2386 | } | ||
2387 | else | ||
2388 | { | ||
2389 | LLVector3 d1 = p1 - pa; | ||
2390 | LLVector3 d2 = p2 - pb; | ||
2391 | |||
2392 | if (d1.magVecSquared() < d2.magVecSquared()) | ||
2393 | { | ||
2394 | use_tri1a2 = TRUE; | ||
2395 | } | ||
2396 | else | ||
2397 | { | ||
2398 | use_tri1a2 = FALSE; | ||
2399 | } | ||
2400 | } | ||
2401 | |||
2402 | if (use_tri1a2) | ||
2403 | { | ||
2404 | if (count + 3 >= MAX_INDEX) | ||
2405 | goto noindices; | ||
2406 | index[count++] = pt1; | ||
2407 | index[count++] = pt2; | ||
2408 | index[count++] = pt1 + 1; | ||
2409 | pt1++; | ||
2410 | } | ||
2411 | else | ||
2412 | { | ||
2413 | if (count + 3 >= MAX_INDEX) | ||
2414 | goto noindices; | ||
2415 | index[count++] = pt1; | ||
2416 | index[count++] = pt2; | ||
2417 | index[count++] = pt2 - 1; | ||
2418 | pt2--; | ||
2419 | } | ||
2420 | } | ||
2421 | } | ||
2422 | } | ||
2423 | else | ||
2424 | { | ||
2425 | // Open solid | ||
2426 | |||
2427 | if ( (size_t - 1) * (((size_s -1) * 6) + 6) >= MAX_INDEX) | ||
2428 | goto noindices; | ||
2429 | |||
2430 | for (t = 0; t < size_t - 1; t++) | ||
2431 | { | ||
2432 | // Outer face + 1 cut face | ||
2433 | for (s = 0; s < size_s - 1; s++) | ||
2434 | { | ||
2435 | i = s + t*size_s; | ||
2436 | |||
2437 | index[count++] = i; // x,y | ||
2438 | index[count++] = i + 1; // x+1,y | ||
2439 | index[count++] = i + size_s; // x,y+1 | ||
2440 | |||
2441 | index[count++] = i + size_s; // x,y+1 | ||
2442 | index[count++] = i + 1; // x+1,y | ||
2443 | index[count++] = i + size_s + 1; // x+1,y+1 | ||
2444 | } | ||
2445 | |||
2446 | // The other cut face | ||
2447 | index[count++] = (size_s - 1) + (t*size_s); // x,y | ||
2448 | index[count++] = 0 + t*size_s; // x+1,y | ||
2449 | index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1 | ||
2450 | |||
2451 | index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1 | ||
2452 | index[count++] = 0 + (t*size_s); // x+1,y | ||
2453 | index[count++] = 0 + (t+1)*size_s; // x+1,y+1 | ||
2454 | } | ||
2455 | |||
2456 | // Do the top and bottom caps, if necessary | ||
2457 | if (path_open) | ||
2458 | { | ||
2459 | if ( count + (size_s - 2) * 3 >= MAX_INDEX) | ||
2460 | goto noindices; | ||
2461 | for (s = 0; s < size_s - 2; s++) | ||
2462 | { | ||
2463 | index[count++] = s+1; | ||
2464 | index[count++] = s; | ||
2465 | index[count++] = size_s - 1; | ||
2466 | } | ||
2467 | |||
2468 | // We've got a top cap | ||
2469 | S32 offset = (size_t - 1)*size_s; | ||
2470 | if ( count + (size_s - 2) * 3 >= MAX_INDEX) | ||
2471 | goto noindices; | ||
2472 | for (s = 0; s < size_s - 2; s++) | ||
2473 | { | ||
2474 | // Inverted ordering from bottom cap. | ||
2475 | index[count++] = offset + size_s - 1; | ||
2476 | index[count++] = offset + s; | ||
2477 | index[count++] = offset + s + 1; | ||
2478 | } | ||
2479 | } | ||
2480 | } | ||
2481 | } | ||
2482 | else if (hollow) | ||
2483 | { | ||
2484 | // Closed hollow | ||
2485 | // Outer face | ||
2486 | |||
2487 | if ( (size_t - 1) * (size_s_out - 1) * 6 >= MAX_INDEX) | ||
2488 | goto noindices; | ||
2489 | for (t = 0; t < size_t - 1; t++) | ||
2490 | { | ||
2491 | for (s = 0; s < size_s_out - 1; s++) | ||
2492 | { | ||
2493 | i = s + t*size_s; | ||
2494 | |||
2495 | index[count++] = i; // x,y | ||
2496 | index[count++] = i + 1; // x+1,y | ||
2497 | index[count++] = i + size_s; // x,y+1 | ||
2498 | |||
2499 | index[count++] = i + size_s; // x,y+1 | ||
2500 | index[count++] = i + 1; // x+1,y | ||
2501 | index[count++] = i + 1 + size_s; // x+1,y+1 | ||
2502 | } | ||
2503 | } | ||
2504 | |||
2505 | // Inner face | ||
2506 | // Invert facing from outer face | ||
2507 | if ( count + (size_t - 1) * ((size_s - 1) - size_s_out) * 6 >= MAX_INDEX) | ||
2508 | goto noindices; | ||
2509 | for (t = 0; t < size_t - 1; t++) | ||
2510 | { | ||
2511 | for (s = size_s_out; s < size_s - 1; s++) | ||
2512 | { | ||
2513 | i = s + t*size_s; | ||
2514 | |||
2515 | index[count++] = i; // x,y | ||
2516 | index[count++] = i + 1; // x+1,y | ||
2517 | index[count++] = i + size_s; // x,y+1 | ||
2518 | |||
2519 | index[count++] = i + size_s; // x,y+1 | ||
2520 | index[count++] = i + 1; // x+1,y | ||
2521 | index[count++] = i + 1 + size_s; // x+1,y+1 | ||
2522 | } | ||
2523 | } | ||
2524 | |||
2525 | // Do the top and bottom caps, if necessary | ||
2526 | if (path_open) | ||
2527 | { | ||
2528 | // Top cap | ||
2529 | S32 pt1 = 0; | ||
2530 | S32 pt2 = size_s-1; | ||
2531 | S32 i = (size_t - 1)*size_s; | ||
2532 | |||
2533 | while (pt2 - pt1 > 1) | ||
2534 | { | ||
2535 | // Use the profile points instead of the mesh, since you want | ||
2536 | // the un-transformed profile distances. | ||
2537 | LLVector3 p1 = getProfile().mProfile[pt1]; | ||
2538 | LLVector3 p2 = getProfile().mProfile[pt2]; | ||
2539 | LLVector3 pa = getProfile().mProfile[pt1+1]; | ||
2540 | LLVector3 pb = getProfile().mProfile[pt2-1]; | ||
2541 | |||
2542 | p1.mV[VZ] = 0.f; | ||
2543 | p2.mV[VZ] = 0.f; | ||
2544 | pa.mV[VZ] = 0.f; | ||
2545 | pb.mV[VZ] = 0.f; | ||
2546 | |||
2547 | // Use area of triangle to determine backfacing | ||
2548 | F32 area_1a2, area_1ba, area_21b, area_2ab; | ||
2549 | area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + | ||
2550 | (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + | ||
2551 | (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); | ||
2552 | |||
2553 | area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + | ||
2554 | (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + | ||
2555 | (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); | ||
2556 | |||
2557 | area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + | ||
2558 | (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + | ||
2559 | (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); | ||
2560 | |||
2561 | area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + | ||
2562 | (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + | ||
2563 | (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); | ||
2564 | |||
2565 | BOOL use_tri1a2 = TRUE; | ||
2566 | BOOL tri_1a2 = TRUE; | ||
2567 | BOOL tri_21b = TRUE; | ||
2568 | |||
2569 | if (area_1a2 < 0) | ||
2570 | { | ||
2571 | tri_1a2 = FALSE; | ||
2572 | } | ||
2573 | if (area_2ab < 0) | ||
2574 | { | ||
2575 | // Can't use, because it contains point b | ||
2576 | tri_1a2 = FALSE; | ||
2577 | } | ||
2578 | if (area_21b < 0) | ||
2579 | { | ||
2580 | tri_21b = FALSE; | ||
2581 | } | ||
2582 | if (area_1ba < 0) | ||
2583 | { | ||
2584 | // Can't use, because it contains point b | ||
2585 | tri_21b = FALSE; | ||
2586 | } | ||
2587 | |||
2588 | if (!tri_1a2) | ||
2589 | { | ||
2590 | use_tri1a2 = FALSE; | ||
2591 | } | ||
2592 | else if (!tri_21b) | ||
2593 | { | ||
2594 | use_tri1a2 = TRUE; | ||
2595 | } | ||
2596 | else | ||
2597 | { | ||
2598 | LLVector3 d1 = p1 - pa; | ||
2599 | LLVector3 d2 = p2 - pb; | ||
2600 | |||
2601 | if (d1.magVecSquared() < d2.magVecSquared()) | ||
2602 | { | ||
2603 | use_tri1a2 = TRUE; | ||
2604 | } | ||
2605 | else | ||
2606 | { | ||
2607 | use_tri1a2 = FALSE; | ||
2608 | } | ||
2609 | } | ||
2610 | |||
2611 | if (use_tri1a2) | ||
2612 | { | ||
2613 | if (count + 3 >= MAX_INDEX) | ||
2614 | goto noindices; | ||
2615 | index[count++] = pt1 + i; | ||
2616 | index[count++] = pt1 + 1 + i; | ||
2617 | index[count++] = pt2 + i; | ||
2618 | pt1++; | ||
2619 | } | ||
2620 | else | ||
2621 | { | ||
2622 | if (count + 3 >= MAX_INDEX) | ||
2623 | goto noindices; | ||
2624 | index[count++] = pt1 + i; | ||
2625 | index[count++] = pt2 - 1 + i; | ||
2626 | index[count++] = pt2 + i; | ||
2627 | pt2--; | ||
2628 | } | ||
2629 | } | ||
2630 | |||
2631 | // Bottom cap | ||
2632 | pt1 = 0; | ||
2633 | pt2 = size_s-1; | ||
2634 | while (pt2 - pt1 > 1) | ||
2635 | { | ||
2636 | // Use the profile points instead of the mesh, since you want | ||
2637 | // the un-transformed profile distances. | ||
2638 | LLVector3 p1 = getProfile().mProfile[pt1]; | ||
2639 | LLVector3 p2 = getProfile().mProfile[pt2]; | ||
2640 | LLVector3 pa = getProfile().mProfile[pt1+1]; | ||
2641 | LLVector3 pb = getProfile().mProfile[pt2-1]; | ||
2642 | |||
2643 | p1.mV[VZ] = 0.f; | ||
2644 | p2.mV[VZ] = 0.f; | ||
2645 | pa.mV[VZ] = 0.f; | ||
2646 | pb.mV[VZ] = 0.f; | ||
2647 | |||
2648 | // Use area of triangle to determine backfacing | ||
2649 | F32 area_1a2, area_1ba, area_21b, area_2ab; | ||
2650 | area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + | ||
2651 | (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + | ||
2652 | (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); | ||
2653 | |||
2654 | area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + | ||
2655 | (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + | ||
2656 | (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); | ||
2657 | |||
2658 | area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + | ||
2659 | (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + | ||
2660 | (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); | ||
2661 | |||
2662 | area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + | ||
2663 | (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + | ||
2664 | (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); | ||
2665 | |||
2666 | BOOL use_tri1a2 = TRUE; | ||
2667 | BOOL tri_1a2 = TRUE; | ||
2668 | BOOL tri_21b = TRUE; | ||
2669 | |||
2670 | if (area_1a2 < 0) | ||
2671 | { | ||
2672 | tri_1a2 = FALSE; | ||
2673 | } | ||
2674 | if (area_2ab < 0) | ||
2675 | { | ||
2676 | // Can't use, because it contains point b | ||
2677 | tri_1a2 = FALSE; | ||
2678 | } | ||
2679 | if (area_21b < 0) | ||
2680 | { | ||
2681 | tri_21b = FALSE; | ||
2682 | } | ||
2683 | if (area_1ba < 0) | ||
2684 | { | ||
2685 | // Can't use, because it contains point b | ||
2686 | tri_21b = FALSE; | ||
2687 | } | ||
2688 | |||
2689 | if (!tri_1a2) | ||
2690 | { | ||
2691 | use_tri1a2 = FALSE; | ||
2692 | } | ||
2693 | else if (!tri_21b) | ||
2694 | { | ||
2695 | use_tri1a2 = TRUE; | ||
2696 | } | ||
2697 | else | ||
2698 | { | ||
2699 | LLVector3 d1 = p1 - pa; | ||
2700 | LLVector3 d2 = p2 - pb; | ||
2701 | |||
2702 | if (d1.magVecSquared() < d2.magVecSquared()) | ||
2703 | { | ||
2704 | use_tri1a2 = TRUE; | ||
2705 | } | ||
2706 | else | ||
2707 | { | ||
2708 | use_tri1a2 = FALSE; | ||
2709 | } | ||
2710 | } | ||
2711 | |||
2712 | if (use_tri1a2) | ||
2713 | { | ||
2714 | if (count + 3 >= MAX_INDEX) | ||
2715 | goto noindices; | ||
2716 | index[count++] = pt1; | ||
2717 | index[count++] = pt2; | ||
2718 | index[count++] = pt1 + 1; | ||
2719 | pt1++; | ||
2720 | } | ||
2721 | else | ||
2722 | { | ||
2723 | if (count + 3 >= MAX_INDEX) | ||
2724 | goto noindices; | ||
2725 | index[count++] = pt1; | ||
2726 | index[count++] = pt2; | ||
2727 | index[count++] = pt2 - 1; | ||
2728 | pt2--; | ||
2729 | } | ||
2730 | } | ||
2731 | } | ||
2732 | } | ||
2733 | else | ||
2734 | { | ||
2735 | // Closed solid. Easy case. | ||
2736 | if ( (size_t - 1) * (size_s - 1) * 6 > MAX_INDEX) | ||
2737 | goto noindices; | ||
2738 | for (t = 0; t < size_t - 1; t++) | ||
2739 | { | ||
2740 | for (s = 0; s < size_s - 1; s++) | ||
2741 | { | ||
2742 | // Should wrap properly, but for now... | ||
2743 | i = s + t*size_s; | ||
2744 | |||
2745 | index[count++] = i; // x,y | ||
2746 | index[count++] = i + 1; // x+1,y | ||
2747 | index[count++] = i + size_s; // x,y+1 | ||
2748 | |||
2749 | index[count++] = i + size_s; // x,y+1 | ||
2750 | index[count++] = i + 1; // x+1,y | ||
2751 | index[count++] = i + size_s + 1; // x+1,y+1 | ||
2752 | } | ||
2753 | } | ||
2754 | |||
2755 | // Do the top and bottom caps, if necessary | ||
2756 | if (path_open) | ||
2757 | { | ||
2758 | // bottom cap | ||
2759 | if ( count + (size_s - 2 - 1) * 3 >= MAX_INDEX) | ||
2760 | goto noindices; | ||
2761 | for (s = 1; s < size_s - 2; s++) | ||
2762 | { | ||
2763 | index[count++] = s+1; | ||
2764 | index[count++] = s; | ||
2765 | index[count++] = 0; | ||
2766 | } | ||
2767 | |||
2768 | // top cap | ||
2769 | S32 offset = (size_t - 1)*size_s; | ||
2770 | if ( count + (size_s - 2 - 1) * 3 >= MAX_INDEX) | ||
2771 | goto noindices; | ||
2772 | for (s = 1; s < size_s - 2; s++) | ||
2773 | { | ||
2774 | // Inverted ordering from bottom cap. | ||
2775 | index[count++] = offset; | ||
2776 | index[count++] = offset + s; | ||
2777 | index[count++] = offset + s + 1; | ||
2778 | } | ||
2779 | } | ||
2780 | } | ||
2781 | |||
2782 | #if 0 | ||
2783 | S32 num_vertices = mMesh.size(); | ||
2784 | for (i = 0; i < count; i+=3) | ||
2785 | { | ||
2786 | llinfos << index[i] << ":" << index[i+1] << ":" << index[i+2] << llendl; | ||
2787 | llassert(index[i] < num_vertices); | ||
2788 | llassert(index[i+1] < num_vertices); | ||
2789 | llassert(index[i+2] < num_vertices); | ||
2790 | } | ||
2791 | #endif | ||
2792 | |||
2793 | indices = new S32[count]; | ||
2794 | noindices: | ||
2795 | if (!indices) | ||
2796 | { | ||
2797 | llwarns << "Couldn't allocate triangle indices" << llendl; | ||
2798 | num_indices = 0; | ||
2799 | return NULL; | ||
2800 | } | ||
2801 | num_indices = count; | ||
2802 | memcpy(indices, index, count * sizeof(S32)); | ||
2803 | return indices; | ||
2804 | } | ||
2805 | |||
2806 | //----------------------------------------------------------------------------- | ||
2807 | // generateSilhouetteVertices() | ||
2808 | //----------------------------------------------------------------------------- | ||
2809 | void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, | ||
2810 | std::vector<LLVector3> &normals, | ||
2811 | std::vector<S32> &segments, | ||
2812 | const LLVector3& obj_cam_vec, | ||
2813 | const LLMatrix4& mat, | ||
2814 | const LLMatrix3& norm_mat) | ||
2815 | { | ||
2816 | vertices.clear(); | ||
2817 | normals.clear(); | ||
2818 | segments.clear(); | ||
2819 | |||
2820 | //for each face | ||
2821 | for (S32 i = 0; i < getNumFaces(); i++) { | ||
2822 | LLVolumeFace face = this->getVolumeFace(i); | ||
2823 | |||
2824 | if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { | ||
2825 | |||
2826 | } | ||
2827 | else { | ||
2828 | |||
2829 | //============================================== | ||
2830 | //DEBUG draw edge map instead of silhouette edge | ||
2831 | //============================================== | ||
2832 | |||
2833 | #if DEBUG_SILHOUETTE_EDGE_MAP | ||
2834 | |||
2835 | //for each triangle | ||
2836 | U32 count = face.mIndices.size(); | ||
2837 | for (U32 j = 0; j < count/3; j++) { | ||
2838 | //get vertices | ||
2839 | S32 v1 = face.mIndices[j*3+0]; | ||
2840 | S32 v2 = face.mIndices[j*3+1]; | ||
2841 | S32 v3 = face.mIndices[j*3+2]; | ||
2842 | |||
2843 | //get current face center | ||
2844 | LLVector3 cCenter = (face.mVertices[v1].mPosition + | ||
2845 | face.mVertices[v2].mPosition + | ||
2846 | face.mVertices[v3].mPosition) / 3.0f; | ||
2847 | |||
2848 | //for each edge | ||
2849 | for (S32 k = 0; k < 3; k++) { | ||
2850 | S32 nIndex = face.mEdge[j*3+k]; | ||
2851 | if (nIndex <= -1) { | ||
2852 | continue; | ||
2853 | } | ||
2854 | |||
2855 | if (nIndex >= (S32) count/3) { | ||
2856 | continue; | ||
2857 | } | ||
2858 | //get neighbor vertices | ||
2859 | v1 = face.mIndices[nIndex*3+0]; | ||
2860 | v2 = face.mIndices[nIndex*3+1]; | ||
2861 | v3 = face.mIndices[nIndex*3+2]; | ||
2862 | |||
2863 | //get neighbor face center | ||
2864 | LLVector3 nCenter = (face.mVertices[v1].mPosition + | ||
2865 | face.mVertices[v2].mPosition + | ||
2866 | face.mVertices[v3].mPosition) / 3.0f; | ||
2867 | |||
2868 | //draw line | ||
2869 | vertices.push_back(cCenter); | ||
2870 | vertices.push_back(nCenter); | ||
2871 | normals.push_back(LLVector3(1,1,1)); | ||
2872 | normals.push_back(LLVector3(1,1,1)); | ||
2873 | segments.push_back(vertices.size()); | ||
2874 | } | ||
2875 | } | ||
2876 | |||
2877 | continue; | ||
2878 | |||
2879 | //============================================== | ||
2880 | //DEBUG | ||
2881 | //============================================== | ||
2882 | |||
2883 | //============================================== | ||
2884 | //DEBUG draw normals instead of silhouette edge | ||
2885 | //============================================== | ||
2886 | #elif DEBUG_SILHOUETTE_NORMALS | ||
2887 | |||
2888 | //for each vertex | ||
2889 | for (U32 j = 0; j < face.mVertices.size(); j++) { | ||
2890 | vertices.push_back(face.mVertices[j].mPosition); | ||
2891 | vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mNormal*0.1f); | ||
2892 | normals.push_back(LLVector3(0,0,1)); | ||
2893 | normals.push_back(LLVector3(0,0,1)); | ||
2894 | segments.push_back(vertices.size()); | ||
2895 | #if DEBUG_SILHOUETTE_BINORMALS | ||
2896 | vertices.push_back(face.mVertices[j].mPosition); | ||
2897 | vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mBinormal*0.1f); | ||
2898 | normals.push_back(LLVector3(0,0,1)); | ||
2899 | normals.push_back(LLVector3(0,0,1)); | ||
2900 | segments.push_back(vertices.size()); | ||
2901 | #endif | ||
2902 | } | ||
2903 | |||
2904 | continue; | ||
2905 | #else | ||
2906 | //============================================== | ||
2907 | //DEBUG | ||
2908 | //============================================== | ||
2909 | |||
2910 | static const U8 AWAY = 0x01, | ||
2911 | TOWARDS = 0x02; | ||
2912 | |||
2913 | //for each triangle | ||
2914 | std::vector<U8> fFacing; | ||
2915 | vector_append(fFacing, face.mIndices.size()/3); | ||
2916 | for (U32 j = 0; j < face.mIndices.size()/3; j++) | ||
2917 | { | ||
2918 | //approximate normal | ||
2919 | S32 v1 = face.mIndices[j*3+0]; | ||
2920 | S32 v2 = face.mIndices[j*3+1]; | ||
2921 | S32 v3 = face.mIndices[j*3+2]; | ||
2922 | |||
2923 | LLVector3 norm = (face.mVertices[v1].mPosition - face.mVertices[v2].mPosition) % | ||
2924 | (face.mVertices[v2].mPosition - face.mVertices[v3].mPosition); | ||
2925 | |||
2926 | if (norm.magVecSquared() < 0.00000001f) | ||
2927 | { | ||
2928 | fFacing[j] = AWAY | TOWARDS; | ||
2929 | } | ||
2930 | else | ||
2931 | { | ||
2932 | //get view vector | ||
2933 | LLVector3 view = (obj_cam_vec-face.mVertices[v1].mPosition); | ||
2934 | bool away = view * norm > 0.0f; | ||
2935 | if (away) | ||
2936 | { | ||
2937 | fFacing[j] = AWAY; | ||
2938 | } | ||
2939 | else | ||
2940 | { | ||
2941 | fFacing[j] = TOWARDS; | ||
2942 | } | ||
2943 | } | ||
2944 | } | ||
2945 | |||
2946 | //for each triangle | ||
2947 | for (U32 j = 0; j < face.mIndices.size()/3; j++) | ||
2948 | { | ||
2949 | if (fFacing[j] == (AWAY | TOWARDS)) | ||
2950 | { //this is a degenerate triangle | ||
2951 | //take neighbor facing (degenerate faces get facing of one of their neighbors) | ||
2952 | // *FIX IF NEEDED: this does not deal with neighboring degenerate faces | ||
2953 | for (S32 k = 0; k < 3; k++) | ||
2954 | { | ||
2955 | S32 index = face.mEdge[j*3+k]; | ||
2956 | if (index != -1) | ||
2957 | { | ||
2958 | fFacing[j] = fFacing[index]; | ||
2959 | break; | ||
2960 | } | ||
2961 | } | ||
2962 | continue; //skip degenerate face | ||
2963 | } | ||
2964 | |||
2965 | //for each edge | ||
2966 | for (S32 k = 0; k < 3; k++) { | ||
2967 | S32 index = face.mEdge[j*3+k]; | ||
2968 | if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) { | ||
2969 | //our neighbor is degenerate, make him face our direction | ||
2970 | fFacing[face.mEdge[j*3+k]] = fFacing[j]; | ||
2971 | continue; | ||
2972 | } | ||
2973 | |||
2974 | if (index == -1 || //edge has no neighbor, MUST be a silhouette edge | ||
2975 | (fFacing[index] & fFacing[j]) == 0) { //we found a silhouette edge | ||
2976 | |||
2977 | S32 v1 = face.mIndices[j*3+k]; | ||
2978 | S32 v2 = face.mIndices[j*3+((k+1)%3)]; | ||
2979 | |||
2980 | vertices.push_back(face.mVertices[v1].mPosition*mat); | ||
2981 | normals.push_back(face.mVertices[v1].mNormal*norm_mat); | ||
2982 | |||
2983 | vertices.push_back(face.mVertices[v2].mPosition*mat); | ||
2984 | normals.push_back(face.mVertices[v2].mNormal*norm_mat); | ||
2985 | segments.push_back(vertices.size()); | ||
2986 | } | ||
2987 | } | ||
2988 | } | ||
2989 | #endif | ||
2990 | } | ||
2991 | } | ||
2992 | } | ||
2993 | |||
2994 | S32 LLVolume::lineSegmentIntersect(const LLVector3& start, LLVector3& end) const | ||
2995 | { | ||
2996 | S32 ret = -1; | ||
2997 | |||
2998 | LLVector3 vec = end - start; | ||
2999 | |||
3000 | for (U32 i = 0; i < (U32)getNumFaces(); i++) | ||
3001 | { | ||
3002 | LLVolumeFace face = getVolumeFace(i); | ||
3003 | |||
3004 | for (U32 j = 0; j < face.mIndices.size()/3; j++) | ||
3005 | { | ||
3006 | //approximate normal | ||
3007 | S32 v1 = face.mIndices[j*3+0]; | ||
3008 | S32 v2 = face.mIndices[j*3+1]; | ||
3009 | S32 v3 = face.mIndices[j*3+2]; | ||
3010 | |||
3011 | LLVector3 norm = (face.mVertices[v2].mPosition - face.mVertices[v1].mPosition) % | ||
3012 | (face.mVertices[v3].mPosition - face.mVertices[v2].mPosition); | ||
3013 | |||
3014 | if (norm.magVecSquared() >= 0.00000001f) | ||
3015 | { | ||
3016 | //get view vector | ||
3017 | //LLVector3 view = (start-face.mVertices[v1].mPosition); | ||
3018 | //if (view * norm < 0.0f) | ||
3019 | { | ||
3020 | if (LLTriangleLineSegmentIntersect( face.mVertices[v1].mPosition, | ||
3021 | face.mVertices[v2].mPosition, | ||
3022 | face.mVertices[v3].mPosition, | ||
3023 | end, | ||
3024 | vec)) | ||
3025 | { | ||
3026 | vec = end-start; | ||
3027 | ret = (S32) i; | ||
3028 | } | ||
3029 | } | ||
3030 | } | ||
3031 | } | ||
3032 | } | ||
3033 | |||
3034 | return ret; | ||
3035 | } | ||
3036 | |||
3037 | class LLVertexIndexPair | ||
3038 | { | ||
3039 | public: | ||
3040 | LLVertexIndexPair(const LLVector3 &vertex, const S32 index); | ||
3041 | |||
3042 | LLVector3 mVertex; | ||
3043 | S32 mIndex; | ||
3044 | }; | ||
3045 | |||
3046 | LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index) | ||
3047 | { | ||
3048 | mVertex = vertex; | ||
3049 | mIndex = index; | ||
3050 | } | ||
3051 | |||
3052 | const F32 VERTEX_SLOP = 0.00001f; | ||
3053 | const F32 VERTEX_SLOP_SQRD = VERTEX_SLOP * VERTEX_SLOP; | ||
3054 | |||
3055 | struct lessVertex | ||
3056 | { | ||
3057 | bool operator()(const LLVertexIndexPair *a, const LLVertexIndexPair *b) | ||
3058 | { | ||
3059 | const F32 slop = VERTEX_SLOP; | ||
3060 | |||
3061 | if (a->mVertex.mV[0] + slop < b->mVertex.mV[0]) | ||
3062 | { | ||
3063 | return TRUE; | ||
3064 | } | ||
3065 | else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0]) | ||
3066 | { | ||
3067 | return FALSE; | ||
3068 | } | ||
3069 | |||
3070 | if (a->mVertex.mV[1] + slop < b->mVertex.mV[1]) | ||
3071 | { | ||
3072 | return TRUE; | ||
3073 | } | ||
3074 | else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1]) | ||
3075 | { | ||
3076 | return FALSE; | ||
3077 | } | ||
3078 | |||
3079 | if (a->mVertex.mV[2] + slop < b->mVertex.mV[2]) | ||
3080 | { | ||
3081 | return TRUE; | ||
3082 | } | ||
3083 | else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2]) | ||
3084 | { | ||
3085 | return FALSE; | ||
3086 | } | ||
3087 | |||
3088 | return FALSE; | ||
3089 | } | ||
3090 | }; | ||
3091 | |||
3092 | struct lessTriangle | ||
3093 | { | ||
3094 | bool operator()(const S32 *a, const S32 *b) | ||
3095 | { | ||
3096 | if (*a < *b) | ||
3097 | { | ||
3098 | return TRUE; | ||
3099 | } | ||
3100 | else if (*a > *b) | ||
3101 | { | ||
3102 | return FALSE; | ||
3103 | } | ||
3104 | |||
3105 | if (*(a+1) < *(b+1)) | ||
3106 | { | ||
3107 | return TRUE; | ||
3108 | } | ||
3109 | else if (*(a+1) > *(b+1)) | ||
3110 | { | ||
3111 | return FALSE; | ||
3112 | } | ||
3113 | |||
3114 | if (*(a+2) < *(b+2)) | ||
3115 | { | ||
3116 | return TRUE; | ||
3117 | } | ||
3118 | else if (*(a+2) > *(b+2)) | ||
3119 | { | ||
3120 | return FALSE; | ||
3121 | } | ||
3122 | |||
3123 | return FALSE; | ||
3124 | } | ||
3125 | }; | ||
3126 | |||
3127 | BOOL equalTriangle(const S32 *a, const S32 *b) | ||
3128 | { | ||
3129 | if ((*a == *b) && (*(a+1) == *(b+1)) && ((*a+2) == (*b+2))) | ||
3130 | { | ||
3131 | return TRUE; | ||
3132 | } | ||
3133 | return FALSE; | ||
3134 | } | ||
3135 | |||
3136 | BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices, | ||
3137 | const std::vector<Point>& input_vertices, | ||
3138 | const S32 num_input_triangles, | ||
3139 | S32 *input_triangles, | ||
3140 | S32 &num_output_vertices, | ||
3141 | LLVector3 **output_vertices, | ||
3142 | S32 &num_output_triangles, | ||
3143 | S32 **output_triangles) | ||
3144 | { | ||
3145 | // Here's how we do this: | ||
3146 | // Create a structure which contains the original vertex index and the | ||
3147 | // LLVector3 data. | ||
3148 | // "Sort" the data by the vectors | ||
3149 | // Create an array the size of the old vertex list, with a mapping of | ||
3150 | // old indices to new indices. | ||
3151 | // Go through triangles, shift so the lowest index is first | ||
3152 | // Sort triangles by first index | ||
3153 | // Remove duplicate triangles | ||
3154 | // Allocate and pack new triangle data. | ||
3155 | |||
3156 | //LLTimer cleanupTimer; | ||
3157 | //llinfos << "In vertices: " << num_input_vertices << llendl; | ||
3158 | //llinfos << "In triangles: " << num_input_triangles << llendl; | ||
3159 | |||
3160 | S32 i; | ||
3161 | typedef std::multiset<LLVertexIndexPair*, lessVertex> vertex_set_t; | ||
3162 | vertex_set_t vertex_list; | ||
3163 | |||
3164 | LLVertexIndexPair *pairp = NULL; | ||
3165 | for (i = 0; i < num_input_vertices; i++) | ||
3166 | { | ||
3167 | LLVertexIndexPair *new_pairp = new LLVertexIndexPair(input_vertices[i].mPos, i); | ||
3168 | vertex_list.insert(new_pairp); | ||
3169 | } | ||
3170 | |||
3171 | // Generate the vertex mapping and the list of vertices without | ||
3172 | // duplicates. This will crash if there are no vertices. | ||
3173 | S32 *vertex_mapping = new S32[num_input_vertices]; | ||
3174 | LLVector3 *new_vertices = new LLVector3[num_input_vertices]; | ||
3175 | LLVertexIndexPair *prev_pairp = NULL; | ||
3176 | |||
3177 | S32 new_num_vertices; | ||
3178 | |||
3179 | new_num_vertices = 0; | ||
3180 | for (vertex_set_t::iterator iter = vertex_list.begin(), | ||
3181 | end = vertex_list.end(); | ||
3182 | iter != end; iter++) | ||
3183 | { | ||
3184 | pairp = *iter; | ||
3185 | if (!prev_pairp || ((pairp->mVertex - prev_pairp->mVertex).magVecSquared() >= VERTEX_SLOP_SQRD)) | ||
3186 | { | ||
3187 | new_vertices[new_num_vertices] = pairp->mVertex; | ||
3188 | //llinfos << "Added vertex " << new_num_vertices << " : " << pairp->mVertex << llendl; | ||
3189 | new_num_vertices++; | ||
3190 | // Update the previous | ||
3191 | prev_pairp = pairp; | ||
3192 | } | ||
3193 | else | ||
3194 | { | ||
3195 | //llinfos << "Removed duplicate vertex " << pairp->mVertex << llendl; | ||
3196 | } | ||
3197 | vertex_mapping[pairp->mIndex] = new_num_vertices - 1; | ||
3198 | } | ||
3199 | |||
3200 | // Iterate through triangles and remove degenerates, re-ordering vertices | ||
3201 | // along the way. | ||
3202 | S32 *new_triangles = new S32[num_input_triangles * 3]; | ||
3203 | S32 new_num_triangles = 0; | ||
3204 | |||
3205 | for (i = 0; i < num_input_triangles; i++) | ||
3206 | { | ||
3207 | //llinfos << "Checking triangle " << input_triangles[i*3] << ":" << input_triangles[i*3+1] << ":" << input_triangles[i*3+2] << llendl; | ||
3208 | input_triangles[i*3] = vertex_mapping[input_triangles[i*3]]; | ||
3209 | input_triangles[i*3+1] = vertex_mapping[input_triangles[i*3+1]]; | ||
3210 | input_triangles[i*3+2] = vertex_mapping[input_triangles[i*3+2]]; | ||
3211 | |||
3212 | if ((input_triangles[i*3] == input_triangles[i*3+1]) | ||
3213 | || (input_triangles[i*3] == input_triangles[i*3+2]) | ||
3214 | || (input_triangles[i*3+1] == input_triangles[i*3+2])) | ||
3215 | { | ||
3216 | //llinfos << "Removing degenerate triangle " << input_triangles[i*3] << ":" << input_triangles[i*3+1] << ":" << input_triangles[i*3+2] << llendl; | ||
3217 | // Degenerate triangle, skip | ||
3218 | continue; | ||
3219 | } | ||
3220 | |||
3221 | if (input_triangles[i*3] < input_triangles[i*3+1]) | ||
3222 | { | ||
3223 | if (input_triangles[i*3] < input_triangles[i*3+2]) | ||
3224 | { | ||
3225 | // (0 < 1) && (0 < 2) | ||
3226 | new_triangles[new_num_triangles*3] = input_triangles[i*3]; | ||
3227 | new_triangles[new_num_triangles*3+1] = input_triangles[i*3+1]; | ||
3228 | new_triangles[new_num_triangles*3+2] = input_triangles[i*3+2]; | ||
3229 | } | ||
3230 | else | ||
3231 | { | ||
3232 | // (0 < 1) && (2 < 0) | ||
3233 | new_triangles[new_num_triangles*3] = input_triangles[i*3+2]; | ||
3234 | new_triangles[new_num_triangles*3+1] = input_triangles[i*3]; | ||
3235 | new_triangles[new_num_triangles*3+2] = input_triangles[i*3+1]; | ||
3236 | } | ||
3237 | } | ||
3238 | else if (input_triangles[i*3+1] < input_triangles[i*3+2]) | ||
3239 | { | ||
3240 | // (1 < 0) && (1 < 2) | ||
3241 | new_triangles[new_num_triangles*3] = input_triangles[i*3+1]; | ||
3242 | new_triangles[new_num_triangles*3+1] = input_triangles[i*3+2]; | ||
3243 | new_triangles[new_num_triangles*3+2] = input_triangles[i*3]; | ||
3244 | } | ||
3245 | else | ||
3246 | { | ||
3247 | // (1 < 0) && (2 < 1) | ||
3248 | new_triangles[new_num_triangles*3] = input_triangles[i*3+2]; | ||
3249 | new_triangles[new_num_triangles*3+1] = input_triangles[i*3]; | ||
3250 | new_triangles[new_num_triangles*3+2] = input_triangles[i*3+1]; | ||
3251 | } | ||
3252 | new_num_triangles++; | ||
3253 | } | ||
3254 | |||
3255 | if (new_num_triangles == 0) | ||
3256 | { | ||
3257 | llwarns << "Created volume object with 0 faces." << llendl; | ||
3258 | return FALSE; | ||
3259 | } | ||
3260 | |||
3261 | typedef std::set<S32*, lessTriangle> triangle_set_t; | ||
3262 | triangle_set_t triangle_list; | ||
3263 | |||
3264 | for (i = 0; i < new_num_triangles; i++) | ||
3265 | { | ||
3266 | triangle_list.insert(&new_triangles[i*3]); | ||
3267 | } | ||
3268 | |||
3269 | // Sort through the triangle list, and delete duplicates | ||
3270 | |||
3271 | S32 *prevp = NULL; | ||
3272 | S32 *curp = NULL; | ||
3273 | |||
3274 | S32 *sorted_tris = new S32[new_num_triangles*3]; | ||
3275 | S32 cur_tri = 0; | ||
3276 | for (triangle_set_t::iterator iter = triangle_list.begin(), | ||
3277 | end = triangle_list.end(); | ||
3278 | iter != end; iter++) | ||
3279 | { | ||
3280 | curp = *iter; | ||
3281 | if (!prevp || !equalTriangle(prevp, curp)) | ||
3282 | { | ||
3283 | //llinfos << "Added triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl; | ||
3284 | sorted_tris[cur_tri*3] = *curp; | ||
3285 | sorted_tris[cur_tri*3+1] = *(curp+1); | ||
3286 | sorted_tris[cur_tri*3+2] = *(curp+2); | ||
3287 | cur_tri++; | ||
3288 | prevp = curp; | ||
3289 | } | ||
3290 | else | ||
3291 | { | ||
3292 | //llinfos << "Skipped triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl; | ||
3293 | } | ||
3294 | } | ||
3295 | |||
3296 | *output_vertices = new LLVector3[new_num_vertices]; | ||
3297 | num_output_vertices = new_num_vertices; | ||
3298 | for (i = 0; i < new_num_vertices; i++) | ||
3299 | { | ||
3300 | (*output_vertices)[i] = new_vertices[i]; | ||
3301 | } | ||
3302 | |||
3303 | *output_triangles = new S32[cur_tri*3]; | ||
3304 | num_output_triangles = cur_tri; | ||
3305 | memcpy(*output_triangles, sorted_tris, 3*cur_tri*sizeof(S32)); | ||
3306 | |||
3307 | /* | ||
3308 | llinfos << "Out vertices: " << num_output_vertices << llendl; | ||
3309 | llinfos << "Out triangles: " << num_output_triangles << llendl; | ||
3310 | for (i = 0; i < num_output_vertices; i++) | ||
3311 | { | ||
3312 | llinfos << i << ":" << (*output_vertices)[i] << llendl; | ||
3313 | } | ||
3314 | for (i = 0; i < num_output_triangles; i++) | ||
3315 | { | ||
3316 | llinfos << i << ":" << (*output_triangles)[i*3] << ":" << (*output_triangles)[i*3+1] << ":" << (*output_triangles)[i*3+2] << llendl; | ||
3317 | } | ||
3318 | */ | ||
3319 | |||
3320 | //llinfos << "Out vertices: " << num_output_vertices << llendl; | ||
3321 | //llinfos << "Out triangles: " << num_output_triangles << llendl; | ||
3322 | delete[] vertex_mapping; | ||
3323 | vertex_mapping = NULL; | ||
3324 | delete[] new_vertices; | ||
3325 | new_vertices = NULL; | ||
3326 | delete[] new_triangles; | ||
3327 | new_triangles = NULL; | ||
3328 | delete[] sorted_tris; | ||
3329 | sorted_tris = NULL; | ||
3330 | triangle_list.clear(); | ||
3331 | std::for_each(vertex_list.begin(), vertex_list.end(), DeletePointer()); | ||
3332 | vertex_list.clear(); | ||
3333 | |||
3334 | return TRUE; | ||
3335 | } | ||
3336 | |||
3337 | |||
3338 | BOOL LLVolumeParams::importFile(FILE *fp) | ||
3339 | { | ||
3340 | //llinfos << "importing volume" << llendl; | ||
3341 | const S32 BUFSIZE = 16384; | ||
3342 | char buffer[BUFSIZE]; | ||
3343 | char keyword[256]; | ||
3344 | keyword[0] = 0; | ||
3345 | |||
3346 | while (!feof(fp)) | ||
3347 | { | ||
3348 | fgets(buffer, BUFSIZE, fp); | ||
3349 | sscanf(buffer, " %s", keyword); | ||
3350 | if (!keyword) | ||
3351 | { | ||
3352 | continue; | ||
3353 | } | ||
3354 | if (!strcmp("{", keyword)) | ||
3355 | { | ||
3356 | continue; | ||
3357 | } | ||
3358 | if (!strcmp("}",keyword)) | ||
3359 | { | ||
3360 | break; | ||
3361 | } | ||
3362 | else if (!strcmp("profile", keyword)) | ||
3363 | { | ||
3364 | mProfileParams.importFile(fp); | ||
3365 | } | ||
3366 | else if (!strcmp("path",keyword)) | ||
3367 | { | ||
3368 | mPathParams.importFile(fp); | ||
3369 | } | ||
3370 | else | ||
3371 | { | ||
3372 | llwarns << "unknown keyword " << keyword << " in volume import" << llendl; | ||
3373 | } | ||
3374 | } | ||
3375 | |||
3376 | return TRUE; | ||
3377 | } | ||
3378 | |||
3379 | BOOL LLVolumeParams::exportFile(FILE *fp) const | ||
3380 | { | ||
3381 | fprintf(fp,"\tshape 0\n"); | ||
3382 | fprintf(fp,"\t{\n"); | ||
3383 | mPathParams.exportFile(fp); | ||
3384 | mProfileParams.exportFile(fp); | ||
3385 | fprintf(fp, "\t}\n"); | ||
3386 | return TRUE; | ||
3387 | } | ||
3388 | |||
3389 | |||
3390 | BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream) | ||
3391 | { | ||
3392 | //llinfos << "importing volume" << llendl; | ||
3393 | const S32 BUFSIZE = 16384; | ||
3394 | char buffer[BUFSIZE]; | ||
3395 | char keyword[256]; | ||
3396 | keyword[0] = 0; | ||
3397 | |||
3398 | while (input_stream.good()) | ||
3399 | { | ||
3400 | input_stream.getline(buffer, BUFSIZE); | ||
3401 | sscanf(buffer, " %s", keyword); | ||
3402 | if (!keyword) | ||
3403 | { | ||
3404 | continue; | ||
3405 | } | ||
3406 | if (!strcmp("{", keyword)) | ||
3407 | { | ||
3408 | continue; | ||
3409 | } | ||
3410 | if (!strcmp("}",keyword)) | ||
3411 | { | ||
3412 | break; | ||
3413 | } | ||
3414 | else if (!strcmp("profile", keyword)) | ||
3415 | { | ||
3416 | mProfileParams.importLegacyStream(input_stream); | ||
3417 | } | ||
3418 | else if (!strcmp("path",keyword)) | ||
3419 | { | ||
3420 | mPathParams.importLegacyStream(input_stream); | ||
3421 | } | ||
3422 | else | ||
3423 | { | ||
3424 | llwarns << "unknown keyword " << keyword << " in volume import" << llendl; | ||
3425 | } | ||
3426 | } | ||
3427 | |||
3428 | return TRUE; | ||
3429 | } | ||
3430 | |||
3431 | BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const | ||
3432 | { | ||
3433 | output_stream <<"\tshape 0\n"; | ||
3434 | output_stream <<"\t{\n"; | ||
3435 | mPathParams.exportLegacyStream(output_stream); | ||
3436 | mProfileParams.exportLegacyStream(output_stream); | ||
3437 | output_stream << "\t}\n"; | ||
3438 | return TRUE; | ||
3439 | } | ||
3440 | |||
3441 | LLSD LLVolumeParams::asLLSD() const | ||
3442 | { | ||
3443 | LLSD sd = LLSD(); | ||
3444 | sd["path"] = mPathParams; | ||
3445 | sd["profile"] = mProfileParams; | ||
3446 | return sd; | ||
3447 | } | ||
3448 | |||
3449 | bool LLVolumeParams::fromLLSD(LLSD& sd) | ||
3450 | { | ||
3451 | mPathParams.fromLLSD(sd["path"]); | ||
3452 | mProfileParams.fromLLSD(sd["profile"]); | ||
3453 | return true; | ||
3454 | } | ||
3455 | |||
3456 | void LLVolumeParams::reduceS(F32 begin, F32 end) | ||
3457 | { | ||
3458 | begin = llclampf(begin); | ||
3459 | end = llclampf(end); | ||
3460 | if (begin > end) | ||
3461 | { | ||
3462 | F32 temp = begin; | ||
3463 | begin = end; | ||
3464 | end = temp; | ||
3465 | } | ||
3466 | F32 a = mProfileParams.getBegin(); | ||
3467 | F32 b = mProfileParams.getEnd(); | ||
3468 | mProfileParams.setBegin(a + begin * (b - a)); | ||
3469 | mProfileParams.setEnd(a + end * (b - a)); | ||
3470 | } | ||
3471 | |||
3472 | void LLVolumeParams::reduceT(F32 begin, F32 end) | ||
3473 | { | ||
3474 | begin = llclampf(begin); | ||
3475 | end = llclampf(end); | ||
3476 | if (begin > end) | ||
3477 | { | ||
3478 | F32 temp = begin; | ||
3479 | begin = end; | ||
3480 | end = temp; | ||
3481 | } | ||
3482 | F32 a = mPathParams.getBegin(); | ||
3483 | F32 b = mPathParams.getEnd(); | ||
3484 | mPathParams.setBegin(a + begin * (b - a)); | ||
3485 | mPathParams.setEnd(a + end * (b - a)); | ||
3486 | } | ||
3487 | |||
3488 | BOOL LLVolumeParams::isConvex() const | ||
3489 | { | ||
3490 | // The logic for determining convexity is a little convoluted. | ||
3491 | |||
3492 | // Do we need to take getTwistBegin into account? DK 08/12/04 | ||
3493 | if ( mProfileParams.getHollow() != 0.0f | ||
3494 | || mPathParams.getTwist() != mPathParams.getTwistBegin() ) | ||
3495 | { | ||
3496 | // hollow or twist gaurantees concavity | ||
3497 | return FALSE; | ||
3498 | } | ||
3499 | |||
3500 | F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin(); | ||
3501 | BOOL concave_profile = (profile_length < 1.0f) && (profile_length > 0.5f); | ||
3502 | if (concave_profile) | ||
3503 | { | ||
3504 | // concave profile | ||
3505 | return FALSE; | ||
3506 | } | ||
3507 | |||
3508 | U8 path_type = mPathParams.getCurveType(); | ||
3509 | if ( LL_PCODE_PATH_LINE == path_type ) | ||
3510 | { | ||
3511 | // straight paths with convex profile | ||
3512 | return TRUE; | ||
3513 | } | ||
3514 | |||
3515 | F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); | ||
3516 | BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f); | ||
3517 | if (concave_path) | ||
3518 | { | ||
3519 | return FALSE; | ||
3520 | } | ||
3521 | |||
3522 | // we're left with spheres, toroids and tubes | ||
3523 | // only the spheres can be convex | ||
3524 | U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; | ||
3525 | if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) | ||
3526 | { | ||
3527 | return TRUE; | ||
3528 | } | ||
3529 | |||
3530 | // it's a toroid or tube | ||
3531 | return FALSE; | ||
3532 | } | ||
3533 | |||
3534 | LLFaceID LLVolume::generateFaceMask() | ||
3535 | { | ||
3536 | LLFaceID new_mask = 0x0000; | ||
3537 | |||
3538 | switch(mProfilep->mParams.getCurveType() & LL_PCODE_PROFILE_MASK) | ||
3539 | { | ||
3540 | case LL_PCODE_PROFILE_CIRCLE: | ||
3541 | case LL_PCODE_PROFILE_CIRCLE_HALF: | ||
3542 | new_mask |= LL_FACE_OUTER_SIDE_0; | ||
3543 | break; | ||
3544 | case LL_PCODE_PROFILE_SQUARE: | ||
3545 | { | ||
3546 | for(S32 side = (S32)(mProfilep->mParams.getBegin() * 4.f); side < llceil(mProfilep->mParams.getEnd() * 4.f); side++) | ||
3547 | { | ||
3548 | new_mask |= LL_FACE_OUTER_SIDE_0 << side; | ||
3549 | } | ||
3550 | } | ||
3551 | break; | ||
3552 | case LL_PCODE_PROFILE_ISOTRI: | ||
3553 | case LL_PCODE_PROFILE_EQUALTRI: | ||
3554 | case LL_PCODE_PROFILE_RIGHTTRI: | ||
3555 | { | ||
3556 | for(S32 side = (S32)(mProfilep->mParams.getBegin() * 3.f); side < llceil(mProfilep->mParams.getEnd() * 3.f); side++) | ||
3557 | { | ||
3558 | new_mask |= LL_FACE_OUTER_SIDE_0 << side; | ||
3559 | } | ||
3560 | } | ||
3561 | break; | ||
3562 | default: | ||
3563 | llerrs << "Unknown profile!" << llendl | ||
3564 | break; | ||
3565 | } | ||
3566 | |||
3567 | // handle hollow objects | ||
3568 | if (mProfilep->isHollow()) | ||
3569 | { | ||
3570 | new_mask |= LL_FACE_INNER_SIDE; | ||
3571 | } | ||
3572 | |||
3573 | // handle open profile curves | ||
3574 | if (mProfilep->isOpen()) | ||
3575 | { | ||
3576 | new_mask |= LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END; | ||
3577 | } | ||
3578 | |||
3579 | // handle open path curves | ||
3580 | if (mPathp->isOpen()) | ||
3581 | { | ||
3582 | new_mask |= LL_FACE_PATH_BEGIN | LL_FACE_PATH_END; | ||
3583 | } | ||
3584 | |||
3585 | return new_mask; | ||
3586 | } | ||
3587 | |||
3588 | BOOL LLVolume::isFaceMaskValid(LLFaceID face_mask) | ||
3589 | { | ||
3590 | LLFaceID test_mask = 0; | ||
3591 | for(S32 i = 0; i < getNumFaces(); i++) | ||
3592 | { | ||
3593 | test_mask |= mProfilep->mFaces[i].mFaceID; | ||
3594 | } | ||
3595 | |||
3596 | return test_mask == face_mask; | ||
3597 | } | ||
3598 | |||
3599 | BOOL LLVolume::isConvex() const | ||
3600 | { | ||
3601 | // mParams.isConvex() may return FALSE even though the final | ||
3602 | // geometry is actually convex due to LOD approximations. | ||
3603 | // TODO -- provide LLPath and LLProfile with isConvex() methods | ||
3604 | // that correctly determine convexity. -- Leviathan | ||
3605 | return mParams.isConvex(); | ||
3606 | } | ||
3607 | |||
3608 | |||
3609 | std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params) | ||
3610 | { | ||
3611 | s << "{type=" << (U32) profile_params.mCurveType; | ||
3612 | s << ", begin=" << profile_params.mBegin; | ||
3613 | s << ", end=" << profile_params.mEnd; | ||
3614 | s << ", hollow=" << profile_params.mHollow; | ||
3615 | s << "}"; | ||
3616 | return s; | ||
3617 | } | ||
3618 | |||
3619 | |||
3620 | std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params) | ||
3621 | { | ||
3622 | s << "{type=" << (U32) path_params.mCurveType; | ||
3623 | s << ", begin=" << path_params.mBegin; | ||
3624 | s << ", end=" << path_params.mEnd; | ||
3625 | s << ", twist=" << path_params.mTwistEnd; | ||
3626 | s << ", scale=" << path_params.mScale; | ||
3627 | s << ", shear=" << path_params.mShear; | ||
3628 | s << ", twist_begin=" << path_params.mTwistBegin; | ||
3629 | s << ", radius_offset=" << path_params.mRadiusOffset; | ||
3630 | s << ", taper=" << path_params.mTaper; | ||
3631 | s << ", revolutions=" << path_params.mRevolutions; | ||
3632 | s << ", skew=" << path_params.mSkew; | ||
3633 | s << "}"; | ||
3634 | return s; | ||
3635 | } | ||
3636 | |||
3637 | |||
3638 | std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params) | ||
3639 | { | ||
3640 | s << "{profileparams = " << volume_params.mProfileParams; | ||
3641 | s << ", pathparams = " << volume_params.mPathParams; | ||
3642 | s << "}"; | ||
3643 | return s; | ||
3644 | } | ||
3645 | |||
3646 | |||
3647 | std::ostream& operator<<(std::ostream &s, const LLProfile &profile) | ||
3648 | { | ||
3649 | s << " {open=" << (U32) profile.mOpen; | ||
3650 | s << ", dirty=" << profile.mDirty; | ||
3651 | s << ", totalout=" << profile.mTotalOut; | ||
3652 | s << ", total=" << profile.mTotal; | ||
3653 | s << "}"; | ||
3654 | return s; | ||
3655 | } | ||
3656 | |||
3657 | |||
3658 | std::ostream& operator<<(std::ostream &s, const LLPath &path) | ||
3659 | { | ||
3660 | s << "{open=" << (U32) path.mOpen; | ||
3661 | s << ", dirty=" << path.mDirty; | ||
3662 | s << ", step=" << path.mStep; | ||
3663 | s << ", total=" << path.mTotal; | ||
3664 | s << "}"; | ||
3665 | return s; | ||
3666 | } | ||
3667 | |||
3668 | std::ostream& operator<<(std::ostream &s, const LLVolume &volume) | ||
3669 | { | ||
3670 | s << "{params = " << volume.mParams; | ||
3671 | s << ", path = " << *volume.mPathp; | ||
3672 | s << ", profile = " << *volume.mProfilep; | ||
3673 | s << "}"; | ||
3674 | return s; | ||
3675 | } | ||
3676 | |||
3677 | |||
3678 | std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) | ||
3679 | { | ||
3680 | s << "{params = " << volumep->mParams; | ||
3681 | s << ", path = " << *(volumep->mPathp); | ||
3682 | s << ", profile = " << *(volumep->mProfilep); | ||
3683 | s << "}"; | ||
3684 | return s; | ||
3685 | } | ||
3686 | |||
3687 | |||
3688 | LLVolumeFace::LLVolumeFace() | ||
3689 | { | ||
3690 | mTypeMask = 0; | ||
3691 | mID = 0; | ||
3692 | mBeginS = 0; | ||
3693 | mBeginT = 0; | ||
3694 | mNumS = 0; | ||
3695 | mNumT = 0; | ||
3696 | } | ||
3697 | |||
3698 | |||
3699 | BOOL LLVolumeFace::create() | ||
3700 | { | ||
3701 | if (mTypeMask & CAP_MASK) | ||
3702 | { | ||
3703 | return createCap(); | ||
3704 | } | ||
3705 | else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) | ||
3706 | { | ||
3707 | return createSide(); | ||
3708 | } | ||
3709 | else | ||
3710 | { | ||
3711 | llerrs << "Unknown/uninitialized face type!" << llendl; | ||
3712 | return FALSE; | ||
3713 | } | ||
3714 | } | ||
3715 | |||
3716 | void LerpPlanarVertex(LLVolumeFace::VertexData& v0, | ||
3717 | LLVolumeFace::VertexData& v1, | ||
3718 | LLVolumeFace::VertexData& v2, | ||
3719 | LLVolumeFace::VertexData& vout, | ||
3720 | F32 coef01, | ||
3721 | F32 coef02) | ||
3722 | { | ||
3723 | vout.mPosition = v0.mPosition + ((v1.mPosition-v0.mPosition)*coef01)+((v2.mPosition-v0.mPosition)*coef02); | ||
3724 | vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02); | ||
3725 | vout.mNormal = v0.mNormal; | ||
3726 | vout.mBinormal = v0.mBinormal; | ||
3727 | } | ||
3728 | |||
3729 | BOOL LLVolumeFace::createUnCutCubeCap() | ||
3730 | { | ||
3731 | const std::vector<LLVolume::Point>& mesh = mVolumep->getMesh(); | ||
3732 | const std::vector<LLVector3>& profile = mVolumep->getProfile().mProfile; | ||
3733 | S32 max_s = mVolumep->getProfile().getTotal(); | ||
3734 | S32 max_t = mVolumep->getPath().mPath.size(); | ||
3735 | |||
3736 | // S32 i; | ||
3737 | S32 num_vertices = 0, num_indices = 0; | ||
3738 | S32 grid_size = (profile.size()-1)/4; | ||
3739 | S32 quad_count = (grid_size * grid_size); | ||
3740 | |||
3741 | num_vertices = (grid_size+1)*(grid_size+1); | ||
3742 | num_indices = quad_count * 4; | ||
3743 | |||
3744 | S32 offset = 0; | ||
3745 | if (mTypeMask & TOP_MASK) | ||
3746 | offset = (max_t-1) * max_s; | ||
3747 | else | ||
3748 | offset = mBeginS; | ||
3749 | |||
3750 | VertexData corners[4]; | ||
3751 | VertexData baseVert; | ||
3752 | for(int t = 0; t < 4; t++){ | ||
3753 | corners[t].mPosition = mesh[offset + (grid_size*t)].mPos; | ||
3754 | corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f; | ||
3755 | corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1]; | ||
3756 | } | ||
3757 | baseVert.mNormal = | ||
3758 | ((corners[1].mPosition-corners[0].mPosition) % | ||
3759 | (corners[2].mPosition-corners[1].mPosition)); | ||
3760 | baseVert.mNormal.normVec(); | ||
3761 | if(!(mTypeMask & TOP_MASK)){ | ||
3762 | baseVert.mNormal *= -1.0f; | ||
3763 | }else{ | ||
3764 | //Swap the UVs on the U(X) axis for top face | ||
3765 | LLVector2 swap; | ||
3766 | swap = corners[0].mTexCoord; | ||
3767 | corners[0].mTexCoord=corners[3].mTexCoord; | ||
3768 | corners[3].mTexCoord=swap; | ||
3769 | swap = corners[1].mTexCoord; | ||
3770 | corners[1].mTexCoord=corners[2].mTexCoord; | ||
3771 | corners[2].mTexCoord=swap; | ||
3772 | } | ||
3773 | baseVert.mBinormal = calc_binormal_from_triangle( | ||
3774 | corners[0].mPosition, corners[0].mTexCoord, | ||
3775 | corners[1].mPosition, corners[1].mTexCoord, | ||
3776 | corners[2].mPosition, corners[2].mTexCoord); | ||
3777 | for(int t = 0; t < 4; t++){ | ||
3778 | corners[t].mBinormal = baseVert.mBinormal; | ||
3779 | corners[t].mNormal = baseVert.mNormal; | ||
3780 | } | ||
3781 | |||
3782 | S32 vtop = mVertices.size(); | ||
3783 | // S32 itop = mIndices.size(); | ||
3784 | /// vector_append(mVertices,4); | ||
3785 | // vector_append(mIndices,4); | ||
3786 | // LLVector3 new_pt = lerp(pt1, pt2, t_fraction); | ||
3787 | #if 0 | ||
3788 | for(int t=0;t<4;t++){ | ||
3789 | VertexData vd; | ||
3790 | vd.mPosition = corners[t].mPosition; | ||
3791 | vd.mNormal = | ||
3792 | ((corners[(t+1)%4].mPosition-corners[t].mPosition)% | ||
3793 | (corners[(t+2)%4].mPosition-corners[(t+1)%4].mPosition)); | ||
3794 | vd.mNormal.normVec(); | ||
3795 | |||
3796 | if (mTypeMask & TOP_MASK) | ||
3797 | vd.mNormal *= -1.0f; | ||
3798 | vd.mBinormal = vd.mNormal; | ||
3799 | vd.mTexCoord = corners[t].mTexCoord; | ||
3800 | mVertices.push_back(vd); | ||
3801 | } | ||
3802 | int idxs[] = {0,1,2,2,3,0}; | ||
3803 | if (mTypeMask & TOP_MASK){ | ||
3804 | for(int i=0;i<6;i++)mIndices.push_back(vtop+idxs[i]); | ||
3805 | }else{ | ||
3806 | for(int i=5;i>=0;i--)mIndices.push_back(vtop+idxs[i]); | ||
3807 | } | ||
3808 | #else | ||
3809 | for(int gx = 0;gx<grid_size+1;gx++){ | ||
3810 | for(int gy = 0;gy<grid_size+1;gy++){ | ||
3811 | VertexData newVert; | ||
3812 | LerpPlanarVertex( | ||
3813 | corners[0], | ||
3814 | corners[1], | ||
3815 | corners[3], | ||
3816 | newVert, | ||
3817 | (F32)gx/(F32)grid_size, | ||
3818 | (F32)gy/(F32)grid_size); | ||
3819 | mVertices.push_back(newVert); | ||
3820 | } | ||
3821 | } | ||
3822 | int idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; | ||
3823 | for(int gx = 0;gx<grid_size;gx++){ | ||
3824 | for(int gy = 0;gy<grid_size;gy++){ | ||
3825 | if (mTypeMask & TOP_MASK){ | ||
3826 | for(int i=5;i>=0;i--)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); | ||
3827 | }else{ | ||
3828 | for(int i=0;i<6;i++)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); | ||
3829 | } | ||
3830 | } | ||
3831 | } | ||
3832 | #endif | ||
3833 | return TRUE; | ||
3834 | } | ||
3835 | |||
3836 | |||
3837 | BOOL LLVolumeFace::createCap() | ||
3838 | { | ||
3839 | if (!(mTypeMask & HOLLOW_MASK) && | ||
3840 | !(mTypeMask & OPEN_MASK) && | ||
3841 | ((this->mVolumep->getParams().getPathParams().getBegin()==0.0f)&& | ||
3842 | (this->mVolumep->getParams().getPathParams().getEnd()==1.0f))&& | ||
3843 | (mVolumep->getProfile().mParams.getCurveType()==LL_PCODE_PROFILE_SQUARE && | ||
3844 | mVolumep->getPath().mParams.getCurveType()==LL_PCODE_PATH_LINE) | ||
3845 | ){ | ||
3846 | return createUnCutCubeCap(); | ||
3847 | } | ||
3848 | |||
3849 | S32 i; | ||
3850 | S32 num_vertices = 0, num_indices = 0; | ||
3851 | |||
3852 | const std::vector<LLVolume::Point>& mesh = mVolumep->getMesh(); | ||
3853 | const std::vector<LLVector3>& profile = mVolumep->getProfile().mProfile; | ||
3854 | |||
3855 | // All types of caps have the same number of vertices and indices | ||
3856 | num_vertices = profile.size(); | ||
3857 | num_indices = (profile.size() - 2)*3; | ||
3858 | vector_append(mVertices,num_vertices); | ||
3859 | vector_append(mIndices,num_indices); | ||
3860 | |||
3861 | S32 max_s = mVolumep->getProfile().getTotal(); | ||
3862 | S32 max_t = mVolumep->getPath().mPath.size(); | ||
3863 | |||
3864 | mCenter.clearVec(); | ||
3865 | |||
3866 | S32 offset = 0; | ||
3867 | if (mTypeMask & TOP_MASK) | ||
3868 | { | ||
3869 | offset = (max_t-1) * max_s; | ||
3870 | } | ||
3871 | else | ||
3872 | { | ||
3873 | offset = mBeginS; | ||
3874 | } | ||
3875 | |||
3876 | // Figure out the normal, assume all caps are flat faces. | ||
3877 | // Cross product to get normals. | ||
3878 | |||
3879 | LLVector2 cuv = LLVector2(0,0); | ||
3880 | |||
3881 | // Copy the vertices into the array | ||
3882 | for (i = 0; i < num_vertices; i++) | ||
3883 | { | ||
3884 | |||
3885 | if (mTypeMask & TOP_MASK) | ||
3886 | { | ||
3887 | mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f; | ||
3888 | mVertices[i].mTexCoord.mV[1] = profile[i].mV[1]+0.5f; | ||
3889 | } | ||
3890 | else | ||
3891 | { | ||
3892 | // Mirror for underside. | ||
3893 | mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f; | ||
3894 | mVertices[i].mTexCoord.mV[1] = 0.5f - profile[i].mV[1]; | ||
3895 | } | ||
3896 | |||
3897 | if(i){ | ||
3898 | //Dont include the first point of the profile in the average | ||
3899 | cuv += mVertices[i].mTexCoord; | ||
3900 | mCenter += mVertices[i].mPosition = mesh[i + offset].mPos; | ||
3901 | } | ||
3902 | else mVertices[i].mPosition = mesh[i + offset].mPos; | ||
3903 | //mVertices[i].mNormal = normal; | ||
3904 | } | ||
3905 | |||
3906 | mCenter /= (F32)(num_vertices-1); | ||
3907 | cuv /= (F32)(num_vertices-1); | ||
3908 | |||
3909 | LLVector3 binormal = calc_binormal_from_triangle( | ||
3910 | mCenter, cuv, | ||
3911 | mVertices[0].mPosition, mVertices[0].mTexCoord, | ||
3912 | mVertices[1].mPosition, mVertices[1].mTexCoord); | ||
3913 | binormal.normVec(); | ||
3914 | |||
3915 | LLVector3 d0; | ||
3916 | LLVector3 d1; | ||
3917 | LLVector3 normal; | ||
3918 | |||
3919 | d0 = mCenter-mVertices[0].mPosition; | ||
3920 | d1 = mCenter-mVertices[1].mPosition; | ||
3921 | |||
3922 | normal = (mTypeMask & TOP_MASK) ? (d0%d1) : (d1%d0); | ||
3923 | normal.normVec(); | ||
3924 | |||
3925 | VertexData vd; | ||
3926 | vd.mPosition = mCenter; | ||
3927 | vd.mNormal = normal; | ||
3928 | vd.mBinormal = binormal; | ||
3929 | vd.mTexCoord = cuv; | ||
3930 | |||
3931 | if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) | ||
3932 | { | ||
3933 | mVertices.push_back(vd); | ||
3934 | num_vertices++; | ||
3935 | vector_append(mIndices, 3); | ||
3936 | } | ||
3937 | |||
3938 | |||
3939 | for (i = 0; i < num_vertices; i++) | ||
3940 | { | ||
3941 | mVertices[i].mBinormal = binormal; | ||
3942 | mVertices[i].mNormal = normal; | ||
3943 | } | ||
3944 | |||
3945 | if (mTypeMask & HOLLOW_MASK) | ||
3946 | { | ||
3947 | if (mTypeMask & TOP_MASK) | ||
3948 | { | ||
3949 | // HOLLOW TOP | ||
3950 | // Does it matter if it's open or closed? - djs | ||
3951 | |||
3952 | S32 pt1 = 0, pt2 = num_vertices - 1; | ||
3953 | i = 0; | ||
3954 | while (pt2 - pt1 > 1) | ||
3955 | { | ||
3956 | // Use the profile points instead of the mesh, since you want | ||
3957 | // the un-transformed profile distances. | ||
3958 | LLVector3 p1 = profile[pt1]; | ||
3959 | LLVector3 p2 = profile[pt2]; | ||
3960 | LLVector3 pa = profile[pt1+1]; | ||
3961 | LLVector3 pb = profile[pt2-1]; | ||
3962 | |||
3963 | p1.mV[VZ] = 0.f; | ||
3964 | p2.mV[VZ] = 0.f; | ||
3965 | pa.mV[VZ] = 0.f; | ||
3966 | pb.mV[VZ] = 0.f; | ||
3967 | |||
3968 | // Use area of triangle to determine backfacing | ||
3969 | F32 area_1a2, area_1ba, area_21b, area_2ab; | ||
3970 | area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + | ||
3971 | (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + | ||
3972 | (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); | ||
3973 | |||
3974 | area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + | ||
3975 | (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + | ||
3976 | (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); | ||
3977 | |||
3978 | area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + | ||
3979 | (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + | ||
3980 | (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); | ||
3981 | |||
3982 | area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + | ||
3983 | (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + | ||
3984 | (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); | ||
3985 | |||
3986 | BOOL use_tri1a2 = TRUE; | ||
3987 | BOOL tri_1a2 = TRUE; | ||
3988 | BOOL tri_21b = TRUE; | ||
3989 | |||
3990 | if (area_1a2 < 0) | ||
3991 | { | ||
3992 | tri_1a2 = FALSE; | ||
3993 | } | ||
3994 | if (area_2ab < 0) | ||
3995 | { | ||
3996 | // Can't use, because it contains point b | ||
3997 | tri_1a2 = FALSE; | ||
3998 | } | ||
3999 | if (area_21b < 0) | ||
4000 | { | ||
4001 | tri_21b = FALSE; | ||
4002 | } | ||
4003 | if (area_1ba < 0) | ||
4004 | { | ||
4005 | // Can't use, because it contains point b | ||
4006 | tri_21b = FALSE; | ||
4007 | } | ||
4008 | |||
4009 | if (!tri_1a2) | ||
4010 | { | ||
4011 | use_tri1a2 = FALSE; | ||
4012 | } | ||
4013 | else if (!tri_21b) | ||
4014 | { | ||
4015 | use_tri1a2 = TRUE; | ||
4016 | } | ||
4017 | else | ||
4018 | { | ||
4019 | LLVector3 d1 = p1 - pa; | ||
4020 | LLVector3 d2 = p2 - pb; | ||
4021 | |||
4022 | if (d1.magVecSquared() < d2.magVecSquared()) | ||
4023 | { | ||
4024 | use_tri1a2 = TRUE; | ||
4025 | } | ||
4026 | else | ||
4027 | { | ||
4028 | use_tri1a2 = FALSE; | ||
4029 | } | ||
4030 | } | ||
4031 | |||
4032 | if (use_tri1a2) | ||
4033 | { | ||
4034 | mIndices[i++] = pt1; | ||
4035 | mIndices[i++] = pt1 + 1; | ||
4036 | mIndices[i++] = pt2; | ||
4037 | pt1++; | ||
4038 | } | ||
4039 | else | ||
4040 | { | ||
4041 | mIndices[i++] = pt1; | ||
4042 | mIndices[i++] = pt2 - 1; | ||
4043 | mIndices[i++] = pt2; | ||
4044 | pt2--; | ||
4045 | } | ||
4046 | } | ||
4047 | } | ||
4048 | else | ||
4049 | { | ||
4050 | // HOLLOW BOTTOM | ||
4051 | // Does it matter if it's open or closed? - djs | ||
4052 | |||
4053 | llassert(mTypeMask & BOTTOM_MASK); | ||
4054 | S32 pt1 = 0, pt2 = num_vertices - 1; | ||
4055 | |||
4056 | i = 0; | ||
4057 | while (pt2 - pt1 > 1) | ||
4058 | { | ||
4059 | // Use the profile points instead of the mesh, since you want | ||
4060 | // the un-transformed profile distances. | ||
4061 | LLVector3 p1 = profile[pt1]; | ||
4062 | LLVector3 p2 = profile[pt2]; | ||
4063 | LLVector3 pa = profile[pt1+1]; | ||
4064 | LLVector3 pb = profile[pt2-1]; | ||
4065 | |||
4066 | p1.mV[VZ] = 0.f; | ||
4067 | p2.mV[VZ] = 0.f; | ||
4068 | pa.mV[VZ] = 0.f; | ||
4069 | pb.mV[VZ] = 0.f; | ||
4070 | |||
4071 | // Use area of triangle to determine backfacing | ||
4072 | F32 area_1a2, area_1ba, area_21b, area_2ab; | ||
4073 | area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + | ||
4074 | (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + | ||
4075 | (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); | ||
4076 | |||
4077 | area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + | ||
4078 | (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + | ||
4079 | (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); | ||
4080 | |||
4081 | area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + | ||
4082 | (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + | ||
4083 | (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); | ||
4084 | |||
4085 | area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + | ||
4086 | (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + | ||
4087 | (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); | ||
4088 | |||
4089 | BOOL use_tri1a2 = TRUE; | ||
4090 | BOOL tri_1a2 = TRUE; | ||
4091 | BOOL tri_21b = TRUE; | ||
4092 | |||
4093 | if (area_1a2 < 0) | ||
4094 | { | ||
4095 | tri_1a2 = FALSE; | ||
4096 | } | ||
4097 | if (area_2ab < 0) | ||
4098 | { | ||
4099 | // Can't use, because it contains point b | ||
4100 | tri_1a2 = FALSE; | ||
4101 | } | ||
4102 | if (area_21b < 0) | ||
4103 | { | ||
4104 | tri_21b = FALSE; | ||
4105 | } | ||
4106 | if (area_1ba < 0) | ||
4107 | { | ||
4108 | // Can't use, because it contains point b | ||
4109 | tri_21b = FALSE; | ||
4110 | } | ||
4111 | |||
4112 | if (!tri_1a2) | ||
4113 | { | ||
4114 | use_tri1a2 = FALSE; | ||
4115 | } | ||
4116 | else if (!tri_21b) | ||
4117 | { | ||
4118 | use_tri1a2 = TRUE; | ||
4119 | } | ||
4120 | else | ||
4121 | { | ||
4122 | LLVector3 d1 = p1 - pa; | ||
4123 | LLVector3 d2 = p2 - pb; | ||
4124 | |||
4125 | if (d1.magVecSquared() < d2.magVecSquared()) | ||
4126 | { | ||
4127 | use_tri1a2 = TRUE; | ||
4128 | } | ||
4129 | else | ||
4130 | { | ||
4131 | use_tri1a2 = FALSE; | ||
4132 | } | ||
4133 | } | ||
4134 | |||
4135 | // Flipped backfacing from top | ||
4136 | if (use_tri1a2) | ||
4137 | { | ||
4138 | mIndices[i++] = pt1; | ||
4139 | mIndices[i++] = pt2; | ||
4140 | mIndices[i++] = pt1 + 1; | ||
4141 | pt1++; | ||
4142 | } | ||
4143 | else | ||
4144 | { | ||
4145 | mIndices[i++] = pt1; | ||
4146 | mIndices[i++] = pt2; | ||
4147 | mIndices[i++] = pt2 - 1; | ||
4148 | pt2--; | ||
4149 | } | ||
4150 | } | ||
4151 | } | ||
4152 | } | ||
4153 | else | ||
4154 | { | ||
4155 | // Not hollow, generate the triangle fan. | ||
4156 | if (mTypeMask & TOP_MASK) | ||
4157 | { | ||
4158 | if (mTypeMask & OPEN_MASK) | ||
4159 | { | ||
4160 | // SOLID OPEN TOP | ||
4161 | // Generate indices | ||
4162 | // This is a tri-fan, so we reuse the same first point for all triangles. | ||
4163 | for (i = 0; i < (num_vertices - 2); i++) | ||
4164 | { | ||
4165 | mIndices[3*i] = num_vertices - 1; | ||
4166 | mIndices[3*i+1] = i; | ||
4167 | mIndices[3*i+2] = i + 1; | ||
4168 | } | ||
4169 | } | ||
4170 | else | ||
4171 | { | ||
4172 | // SOLID CLOSED TOP | ||
4173 | for (i = 0; i < (num_vertices - 2); i++) | ||
4174 | { | ||
4175 | //MSMSM fix these caps but only for the un-cut case | ||
4176 | mIndices[3*i] = num_vertices - 1; | ||
4177 | mIndices[3*i+1] = i; | ||
4178 | mIndices[3*i+2] = i + 1; | ||
4179 | } | ||
4180 | } | ||
4181 | } | ||
4182 | else | ||
4183 | { | ||
4184 | if (mTypeMask & OPEN_MASK) | ||
4185 | { | ||
4186 | // SOLID OPEN BOTTOM | ||
4187 | // Generate indices | ||
4188 | // This is a tri-fan, so we reuse the same first point for all triangles. | ||
4189 | for (i = 0; i < (num_vertices - 2); i++) | ||
4190 | { | ||
4191 | mIndices[3*i] = num_vertices - 1; | ||
4192 | mIndices[3*i+1] = i + 1; | ||
4193 | mIndices[3*i+2] = i; | ||
4194 | } | ||
4195 | } | ||
4196 | else | ||
4197 | { | ||
4198 | // SOLID CLOSED BOTTOM | ||
4199 | for (i = 0; i < (num_vertices - 2); i++) | ||
4200 | { | ||
4201 | //MSMSM fix these caps but only for the un-cut case | ||
4202 | mIndices[3*i] = num_vertices - 1; | ||
4203 | mIndices[3*i+1] = i + 1; | ||
4204 | mIndices[3*i+2] = i; | ||
4205 | } | ||
4206 | } | ||
4207 | } | ||
4208 | } | ||
4209 | return TRUE; | ||
4210 | } | ||
4211 | |||
4212 | |||
4213 | BOOL LLVolumeFace::createSide() | ||
4214 | { | ||
4215 | BOOL flat = mTypeMask & FLAT_MASK; | ||
4216 | S32 num_vertices, num_indices; | ||
4217 | |||
4218 | |||
4219 | const std::vector<LLVolume::Point>& mesh = mVolumep->getMesh(); | ||
4220 | const std::vector<LLVector3>& profile = mVolumep->getProfile().mProfile; | ||
4221 | const std::vector<LLPath::PathPt>& path_data = mVolumep->getPath().mPath; | ||
4222 | |||
4223 | S32 max_s = mVolumep->getProfile().getTotal(); | ||
4224 | |||
4225 | S32 s, t, i; | ||
4226 | F32 ss, tt; | ||
4227 | |||
4228 | num_vertices = mNumS*mNumT; | ||
4229 | num_indices = (mNumS-1)*(mNumT-1)*6; | ||
4230 | vector_append(mVertices,num_vertices); | ||
4231 | vector_append(mIndices,num_indices); | ||
4232 | vector_append(mEdge, num_indices); | ||
4233 | |||
4234 | mCenter.clearVec(); | ||
4235 | |||
4236 | S32 begin_stex = llfloor( profile[mBeginS].mV[2] ); | ||
4237 | S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS; | ||
4238 | |||
4239 | S32 cur_vertex = 0; | ||
4240 | // Copy the vertices into the array | ||
4241 | for (t = mBeginT; t < mBeginT + mNumT; t++) | ||
4242 | { | ||
4243 | tt = path_data[t].mTexT; | ||
4244 | for (s = 0; s < num_s; s++) | ||
4245 | { | ||
4246 | if (mTypeMask & END_MASK) | ||
4247 | { | ||
4248 | if (s) | ||
4249 | { | ||
4250 | ss = 1.f; | ||
4251 | } | ||
4252 | else | ||
4253 | { | ||
4254 | ss = 0.f; | ||
4255 | } | ||
4256 | } | ||
4257 | else | ||
4258 | { | ||
4259 | // Get s value for tex-coord. | ||
4260 | if (!flat) | ||
4261 | { | ||
4262 | ss = profile[mBeginS + s].mV[2]; | ||
4263 | } | ||
4264 | else | ||
4265 | { | ||
4266 | ss = profile[mBeginS + s].mV[2] - begin_stex; | ||
4267 | } | ||
4268 | } | ||
4269 | |||
4270 | // Check to see if this triangle wraps around the array. | ||
4271 | if (mBeginS + s >= max_s) | ||
4272 | { | ||
4273 | // We're wrapping | ||
4274 | i = mBeginS + s + max_s*(t-1); | ||
4275 | } | ||
4276 | else | ||
4277 | { | ||
4278 | i = mBeginS + s + max_s*t; | ||
4279 | } | ||
4280 | |||
4281 | mCenter += mVertices[cur_vertex].mPosition = mesh[i].mPos; | ||
4282 | mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); | ||
4283 | |||
4284 | mVertices[cur_vertex].mNormal = LLVector3(0,0,0); | ||
4285 | mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); | ||
4286 | |||
4287 | cur_vertex++; | ||
4288 | |||
4289 | if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0) | ||
4290 | { | ||
4291 | mCenter += mVertices[cur_vertex].mPosition = mesh[i].mPos; | ||
4292 | mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); | ||
4293 | |||
4294 | mVertices[cur_vertex].mNormal = LLVector3(0,0,0); | ||
4295 | mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); | ||
4296 | cur_vertex++; | ||
4297 | } | ||
4298 | } | ||
4299 | |||
4300 | if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) | ||
4301 | { | ||
4302 | if (mTypeMask & OPEN_MASK) | ||
4303 | { | ||
4304 | s = num_s-1; | ||
4305 | } | ||
4306 | else | ||
4307 | { | ||
4308 | s = 0; | ||
4309 | } | ||
4310 | |||
4311 | i = mBeginS + s + max_s*t; | ||
4312 | ss = profile[mBeginS + s].mV[2] - begin_stex; | ||
4313 | mCenter += mVertices[cur_vertex].mPosition = mesh[i].mPos; | ||
4314 | mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); | ||
4315 | |||
4316 | mVertices[cur_vertex].mNormal = LLVector3(0,0,0); | ||
4317 | mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); | ||
4318 | cur_vertex++; | ||
4319 | } | ||
4320 | } | ||
4321 | mCenter /= (F32)num_vertices; | ||
4322 | |||
4323 | S32 cur_index = 0; | ||
4324 | S32 cur_edge = 0; | ||
4325 | BOOL flat_face = mTypeMask & FLAT_MASK; | ||
4326 | |||
4327 | // Now we generate the indices. | ||
4328 | for (t = 0; t < (mNumT-1); t++) | ||
4329 | { | ||
4330 | for (s = 0; s < (mNumS-1); s++) | ||
4331 | { | ||
4332 | mIndices[cur_index++] = s + mNumS*t; //bottom left | ||
4333 | mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right | ||
4334 | mIndices[cur_index++] = s + mNumS*(t+1); //top left | ||
4335 | mIndices[cur_index++] = s + mNumS*t; //bottom left | ||
4336 | mIndices[cur_index++] = s+1 + mNumS*t; //bottom right | ||
4337 | mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right | ||
4338 | |||
4339 | mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; //bottom left/top right neighbor face | ||
4340 | if (t < mNumT-2) { //top right/top left neighbor face | ||
4341 | mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1; | ||
4342 | } | ||
4343 | else if (mNumT <= 3 || mVolumep->getPath().isOpen() == TRUE) { //no neighbor | ||
4344 | mEdge[cur_edge++] = -1; | ||
4345 | } | ||
4346 | else { //wrap on T | ||
4347 | mEdge[cur_edge++] = s*2+1; | ||
4348 | } | ||
4349 | if (s > 0) { //top left/bottom left neighbor face | ||
4350 | mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1; | ||
4351 | } | ||
4352 | else if (flat_face || mVolumep->getProfile().isOpen() == TRUE) { //no neighbor | ||
4353 | mEdge[cur_edge++] = -1; | ||
4354 | } | ||
4355 | else { //wrap on S | ||
4356 | mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1; | ||
4357 | } | ||
4358 | |||
4359 | if (t > 0) { //bottom left/bottom right neighbor face | ||
4360 | mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2; | ||
4361 | } | ||
4362 | else if (mNumT <= 3 || mVolumep->getPath().isOpen() == TRUE) { //no neighbor | ||
4363 | mEdge[cur_edge++] = -1; | ||
4364 | } | ||
4365 | else { //wrap on T | ||
4366 | mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2; | ||
4367 | } | ||
4368 | if (s < mNumS-2) { //bottom right/top right neighbor face | ||
4369 | mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2; | ||
4370 | } | ||
4371 | else if (flat_face || mVolumep->getProfile().isOpen() == TRUE) { //no neighbor | ||
4372 | mEdge[cur_edge++] = -1; | ||
4373 | } | ||
4374 | else { //wrap on S | ||
4375 | mEdge[cur_edge++] = (mNumS-1)*2*t; | ||
4376 | } | ||
4377 | mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; //top right/bottom left neighbor face | ||
4378 | } | ||
4379 | } | ||
4380 | |||
4381 | |||
4382 | //generate normals | ||
4383 | for (U32 i = 0; i < mIndices.size()/3; i++) { //for each triangle | ||
4384 | const VertexData& v0 = mVertices[mIndices[i*3+0]]; | ||
4385 | const VertexData& v1 = mVertices[mIndices[i*3+1]]; | ||
4386 | const VertexData& v2 = mVertices[mIndices[i*3+2]]; | ||
4387 | |||
4388 | //calculate triangle normal | ||
4389 | LLVector3 norm = (v0.mPosition-v1.mPosition)% | ||
4390 | (v0.mPosition-v2.mPosition); | ||
4391 | |||
4392 | //calculate binormal | ||
4393 | LLVector3 binorm = calc_binormal_from_triangle(v0.mPosition, v0.mTexCoord, | ||
4394 | v1.mPosition, v1.mTexCoord, | ||
4395 | v2.mPosition, v2.mTexCoord); | ||
4396 | |||
4397 | for (U32 j = 0; j < 3; j++) { //add triangle normal to vertices | ||
4398 | mVertices[mIndices[i*3+j]].mNormal += norm; // * (weight_sum - d[j])/weight_sum; | ||
4399 | mVertices[mIndices[i*3+j]].mBinormal += binorm; // * (weight_sum - d[j])/weight_sum; | ||
4400 | } | ||
4401 | |||
4402 | //even out quad contributions | ||
4403 | if (i % 2 == 0) { | ||
4404 | mVertices[mIndices[i*3+2]].mNormal += norm; | ||
4405 | mVertices[mIndices[i*3+2]].mBinormal += binorm; | ||
4406 | } | ||
4407 | else { | ||
4408 | mVertices[mIndices[i*3+1]].mNormal += norm; | ||
4409 | mVertices[mIndices[i*3+1]].mBinormal += binorm; | ||
4410 | } | ||
4411 | } | ||
4412 | |||
4413 | if (mVolumep->getPath().isOpen() == FALSE) { //wrap normals on T | ||
4414 | for (S32 i = 0; i < mNumS; i++) { | ||
4415 | LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal; | ||
4416 | mVertices[i].mNormal = norm; | ||
4417 | mVertices[mNumS*(mNumT-1)+i].mNormal = norm; | ||
4418 | } | ||
4419 | } | ||
4420 | |||
4421 | if (mVolumep->getProfile().isOpen() == FALSE) { //wrap normals on S | ||
4422 | for (S32 i = 0; i < mNumT; i++) { | ||
4423 | LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal; | ||
4424 | mVertices[mNumS * i].mNormal = norm; | ||
4425 | mVertices[mNumS * i+mNumS-1].mNormal = norm; | ||
4426 | } | ||
4427 | } | ||
4428 | |||
4429 | if (mVolumep->getPathType() == LL_PCODE_PATH_CIRCLE && ((mVolumep->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF)) { | ||
4430 | if ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f) | ||
4431 | { //all lower S have same normal | ||
4432 | for (S32 i = 0; i < mNumT; i++) { | ||
4433 | mVertices[mNumS*i].mNormal = LLVector3(1,0,0); | ||
4434 | } | ||
4435 | } | ||
4436 | |||
4437 | if ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 0.000001f) | ||
4438 | { //all upper T have same normal | ||
4439 | for (S32 i = 0; i < mNumT; i++) { | ||
4440 | mVertices[mNumS*i+mNumS-1].mNormal = LLVector3(-1,0,0); | ||
4441 | } | ||
4442 | } | ||
4443 | } | ||
4444 | |||
4445 | //this loop would LOVE OpenMP | ||
4446 | LLVector3 min = mVolumep->mBounds[0] - mVolumep->mBounds[1]; | ||
4447 | LLVector3 max = mVolumep->mBounds[0] + mVolumep->mBounds[1]; | ||
4448 | |||
4449 | if (min == max && min == LLVector3(512,512,512)) | ||
4450 | { | ||
4451 | min = max = mVertices[0].mPosition; | ||
4452 | } | ||
4453 | |||
4454 | for (U32 i = 0; i < mVertices.size(); i++) { | ||
4455 | mVertices[i].mNormal.normVec(); | ||
4456 | mVertices[i].mBinormal.normVec(); | ||
4457 | |||
4458 | for (U32 j = 0; j < 3; j++) { | ||
4459 | if (mVertices[i].mPosition.mV[j] > max.mV[j]) { | ||
4460 | max.mV[j] = mVertices[i].mPosition.mV[j]; | ||
4461 | } | ||
4462 | if (mVertices[i].mPosition.mV[j] < min.mV[j]) { | ||
4463 | min.mV[j] = mVertices[i].mPosition.mV[j]; | ||
4464 | } | ||
4465 | } | ||
4466 | } | ||
4467 | |||
4468 | mVolumep->mBounds[0] = (min + max) * 0.5f; //center | ||
4469 | mVolumep->mBounds[1] = (max - min) * 0.5f; //half-height | ||
4470 | |||
4471 | return TRUE; | ||
4472 | } | ||
4473 | |||
4474 | // Static | ||
4475 | BOOL LLVolumeFace::updateColors(LLColor4U *old_colors, const S32 num_old, const LLVolumeFace &old_vf, | ||
4476 | LLStrider<LLColor4U> &new_colors, const S32 num_new, const LLVolumeFace &new_vf) | ||
4477 | { | ||
4478 | if (new_vf.mTypeMask & CAP_MASK) | ||
4479 | { | ||
4480 | // These aren't interpolated correctly. Need to fix when shadows go in... | ||
4481 | F32 ratio = (F32)num_old / (F32)num_new; | ||
4482 | S32 v = 0; | ||
4483 | for (v = 0; v < num_new; v++) | ||
4484 | { | ||
4485 | new_colors[v] = old_colors[(S32)(v*ratio)]; | ||
4486 | } | ||
4487 | return FALSE; | ||
4488 | } | ||
4489 | else if (new_vf.mTypeMask & END_MASK) | ||
4490 | { | ||
4491 | // These aren't interpolated correctly. Need to fix when shadows go in... | ||
4492 | F32 ratio = (F32)num_old / (F32)num_new; | ||
4493 | S32 v = 0; | ||
4494 | for (v = 0; v < num_new; v++) | ||
4495 | { | ||
4496 | new_colors[v] = old_colors[(S32)(v*ratio)]; | ||
4497 | } | ||
4498 | return FALSE; | ||
4499 | } | ||
4500 | else if (new_vf.mTypeMask & SIDE_MASK) | ||
4501 | { | ||
4502 | S32 s, t; | ||
4503 | F32 s_ratio = (F32)old_vf.mNumS / (F32)new_vf.mNumS; | ||
4504 | F32 t_ratio = (F32)old_vf.mNumT / (F32)new_vf.mNumT; | ||
4505 | |||
4506 | S32 v = 0; | ||
4507 | for (t = 0; t < new_vf.mNumT; t++) | ||
4508 | { | ||
4509 | F32 t_frac = t * t_ratio; | ||
4510 | S32 old_t = (S32)t_frac; | ||
4511 | S32 t_target = llmin(old_t + 1, (old_vf.mNumT - 1)); | ||
4512 | t_frac -= old_t; | ||
4513 | for (s = 0; s < new_vf.mNumS; s++) | ||
4514 | { | ||
4515 | F32 s_frac = s * s_ratio; | ||
4516 | S32 old_s = (S32)s_frac; | ||
4517 | S32 s_target = llmin(old_s + 1, (old_vf.mNumS - 1)); | ||
4518 | s_frac -= old_s; | ||
4519 | |||
4520 | // Interpolate along s, then along t. | ||
4521 | LLColor4U s_interp0 = old_colors[old_t * old_vf.mNumS + old_s].multAll(1.f - s_frac).addClampMax(old_colors[old_t * old_vf.mNumS + s_target].multAll(s_frac)); | ||
4522 | LLColor4U s_interp1 = old_colors[t_target * old_vf.mNumS + old_s].multAll(1.f - s_frac).addClampMax(old_colors[t_target * old_vf.mNumS + s_target].multAll(s_frac)); | ||
4523 | new_colors[v] = s_interp0.multAll(1.f - t_frac).addClampMax(s_interp1.multAll(t_frac)); | ||
4524 | v++; | ||
4525 | } | ||
4526 | } | ||
4527 | } | ||
4528 | else | ||
4529 | { | ||
4530 | llerrs << "Unknown/uninitialized face type!" << llendl; | ||
4531 | return FALSE; | ||
4532 | } | ||
4533 | return TRUE; | ||
4534 | } | ||
4535 | |||
4536 | |||
4537 | // Finds binormal based on three vertices with texture coordinates. | ||
4538 | // Fills in dummy values if the triangle has degenerate texture coordinates. | ||
4539 | LLVector3 calc_binormal_from_triangle( | ||
4540 | const LLVector3& pos0, | ||
4541 | const LLVector2& tex0, | ||
4542 | const LLVector3& pos1, | ||
4543 | const LLVector2& tex1, | ||
4544 | const LLVector3& pos2, | ||
4545 | const LLVector2& tex2) | ||
4546 | { | ||
4547 | LLVector3 rx0( pos0.mV[VX], tex0.mV[VX], tex0.mV[VY] ); | ||
4548 | LLVector3 rx1( pos1.mV[VX], tex1.mV[VX], tex1.mV[VY] ); | ||
4549 | LLVector3 rx2( pos2.mV[VX], tex2.mV[VX], tex2.mV[VY] ); | ||
4550 | |||
4551 | LLVector3 ry0( pos0.mV[VY], tex0.mV[VX], tex0.mV[VY] ); | ||
4552 | LLVector3 ry1( pos1.mV[VY], tex1.mV[VX], tex1.mV[VY] ); | ||
4553 | LLVector3 ry2( pos2.mV[VY], tex2.mV[VX], tex2.mV[VY] ); | ||
4554 | |||
4555 | LLVector3 rz0( pos0.mV[VZ], tex0.mV[VX], tex0.mV[VY] ); | ||
4556 | LLVector3 rz1( pos1.mV[VZ], tex1.mV[VX], tex1.mV[VY] ); | ||
4557 | LLVector3 rz2( pos2.mV[VZ], tex2.mV[VX], tex2.mV[VY] ); | ||
4558 | |||
4559 | LLVector3 r0 = (rx0 - rx1) % (rx0 - rx2); | ||
4560 | LLVector3 r1 = (ry0 - ry1) % (ry0 - ry2); | ||
4561 | LLVector3 r2 = (rz0 - rz1) % (rz0 - rz2); | ||
4562 | |||
4563 | if( r0.mV[VX] && r1.mV[VX] && r2.mV[VX] ) | ||
4564 | { | ||
4565 | LLVector3 binormal( | ||
4566 | -r0.mV[VZ] / r0.mV[VX], | ||
4567 | -r1.mV[VZ] / r1.mV[VX], | ||
4568 | -r2.mV[VZ] / r2.mV[VX]); | ||
4569 | //binormal.normVec(); | ||
4570 | return binormal; | ||
4571 | } | ||
4572 | else | ||
4573 | { | ||
4574 | return LLVector3( 0, 1 , 0 ); | ||
4575 | } | ||
4576 | } | ||