diff options
Diffstat (limited to 'linden/indra/llcharacter/llmotioncontroller.cpp')
-rw-r--r-- | linden/indra/llcharacter/llmotioncontroller.cpp | 946 |
1 files changed, 946 insertions, 0 deletions
diff --git a/linden/indra/llcharacter/llmotioncontroller.cpp b/linden/indra/llcharacter/llmotioncontroller.cpp new file mode 100644 index 0000000..3e1456b --- /dev/null +++ b/linden/indra/llcharacter/llmotioncontroller.cpp | |||
@@ -0,0 +1,946 @@ | |||
1 | /** | ||
2 | * @file llmotioncontroller.cpp | ||
3 | * @brief Implementation of LLMotionController 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 "linden_common.h" | ||
32 | |||
33 | #include "llmotioncontroller.h" | ||
34 | #include "llkeyframemotion.h" | ||
35 | #include "llmath.h" | ||
36 | #include "lltimer.h" | ||
37 | #include "llanimationstates.h" | ||
38 | #include "llstl.h" | ||
39 | |||
40 | const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_JOINTS / 4; | ||
41 | const U32 MAX_MOTION_INSTANCES = 32; | ||
42 | |||
43 | //----------------------------------------------------------------------------- | ||
44 | // Constants and statics | ||
45 | //----------------------------------------------------------------------------- | ||
46 | LLMotionRegistry LLMotionController::sRegistry; | ||
47 | |||
48 | //----------------------------------------------------------------------------- | ||
49 | // LLMotionTableEntry() | ||
50 | //----------------------------------------------------------------------------- | ||
51 | LLMotionTableEntry::LLMotionTableEntry() | ||
52 | { | ||
53 | mConstructor = NULL; | ||
54 | mID.setNull(); | ||
55 | } | ||
56 | |||
57 | LLMotionTableEntry::LLMotionTableEntry(LLMotionConstructor constructor, const LLUUID& id) | ||
58 | : mConstructor(constructor), mID(id) | ||
59 | { | ||
60 | |||
61 | } | ||
62 | |||
63 | //----------------------------------------------------------------------------- | ||
64 | // create() | ||
65 | //----------------------------------------------------------------------------- | ||
66 | LLMotion* LLMotionTableEntry::create(const LLUUID &id) | ||
67 | { | ||
68 | LLMotion* motionp = mConstructor(id); | ||
69 | |||
70 | return motionp; | ||
71 | } | ||
72 | |||
73 | |||
74 | //----------------------------------------------------------------------------- | ||
75 | //----------------------------------------------------------------------------- | ||
76 | // LLMotionRegistry class | ||
77 | //----------------------------------------------------------------------------- | ||
78 | //----------------------------------------------------------------------------- | ||
79 | |||
80 | //----------------------------------------------------------------------------- | ||
81 | // LLMotionRegistry() | ||
82 | // Class Constructor | ||
83 | //----------------------------------------------------------------------------- | ||
84 | LLMotionRegistry::LLMotionRegistry() : mMotionTable(LLMotionTableEntry::uuidEq, LLMotionTableEntry()) | ||
85 | { | ||
86 | |||
87 | } | ||
88 | |||
89 | |||
90 | //----------------------------------------------------------------------------- | ||
91 | // ~LLMotionRegistry() | ||
92 | // Class Destructor | ||
93 | //----------------------------------------------------------------------------- | ||
94 | LLMotionRegistry::~LLMotionRegistry() | ||
95 | { | ||
96 | mMotionTable.removeAll(); | ||
97 | } | ||
98 | |||
99 | |||
100 | //----------------------------------------------------------------------------- | ||
101 | // addMotion() | ||
102 | //----------------------------------------------------------------------------- | ||
103 | BOOL LLMotionRegistry::addMotion( const LLUUID& id, LLMotionConstructor constructor ) | ||
104 | { | ||
105 | // llinfos << "Registering motion: " << name << llendl; | ||
106 | if (!mMotionTable.check(id)) | ||
107 | { | ||
108 | mMotionTable.set(id, LLMotionTableEntry(constructor, id)); | ||
109 | return TRUE; | ||
110 | } | ||
111 | |||
112 | return FALSE; | ||
113 | } | ||
114 | |||
115 | //----------------------------------------------------------------------------- | ||
116 | // markBad() | ||
117 | //----------------------------------------------------------------------------- | ||
118 | void LLMotionRegistry::markBad( const LLUUID& id ) | ||
119 | { | ||
120 | mMotionTable.set(id, LLMotionTableEntry()); | ||
121 | } | ||
122 | |||
123 | //----------------------------------------------------------------------------- | ||
124 | // createMotion() | ||
125 | //----------------------------------------------------------------------------- | ||
126 | LLMotion *LLMotionRegistry::createMotion( const LLUUID &id ) | ||
127 | { | ||
128 | LLMotionTableEntry motion_entry = mMotionTable.get(id); | ||
129 | LLMotion* motion = NULL; | ||
130 | |||
131 | if ( motion_entry.getID().isNull() ) | ||
132 | { | ||
133 | // *FIX: need to replace with a better default scheme. RN | ||
134 | motion = LLKeyframeMotion::create(id); | ||
135 | } | ||
136 | else | ||
137 | { | ||
138 | motion = motion_entry.create(id); | ||
139 | } | ||
140 | |||
141 | return motion; | ||
142 | } | ||
143 | |||
144 | //----------------------------------------------------------------------------- | ||
145 | //----------------------------------------------------------------------------- | ||
146 | // LLMotionController class | ||
147 | //----------------------------------------------------------------------------- | ||
148 | //----------------------------------------------------------------------------- | ||
149 | |||
150 | //----------------------------------------------------------------------------- | ||
151 | // LLMotionController() | ||
152 | // Class Constructor | ||
153 | //----------------------------------------------------------------------------- | ||
154 | LLMotionController::LLMotionController( ) | ||
155 | { | ||
156 | mTime = 0.f; | ||
157 | mTimeOffset = 0.f; | ||
158 | mLastTime = 0.0f; | ||
159 | mHasRunOnce = FALSE; | ||
160 | mPaused = FALSE; | ||
161 | mPauseTime = 0.f; | ||
162 | mTimeStep = 0.f; | ||
163 | mTimeStepCount = 0; | ||
164 | mLastInterp = 0.f; | ||
165 | mTimeFactor = 1.f; | ||
166 | } | ||
167 | |||
168 | |||
169 | //----------------------------------------------------------------------------- | ||
170 | // ~LLMotionController() | ||
171 | // Class Destructor | ||
172 | //----------------------------------------------------------------------------- | ||
173 | LLMotionController::~LLMotionController() | ||
174 | { | ||
175 | deleteAllMotions(); | ||
176 | } | ||
177 | |||
178 | //----------------------------------------------------------------------------- | ||
179 | // deleteAllMotions() | ||
180 | //----------------------------------------------------------------------------- | ||
181 | void LLMotionController::deleteAllMotions() | ||
182 | { | ||
183 | mLoadingMotions.removeAllNodes(); | ||
184 | mLoadedMotions.clear(); | ||
185 | mActiveMotions.removeAllNodes(); | ||
186 | |||
187 | for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer()); | ||
188 | mAllMotions.clear(); | ||
189 | } | ||
190 | |||
191 | //----------------------------------------------------------------------------- | ||
192 | // addLoadedMotion() | ||
193 | //----------------------------------------------------------------------------- | ||
194 | void LLMotionController::addLoadedMotion(LLMotion* motionp) | ||
195 | { | ||
196 | if (mLoadedMotions.size() > MAX_MOTION_INSTANCES) | ||
197 | { | ||
198 | // too many motions active this frame, kill all blenders | ||
199 | mPoseBlender.clearBlenders(); | ||
200 | |||
201 | for (U32 i = 0; i < mLoadedMotions.size(); i++) | ||
202 | { | ||
203 | LLMotion* cur_motionp = mLoadedMotions.front(); | ||
204 | mLoadedMotions.pop_front(); | ||
205 | |||
206 | // motion isn't playing, delete it | ||
207 | if (!isMotionActive(cur_motionp)) | ||
208 | { | ||
209 | mCharacter->requestStopMotion(cur_motionp); | ||
210 | mAllMotions.erase(cur_motionp->getID()); | ||
211 | delete cur_motionp; | ||
212 | if (mLoadedMotions.size() <= MAX_MOTION_INSTANCES) | ||
213 | { | ||
214 | break; | ||
215 | } | ||
216 | } | ||
217 | else | ||
218 | { | ||
219 | // put active motion on back | ||
220 | mLoadedMotions.push_back(cur_motionp); | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | mLoadedMotions.push_back(motionp); | ||
225 | } | ||
226 | |||
227 | //----------------------------------------------------------------------------- | ||
228 | // setTimeStep() | ||
229 | //----------------------------------------------------------------------------- | ||
230 | void LLMotionController::setTimeStep(F32 step) | ||
231 | { | ||
232 | mTimeStep = step; | ||
233 | |||
234 | if (step != 0.f) | ||
235 | { | ||
236 | // make sure timestamps conform to new quantum | ||
237 | for( LLMotion* motionp = mActiveMotions.getFirstData(); | ||
238 | motionp != NULL; | ||
239 | motionp = mActiveMotions.getNextData() ) | ||
240 | { | ||
241 | motionp->mActivationTimestamp = (F32)llfloor(motionp->mActivationTimestamp / step) * step; | ||
242 | BOOL stopped = motionp->isStopped(); | ||
243 | motionp->setStopTime((F32)llfloor(motionp->getStopTime() / step) * step); | ||
244 | motionp->setStopped(stopped); | ||
245 | motionp->mSendStopTimestamp = (F32)llfloor(motionp->mSendStopTimestamp / step) * step; | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | |||
250 | //----------------------------------------------------------------------------- | ||
251 | // setTimeFactor() | ||
252 | //----------------------------------------------------------------------------- | ||
253 | void LLMotionController::setTimeFactor(F32 time_factor) | ||
254 | { | ||
255 | mTimeOffset += mTimer.getElapsedTimeAndResetF32() * mTimeFactor; | ||
256 | mTimeFactor = time_factor; | ||
257 | } | ||
258 | |||
259 | //----------------------------------------------------------------------------- | ||
260 | // getFirstActiveMotion() | ||
261 | //----------------------------------------------------------------------------- | ||
262 | LLMotion* LLMotionController::getFirstActiveMotion() | ||
263 | { | ||
264 | return mActiveMotions.getFirstData(); | ||
265 | } | ||
266 | |||
267 | //----------------------------------------------------------------------------- | ||
268 | // getNextActiveMotion() | ||
269 | //----------------------------------------------------------------------------- | ||
270 | LLMotion* LLMotionController::getNextActiveMotion() | ||
271 | { | ||
272 | return mActiveMotions.getNextData(); | ||
273 | } | ||
274 | |||
275 | |||
276 | //----------------------------------------------------------------------------- | ||
277 | // setCharacter() | ||
278 | //----------------------------------------------------------------------------- | ||
279 | void LLMotionController::setCharacter(LLCharacter *character) | ||
280 | { | ||
281 | mCharacter = character; | ||
282 | } | ||
283 | |||
284 | |||
285 | //----------------------------------------------------------------------------- | ||
286 | // addMotion() | ||
287 | //----------------------------------------------------------------------------- | ||
288 | BOOL LLMotionController::addMotion( const LLUUID& id, LLMotionConstructor constructor ) | ||
289 | { | ||
290 | return sRegistry.addMotion(id, constructor); | ||
291 | } | ||
292 | |||
293 | //----------------------------------------------------------------------------- | ||
294 | // removeMotion() | ||
295 | //----------------------------------------------------------------------------- | ||
296 | void LLMotionController::removeMotion( const LLUUID& id) | ||
297 | { | ||
298 | LLMotion* motionp = findMotion(id); | ||
299 | if (motionp) | ||
300 | { | ||
301 | stopMotionLocally(id, TRUE); | ||
302 | |||
303 | mLoadingMotions.deleteData(motionp); | ||
304 | std::deque<LLMotion*>::iterator motion_it; | ||
305 | for (motion_it = mLoadedMotions.begin(); motion_it != mLoadedMotions.end(); ++motion_it) | ||
306 | { | ||
307 | if(*motion_it == motionp) | ||
308 | { | ||
309 | mLoadedMotions.erase(motion_it); | ||
310 | break; | ||
311 | } | ||
312 | } | ||
313 | mActiveMotions.deleteData(motionp); | ||
314 | mAllMotions.erase(id); | ||
315 | delete motionp; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | //----------------------------------------------------------------------------- | ||
320 | // createMotion() | ||
321 | //----------------------------------------------------------------------------- | ||
322 | LLMotion* LLMotionController::createMotion( const LLUUID &id ) | ||
323 | { | ||
324 | // do we have an instance of this motion for this character? | ||
325 | LLMotion *motion = findMotion(id); | ||
326 | |||
327 | // if not, we need to create one | ||
328 | if (!motion) | ||
329 | { | ||
330 | // look up constructor and create it | ||
331 | motion = sRegistry.createMotion(id); | ||
332 | if (!motion) | ||
333 | { | ||
334 | return NULL; | ||
335 | } | ||
336 | |||
337 | // look up name for default motions | ||
338 | const char* motion_name = gAnimLibrary.animStateToString(id); | ||
339 | if (motion_name) | ||
340 | { | ||
341 | motion->setName(motion_name); | ||
342 | } | ||
343 | |||
344 | // initialize the new instance | ||
345 | LLMotion::LLMotionInitStatus stat = motion->onInitialize(mCharacter); | ||
346 | switch(stat) | ||
347 | { | ||
348 | case LLMotion::STATUS_FAILURE: | ||
349 | llinfos << "Motion " << id << " init failed." << llendl; | ||
350 | sRegistry.markBad(id); | ||
351 | delete motion; | ||
352 | return NULL; | ||
353 | case LLMotion::STATUS_HOLD: | ||
354 | mLoadingMotions.addData(motion); | ||
355 | break; | ||
356 | case LLMotion::STATUS_SUCCESS: | ||
357 | // add motion to our list | ||
358 | addLoadedMotion(motion); | ||
359 | break; | ||
360 | default: | ||
361 | llerrs << "Invalid initialization status" << llendl; | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | mAllMotions[id] = motion; | ||
366 | } | ||
367 | return motion; | ||
368 | } | ||
369 | |||
370 | //----------------------------------------------------------------------------- | ||
371 | // startMotion() | ||
372 | //----------------------------------------------------------------------------- | ||
373 | BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset) | ||
374 | { | ||
375 | // look for motion in our list of created motions | ||
376 | LLMotion *motion = createMotion(id); | ||
377 | |||
378 | if (!motion) | ||
379 | { | ||
380 | return FALSE; | ||
381 | } | ||
382 | //if the motion is already active, then we're done | ||
383 | else if (isMotionActive(motion)) // motion is playing and... | ||
384 | { | ||
385 | if (motion->isStopped()) // motion has been stopped | ||
386 | { | ||
387 | deactivateMotion(motion); | ||
388 | } | ||
389 | else if (mTime < motion->mSendStopTimestamp) // motion is still active | ||
390 | { | ||
391 | return TRUE; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | // llinfos << "Starting motion " << name << llendl; | ||
396 | return activateMotion(motion, mTime - start_offset); | ||
397 | } | ||
398 | |||
399 | |||
400 | //----------------------------------------------------------------------------- | ||
401 | // stopMotionLocally() | ||
402 | //----------------------------------------------------------------------------- | ||
403 | BOOL LLMotionController::stopMotionLocally(const LLUUID &id, BOOL stop_immediate) | ||
404 | { | ||
405 | // if already inactive, return false | ||
406 | LLMotion *motion = findMotion(id); | ||
407 | if (!motion) | ||
408 | { | ||
409 | return FALSE; | ||
410 | } | ||
411 | |||
412 | // If on active list, stop it | ||
413 | if (isMotionActive(motion) && !motion->isStopped()) | ||
414 | { | ||
415 | // when using timesteps, set stop time to last frame's time, otherwise grab current timer value | ||
416 | // *FIX: should investigate this inconsistency...hints of obscure bugs | ||
417 | |||
418 | F32 stop_time = (mTimeStep != 0.f || mPaused) ? (mTime) : mTimeOffset + (mTimer.getElapsedTimeF32() * mTimeFactor); | ||
419 | motion->setStopTime(stop_time); | ||
420 | |||
421 | if (stop_immediate) | ||
422 | { | ||
423 | deactivateMotion(motion); | ||
424 | } | ||
425 | return TRUE; | ||
426 | } | ||
427 | else if (isMotionLoading(motion)) | ||
428 | { | ||
429 | motion->setStopped(TRUE); | ||
430 | return TRUE; | ||
431 | } | ||
432 | |||
433 | return FALSE; | ||
434 | } | ||
435 | |||
436 | |||
437 | //----------------------------------------------------------------------------- | ||
438 | // updateRegularMotions() | ||
439 | //----------------------------------------------------------------------------- | ||
440 | void LLMotionController::updateRegularMotions() | ||
441 | { | ||
442 | updateMotionsByType(LLMotion::NORMAL_BLEND); | ||
443 | } | ||
444 | |||
445 | //----------------------------------------------------------------------------- | ||
446 | // updateAdditiveMotions() | ||
447 | //----------------------------------------------------------------------------- | ||
448 | void LLMotionController::updateAdditiveMotions() | ||
449 | { | ||
450 | updateMotionsByType(LLMotion::ADDITIVE_BLEND); | ||
451 | } | ||
452 | |||
453 | //----------------------------------------------------------------------------- | ||
454 | // resetJointSignatures() | ||
455 | //----------------------------------------------------------------------------- | ||
456 | void LLMotionController::resetJointSignatures() | ||
457 | { | ||
458 | memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS); | ||
459 | memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS); | ||
460 | } | ||
461 | |||
462 | //----------------------------------------------------------------------------- | ||
463 | // updateMotionsByType() | ||
464 | //----------------------------------------------------------------------------- | ||
465 | void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type) | ||
466 | { | ||
467 | BOOL update_result = TRUE; | ||
468 | U8 last_joint_signature[LL_CHARACTER_MAX_JOINTS]; | ||
469 | |||
470 | memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS); | ||
471 | |||
472 | // iterate through active motions in chronological order | ||
473 | for(LLMotion* motionp = mActiveMotions.getFirstData(); | ||
474 | motionp != NULL; | ||
475 | motionp = mActiveMotions.getNextData()) | ||
476 | { | ||
477 | if (motionp->getBlendType() != anim_type) | ||
478 | { | ||
479 | continue; | ||
480 | } | ||
481 | |||
482 | BOOL update_motion = FALSE; | ||
483 | |||
484 | if (motionp->getPose()->getWeight() < 1.f) | ||
485 | { | ||
486 | update_motion = TRUE; | ||
487 | } | ||
488 | else | ||
489 | { | ||
490 | S32 i; | ||
491 | // NUM_JOINT_SIGNATURE_STRIDES should be multiple of 4 | ||
492 | for (i = 0; i < NUM_JOINT_SIGNATURE_STRIDES; i++) | ||
493 | { | ||
494 | U32 *current_signature = (U32*)&(mJointSignature[0][i * 4]); | ||
495 | U32 test_signature = *(U32*)&(motionp->mJointSignature[0][i * 4]); | ||
496 | |||
497 | if ((*current_signature | test_signature) > (*current_signature)) | ||
498 | { | ||
499 | *current_signature |= test_signature; | ||
500 | update_motion = TRUE; | ||
501 | } | ||
502 | |||
503 | *((U32*)&last_joint_signature[i * 4]) = *(U32*)&(mJointSignature[1][i * 4]); | ||
504 | current_signature = (U32*)&(mJointSignature[1][i * 4]); | ||
505 | test_signature = *(U32*)&(motionp->mJointSignature[1][i * 4]); | ||
506 | |||
507 | if ((*current_signature | test_signature) > (*current_signature)) | ||
508 | { | ||
509 | *current_signature |= test_signature; | ||
510 | update_motion = TRUE; | ||
511 | } | ||
512 | } | ||
513 | } | ||
514 | |||
515 | if (!update_motion) | ||
516 | { | ||
517 | if (motionp->isStopped() && mTime > motionp->getStopTime() + motionp->getEaseOutDuration()) | ||
518 | { | ||
519 | deactivateMotion(motionp); | ||
520 | } | ||
521 | else if (motionp->isStopped() && mTime > motionp->getStopTime()) | ||
522 | { | ||
523 | // is this the first iteration in the ease out phase? | ||
524 | if (mLastTime <= motionp->getStopTime()) | ||
525 | { | ||
526 | // store residual weight for this motion | ||
527 | motionp->mResidualWeight = motionp->getPose()->getWeight(); | ||
528 | } | ||
529 | } | ||
530 | else if (mTime > motionp->mSendStopTimestamp) | ||
531 | { | ||
532 | // notify character of timed stop event on first iteration past sendstoptimestamp | ||
533 | // this will only be called when an animation stops itself (runs out of time) | ||
534 | if (mLastTime <= motionp->mSendStopTimestamp) | ||
535 | { | ||
536 | mCharacter->requestStopMotion( motionp ); | ||
537 | stopMotionLocally(motionp->getID(), FALSE); | ||
538 | } | ||
539 | } | ||
540 | else if (mTime >= motionp->mActivationTimestamp) | ||
541 | { | ||
542 | if (mLastTime < motionp->mActivationTimestamp) | ||
543 | { | ||
544 | motionp->mResidualWeight = motionp->getPose()->getWeight(); | ||
545 | } | ||
546 | } | ||
547 | continue; | ||
548 | } | ||
549 | |||
550 | LLPose *posep = motionp->getPose(); | ||
551 | |||
552 | // only filter by LOD after running every animation at least once (to prime the avatar state) | ||
553 | if (mHasRunOnce && motionp->getMinPixelArea() > mCharacter->getPixelArea()) | ||
554 | { | ||
555 | motionp->fadeOut(); | ||
556 | |||
557 | //should we notify the simulator that this motion should be stopped (check even if skipped by LOD logic) | ||
558 | if (mTime > motionp->mSendStopTimestamp) | ||
559 | { | ||
560 | // notify character of timed stop event on first iteration past sendstoptimestamp | ||
561 | // this will only be called when an animation stops itself (runs out of time) | ||
562 | if (mLastTime <= motionp->mSendStopTimestamp) | ||
563 | { | ||
564 | mCharacter->requestStopMotion( motionp ); | ||
565 | stopMotionLocally(motionp->getID(), FALSE); | ||
566 | } | ||
567 | } | ||
568 | |||
569 | if (motionp->getFadeWeight() < 0.01f) | ||
570 | { | ||
571 | if (motionp->isStopped() && mTime > motionp->getStopTime() + motionp->getEaseOutDuration()) | ||
572 | { | ||
573 | posep->setWeight(0.f); | ||
574 | deactivateMotion(motionp); | ||
575 | } | ||
576 | continue; | ||
577 | } | ||
578 | } | ||
579 | else | ||
580 | { | ||
581 | motionp->fadeIn(); | ||
582 | } | ||
583 | |||
584 | //********************** | ||
585 | // MOTION INACTIVE | ||
586 | //********************** | ||
587 | if (motionp->isStopped() && mTime > motionp->getStopTime() + motionp->getEaseOutDuration()) | ||
588 | { | ||
589 | // this motion has gone on too long, deactivate it | ||
590 | // did we have a chance to stop it? | ||
591 | if (mLastTime <= motionp->getStopTime()) | ||
592 | { | ||
593 | // if not, let's stop it this time through and deactivate it the next | ||
594 | |||
595 | posep->setWeight(motionp->getFadeWeight()); | ||
596 | motionp->onUpdate(motionp->getStopTime() - motionp->mActivationTimestamp, last_joint_signature); | ||
597 | } | ||
598 | else | ||
599 | { | ||
600 | posep->setWeight(0.f); | ||
601 | deactivateMotion(motionp); | ||
602 | continue; | ||
603 | } | ||
604 | } | ||
605 | |||
606 | //********************** | ||
607 | // MOTION EASE OUT | ||
608 | //********************** | ||
609 | else if (motionp->isStopped() && mTime > motionp->getStopTime()) | ||
610 | { | ||
611 | // is this the first iteration in the ease out phase? | ||
612 | if (mLastTime <= motionp->getStopTime()) | ||
613 | { | ||
614 | // store residual weight for this motion | ||
615 | motionp->mResidualWeight = motionp->getPose()->getWeight(); | ||
616 | } | ||
617 | |||
618 | if (motionp->getEaseOutDuration() == 0.f) | ||
619 | { | ||
620 | posep->setWeight(0.f); | ||
621 | } | ||
622 | else | ||
623 | { | ||
624 | posep->setWeight(motionp->getFadeWeight() * motionp->mResidualWeight * cubic_step(1.f - ((mTime - motionp->getStopTime()) / motionp->getEaseOutDuration()))); | ||
625 | } | ||
626 | |||
627 | // perform motion update | ||
628 | update_result = motionp->onUpdate(mTime - motionp->mActivationTimestamp, last_joint_signature); | ||
629 | } | ||
630 | |||
631 | //********************** | ||
632 | // MOTION ACTIVE | ||
633 | //********************** | ||
634 | else if (mTime > motionp->mActivationTimestamp + motionp->getEaseInDuration()) | ||
635 | { | ||
636 | posep->setWeight(motionp->getFadeWeight()); | ||
637 | |||
638 | //should we notify the simulator that this motion should be stopped? | ||
639 | if (mTime > motionp->mSendStopTimestamp) | ||
640 | { | ||
641 | // notify character of timed stop event on first iteration past sendstoptimestamp | ||
642 | // this will only be called when an animation stops itself (runs out of time) | ||
643 | if (mLastTime <= motionp->mSendStopTimestamp) | ||
644 | { | ||
645 | mCharacter->requestStopMotion( motionp ); | ||
646 | stopMotionLocally(motionp->getID(), FALSE); | ||
647 | } | ||
648 | } | ||
649 | |||
650 | // perform motion update | ||
651 | update_result = motionp->onUpdate(mTime - motionp->mActivationTimestamp, last_joint_signature); | ||
652 | } | ||
653 | |||
654 | //********************** | ||
655 | // MOTION EASE IN | ||
656 | //********************** | ||
657 | else if (mTime >= motionp->mActivationTimestamp) | ||
658 | { | ||
659 | if (mLastTime < motionp->mActivationTimestamp) | ||
660 | { | ||
661 | motionp->mResidualWeight = motionp->getPose()->getWeight(); | ||
662 | } | ||
663 | if (motionp->getEaseInDuration() == 0.f) | ||
664 | { | ||
665 | posep->setWeight(motionp->getFadeWeight()); | ||
666 | } | ||
667 | else | ||
668 | { | ||
669 | // perform motion update | ||
670 | posep->setWeight(motionp->getFadeWeight() * motionp->mResidualWeight + (1.f - motionp->mResidualWeight) * cubic_step((mTime - motionp->mActivationTimestamp) / motionp->getEaseInDuration())); | ||
671 | } | ||
672 | // perform motion update | ||
673 | update_result = motionp->onUpdate(mTime - motionp->mActivationTimestamp, last_joint_signature); | ||
674 | } | ||
675 | else | ||
676 | { | ||
677 | posep->setWeight(0.f); | ||
678 | update_result = motionp->onUpdate(0.f, last_joint_signature); | ||
679 | } | ||
680 | |||
681 | // allow motions to deactivate themselves | ||
682 | if (!update_result) | ||
683 | { | ||
684 | if (!motionp->isStopped() || motionp->getStopTime() > mTime) | ||
685 | { | ||
686 | // animation has stopped itself due to internal logic | ||
687 | // propagate this to the network | ||
688 | // as not all viewers are guaranteed to have access to the same logic | ||
689 | mCharacter->requestStopMotion( motionp ); | ||
690 | stopMotionLocally(motionp->getID(), FALSE); | ||
691 | } | ||
692 | |||
693 | } | ||
694 | |||
695 | // even if onupdate returns FALSE, add this motion in to the blend one last time | ||
696 | mPoseBlender.addMotion(motionp); | ||
697 | } | ||
698 | } | ||
699 | |||
700 | |||
701 | //----------------------------------------------------------------------------- | ||
702 | // updateMotion() | ||
703 | //----------------------------------------------------------------------------- | ||
704 | void LLMotionController::updateMotion() | ||
705 | { | ||
706 | BOOL use_quantum = (mTimeStep != 0.f); | ||
707 | |||
708 | // Update timing info for this time step. | ||
709 | if (!mPaused) | ||
710 | { | ||
711 | F32 update_time = mTimeOffset + (mTimer.getElapsedTimeF32() * mTimeFactor); | ||
712 | if (use_quantum) | ||
713 | { | ||
714 | F32 time_interval = fmodf(update_time, mTimeStep); | ||
715 | |||
716 | // always animate *ahead* of actual time | ||
717 | S32 quantum_count = llmax(0, llfloor((update_time - time_interval) / mTimeStep)) + 1; | ||
718 | if (quantum_count == mTimeStepCount) | ||
719 | { | ||
720 | // we're still in same time quantum as before, so just interpolate and exit | ||
721 | if (!mPaused) | ||
722 | { | ||
723 | F32 interp = time_interval / mTimeStep; | ||
724 | mPoseBlender.interpolate(interp - mLastInterp); | ||
725 | mLastInterp = interp; | ||
726 | } | ||
727 | |||
728 | return; | ||
729 | } | ||
730 | |||
731 | // is calculating a new keyframe pose, make sure the last one gets applied | ||
732 | mPoseBlender.interpolate(1.f); | ||
733 | mPoseBlender.clearBlenders(); | ||
734 | |||
735 | mTimeStepCount = quantum_count; | ||
736 | mLastTime = mTime; | ||
737 | mTime = (F32)quantum_count * mTimeStep; | ||
738 | mLastInterp = 0.f; | ||
739 | } | ||
740 | else | ||
741 | { | ||
742 | mLastTime = mTime; | ||
743 | mTime = update_time; | ||
744 | } | ||
745 | } | ||
746 | |||
747 | // query pending motions for completion | ||
748 | LLMotion* motionp; | ||
749 | |||
750 | for ( motionp = mLoadingMotions.getFirstData(); | ||
751 | motionp != NULL; | ||
752 | motionp = mLoadingMotions.getNextData() ) | ||
753 | { | ||
754 | LLMotion::LLMotionInitStatus status = motionp->onInitialize(mCharacter); | ||
755 | if (status == LLMotion::STATUS_SUCCESS) | ||
756 | { | ||
757 | mLoadingMotions.removeCurrentData(); | ||
758 | // add motion to our loaded motion list | ||
759 | addLoadedMotion(motionp); | ||
760 | // this motion should be playing | ||
761 | if (!motionp->isStopped()) | ||
762 | { | ||
763 | activateMotion(motionp, mTime); | ||
764 | } | ||
765 | } | ||
766 | else if (status == LLMotion::STATUS_FAILURE) | ||
767 | { | ||
768 | llinfos << "Motion " << motionp->getID() << " init failed." << llendl; | ||
769 | sRegistry.markBad(motionp->getID()); | ||
770 | mLoadingMotions.removeCurrentData(); | ||
771 | mAllMotions.erase(motionp->getID()); | ||
772 | delete motionp; | ||
773 | } | ||
774 | } | ||
775 | |||
776 | resetJointSignatures(); | ||
777 | |||
778 | if (!mPaused) | ||
779 | { | ||
780 | // update additive motions | ||
781 | updateAdditiveMotions(); | ||
782 | resetJointSignatures(); | ||
783 | |||
784 | // update all regular motions | ||
785 | updateRegularMotions(); | ||
786 | |||
787 | if (use_quantum) | ||
788 | { | ||
789 | mPoseBlender.blendAndCache(TRUE); | ||
790 | } | ||
791 | else | ||
792 | { | ||
793 | mPoseBlender.blendAndApply(); | ||
794 | } | ||
795 | } | ||
796 | |||
797 | mHasRunOnce = TRUE; | ||
798 | // llinfos << "Motion controller time " << motionTimer.getElapsedTimeF32() << llendl; | ||
799 | } | ||
800 | |||
801 | |||
802 | //----------------------------------------------------------------------------- | ||
803 | // activateMotion() | ||
804 | //----------------------------------------------------------------------------- | ||
805 | BOOL LLMotionController::activateMotion(LLMotion *motion, F32 time) | ||
806 | { | ||
807 | if (mLoadingMotions.checkData(motion)) | ||
808 | { | ||
809 | // we want to start this motion, but we can't yet, so flag it as started | ||
810 | motion->setStopped(FALSE); | ||
811 | // report pending animations as activated | ||
812 | return TRUE; | ||
813 | } | ||
814 | |||
815 | motion->mResidualWeight = motion->getPose()->getWeight(); | ||
816 | motion->mActivationTimestamp = time; | ||
817 | |||
818 | // set stop time based on given duration and ease out time | ||
819 | if (motion->getDuration() != 0.f && !motion->getLoop()) | ||
820 | { | ||
821 | F32 ease_out_time; | ||
822 | F32 motion_duration; | ||
823 | |||
824 | // should we stop at the end of motion duration, or a bit earlier | ||
825 | // to allow it to ease out while moving? | ||
826 | ease_out_time = motion->getEaseOutDuration(); | ||
827 | |||
828 | // is the clock running when the motion is easing in? | ||
829 | // if not (POSTURE_EASE) then we need to wait that much longer before triggering the stop | ||
830 | motion_duration = llmax(motion->getDuration() - ease_out_time, 0.f); | ||
831 | motion->mSendStopTimestamp = time + motion_duration; | ||
832 | } | ||
833 | else | ||
834 | { | ||
835 | motion->mSendStopTimestamp = F32_MAX; | ||
836 | } | ||
837 | |||
838 | mActiveMotions.addData(motion); | ||
839 | |||
840 | motion->activate(); | ||
841 | motion->onUpdate(0.f, mJointSignature[1]); | ||
842 | |||
843 | return TRUE; | ||
844 | } | ||
845 | |||
846 | //----------------------------------------------------------------------------- | ||
847 | // deactivateMotion() | ||
848 | //----------------------------------------------------------------------------- | ||
849 | BOOL LLMotionController::deactivateMotion(LLMotion *motion) | ||
850 | { | ||
851 | motion->deactivate(); | ||
852 | mActiveMotions.removeData(motion); | ||
853 | |||
854 | return TRUE; | ||
855 | } | ||
856 | |||
857 | //----------------------------------------------------------------------------- | ||
858 | // isMotionActive() | ||
859 | //----------------------------------------------------------------------------- | ||
860 | BOOL LLMotionController::isMotionActive(LLMotion *motion) | ||
861 | { | ||
862 | if (motion && motion->isActive()) | ||
863 | { | ||
864 | return TRUE; | ||
865 | } | ||
866 | |||
867 | return FALSE; | ||
868 | } | ||
869 | |||
870 | //----------------------------------------------------------------------------- | ||
871 | // isMotionLoading() | ||
872 | //----------------------------------------------------------------------------- | ||
873 | BOOL LLMotionController::isMotionLoading(LLMotion* motion) | ||
874 | { | ||
875 | return mLoadingMotions.checkData(motion); | ||
876 | } | ||
877 | |||
878 | |||
879 | //----------------------------------------------------------------------------- | ||
880 | // findMotion() | ||
881 | //----------------------------------------------------------------------------- | ||
882 | LLMotion *LLMotionController::findMotion(const LLUUID& id) | ||
883 | { | ||
884 | return mAllMotions[id]; | ||
885 | } | ||
886 | |||
887 | |||
888 | //----------------------------------------------------------------------------- | ||
889 | // flushAllMotions() | ||
890 | //----------------------------------------------------------------------------- | ||
891 | void LLMotionController::flushAllMotions() | ||
892 | { | ||
893 | LLDynamicArray<LLUUID> active_motions; | ||
894 | LLDynamicArray<F32> active_motion_times; | ||
895 | |||
896 | for (LLMotion* motionp = mActiveMotions.getFirstData(); | ||
897 | motionp; | ||
898 | motionp = mActiveMotions.getNextData()) | ||
899 | { | ||
900 | active_motions.put(motionp->getID()); | ||
901 | active_motion_times.put(mTime - motionp->mActivationTimestamp); | ||
902 | motionp->deactivate(); | ||
903 | } | ||
904 | |||
905 | // delete all motion instances | ||
906 | deleteAllMotions(); | ||
907 | |||
908 | // kill current hand pose that was previously called out by | ||
909 | // keyframe motion | ||
910 | mCharacter->removeAnimationData("Hand Pose"); | ||
911 | |||
912 | // restart motions | ||
913 | for (S32 i = 0; i < active_motions.count(); i++) | ||
914 | { | ||
915 | startMotion(active_motions[i], active_motion_times[i]); | ||
916 | } | ||
917 | } | ||
918 | |||
919 | //----------------------------------------------------------------------------- | ||
920 | // pause() | ||
921 | //----------------------------------------------------------------------------- | ||
922 | void LLMotionController::pause() | ||
923 | { | ||
924 | if (!mPaused) | ||
925 | { | ||
926 | //llinfos << "Pausing animations..." << llendl; | ||
927 | mPauseTime = mTimer.getElapsedTimeF32(); | ||
928 | mPaused = TRUE; | ||
929 | } | ||
930 | |||
931 | } | ||
932 | |||
933 | //----------------------------------------------------------------------------- | ||
934 | // unpause() | ||
935 | //----------------------------------------------------------------------------- | ||
936 | void LLMotionController::unpause() | ||
937 | { | ||
938 | if (mPaused) | ||
939 | { | ||
940 | //llinfos << "Unpausing animations..." << llendl; | ||
941 | mTimer.reset(); | ||
942 | mTimer.setAge(mPauseTime); | ||
943 | mPaused = FALSE; | ||
944 | } | ||
945 | } | ||
946 | // End | ||