//----------------------------------------------------------------------------- // setInfo() //----------------------------------------------------------------------------- BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) { llassert(mInfo == NULL); if (info->mID < 0) return FALSE; mInfo = info; mID = info->mID; setWeight(getDefaultWeight(), FALSE ); LLVOAvatar* avatarp = mMesh->getAvatar(); LLPolyMorphTargetInfo::volume_info_list_t::iterator iter; for (iter = getInfo()->mVolumeInfoList.begin(); iter != getInfo()->mVolumeInfoList.end(); iter++) { LLPolyVolumeMorphInfo *volume_info = &(*iter); for (S32 i = 0; i < avatarp->mNumCollisionVolumes; i++) { if (avatarp->mCollisionVolumes[i].getName() == volume_info->mName) { mVolumeMorphs.push_back(LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i], volume_info->mScale, volume_info->mPos)); break; } } } mMorphData = mMesh->getMorphData(getInfo()->mMorphName); if (!mMorphData) { llwarns << "No morph target named " << getInfo()->mMorphName << " found in mesh." << llendl; return FALSE; // Continue, ignoring this tag } return TRUE; }
//----------------------------------------------------------------------------- // apply() //----------------------------------------------------------------------------- void LLPolySkeletalDistortion::apply( ESex avatar_sex ) { F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); LLJoint* joint; joint_vec_map_t::iterator iter; for (iter = mJointScales.begin(); iter != mJointScales.end(); iter++) { joint = iter->first; LLVector3 newScale = joint->getScale(); LLVector3 scaleDelta = iter->second; newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta); joint->setScale(newScale); } for (iter = mJointOffsets.begin(); iter != mJointOffsets.end(); iter++) { joint = iter->first; LLVector3 newPosition = joint->getPosition(); LLVector3 positionDelta = iter->second; newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta); joint->setPosition(newPosition); } if (mLastWeight != mCurWeight && !mIsAnimating) { mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1); } mLastWeight = mCurWeight; }
BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) { llassert(mInfo == NULL); if (info->mID < 0) return FALSE; mInfo = info; mID = info->mID; setWeight(getDefaultWeight(), FALSE ); LLDriverParamInfo::entry_info_list_t::iterator iter; mDriven.reserve(getInfo()->mDrivenInfoList.size()); for (iter = getInfo()->mDrivenInfoList.begin(); iter != getInfo()->mDrivenInfoList.end(); iter++) { LLDrivenEntryInfo *driven_info = &(*iter); S32 driven_id = driven_info->mDrivenID; LLViewerVisualParam* param = (LLViewerVisualParam*)mAvatarp->getVisualParam( driven_id ); if (param) { mDriven.push_back(LLDrivenEntry( param, driven_info )); } else { llerrs << "<driven> Unable to resolve driven parameter: " << driven_id << llendl; mInfo = NULL; return FALSE; } } return TRUE; }
LLColor4 LLTexLayerParamColor::getNetColor() const { const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); llassert(info->mNumColors >= 1); F32 effective_weight = (mAvatar && (mAvatar->getSex() & getSex())) ? mCurWeight : getDefaultWeight(); S32 index_last = info->mNumColors - 1; F32 scaled_weight = effective_weight * index_last; S32 index_start = (S32) scaled_weight; S32 index_end = index_start + 1; if (index_start == index_last) { return info->mColors[index_last]; } else { F32 weight = scaled_weight - index_start; const LLColor4 *start = &info->mColors[ index_start ]; const LLColor4 *end = &info->mColors[ index_end ]; return LLColor4((1.f - weight) * start->mV[VX] + weight * end->mV[VX], (1.f - weight) * start->mV[VY] + weight * end->mV[VY], (1.f - weight) * start->mV[VZ] + weight * end->mV[VZ], (1.f - weight) * start->mV[VW] + weight * end->mV[VW]); } }
BOOL LLTexLayerParamAlpha::getSkip() const { if (!mTexLayer) { return TRUE; } const LLVOAvatar *avatar = mTexLayer->getTexLayerSet()->getAvatar(); if (((LLTexLayerParamAlphaInfo *)getInfo())->mSkipIfZeroWeight) { F32 effective_weight = (avatar->getSex() & getSex()) ? mCurWeight : getDefaultWeight(); if (is_approx_zero(effective_weight)) { return TRUE; } } LLWearableType::EType type = (LLWearableType::EType)getWearableType(); if ((type != LLWearableType::WT_INVALID) && !avatar->isWearingWearableType(type)) { return TRUE; } return FALSE; }
BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info) { llassert(mInfo == NULL); if (info->mID < 0) return FALSE; mInfo = info; mID = info->mID; setWeight(getDefaultWeight(), FALSE ); return TRUE; }
BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info) { llassert(mInfo == NULL); if (info->mID < 0) return FALSE; mInfo = info; mID = info->mID; // <FS:Ansariel> [Legacy Bake] //setWeight(getDefaultWeight()); setWeight(getDefaultWeight(), FALSE); return TRUE; }
BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) { llassert(mInfo == NULL); if (info->mID < 0) return FALSE; mInfo = info; mID = info->mID; setWeight(getDefaultWeight(), FALSE ); LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter; for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++) { LLPolySkeletalBoneInfo *bone_info = &(*iter); LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName); if (!joint) { LL_WARNS() << "Joint " << bone_info->mBoneName << " not found." << LL_ENDL; continue; } if (mJointScales.find(joint) != mJointScales.end()) { LL_WARNS() << "Scale deformation already supplied for joint " << joint->getName() << "." << LL_ENDL; } // store it mJointScales[joint] = bone_info->mScaleDeformation; // apply to children that need to inherit it for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); iter != joint->mChildren.end(); ++iter) { LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter); if (child_joint->inheritScale()) { LLVector3 childDeformation = LLVector3(child_joint->getScale()); childDeformation.scaleVec(bone_info->mScaleDeformation); mJointScales[child_joint] = childDeformation; } } if (bone_info->mHasPositionDeformation) { if (mJointOffsets.find(joint) != mJointOffsets.end()) { LL_WARNS() << "Offset deformation already supplied for joint " << joint->getName() << "." << LL_ENDL; } mJointOffsets[joint] = bone_info->mPositionDeformation; } } return TRUE; }
BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) { llassert(mInfo == NULL); if (info->mID < 0) return FALSE; mInfo = info; mID = info->mID; info->mDriverParam = this; setWeight(getDefaultWeight()); return TRUE; }
//----------------------------------------------------------------------------- // setInfo() //----------------------------------------------------------------------------- BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) { llassert(mInfo == NULL); if (info->mID < 0) return FALSE; mInfo = info; mID = info->mID; // <FS:Ansariel> [Legacy Bake] //setWeight(getDefaultWeight()); setWeight(getDefaultWeight(), FALSE); LLAvatarAppearance* avatarp = mMesh->getAvatar(); LLPolyMorphTargetInfo::volume_info_list_t::iterator iter; for (iter = getInfo()->mVolumeInfoList.begin(); iter != getInfo()->mVolumeInfoList.end(); iter++) { LLPolyVolumeMorphInfo *volume_info = &(*iter); for (S32 i = 0; i < avatarp->mNumCollisionVolumes; i++) { if (avatarp->mCollisionVolumes[i].getName() == volume_info->mName) { mVolumeMorphs.push_back(LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i], volume_info->mScale, volume_info->mPos)); break; } } } std::string morph_param_name = getInfo()->mMorphName; mMorphData = mMesh->getMorphData(morph_param_name); if (!mMorphData) { const std::string driven_tag = "_Driven"; U32 pos = morph_param_name.find(driven_tag); if (pos > 0) { morph_param_name = morph_param_name.substr(0,pos); mMorphData = mMesh->getMorphData(morph_param_name); } } if (!mMorphData) { LL_WARNS() << "No morph target named " << morph_param_name << " found in mesh." << LL_ENDL; return FALSE; // Continue, ignoring this tag } return TRUE; }
void LLPolySkeletalDistortion::apply( ESex avatar_sex ) { LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY); F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); LLJoint* joint; joint_vec_map_t::iterator iter; for (iter = mJointScales.begin(); iter != mJointScales.end(); iter++) { joint = iter->first; LLVector3 newScale = joint->getScale(); LLVector3 scaleDelta = iter->second; newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta); //An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached // needed? // joint->storeScaleForReset( newScale ); joint->setScale(newScale); } for (iter = mJointOffsets.begin(); iter != mJointOffsets.end(); iter++) { joint = iter->first; LLVector3 newPosition = joint->getPosition(); LLVector3 positionDelta = iter->second; newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta); joint->setPosition(newPosition); } if (mLastWeight != mCurWeight && !mIsAnimating) { mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1); } mLastWeight = mCurWeight; }
void LLPolyMorphTarget::apply( ESex avatar_sex ) { if (!mMorphData || mNumMorphMasksPending > 0) { return; } LL_RECORD_BLOCK_TIME(FTM_APPLY_MORPH_TARGET); mLastSex = avatar_sex; // Check for NaN condition (NaN is detected if a variable doesn't equal itself. if (mCurWeight != mCurWeight) { mCurWeight = 0.0; } if (mLastWeight != mLastWeight) { mLastWeight = mCurWeight+.001; } // perform differential update of morph F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight); // store last weight mLastWeight += delta_weight; if (delta_weight != 0.f) { llassert(!mMesh->isLOD()); LLVector4a *coords = mMesh->getWritableCoords(); LLVector4a *scaled_normals = mMesh->getScaledNormals(); LLVector4a *normals = mMesh->getWritableNormals(); LLVector4a *scaled_binormals = mMesh->getScaledBinormals(); LLVector4a *binormals = mMesh->getWritableBinormals(); LLVector4a *clothing_weights = mMesh->getWritableClothingWeights(); LLVector2 *tex_coords = mMesh->getWritableTexCoords(); F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL; for(U32 vert_index_morph = 0; vert_index_morph < mMorphData->mNumIndices; vert_index_morph++) { S32 vert_index_mesh = mMorphData->mVertexIndices[vert_index_morph]; F32 maskWeight = 1.f; if (maskWeightArray) { maskWeight = maskWeightArray[vert_index_morph]; } LLVector4a pos = mMorphData->mCoords[vert_index_morph]; pos.mul(delta_weight*maskWeight); coords[vert_index_mesh].add(pos); if (getInfo()->mIsClothingMorph && clothing_weights) { LLVector4a clothing_offset = mMorphData->mCoords[vert_index_morph]; clothing_offset.mul(delta_weight * maskWeight); LLVector4a* clothing_weight = &clothing_weights[vert_index_mesh]; clothing_weight->add(clothing_offset); clothing_weight->getF32ptr()[VW] = maskWeight; } // calculate new normals based on half angles LLVector4a norm = mMorphData->mNormals[vert_index_morph]; norm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR); scaled_normals[vert_index_mesh].add(norm); norm = scaled_normals[vert_index_mesh]; // guard against degenerate input data before we create NaNs below! // norm.normalize3fast(); normals[vert_index_mesh] = norm; // calculate new binormals LLVector4a binorm = mMorphData->mBinormals[vert_index_morph]; // guard against degenerate input data before we create NaNs below! // if (!binorm.isFinite3() || (binorm.dot3(binorm).getF32() <= F_APPROXIMATELY_ZERO)) { binorm.set(1,0,0,1); } binorm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR); scaled_binormals[vert_index_mesh].add(binorm); LLVector4a tangent; tangent.setCross3(scaled_binormals[vert_index_mesh], norm); LLVector4a& normalized_binormal = binormals[vert_index_mesh]; normalized_binormal.setCross3(norm, tangent); normalized_binormal.normalize3fast(); tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight; } // now apply volume changes for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ ) { LLPolyVolumeMorph* volume_morph = &(*iter); LLVector3 scale_delta = volume_morph->mScale * delta_weight; LLVector3 pos_delta = volume_morph->mPos * delta_weight; volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta); volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta); } } if (mNext) { mNext->apply(avatar_sex); } }
//----------------------------------------------------------------------------- // apply() //----------------------------------------------------------------------------- void LLPolyMorphTarget::apply( ESex avatar_sex ) { if (!mMorphData || mNumMorphMasksPending > 0) { return; } mLastSex = avatar_sex; // Check for NaN condition (NaN is detected if a variable doesn't equal itself. if (mCurWeight != mCurWeight) { mCurWeight = 0.0; } if (mLastWeight != mLastWeight) { mLastWeight = mCurWeight+.001; } // perform differential update of morph F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight); // store last weight mLastWeight += delta_weight; if (delta_weight != 0.f) { llassert(!mMesh->isLOD()); LLVector4 *coords = mMesh->getWritableCoords(); LLVector3 *scaled_normals = mMesh->getScaledNormals(); LLVector4 *normals = mMesh->getWritableNormals(); LLVector3 *scaled_binormals = mMesh->getScaledBinormals(); LLVector3 *binormals = mMesh->getWritableBinormals(); LLVector4 *clothing_weights = mMesh->getWritableClothingWeights(); LLVector2 *tex_coords = mMesh->getWritableTexCoords(); F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL; for(U32 vert_index_morph = 0; vert_index_morph < mMorphData->mNumIndices; vert_index_morph++) { S32 vert_index_mesh = mMorphData->mVertexIndices[vert_index_morph]; F32 maskWeight = 1.f; if (maskWeightArray) { maskWeight = maskWeightArray[vert_index_morph]; } coords[vert_index_mesh] += LLVector4(mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight); if (getInfo()->mIsClothingMorph && clothing_weights) { LLVector3 clothing_offset = mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight; LLVector4* clothing_weight = &clothing_weights[vert_index_mesh]; clothing_weight->mV[VX] += clothing_offset.mV[VX]; clothing_weight->mV[VY] += clothing_offset.mV[VY]; clothing_weight->mV[VZ] += clothing_offset.mV[VZ]; clothing_weight->mV[VW] = maskWeight; } // calculate new normals based on half angles scaled_normals[vert_index_mesh] += mMorphData->mNormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR; LLVector3 normalized_normal = scaled_normals[vert_index_mesh]; normalized_normal.normVec(); normals[vert_index_mesh] = LLVector4(normalized_normal); // calculate new binormals scaled_binormals[vert_index_mesh] += mMorphData->mBinormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR; LLVector3 tangent = scaled_binormals[vert_index_mesh] % normalized_normal; LLVector3 normalized_binormal = normalized_normal % tangent; normalized_binormal.normVec(); binormals[vert_index_mesh] = normalized_binormal; tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight; } // now apply volume changes for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ ) { LLPolyVolumeMorph* volume_morph = &(*iter); LLVector3 scale_delta = volume_morph->mScale * delta_weight; LLVector3 pos_delta = volume_morph->mPos * delta_weight; volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta); volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta); } } if (mNext) { mNext->apply(avatar_sex); } }
BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height) { BOOL success = TRUE; if (!mTexLayer) { return success; } F32 effective_weight = (mTexLayer->getTexLayerSet()->getAvatar()->getSex() & getSex()) ? mCurWeight : getDefaultWeight(); BOOL weight_changed = effective_weight != mCachedEffectiveWeight; if (getSkip()) { return success; } LLTexLayerParamAlphaInfo *info = (LLTexLayerParamAlphaInfo *)getInfo(); gGL.flush(); if (info->mMultiplyBlend) { gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO); // Multiplication: approximates a min() function } else { gGL.setSceneBlendType(LLRender::BT_ADD); // Addition: approximates a max() function } if (!info->mStaticImageFileName.empty() && !mStaticImageInvalid) { if (mStaticImageTGA.isNull()) { // Don't load the image file until we actually need it the first time. Like now. mStaticImageTGA = LLTexLayerStaticImageList::getInstance()->getImageTGA(info->mStaticImageFileName); // We now have something in one of our caches LLTexLayerSet::sHasCaches |= mStaticImageTGA.notNull() ? TRUE : FALSE; if (mStaticImageTGA.isNull()) { llwarns << "Unable to load static file: " << info->mStaticImageFileName << llendl; mStaticImageInvalid = TRUE; // don't try again. return FALSE; } } const S32 image_tga_width = mStaticImageTGA->getWidth(); const S32 image_tga_height = mStaticImageTGA->getHeight(); if (!mCachedProcessedTexture || (mCachedProcessedTexture->getWidth() != image_tga_width) || (mCachedProcessedTexture->getHeight() != image_tga_height) || (weight_changed)) { // llinfos << "Building Cached Alpha: " << mName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << effective_weight << llendl; mCachedEffectiveWeight = effective_weight; if (!mCachedProcessedTexture) { mCachedProcessedTexture = LLViewerTextureManager::getLocalTexture(image_tga_width, image_tga_height, 1, FALSE); // We now have something in one of our caches LLTexLayerSet::sHasCaches |= mCachedProcessedTexture ? TRUE : FALSE; mCachedProcessedTexture->setExplicitFormat(GL_ALPHA8, GL_ALPHA); } // Applies domain and effective weight to data as it is decoded. Also resizes the raw image if needed. mStaticImageRaw = NULL; mStaticImageRaw = new LLImageRaw; mStaticImageTGA->decodeAndProcess(mStaticImageRaw, info->mDomain, effective_weight); mNeedsCreateTexture = TRUE; } if (mCachedProcessedTexture) { { // Create the GL texture, and then hang onto it for future use. if (mNeedsCreateTexture) { mCachedProcessedTexture->createGLTexture(0, mStaticImageRaw); mNeedsCreateTexture = FALSE; gGL.getTexUnit(0)->bind(mCachedProcessedTexture); mCachedProcessedTexture->setAddressMode(LLTexUnit::TAM_CLAMP); } LLGLSNoAlphaTest gls_no_alpha_test; gGL.getTexUnit(0)->bind(mCachedProcessedTexture); gl_rect_2d_simple_tex(width, height); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); stop_glerror(); } } // Don't keep the cache for other people's avatars // (It's not really a "cache" in that case, but the logic is the same) if (!mAvatar->isSelf()) { mCachedProcessedTexture = NULL; } } else { LLGLDisable no_alpha(GL_ALPHA_TEST); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f(0.f, 0.f, 0.f, effective_weight); gl_rect_2d_simple(width, height); } return success; }