lldriverparam.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "lldriverparam.h"
00035 
00036 #include "llfasttimer.h"
00037 
00038 //-----------------------------------------------------------------------------
00039 // LLDriverParamInfo
00040 //-----------------------------------------------------------------------------
00041 
00042 LLDriverParamInfo::LLDriverParamInfo()
00043 {
00044 }
00045 
00046 BOOL LLDriverParamInfo::parseXml(LLXmlTreeNode* node)
00047 {
00048         llassert( node->hasName( "param" ) && node->getChildByName( "param_driver" ) );
00049 
00050         if( !LLViewerVisualParamInfo::parseXml( node ))
00051                 return FALSE;
00052 
00053         LLXmlTreeNode* param_driver_node = node->getChildByName( "param_driver" );
00054         if( !param_driver_node )
00055                 return FALSE;
00056 
00057         for (LLXmlTreeNode* child = param_driver_node->getChildByName( "driven" );
00058                  child;
00059                  child = param_driver_node->getNextNamedChild())
00060         {
00061                 S32 driven_id;
00062                 static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
00063                 if( child->getFastAttributeS32( id_string, driven_id ) )
00064                 {
00065                         F32 min1 = mMinWeight;
00066                         F32 max1 = mMaxWeight;
00067                         F32 max2 = max1;
00068                         F32 min2 = max1;
00069 
00070                         //      driven    ________                                                      //
00071                         //      ^        /|       |\                                            //
00072                         //      |       / |       | \                                           //
00073                         //      |      /  |       |  \                                          //
00074                         //      |     /   |       |   \                                         //
00075                         //      |    /    |       |    \                                        //
00076                         //-------|----|-------|----|-------> driver             //
00077                         //  | min1   max1    max2  min2
00078 
00079                         static LLStdStringHandle min1_string = LLXmlTree::addAttributeString("min1");
00080                         child->getFastAttributeF32( min1_string, min1 ); // optional
00081                         static LLStdStringHandle max1_string = LLXmlTree::addAttributeString("max1");
00082                         child->getFastAttributeF32( max1_string, max1 ); // optional
00083                         static LLStdStringHandle max2_string = LLXmlTree::addAttributeString("max2");
00084                         child->getFastAttributeF32( max2_string, max2 ); // optional
00085                         static LLStdStringHandle min2_string = LLXmlTree::addAttributeString("min2");
00086                         child->getFastAttributeF32( min2_string, min2 ); // optional
00087 
00088                         // Push these on the front of the deque, so that we can construct
00089                         // them in order later (faster)
00090                         mDrivenInfoList.push_front( LLDrivenEntryInfo( driven_id, min1, max1, max2, min2 ) );
00091                 }
00092                 else
00093                 {
00094                         llerrs << "<driven> Unable to resolve driven parameter: " << driven_id << llendl;
00095                         return FALSE;
00096                 }
00097         }
00098         return TRUE;
00099 }
00100 
00101 //-----------------------------------------------------------------------------
00102 // LLDriverParam
00103 //-----------------------------------------------------------------------------
00104 
00105 LLDriverParam::LLDriverParam(LLVOAvatar *avatarp)
00106         : mCurrentDistortionParam( NULL ), mAvatarp(avatarp)
00107 {
00108 }
00109 
00110 LLDriverParam::~LLDriverParam()
00111 {
00112 }
00113 
00114 BOOL LLDriverParam::setInfo(LLDriverParamInfo *info)
00115 {
00116         llassert(mInfo == NULL);
00117         if (info->mID < 0)
00118                 return FALSE;
00119         mInfo = info;
00120         mID = info->mID;
00121 
00122         setWeight(getDefaultWeight(), FALSE );
00123         
00124         LLDriverParamInfo::entry_info_list_t::iterator iter;
00125         mDriven.reserve(getInfo()->mDrivenInfoList.size());
00126         for (iter = getInfo()->mDrivenInfoList.begin(); iter != getInfo()->mDrivenInfoList.end(); iter++)
00127         {
00128                 LLDrivenEntryInfo *driven_info = &(*iter);
00129                 S32 driven_id = driven_info->mDrivenID;
00130                 LLViewerVisualParam* param = (LLViewerVisualParam*)mAvatarp->getVisualParam( driven_id );
00131                 if (param)
00132                 {
00133                         mDriven.push_back(LLDrivenEntry( param, driven_info ));
00134                 }
00135                 else
00136                 {
00137                         llerrs << "<driven> Unable to resolve driven parameter: " << driven_id << llendl;
00138                         mInfo = NULL;
00139                         return FALSE;
00140                 }
00141         }
00142         
00143         return TRUE;
00144 }
00145 
00146 #if 0 // obsolete
00147 BOOL LLDriverParam::parseData(LLXmlTreeNode* node)
00148 {
00149         LLDriverParamInfo* info = new LLDriverParamInfo;
00150 
00151         info->parseXml(node);
00152         if (!setInfo(info))
00153         {
00154                 delete info;
00155                 return FALSE;
00156         }
00157         return TRUE;
00158 }
00159 #endif
00160 
00161 void LLDriverParam::setWeight(F32 weight, BOOL set_by_user)
00162 {
00163         F32 min_weight = getMinWeight();
00164         F32 max_weight = getMaxWeight();
00165         if (mIsAnimating)
00166         {
00167                 // allow overshoot when animating
00168                 mCurWeight = weight;
00169         }
00170         else
00171         {
00172                 mCurWeight = llclamp(weight, min_weight, max_weight);
00173         }
00174 
00175         //      driven    ________
00176         //      ^        /|       |\       ^
00177         //      |       / |       | \      |
00178         //      |      /  |       |  \     |
00179         //      |     /   |       |   \    |
00180         //      |    /    |       |    \   |
00181         //-------|----|-------|----|-------> driver
00182         //  | min1   max1    max2  min2
00183 
00184         for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
00185         {
00186                 LLDrivenEntry* driven = &(*iter);
00187                 LLDrivenEntryInfo* info = driven->mInfo;
00188                 
00189                 F32 driven_weight = 0.f;
00190                 F32 driven_min = driven->mParam->getMinWeight();
00191                 F32 driven_max = driven->mParam->getMaxWeight();
00192 
00193                 if (mIsAnimating)
00194                 {
00195                         // driven param doesn't interpolate (textures, for example)
00196                         if (!driven->mParam->getAnimating())
00197                         {
00198                                 continue;
00199                         }
00200                         if( mCurWeight < info->mMin1 )
00201                         {
00202                                 if (info->mMin1 == min_weight)
00203                                 {
00204                                         if (info->mMin1 == info->mMax1)
00205                                         {
00206                                                 driven_weight = driven_max;
00207                                         }
00208                                         else
00209                                         {
00210                                                 //up slope extrapolation
00211                                                 F32 t = (mCurWeight - info->mMin1) / (info->mMax1 - info->mMin1 );
00212                                                 driven_weight = driven_min + t * (driven_max - driven_min);
00213                                         }
00214                                 }
00215                                 else
00216                                 {
00217                                         driven_weight = driven_min;
00218                                 }
00219 
00220                                 driven->mParam->setWeight( driven_weight, set_by_user );
00221                                 continue;
00222                         }
00223                         else 
00224                         if ( mCurWeight > info->mMin2 )
00225                         {
00226                                 if (info->mMin2 == max_weight)
00227                                 {
00228                                         if (info->mMin2 == info->mMax2)
00229                                         {
00230                                                 driven_weight = driven_max;
00231                                         }
00232                                         else
00233                                         {
00234                                                 //down slope extrapolation                                      
00235                                                 F32 t = (mCurWeight - info->mMax2) / (info->mMin2 - info->mMax2 );
00236                                                 driven_weight = driven_max + t * (driven_min - driven_max);
00237                                         }
00238                                 }
00239                                 else
00240                                 {
00241                                         driven_weight = driven_min;
00242                                 }
00243 
00244                                 driven->mParam->setWeight( driven_weight, set_by_user );
00245                                 continue;
00246                         }
00247                 }
00248 
00249                 driven_weight = getDrivenWeight(driven, mCurWeight);
00250                 driven->mParam->setWeight( driven_weight, set_by_user );
00251         }
00252 }
00253 
00254 F32     LLDriverParam::getTotalDistortion()
00255 {
00256         F32 sum = 0.f;
00257         for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
00258         {
00259                 LLDrivenEntry* driven = &(*iter);
00260                 sum += driven->mParam->getTotalDistortion();
00261         }
00262 
00263         return sum; 
00264 }
00265 
00266 const LLVector3 &LLDriverParam::getAvgDistortion()      
00267 {
00268         // It's not actually correct to take the average of averages, but it good enough here.
00269         LLVector3 sum;
00270         S32 count = 0;
00271         for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
00272         {
00273                 LLDrivenEntry* driven = &(*iter);
00274                 sum += driven->mParam->getAvgDistortion();
00275                 count++;
00276         }
00277         sum /= (F32)count;
00278 
00279         mDefaultVec = sum;
00280         return mDefaultVec; 
00281 }
00282 
00283 F32     LLDriverParam::getMaxDistortion() 
00284 {
00285         F32 max = 0.f;
00286         for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
00287         {
00288                 LLDrivenEntry* driven = &(*iter);
00289                 F32 param_max = driven->mParam->getMaxDistortion();
00290                 if( param_max > max )
00291                 {
00292                         max = param_max;
00293                 }
00294         }
00295 
00296         return max; 
00297 }
00298 
00299 
00300 LLVector3       LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)
00301 {
00302         LLVector3 sum;
00303         for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
00304         {
00305                 LLDrivenEntry* driven = &(*iter);
00306                 sum += driven->mParam->getVertexDistortion( index, poly_mesh );
00307         }
00308         return sum;
00309 }
00310 
00311 const LLVector3*        LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
00312 {
00313         mCurrentDistortionParam = NULL;
00314         const LLVector3* v = NULL;
00315         for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
00316         {
00317                 LLDrivenEntry* driven = &(*iter);
00318                 v = driven->mParam->getFirstDistortion( index, poly_mesh );
00319                 if( v )
00320                 {
00321                         mCurrentDistortionParam = driven->mParam;
00322                         break;
00323                 }
00324         }
00325 
00326         return v;
00327 };
00328 
00329 const LLVector3*        LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
00330 {
00331         llassert( mCurrentDistortionParam );
00332         if( !mCurrentDistortionParam )
00333         {
00334                 return NULL;
00335         }
00336 
00337         LLDrivenEntry* driven = NULL;
00338         entry_list_t::iterator iter;
00339         
00340         // Set mDriven iteration to the right point
00341         for( iter = mDriven.begin(); iter != mDriven.end(); iter++ )
00342         {
00343                 driven = &(*iter);
00344                 if( driven->mParam == mCurrentDistortionParam )
00345                 {
00346                         break;
00347                 }
00348         }
00349 
00350         // We're already in the middle of a param's distortions, so get the next one.
00351         const LLVector3* v = driven->mParam->getNextDistortion( index, poly_mesh );
00352         if( (!v) && (iter != mDriven.end()) )
00353         {
00354                 // This param is finished, so start the next param.  It might not have any
00355                 // distortions, though, so we have to loop to find the next param that does.
00356                 for( iter++; iter != mDriven.end(); iter++ )
00357                 {
00358                         driven = &(*iter);
00359                         v = driven->mParam->getFirstDistortion( index, poly_mesh );
00360                         if( v )
00361                         {
00362                                 mCurrentDistortionParam = driven->mParam;
00363                                 break;
00364                         }
00365                 }
00366         }
00367 
00368         return v;
00369 };
00370 
00371 //-----------------------------------------------------------------------------
00372 // setAnimationTarget()
00373 //-----------------------------------------------------------------------------
00374 void LLDriverParam::setAnimationTarget( F32 target_value, BOOL set_by_user )
00375 {
00376         LLVisualParam::setAnimationTarget(target_value, set_by_user);
00377 
00378         for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
00379         {
00380                 LLDrivenEntry* driven = &(*iter);
00381                 F32 driven_weight = getDrivenWeight(driven, mTargetWeight);
00382 
00383                 // this isn't normally necessary, as driver params handle interpolation of their driven params
00384                 // but texture params need to know to assume their final value at beginning of interpolation
00385                 driven->mParam->setAnimationTarget(driven_weight, set_by_user);
00386         }
00387 }
00388 
00389 //-----------------------------------------------------------------------------
00390 // stopAnimating()
00391 //-----------------------------------------------------------------------------
00392 void LLDriverParam::stopAnimating(BOOL set_by_user)
00393 {
00394         LLVisualParam::stopAnimating(set_by_user);
00395 
00396         for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
00397         {
00398                 LLDrivenEntry* driven = &(*iter);
00399                 driven->mParam->setAnimating(FALSE);
00400         }
00401 }
00402 
00403 //-----------------------------------------------------------------------------
00404 // getDrivenWeight()
00405 //-----------------------------------------------------------------------------
00406 F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight)
00407 {
00408         F32 min_weight = getMinWeight();
00409         F32 max_weight = getMaxWeight();
00410         const LLDrivenEntryInfo* info = driven->mInfo;
00411 
00412         F32 driven_weight = 0.f;
00413         F32 driven_min = driven->mParam->getMinWeight();
00414         F32 driven_max = driven->mParam->getMaxWeight();
00415 
00416         if( input_weight <= info->mMin1 )
00417         {
00418                 if( info->mMin1 == info->mMax1 && 
00419                         info->mMin1 <= min_weight)
00420                 {
00421                         driven_weight = driven_max;
00422                 }
00423                 else
00424                 {
00425                         driven_weight = driven_min;
00426                 }
00427         }
00428         else
00429         if( input_weight <= info->mMax1 )
00430         {
00431                 F32 t = (input_weight - info->mMin1) / (info->mMax1 - info->mMin1 );
00432                 driven_weight = driven_min + t * (driven_max - driven_min);
00433         }
00434         else
00435         if( input_weight <= info->mMax2 )
00436         {
00437                 driven_weight = driven_max;
00438         }
00439         else
00440         if( input_weight <= info->mMin2 )
00441         {
00442                 F32 t = (input_weight - info->mMax2) / (info->mMin2 - info->mMax2 );
00443                 driven_weight = driven_max + t * (driven_min - driven_max);
00444         }
00445         else
00446         {
00447                 if (info->mMax2 >= max_weight)
00448                 {
00449                         driven_weight = driven_max;
00450                 }
00451                 else
00452                 {
00453                         driven_weight = driven_min;
00454                 }
00455         }
00456 
00457         return driven_weight;
00458 }

Generated on Thu Jul 1 06:08:27 2010 for Second Life Viewer by  doxygen 1.4.7