PageRenderTime 67ms CodeModel.GetById 24ms app.highlight 37ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/lldriverparam.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 634 lines | 484 code | 72 blank | 78 comment | 95 complexity | 9ecd7b9ea2bdd59af92f178d502851d1 MD5 | raw file
  1/** 
  2 * @file lldriverparam.cpp
  3 * @brief A visual parameter that drives (controls) other visual parameters.
  4 *
  5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "llviewerprecompiledheaders.h"
 28
 29#include "lldriverparam.h"
 30
 31#include "llfasttimer.h"
 32#include "llvoavatar.h"
 33#include "llvoavatarself.h"
 34#include "llagent.h"
 35#include "llwearable.h"
 36#include "llagentwearables.h"
 37
 38//-----------------------------------------------------------------------------
 39// LLDriverParamInfo
 40//-----------------------------------------------------------------------------
 41
 42LLDriverParamInfo::LLDriverParamInfo()
 43{
 44}
 45
 46BOOL LLDriverParamInfo::parseXml(LLXmlTreeNode* node)
 47{
 48	llassert( node->hasName( "param" ) && node->getChildByName( "param_driver" ) );
 49
 50	if( !LLViewerVisualParamInfo::parseXml( node ))
 51		return FALSE;
 52
 53	LLXmlTreeNode* param_driver_node = node->getChildByName( "param_driver" );
 54	if( !param_driver_node )
 55		return FALSE;
 56
 57	for (LLXmlTreeNode* child = param_driver_node->getChildByName( "driven" );
 58		 child;
 59		 child = param_driver_node->getNextNamedChild())
 60	{
 61		S32 driven_id;
 62		static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
 63		if( child->getFastAttributeS32( id_string, driven_id ) )
 64		{
 65			F32 min1 = mMinWeight;
 66			F32 max1 = mMaxWeight;
 67			F32 max2 = max1;
 68			F32 min2 = max1;
 69
 70			//	driven    ________							//
 71			//	^        /|       |\						//
 72			//	|       / |       | \						//
 73			//	|      /  |       |  \						//
 74			//	|     /   |       |   \						//
 75			//	|    /    |       |    \					//
 76			//-------|----|-------|----|-------> driver		//
 77			//  | min1   max1    max2  min2
 78
 79			static LLStdStringHandle min1_string = LLXmlTree::addAttributeString("min1");
 80			child->getFastAttributeF32( min1_string, min1 ); // optional
 81			static LLStdStringHandle max1_string = LLXmlTree::addAttributeString("max1");
 82			child->getFastAttributeF32( max1_string, max1 ); // optional
 83			static LLStdStringHandle max2_string = LLXmlTree::addAttributeString("max2");
 84			child->getFastAttributeF32( max2_string, max2 ); // optional
 85			static LLStdStringHandle min2_string = LLXmlTree::addAttributeString("min2");
 86			child->getFastAttributeF32( min2_string, min2 ); // optional
 87
 88			// Push these on the front of the deque, so that we can construct
 89			// them in order later (faster)
 90			mDrivenInfoList.push_front( LLDrivenEntryInfo( driven_id, min1, max1, max2, min2 ) );
 91		}
 92		else
 93		{
 94			llerrs << "<driven> Unable to resolve driven parameter: " << driven_id << llendl;
 95			return FALSE;
 96		}
 97	}
 98	return TRUE;
 99}
100
101//virtual 
102void LLDriverParamInfo::toStream(std::ostream &out)
103{
104	LLViewerVisualParamInfo::toStream(out);
105	out << "driver" << "\t";
106	out << mDrivenInfoList.size() << "\t";
107	for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++)
108	{
109		LLDrivenEntryInfo driven = *iter;
110		out << driven.mDrivenID << "\t";
111	}
112
113	out << std::endl;
114
115	if(isAgentAvatarValid())
116	{
117		for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++)
118		{
119			LLDrivenEntryInfo driven = *iter;
120			LLViewerVisualParam *param = (LLViewerVisualParam*)gAgentAvatarp->getVisualParam(driven.mDrivenID);
121			if (param)
122			{
123				param->getInfo()->toStream(out);
124				if (param->getWearableType() != mWearableType)
125				{
126					if(param->getCrossWearable())
127					{
128						out << "cross-wearable" << "\t";
129					}
130					else
131					{
132						out << "ERROR!" << "\t";
133					}
134				}
135				else
136				{
137					out << "valid" << "\t";
138				}
139			}
140			else
141			{
142				llwarns << "could not get parameter " << driven.mDrivenID << " from avatar " << gAgentAvatarp << " for driver parameter " << getID() << llendl;
143			}
144			out << std::endl;
145		}
146	}
147}
148
149//-----------------------------------------------------------------------------
150// LLDriverParam
151//-----------------------------------------------------------------------------
152
153LLDriverParam::LLDriverParam(LLVOAvatar *avatarp) : 
154	mCurrentDistortionParam( NULL ), 
155	mAvatarp(avatarp), 
156	mWearablep(NULL)
157{
158}
159
160LLDriverParam::LLDriverParam(LLWearable *wearablep) : 
161	mCurrentDistortionParam( NULL ), 
162	mAvatarp(NULL), 
163	mWearablep(wearablep)
164{
165}
166
167LLDriverParam::~LLDriverParam()
168{
169}
170
171BOOL LLDriverParam::setInfo(LLDriverParamInfo *info)
172{
173	llassert(mInfo == NULL);
174	if (info->mID < 0)
175		return FALSE;
176	mInfo = info;
177	mID = info->mID;
178
179	setWeight(getDefaultWeight(), FALSE );
180
181	return TRUE;
182}
183
184void LLDriverParam::setWearable(LLWearable *wearablep)
185{
186	if (wearablep)
187	{
188		mWearablep = wearablep;
189		mAvatarp = NULL;
190	}
191}
192
193void LLDriverParam::setAvatar(LLVOAvatar *avatarp)
194{
195	if (avatarp)
196	{
197		mWearablep = NULL;
198		mAvatarp = avatarp;
199	}
200}
201
202/*virtual*/ LLViewerVisualParam* LLDriverParam::cloneParam(LLWearable* wearable) const
203{
204	LLDriverParam *new_param;
205	if (wearable)
206	{
207		new_param = new LLDriverParam(wearable);
208	}
209	else
210	{
211		if (mWearablep)
212		{
213			new_param = new LLDriverParam(mWearablep);
214		}
215		else
216		{
217			new_param = new LLDriverParam(mAvatarp);
218		}
219	}
220	*new_param = *this;
221	return new_param;
222}
223
224#if 0 // obsolete
225BOOL LLDriverParam::parseData(LLXmlTreeNode* node)
226{
227	LLDriverParamInfo* info = new LLDriverParamInfo;
228
229	info->parseXml(node);
230	if (!setInfo(info))
231	{
232		delete info;
233		return FALSE;
234	}
235	return TRUE;
236}
237#endif
238
239void LLDriverParam::setWeight(F32 weight, BOOL upload_bake)
240{
241	F32 min_weight = getMinWeight();
242	F32 max_weight = getMaxWeight();
243	if (mIsAnimating)
244	{
245		// allow overshoot when animating
246		mCurWeight = weight;
247	}
248	else
249	{
250		mCurWeight = llclamp(weight, min_weight, max_weight);
251	}
252
253	//	driven    ________
254	//	^        /|       |\       ^
255	//	|       / |       | \      |
256	//	|      /  |       |  \     |
257	//	|     /   |       |   \    |
258	//	|    /    |       |    \   |
259	//-------|----|-------|----|-------> driver
260	//  | min1   max1    max2  min2
261
262	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
263	{
264		LLDrivenEntry* driven = &(*iter);
265		LLDrivenEntryInfo* info = driven->mInfo;
266		
267		F32 driven_weight = 0.f;
268		F32 driven_min = driven->mParam->getMinWeight();
269		F32 driven_max = driven->mParam->getMaxWeight();
270
271		if (mIsAnimating)
272		{
273			// driven param doesn't interpolate (textures, for example)
274			if (!driven->mParam->getAnimating())
275			{
276				continue;
277			}
278			if( mCurWeight < info->mMin1 )
279			{
280				if (info->mMin1 == min_weight)
281				{
282					if (info->mMin1 == info->mMax1)
283					{
284						driven_weight = driven_max;
285					}
286					else
287					{
288						//up slope extrapolation
289						F32 t = (mCurWeight - info->mMin1) / (info->mMax1 - info->mMin1 );
290						driven_weight = driven_min + t * (driven_max - driven_min);
291					}
292				}
293				else
294				{
295					driven_weight = driven_min;
296				}
297				
298				setDrivenWeight(driven,driven_weight,upload_bake);
299				continue;
300			}
301			else 
302			if ( mCurWeight > info->mMin2 )
303			{
304				if (info->mMin2 == max_weight)
305				{
306					if (info->mMin2 == info->mMax2)
307					{
308						driven_weight = driven_max;
309					}
310					else
311					{
312						//down slope extrapolation					
313						F32 t = (mCurWeight - info->mMax2) / (info->mMin2 - info->mMax2 );
314						driven_weight = driven_max + t * (driven_min - driven_max);
315					}
316				}
317				else
318				{
319					driven_weight = driven_min;
320				}
321
322				setDrivenWeight(driven,driven_weight,upload_bake);
323				continue;
324			}
325		}
326
327		driven_weight = getDrivenWeight(driven, mCurWeight);
328		setDrivenWeight(driven,driven_weight,upload_bake);
329	}
330}
331
332F32	LLDriverParam::getTotalDistortion()
333{
334	F32 sum = 0.f;
335	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
336	{
337		LLDrivenEntry* driven = &(*iter);
338		sum += driven->mParam->getTotalDistortion();
339	}
340
341	return sum; 
342}
343
344const LLVector3	&LLDriverParam::getAvgDistortion()	
345{
346	// It's not actually correct to take the average of averages, but it good enough here.
347	LLVector3 sum;
348	S32 count = 0;
349	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
350	{
351		LLDrivenEntry* driven = &(*iter);
352		sum += driven->mParam->getAvgDistortion();
353		count++;
354	}
355	sum /= (F32)count;
356
357	mDefaultVec = sum;
358	return mDefaultVec; 
359}
360
361F32	LLDriverParam::getMaxDistortion() 
362{
363	F32 max = 0.f;
364	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
365	{
366		LLDrivenEntry* driven = &(*iter);
367		F32 param_max = driven->mParam->getMaxDistortion();
368		if( param_max > max )
369		{
370			max = param_max;
371		}
372	}
373
374	return max; 
375}
376
377
378LLVector3	LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)
379{
380	LLVector3 sum;
381	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
382	{
383		LLDrivenEntry* driven = &(*iter);
384		sum += driven->mParam->getVertexDistortion( index, poly_mesh );
385	}
386	return sum;
387}
388
389const LLVector3*	LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
390{
391	mCurrentDistortionParam = NULL;
392	const LLVector3* v = NULL;
393	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
394	{
395		LLDrivenEntry* driven = &(*iter);
396		v = driven->mParam->getFirstDistortion( index, poly_mesh );
397		if( v )
398		{
399			mCurrentDistortionParam = driven->mParam;
400			break;
401		}
402	}
403
404	return v;
405};
406
407const LLVector3*	LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
408{
409	llassert( mCurrentDistortionParam );
410	if( !mCurrentDistortionParam )
411	{
412		return NULL;
413	}
414
415	LLDrivenEntry* driven = NULL;
416	entry_list_t::iterator iter;
417	
418	// Set mDriven iteration to the right point
419	for( iter = mDriven.begin(); iter != mDriven.end(); iter++ )
420	{
421		driven = &(*iter);
422		if( driven->mParam == mCurrentDistortionParam )
423		{
424			break;
425		}
426	}
427
428	llassert(driven);
429	if (!driven)
430	{
431		return NULL; // shouldn't happen, but...
432	}
433
434	// We're already in the middle of a param's distortions, so get the next one.
435	const LLVector3* v = driven->mParam->getNextDistortion( index, poly_mesh );
436	if( (!v) && (iter != mDriven.end()) )
437	{
438		// This param is finished, so start the next param.  It might not have any
439		// distortions, though, so we have to loop to find the next param that does.
440		for( iter++; iter != mDriven.end(); iter++ )
441		{
442			driven = &(*iter);
443			v = driven->mParam->getFirstDistortion( index, poly_mesh );
444			if( v )
445			{
446				mCurrentDistortionParam = driven->mParam;
447				break;
448			}
449		}
450	}
451
452	return v;
453};
454
455//-----------------------------------------------------------------------------
456// setAnimationTarget()
457//-----------------------------------------------------------------------------
458void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake )
459{
460	LLVisualParam::setAnimationTarget(target_value, upload_bake);
461
462	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
463	{
464		LLDrivenEntry* driven = &(*iter);
465		F32 driven_weight = getDrivenWeight(driven, mTargetWeight);
466
467		// this isn't normally necessary, as driver params handle interpolation of their driven params
468		// but texture params need to know to assume their final value at beginning of interpolation
469		driven->mParam->setAnimationTarget(driven_weight, upload_bake);
470	}
471}
472
473//-----------------------------------------------------------------------------
474// stopAnimating()
475//-----------------------------------------------------------------------------
476void LLDriverParam::stopAnimating(BOOL upload_bake)
477{
478	LLVisualParam::stopAnimating(upload_bake);
479
480	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
481	{
482		LLDrivenEntry* driven = &(*iter);
483		driven->mParam->setAnimating(FALSE);
484	}
485}
486
487/*virtual*/ 
488BOOL LLDriverParam::linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params)
489{
490	BOOL success = TRUE;
491	LLDriverParamInfo::entry_info_list_t::iterator iter;
492	for (iter = getInfo()->mDrivenInfoList.begin(); iter != getInfo()->mDrivenInfoList.end(); ++iter)
493	{
494		LLDrivenEntryInfo *driven_info = &(*iter);
495		S32 driven_id = driven_info->mDrivenID;
496
497		// check for already existing links. Do not overwrite.
498		BOOL found = FALSE;
499		for (entry_list_t::iterator driven_iter = mDriven.begin(); driven_iter != mDriven.end() && !found; ++driven_iter)
500		{
501			if (driven_iter->mInfo->mDrivenID == driven_id)
502			{
503				found = TRUE;
504			}
505		}
506
507		if (!found)
508		{
509			LLViewerVisualParam* param = (LLViewerVisualParam*)mapper(driven_id);
510			bool push = param && (!only_cross_params || param->getCrossWearable());
511			if (push)
512			{
513				mDriven.push_back(LLDrivenEntry( param, driven_info ));
514			}
515			else
516			{
517				success = FALSE;
518			}
519		}
520	}
521	
522	return success;	
523}
524
525void LLDriverParam::resetDrivenParams()
526{
527	mDriven.clear();
528	mDriven.reserve(getInfo()->mDrivenInfoList.size());
529}
530
531void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type)
532{
533	bool needs_update = (getWearableType()==driven_type);
534
535	// if the driver has a driven entry for the passed-in wearable type, we need to refresh the value
536	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
537	{
538		LLDrivenEntry* driven = &(*iter);
539		if (driven && driven->mParam && driven->mParam->getCrossWearable() && driven->mParam->getWearableType() == driven_type)
540		{
541			needs_update = true;
542		}
543	}
544
545
546	if (needs_update)
547	{
548		LLWearableType::EType driver_type = (LLWearableType::EType)getWearableType();
549		
550		// If we've gotten here, we've added a new wearable of type "type"
551		// Thus this wearable needs to get updates from the driver wearable.
552		// The call to setVisualParamWeight seems redundant, but is necessary
553		// as the number of driven wearables has changed since the last update. -Nyx
554		LLWearable *wearable = gAgentWearables.getTopWearable(driver_type);
555		if (wearable)
556		{
557			wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false);
558		}
559	}
560}
561
562
563//-----------------------------------------------------------------------------
564// getDrivenWeight()
565//-----------------------------------------------------------------------------
566F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight)
567{
568	F32 min_weight = getMinWeight();
569	F32 max_weight = getMaxWeight();
570	const LLDrivenEntryInfo* info = driven->mInfo;
571
572	F32 driven_weight = 0.f;
573	F32 driven_min = driven->mParam->getMinWeight();
574	F32 driven_max = driven->mParam->getMaxWeight();
575
576	if( input_weight <= info->mMin1 )
577	{
578		if( info->mMin1 == info->mMax1 && 
579			info->mMin1 <= min_weight)
580		{
581			driven_weight = driven_max;
582		}
583		else
584		{
585			driven_weight = driven_min;
586		}
587	}
588	else
589	if( input_weight <= info->mMax1 )
590	{
591		F32 t = (input_weight - info->mMin1) / (info->mMax1 - info->mMin1 );
592		driven_weight = driven_min + t * (driven_max - driven_min);
593	}
594	else
595	if( input_weight <= info->mMax2 )
596	{
597		driven_weight = driven_max;
598	}
599	else
600	if( input_weight <= info->mMin2 )
601	{
602		F32 t = (input_weight - info->mMax2) / (info->mMin2 - info->mMax2 );
603		driven_weight = driven_max + t * (driven_min - driven_max);
604	}
605	else
606	{
607		if (info->mMax2 >= max_weight)
608		{
609			driven_weight = driven_max;
610		}
611		else
612		{
613			driven_weight = driven_min;
614		}
615	}
616
617	return driven_weight;
618}
619
620void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake)
621{
622	if(isAgentAvatarValid() &&
623	   mWearablep && 
624	   driven->mParam->getCrossWearable() &&
625	   mWearablep->isOnTop())
626	{
627		// call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values
628		gAgentAvatarp->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake );
629	}
630	else
631	{
632		driven->mParam->setWeight( driven_weight, upload_bake );
633	}
634}