aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llpolymorph.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llpolymorph.cpp
parentREADME.txt (diff)
downloadmeta-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/newview/llpolymorph.cpp')
-rw-r--r--linden/indra/newview/llpolymorph.cpp658
1 files changed, 658 insertions, 0 deletions
diff --git a/linden/indra/newview/llpolymorph.cpp b/linden/indra/newview/llpolymorph.cpp
new file mode 100644
index 0000000..ae9b37a
--- /dev/null
+++ b/linden/indra/newview/llpolymorph.cpp
@@ -0,0 +1,658 @@
1/**
2 * @file llpolymorph.cpp
3 * @brief Implementation of LLPolyMesh class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28//-----------------------------------------------------------------------------
29// Header Files
30//-----------------------------------------------------------------------------
31#include "llviewerprecompiledheaders.h"
32
33#include "llpolymorph.h"
34#include "linked_lists.h"
35#include "llvoavatar.h"
36#include "llxmltree.h"
37#include "llendianswizzle.h"
38
39//#include "../tools/imdebug/imdebug.h"
40
41const F32 NORMAL_SOFTEN_FACTOR = 0.65f;
42
43LLLinkedList<LLPolyMorphData> gLoadedMorphs;
44
45//-----------------------------------------------------------------------------
46// LLPolyMorphData()
47//-----------------------------------------------------------------------------
48LLPolyMorphData::LLPolyMorphData(char *morph_name)
49{
50 llassert (morph_name);
51
52 mName = new char[strlen(morph_name) + 1];
53 strcpy(mName, morph_name);
54
55 mNumIndices = 0;
56 mCurrentIndex = 0;
57 mTotalDistortion = 0.f;
58 mAvgDistortion.zeroVec();
59 mMaxDistortion = 0.f;
60 mVertexIndices = NULL;
61 mCoords = NULL;
62 mNormals = NULL;
63 mBinormals = NULL;
64 mTexCoords = NULL;
65
66 mMesh = NULL;
67}
68
69//-----------------------------------------------------------------------------
70// ~LLPolyMorphData()
71//-----------------------------------------------------------------------------
72LLPolyMorphData::~LLPolyMorphData()
73{
74 delete [] mName;
75 delete [] mVertexIndices;
76 delete [] mCoords;
77 delete [] mNormals;
78 delete [] mBinormals;
79 delete [] mTexCoords;
80}
81
82//-----------------------------------------------------------------------------
83// loadBinary()
84//-----------------------------------------------------------------------------
85BOOL LLPolyMorphData::loadBinary(FILE *fp, LLPolyMeshSharedData *mesh)
86{
87 S32 numVertices;
88 S32 numRead;
89
90 numRead = fread(&numVertices, sizeof(S32), 1, fp);
91 llendianswizzle(&numVertices, sizeof(S32), 1);
92 if (numRead != 1)
93 {
94 llwarns << "Can't read number of morph target vertices" << llendl;
95 return FALSE;
96 }
97
98 //-------------------------------------------------------------------------
99 // allocate vertices
100 //-------------------------------------------------------------------------
101 mCoords = new LLVector3[numVertices];
102 mNormals = new LLVector3[numVertices];
103 mBinormals = new LLVector3[numVertices];
104 mTexCoords = new LLVector2[numVertices];
105 // Actually, we are allocating more space than we need for the skiplist
106 mVertexIndices = new U32[numVertices];
107 mNumIndices = 0;
108 mTotalDistortion = 0.f;
109 mMaxDistortion = 0.f;
110 mAvgDistortion.zeroVec();
111 mMesh = mesh;
112
113 //-------------------------------------------------------------------------
114 // read vertices
115 //-------------------------------------------------------------------------
116 for(S32 v = 0; v < numVertices; v++)
117 {
118 numRead = fread(&mVertexIndices[v], sizeof(U32), 1, fp);
119 llendianswizzle(&mVertexIndices[v], sizeof(U32), 1);
120 if (numRead != 1)
121 {
122 llwarns << "Can't read morph target vertex number" << llendl;
123 return FALSE;
124 }
125
126 if (mVertexIndices[v] > 10000)
127 {
128 llerrs << "Bad morph index: " << mVertexIndices[v] << llendl;
129 }
130
131
132 numRead = fread(&mCoords[v].mV, sizeof(F32), 3, fp);
133 llendianswizzle(&mCoords[v].mV, sizeof(F32), 3);
134 if (numRead != 3)
135 {
136 llwarns << "Can't read morph target vertex coordinates" << llendl;
137 return FALSE;
138 }
139
140 F32 magnitude = mCoords[v].magVec();
141
142 mTotalDistortion += magnitude;
143 mAvgDistortion.mV[VX] += fabs(mCoords[v].mV[VX]);
144 mAvgDistortion.mV[VY] += fabs(mCoords[v].mV[VY]);
145 mAvgDistortion.mV[VZ] += fabs(mCoords[v].mV[VZ]);
146
147 if (magnitude > mMaxDistortion)
148 {
149 mMaxDistortion = magnitude;
150 }
151
152 numRead = fread(&mNormals[v].mV, sizeof(F32), 3, fp);
153 llendianswizzle(&mNormals[v].mV, sizeof(F32), 3);
154 if (numRead != 3)
155 {
156 llwarns << "Can't read morph target normal" << llendl;
157 return FALSE;
158 }
159
160 numRead = fread(&mBinormals[v].mV, sizeof(F32), 3, fp);
161 llendianswizzle(&mBinormals[v].mV, sizeof(F32), 3);
162 if (numRead != 3)
163 {
164 llwarns << "Can't read morph target binormal" << llendl;
165 return FALSE;
166 }
167
168
169 numRead = fread(&mTexCoords[v].mV, sizeof(F32), 2, fp);
170 llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2);
171 if (numRead != 2)
172 {
173 llwarns << "Can't read morph target uv" << llendl;
174 return FALSE;
175 }
176
177 mNumIndices++;
178 }
179
180 mAvgDistortion = mAvgDistortion * (1.f/(F32)mNumIndices);
181 mAvgDistortion.normVec();
182
183 gLoadedMorphs.addData(this);
184
185 return TRUE;
186}
187
188//-----------------------------------------------------------------------------
189// LLPolyMorphTargetInfo()
190//-----------------------------------------------------------------------------
191LLPolyMorphTargetInfo::LLPolyMorphTargetInfo()
192 : mIsClothingMorph(FALSE)
193{
194}
195
196BOOL LLPolyMorphTargetInfo::parseXml(LLXmlTreeNode* node)
197{
198 llassert( node->hasName( "param" ) && node->getChildByName( "param_morph" ) );
199
200 if (!LLViewerVisualParamInfo::parseXml(node))
201 return FALSE;
202
203 // Get mixed-case name
204 static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
205 if( !node->getFastAttributeString( name_string, mMorphName ) )
206 {
207 llwarns << "Avatar file: <param> is missing name attribute" << llendl;
208 return FALSE; // Continue, ignoring this tag
209 }
210
211 static LLStdStringHandle clothing_morph_string = LLXmlTree::addAttributeString("clothing_morph");
212 node->getFastAttributeBOOL(clothing_morph_string, mIsClothingMorph);
213
214 LLXmlTreeNode *paramNode = node->getChildByName("param_morph");
215
216 for (LLXmlTreeNode* child_node = paramNode->getFirstChild();
217 child_node;
218 child_node = paramNode->getNextChild())
219 {
220 static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
221 if (child_node->hasName("volume_morph"))
222 {
223 LLString volume_name;
224 if (child_node->getFastAttributeString(name_string, volume_name))
225 {
226 LLVector3 scale;
227 static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
228 child_node->getFastAttributeVector3(scale_string, scale);
229
230 LLVector3 pos;
231 static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
232 child_node->getFastAttributeVector3(pos_string, pos);
233
234 mVolumeInfoList.push_back(LLPolyVolumeMorphInfo(volume_name,scale,pos));
235 }
236 }
237 }
238
239 return TRUE;
240}
241
242//-----------------------------------------------------------------------------
243// LLPolyMorphTarget()
244//-----------------------------------------------------------------------------
245LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh)
246 : mMorphData(NULL), mMesh(poly_mesh),
247 mVertMask(NULL),
248 mLastSex(SEX_FEMALE),
249 mNumMorphMasksPending(0)
250{
251}
252
253//-----------------------------------------------------------------------------
254// ~LLPolyMorphTarget()
255//-----------------------------------------------------------------------------
256LLPolyMorphTarget::~LLPolyMorphTarget()
257{
258 delete mVertMask;
259}
260
261//-----------------------------------------------------------------------------
262// setInfo()
263//-----------------------------------------------------------------------------
264BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
265{
266 llassert(mInfo == NULL);
267 if (info->mID < 0)
268 return FALSE;
269 mInfo = info;
270 mID = info->mID;
271 setWeight(getDefaultWeight(), FALSE );
272
273 LLVOAvatar* avatarp = mMesh->getAvatar();
274 LLPolyMorphTargetInfo::volume_info_list_t::iterator iter;
275 for (iter = getInfo()->mVolumeInfoList.begin(); iter != getInfo()->mVolumeInfoList.end(); iter++)
276 {
277 LLPolyVolumeMorphInfo *volume_info = &(*iter);
278 std::string vol_string(volume_info->mName);
279 for (S32 i = 0; i < avatarp->mNumCollisionVolumes; i++)
280 {
281 if (avatarp->mCollisionVolumes[i].getName() == vol_string)
282 {
283 mVolumeMorphs.push_back(LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i],
284 volume_info->mScale,
285 volume_info->mPos));
286 break;
287 }
288 }
289 }
290
291 mMorphData = mMesh->getMorphData(getInfo()->mMorphName.c_str());
292 if (!mMorphData)
293 {
294 llwarns << "No morph target named " << getInfo()->mMorphName << " found in mesh." << llendl;
295 return FALSE; // Continue, ignoring this tag
296 }
297 return TRUE;
298}
299
300#if 0 // obsolete
301//-----------------------------------------------------------------------------
302// parseData()
303//-----------------------------------------------------------------------------
304BOOL LLPolyMorphTarget::parseData(LLXmlTreeNode* node)
305{
306 LLPolyMorphTargetInfo* info = new LLPolyMorphTargetInfo;
307
308 info->parseXml(node);
309 if (!setInfo(info))
310 {
311 delete info;
312 return FALSE;
313 }
314 return TRUE;
315}
316#endif
317
318//-----------------------------------------------------------------------------
319// getVertexDistortion()
320//-----------------------------------------------------------------------------
321LLVector3 LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh *mesh)
322{
323 if (!mMorphData || mMesh != mesh) return LLVector3::zero;
324
325 for(U32 index = 0; index < mMorphData->mNumIndices; index++)
326 {
327 if (mMorphData->mVertexIndices[index] == (U32)requested_index)
328 {
329 return mMorphData->mCoords[index];
330 }
331 }
332
333 return LLVector3::zero;
334}
335
336//-----------------------------------------------------------------------------
337// getFirstDistortion()
338//-----------------------------------------------------------------------------
339const LLVector3 *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
340{
341 if (!mMorphData) return &LLVector3::zero;
342
343 LLVector3* resultVec;
344 mMorphData->mCurrentIndex = 0;
345 if (mMorphData->mNumIndices)
346 {
347 resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex];
348 if (index != NULL)
349 {
350 *index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex];
351 }
352 if (poly_mesh != NULL)
353 {
354 *poly_mesh = mMesh;
355 }
356
357 return resultVec;
358 }
359 return NULL;
360}
361
362//-----------------------------------------------------------------------------
363// getNextDistortion()
364//-----------------------------------------------------------------------------
365const LLVector3 *LLPolyMorphTarget::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
366{
367 if (!mMorphData) return &LLVector3::zero;
368
369 LLVector3* resultVec;
370 mMorphData->mCurrentIndex++;
371 if (mMorphData->mCurrentIndex < mMorphData->mNumIndices)
372 {
373 resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex];
374 if (index != NULL)
375 {
376 *index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex];
377 }
378 if (poly_mesh != NULL)
379 {
380 *poly_mesh = mMesh;
381 }
382 return resultVec;
383 }
384 return NULL;
385}
386
387//-----------------------------------------------------------------------------
388// getTotalDistortion()
389//-----------------------------------------------------------------------------
390F32 LLPolyMorphTarget::getTotalDistortion()
391{
392 if (mMorphData)
393 {
394 return mMorphData->mTotalDistortion;
395 }
396 else
397 {
398 return 0.f;
399 }
400}
401
402//-----------------------------------------------------------------------------
403// getAvgDistortion()
404//-----------------------------------------------------------------------------
405const LLVector3& LLPolyMorphTarget::getAvgDistortion()
406{
407 if (mMorphData)
408 {
409 return mMorphData->mAvgDistortion;
410 }
411 else
412 {
413 return LLVector3::zero;
414 }
415}
416
417//-----------------------------------------------------------------------------
418// getMaxDistortion()
419//-----------------------------------------------------------------------------
420F32 LLPolyMorphTarget::getMaxDistortion()
421{
422 if (mMorphData)
423 {
424 return mMorphData->mMaxDistortion;
425 }
426 else
427 {
428 return 0.f;
429 }
430}
431
432//-----------------------------------------------------------------------------
433// apply()
434//-----------------------------------------------------------------------------
435void LLPolyMorphTarget::apply( ESex avatar_sex )
436{
437 if (!mMorphData || mNumMorphMasksPending > 0)
438 {
439 return;
440 }
441
442 mLastSex = avatar_sex;
443
444 // perform differential update of morph
445 F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight);
446 // store last weight
447 mLastWeight += delta_weight;
448
449 if (delta_weight != 0.f)
450 {
451 llassert(!mMesh->isLOD());
452 LLVector3 *coords = mMesh->getWritableCoords();
453
454 LLVector3 *scaled_normals = mMesh->getScaledNormals();
455 LLVector3 *normals = mMesh->getWritableNormals();
456
457 LLVector3 *scaled_binormals = mMesh->getScaledBinormals();
458 LLVector3 *binormals = mMesh->getWritableBinormals();
459
460 LLVector4 *clothing_weights = mMesh->getWritableClothingWeights();
461 LLVector2 *tex_coords = mMesh->getWritableTexCoords();
462
463 F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
464
465 for(U32 vert_index_morph = 0; vert_index_morph < mMorphData->mNumIndices; vert_index_morph++)
466 {
467 S32 vert_index_mesh = mMorphData->mVertexIndices[vert_index_morph];
468
469 F32 maskWeight = 1.f;
470 if (maskWeightArray)
471 {
472 maskWeight = maskWeightArray[vert_index_morph];
473 }
474
475 coords[vert_index_mesh] += mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight;
476 if (getInfo()->mIsClothingMorph && clothing_weights)
477 {
478 LLVector3 clothing_offset = mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight;
479 LLVector4* clothing_weight = &clothing_weights[vert_index_mesh];
480 clothing_weight->mV[VX] += clothing_offset.mV[VX];
481 clothing_weight->mV[VY] += clothing_offset.mV[VY];
482 clothing_weight->mV[VZ] += clothing_offset.mV[VZ];
483 clothing_weight->mV[VW] = maskWeight;
484 }
485
486 // calculate new normals based on half angles
487 scaled_normals[vert_index_mesh] += mMorphData->mNormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR;
488 LLVector3 normalized_normal = scaled_normals[vert_index_mesh];
489 normalized_normal.normVec();
490 normals[vert_index_mesh] = normalized_normal;
491
492 // calculate new binormals
493 scaled_binormals[vert_index_mesh] += mMorphData->mBinormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR;
494 LLVector3 tangent = scaled_binormals[vert_index_mesh] % normalized_normal;
495 LLVector3 normalized_binormal = normalized_normal % tangent;
496 normalized_binormal.normVec();
497 binormals[vert_index_mesh] = normalized_binormal;
498
499 tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight;
500 }
501
502 // now apply volume changes
503 for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ )
504 {
505 LLPolyVolumeMorph* volume_morph = &(*iter);
506 LLVector3 scale_delta = volume_morph->mScale * delta_weight;
507 LLVector3 pos_delta = volume_morph->mPos * delta_weight;
508
509 volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta);
510 volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta);
511 }
512 }
513
514 if (mNext)
515 {
516 mNext->apply(avatar_sex);
517 }
518}
519
520//-----------------------------------------------------------------------------
521// applyMask()
522//-----------------------------------------------------------------------------
523void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert)
524{
525 LLVector4 *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL;
526
527 if (!mVertMask)
528 {
529 mVertMask = new LLPolyVertexMask(mMorphData);
530 mNumMorphMasksPending--;
531 }
532 else
533 {
534 // remove effect of previous mask
535 F32 *maskWeights = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
536
537 if (maskWeights)
538 {
539 LLVector3 *coords = mMesh->getWritableCoords();
540 LLVector3 *scaled_normals = mMesh->getScaledNormals();
541 LLVector3 *scaled_binormals = mMesh->getScaledBinormals();
542 LLVector2 *tex_coords = mMesh->getWritableTexCoords();
543
544 for(U32 vert = 0; vert < mMorphData->mNumIndices; vert++)
545 {
546 F32 lastMaskWeight = mLastWeight * maskWeights[vert];
547 S32 out_vert = mMorphData->mVertexIndices[vert];
548
549 // remove effect of existing masked morph
550 coords[out_vert] -= mMorphData->mCoords[vert] * lastMaskWeight;
551 scaled_normals[out_vert] -= mMorphData->mNormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR;
552 scaled_binormals[out_vert] -= mMorphData->mBinormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR;
553 tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight;
554
555 if (clothing_weights)
556 {
557 LLVector3 clothing_offset = mMorphData->mCoords[vert] * lastMaskWeight;
558 LLVector4* clothing_weight = &clothing_weights[out_vert];
559 clothing_weight->mV[VX] -= clothing_offset.mV[VX];
560 clothing_weight->mV[VY] -= clothing_offset.mV[VY];
561 clothing_weight->mV[VZ] -= clothing_offset.mV[VZ];
562 }
563 }
564 }
565 }
566
567 // set last weight to 0, since we've removed the effect of this morph
568 mLastWeight = 0.f;
569
570 mVertMask->generateMask(maskTextureData, width, height, num_components, invert, clothing_weights);
571
572 apply(mLastSex);
573}
574
575
576//-----------------------------------------------------------------------------
577// LLPolyVertexMask()
578//-----------------------------------------------------------------------------
579LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data)
580{
581 mWeights = new F32[morph_data->mNumIndices];
582 mMorphData = morph_data;
583 mWeightsGenerated = FALSE;
584}
585
586//-----------------------------------------------------------------------------
587// ~LLPolyVertexMask()
588//-----------------------------------------------------------------------------
589LLPolyVertexMask::~LLPolyVertexMask()
590{
591 delete[] mWeights;
592}
593
594//-----------------------------------------------------------------------------
595// generateMask()
596//-----------------------------------------------------------------------------
597void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4 *clothing_weights)
598{
599// RN debug output that uses Image Debugger (http://www.cs.unc.edu/~baxter/projects/imdebug/)
600// BOOL debugImg = FALSE;
601// if (debugImg)
602// {
603// if (invert)
604// {
605// imdebug("lum rbga=rgba b=8 w=%d h=%d *-1 %p", width, height, maskTextureData);
606// }
607// else
608// {
609// imdebug("lum rbga=rgba b=8 w=%d h=%d %p", width, height, maskTextureData);
610// }
611// }
612 for (U32 index = 0; index < mMorphData->mNumIndices; index++)
613 {
614 S32 vertIndex = mMorphData->mVertexIndices[index];
615 const S32 *sharedVertIndex = mMorphData->mMesh->getSharedVert(vertIndex);
616 LLVector2 uvCoords;
617
618 if (sharedVertIndex)
619 {
620 uvCoords = mMorphData->mMesh->getUVs(*sharedVertIndex);
621 }
622 else
623 {
624 uvCoords = mMorphData->mMesh->getUVs(vertIndex);
625 }
626 U32 s = llclamp((U32)(uvCoords.mV[VX] * (F32)(width - 1)), (U32)0, (U32)width - 1);
627 U32 t = llclamp((U32)(uvCoords.mV[VY] * (F32)(height - 1)), (U32)0, (U32)height - 1);
628
629 mWeights[index] = ((F32) maskTextureData[((t * width + s) * num_components) + (num_components - 1)]) / 255.f;
630
631 if (invert)
632 {
633 mWeights[index] = 1.f - mWeights[index];
634 }
635
636 // now apply step function
637 // mWeights[index] = mWeights[index] > 0.95f ? 1.f : 0.f;
638
639 if (clothing_weights)
640 {
641 clothing_weights[vertIndex].mV[VW] = mWeights[index];
642 }
643 }
644 mWeightsGenerated = TRUE;
645}
646
647//-----------------------------------------------------------------------------
648// getMaskForMorphIndex()
649//-----------------------------------------------------------------------------
650F32* LLPolyVertexMask::getMorphMaskWeights()
651{
652 if (!mWeightsGenerated)
653 {
654 return NULL;
655 }
656
657 return mWeights;
658}