PageRenderTime 75ms CodeModel.GetById 18ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcharacter/llkeyframemotionparam.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 449 lines | 285 code | 63 blank | 101 comment | 74 complexity | 3782b921f73c146180df8596c570c12b MD5 | raw file
  1/** 
  2 * @file llkeyframemotionparam.cpp
  3 * @brief Implementation of LLKeyframeMotion class.
  4 *
  5 * $LicenseInfo:firstyear=2001&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//-----------------------------------------------------------------------------
 28// Header Files
 29//-----------------------------------------------------------------------------
 30#include "linden_common.h"
 31
 32#include "llkeyframemotionparam.h"
 33#include "llcharacter.h"
 34#include "llmath.h"
 35#include "m3math.h"
 36#include "lldir.h"
 37#include "llanimationstates.h"
 38
 39//-----------------------------------------------------------------------------
 40//-----------------------------------------------------------------------------
 41// LLKeyframeMotionParam class
 42//-----------------------------------------------------------------------------
 43//-----------------------------------------------------------------------------
 44
 45//-----------------------------------------------------------------------------
 46// LLKeyframeMotionParam()
 47// Class Constructor
 48//-----------------------------------------------------------------------------
 49LLKeyframeMotionParam::LLKeyframeMotionParam( const LLUUID &id) : LLMotion(id)
 50{
 51	mDefaultKeyframeMotion = NULL;
 52	mCharacter = NULL;
 53
 54	mEaseInDuration = 0.f;
 55	mEaseOutDuration = 0.f;
 56	mDuration = 0.f;
 57	mPriority = LLJoint::LOW_PRIORITY;
 58}
 59
 60
 61//-----------------------------------------------------------------------------
 62// ~LLKeyframeMotionParam()
 63// Class Destructor
 64//-----------------------------------------------------------------------------
 65LLKeyframeMotionParam::~LLKeyframeMotionParam()
 66{
 67	for (motion_map_t::iterator iter = mParameterizedMotions.begin();
 68		 iter != mParameterizedMotions.end(); ++iter)
 69	{
 70		motion_list_t& motionList = iter->second;
 71		for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
 72		{
 73			const ParameterizedMotion& paramMotion = *iter2;
 74			delete paramMotion.mMotion;
 75		}
 76		motionList.clear();
 77	}
 78	mParameterizedMotions.clear();
 79}
 80
 81//-----------------------------------------------------------------------------
 82// LLKeyframeMotionParam::onInitialize(LLCharacter *character)
 83//-----------------------------------------------------------------------------
 84LLMotion::LLMotionInitStatus LLKeyframeMotionParam::onInitialize(LLCharacter *character)
 85{
 86	mCharacter = character;
 87
 88	if (!loadMotions())
 89	{
 90		return STATUS_FAILURE;	
 91	}
 92	
 93	for (motion_map_t::iterator iter = mParameterizedMotions.begin();
 94		 iter != mParameterizedMotions.end(); ++iter)
 95	{
 96		motion_list_t& motionList = iter->second;
 97		for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
 98		{
 99			const ParameterizedMotion& paramMotion = *iter2;
100			LLMotion* motion = paramMotion.mMotion;
101			motion->onInitialize(character);
102
103			if (motion->getDuration() > mEaseInDuration)
104			{
105				mEaseInDuration = motion->getEaseInDuration();
106			}
107
108			if (motion->getEaseOutDuration() > mEaseOutDuration)
109			{
110				mEaseOutDuration = motion->getEaseOutDuration();
111			}
112
113			if (motion->getDuration() > mDuration)
114			{
115				mDuration = motion->getDuration();
116			}
117
118			if (motion->getPriority() > mPriority)
119			{
120				mPriority = motion->getPriority();
121			}
122
123			LLPose *pose = motion->getPose();
124
125			mPoseBlender.addMotion(motion);
126			for (LLJointState *jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState())
127			{
128				LLPose *blendedPose = mPoseBlender.getBlendedPose();
129				blendedPose->addJointState(jsp);
130			}
131		}
132	}
133
134	return STATUS_SUCCESS;
135}
136
137//-----------------------------------------------------------------------------
138// LLKeyframeMotionParam::onActivate()
139//-----------------------------------------------------------------------------
140BOOL LLKeyframeMotionParam::onActivate()
141{
142	for (motion_map_t::iterator iter = mParameterizedMotions.begin();
143		 iter != mParameterizedMotions.end(); ++iter)
144	{
145		motion_list_t& motionList = iter->second;
146		for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
147		{
148			const ParameterizedMotion& paramMotion = *iter2;
149			paramMotion.mMotion->activate(mActivationTimestamp);
150		}
151	}
152	return TRUE;
153}
154
155
156//-----------------------------------------------------------------------------
157// LLKeyframeMotionParam::onUpdate()
158//-----------------------------------------------------------------------------
159BOOL LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask)
160{
161	F32 weightFactor = 1.f / (F32)mParameterizedMotions.size();
162
163	// zero out all pose weights
164	for (motion_map_t::iterator iter = mParameterizedMotions.begin();
165		 iter != mParameterizedMotions.end(); ++iter)
166	{
167		motion_list_t& motionList = iter->second;
168		for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
169		{
170			const ParameterizedMotion& paramMotion = *iter2;
171//			llinfos << "Weight for pose " << paramMotion.mMotion->getName() << " is " << paramMotion.mMotion->getPose()->getWeight() << llendl;
172			paramMotion.mMotion->getPose()->setWeight(0.f);
173		}
174	}
175
176
177	for (motion_map_t::iterator iter = mParameterizedMotions.begin();
178		 iter != mParameterizedMotions.end(); ++iter)
179	{
180		const std::string& paramName = iter->first;
181		F32* paramValue = (F32 *)mCharacter->getAnimationData(paramName);
182		if (NULL == paramValue) // unexpected, but...
183		{
184			llwarns << "paramValue == NULL" << llendl;
185			continue;
186		}
187
188		// DANGER! Do not modify mParameterizedMotions while using these pointers!
189		const ParameterizedMotion* firstMotion = NULL;
190		const ParameterizedMotion* secondMotion = NULL;
191
192		motion_list_t& motionList = iter->second;
193		for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
194		{
195			const ParameterizedMotion& paramMotion = *iter2;
196			paramMotion.mMotion->onUpdate(time, joint_mask);
197			
198			F32 distToParam = paramMotion.mParam - *paramValue;
199			
200			if ( distToParam <= 0.f)
201			{
202				// keep track of the motion closest to the parameter value
203				firstMotion = &paramMotion;
204			}
205			else
206			{
207				// we've passed the parameter value
208				// so store the first motion we find as the second one we want to blend...
209				if (firstMotion && !secondMotion )
210				{
211					secondMotion = &paramMotion;
212				}
213				//...or, if we've seen no other motion so far, make sure we blend to this only
214				else if (!firstMotion)
215				{
216					firstMotion = &paramMotion;
217					secondMotion = &paramMotion;
218				}
219			}
220		}
221
222		LLPose *firstPose;
223		LLPose *secondPose;
224
225		if (firstMotion)
226			firstPose = firstMotion->mMotion->getPose();
227		else
228			firstPose = NULL;
229
230		if (secondMotion)
231			secondPose = secondMotion->mMotion->getPose();
232		else
233			secondPose = NULL;
234		
235		// now modify weight of the subanim (only if we are blending between two motions)
236		if (firstMotion && secondMotion)
237		{
238			if (firstMotion == secondMotion)
239			{
240				firstPose->setWeight(weightFactor);
241			}
242			else if (firstMotion->mParam == secondMotion->mParam)
243			{
244				firstPose->setWeight(0.5f * weightFactor);
245				secondPose->setWeight(0.5f * weightFactor);
246			}
247			else
248			{
249				F32 first_weight = 1.f - 
250					((llclamp(*paramValue - firstMotion->mParam, 0.f, (secondMotion->mParam - firstMotion->mParam))) / 
251						(secondMotion->mParam - firstMotion->mParam));
252				first_weight = llclamp(first_weight, 0.f, 1.f);
253				
254				F32 second_weight = 1.f - first_weight;
255				
256				firstPose->setWeight(first_weight * weightFactor);
257				secondPose->setWeight(second_weight * weightFactor);
258
259//				llinfos << "Parameter " << *paramName << ": " << *paramValue << llendl;
260//				llinfos << "Weights " << firstPose->getWeight() << " " << secondPose->getWeight() << llendl;
261			}
262		}
263		else if (firstMotion && !secondMotion)
264		{
265			firstPose->setWeight(weightFactor);
266		}
267	}
268
269	// blend poses
270	mPoseBlender.blendAndApply();
271
272	llinfos << "Param Motion weight " << mPoseBlender.getBlendedPose()->getWeight() << llendl;
273
274	return TRUE;
275}
276
277//-----------------------------------------------------------------------------
278// LLKeyframeMotionParam::onDeactivate()
279//-----------------------------------------------------------------------------
280void LLKeyframeMotionParam::onDeactivate()
281{
282	for (motion_map_t::iterator iter = mParameterizedMotions.begin();
283		 iter != mParameterizedMotions.end(); ++iter)
284	{
285		motion_list_t& motionList = iter->second;
286		for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
287		{
288			const ParameterizedMotion& paramMotion = *iter2;
289			paramMotion.mMotion->onDeactivate();
290		}
291	}
292}
293
294//-----------------------------------------------------------------------------
295// LLKeyframeMotionParam::addKeyframeMotion()
296//-----------------------------------------------------------------------------
297BOOL LLKeyframeMotionParam::addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value)
298{
299	LLMotion *newMotion = mCharacter->createMotion( id );
300	
301	if (!newMotion)
302	{
303		return FALSE;
304	}
305	
306	newMotion->setName(name);
307
308	// now add motion to this list
309	mParameterizedMotions[param].insert(ParameterizedMotion(newMotion, value));
310
311	return TRUE;
312}
313
314
315//-----------------------------------------------------------------------------
316// LLKeyframeMotionParam::setDefaultKeyframeMotion()
317//-----------------------------------------------------------------------------
318void LLKeyframeMotionParam::setDefaultKeyframeMotion(char *name)
319{
320	for (motion_map_t::iterator iter = mParameterizedMotions.begin();
321		 iter != mParameterizedMotions.end(); ++iter)
322	{
323		motion_list_t& motionList = iter->second;
324		for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
325		{
326			const ParameterizedMotion& paramMotion = *iter2;
327			if (paramMotion.mMotion->getName() == name)
328			{
329				mDefaultKeyframeMotion = paramMotion.mMotion;
330			}
331		}
332	}
333}
334
335//-----------------------------------------------------------------------------
336// loadMotions()
337//-----------------------------------------------------------------------------
338BOOL LLKeyframeMotionParam::loadMotions()
339{
340	//-------------------------------------------------------------------------
341	// Load named file by concatenating the character prefix with the motion name.
342	// Load data into a buffer to be parsed.
343	//-------------------------------------------------------------------------
344	//std::string path = gDirUtilp->getExpandedFilename(LL_PATH_MOTIONS,mCharacter->getAnimationPrefix())
345	//	+ "_" + getName() + ".llp";
346	//RN: deprecated unused reference to "motion" directory
347	std::string path;
348
349
350	//-------------------------------------------------------------------------
351	// open the file
352	//-------------------------------------------------------------------------
353	S32 fileSize = 0;
354	LLAPRFile infile ;
355	infile.open(path, LL_APR_R, NULL, &fileSize);
356	apr_file_t* fp = infile.getFileHandle() ;
357	if (!fp || fileSize == 0)
358	{
359		llinfos << "ERROR: can't open: " << path << llendl;
360		return FALSE;
361	}
362
363	// allocate a text buffer
364	std::vector<char> text(fileSize+1);
365
366	//-------------------------------------------------------------------------
367	// load data from file into buffer
368	//-------------------------------------------------------------------------
369	bool error = false;
370	char *p = &text[0];
371	while ( 1 )
372	{
373		if (apr_file_eof(fp) == APR_EOF)
374		{
375			break;
376		}
377		if (apr_file_gets(p, 1024, fp) != APR_SUCCESS)
378		{
379			error = true;
380			break;
381		}
382		while ( *(++p) )
383			;
384	}
385
386	//-------------------------------------------------------------------------
387	// close the file
388	//-------------------------------------------------------------------------
389	infile.close();
390
391	//-------------------------------------------------------------------------
392	// check for error
393	//-------------------------------------------------------------------------
394	llassert( p <= (&text[0] + fileSize) );
395
396	if ( error )
397	{
398		llinfos << "ERROR: error while reading from " << path << llendl;
399		return FALSE;
400	}
401
402	llinfos << "Loading parametric keyframe data for: " << getName() << llendl;
403
404	//-------------------------------------------------------------------------
405	// parse the text and build keyframe data structures
406	//-------------------------------------------------------------------------
407	p = &text[0];
408	S32 num;
409	char strA[80]; /* Flawfinder: ignore */
410	char strB[80]; /* Flawfinder: ignore */
411	F32 floatA = 0.0f;
412
413
414	//-------------------------------------------------------------------------
415	// get priority
416	//-------------------------------------------------------------------------
417	BOOL isFirstMotion = TRUE;
418	num = sscanf(p, "%79s %79s %f", strA, strB, &floatA);	/* Flawfinder: ignore */
419
420	while(1)
421	{
422		if (num == 0 || num == EOF) break;
423		if ((num != 3))
424		{
425			llinfos << "WARNING: can't read parametric motion" << llendl;
426			return FALSE;
427		}
428
429		addKeyframeMotion(strA, gAnimLibrary.stringToAnimState(std::string(strA)), strB, floatA);
430		if (isFirstMotion)
431		{
432			isFirstMotion = FALSE;
433			setDefaultKeyframeMotion(strA);
434		}
435		
436		p = strstr(p, "\n");
437		if (!p)
438		{
439			break;
440		}
441			
442		p++;
443		num = sscanf(p, "%79s %79s %f", strA, strB, &floatA);	/* Flawfinder: ignore */
444	}
445
446	return TRUE;
447}
448
449// End