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/newview/llpolymorph.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/newview/llpolymorph.cpp')
-rw-r--r-- | linden/indra/newview/llpolymorph.cpp | 658 |
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 | |||
41 | const F32 NORMAL_SOFTEN_FACTOR = 0.65f; | ||
42 | |||
43 | LLLinkedList<LLPolyMorphData> gLoadedMorphs; | ||
44 | |||
45 | //----------------------------------------------------------------------------- | ||
46 | // LLPolyMorphData() | ||
47 | //----------------------------------------------------------------------------- | ||
48 | LLPolyMorphData::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 | //----------------------------------------------------------------------------- | ||
72 | LLPolyMorphData::~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 | //----------------------------------------------------------------------------- | ||
85 | BOOL 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 | //----------------------------------------------------------------------------- | ||
191 | LLPolyMorphTargetInfo::LLPolyMorphTargetInfo() | ||
192 | : mIsClothingMorph(FALSE) | ||
193 | { | ||
194 | } | ||
195 | |||
196 | BOOL 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 | //----------------------------------------------------------------------------- | ||
245 | LLPolyMorphTarget::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 | //----------------------------------------------------------------------------- | ||
256 | LLPolyMorphTarget::~LLPolyMorphTarget() | ||
257 | { | ||
258 | delete mVertMask; | ||
259 | } | ||
260 | |||
261 | //----------------------------------------------------------------------------- | ||
262 | // setInfo() | ||
263 | //----------------------------------------------------------------------------- | ||
264 | BOOL 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 | //----------------------------------------------------------------------------- | ||
304 | BOOL 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 | //----------------------------------------------------------------------------- | ||
321 | LLVector3 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 | //----------------------------------------------------------------------------- | ||
339 | const 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 | //----------------------------------------------------------------------------- | ||
365 | const 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 | //----------------------------------------------------------------------------- | ||
390 | F32 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 | //----------------------------------------------------------------------------- | ||
405 | const 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 | //----------------------------------------------------------------------------- | ||
420 | F32 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 | //----------------------------------------------------------------------------- | ||
435 | void 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 | //----------------------------------------------------------------------------- | ||
523 | void 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 | //----------------------------------------------------------------------------- | ||
579 | LLPolyVertexMask::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 | //----------------------------------------------------------------------------- | ||
589 | LLPolyVertexMask::~LLPolyVertexMask() | ||
590 | { | ||
591 | delete[] mWeights; | ||
592 | } | ||
593 | |||
594 | //----------------------------------------------------------------------------- | ||
595 | // generateMask() | ||
596 | //----------------------------------------------------------------------------- | ||
597 | void 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 | //----------------------------------------------------------------------------- | ||
650 | F32* LLPolyVertexMask::getMorphMaskWeights() | ||
651 | { | ||
652 | if (!mWeightsGenerated) | ||
653 | { | ||
654 | return NULL; | ||
655 | } | ||
656 | |||
657 | return mWeights; | ||
658 | } | ||