aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcharacter/llbvhloader.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcharacter/llbvhloader.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llcharacter/llbvhloader.cpp')
-rw-r--r--linden/indra/llcharacter/llbvhloader.cpp1508
1 files changed, 1508 insertions, 0 deletions
diff --git a/linden/indra/llcharacter/llbvhloader.cpp b/linden/indra/llcharacter/llbvhloader.cpp
new file mode 100644
index 0000000..6aa430f
--- /dev/null
+++ b/linden/indra/llcharacter/llbvhloader.cpp
@@ -0,0 +1,1508 @@
1/**
2 * @file llbvhloader.cpp
3 * @brief Translates a BVH files to LindenLabAnimation format.
4 *
5 * Copyright (c) 2004-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#include "linden_common.h"
29
30#include "llbvhloader.h"
31#include "lldatapacker.h"
32#include "lldir.h"
33#include "llkeyframemotion.h"
34#include "llquantize.h"
35#include "llstl.h"
36#include "llapr.h"
37
38#include <stdio.h>
39#include <string.h>
40#include <stdarg.h>
41#include <llquaternion.h>
42#include <boost/tokenizer.hpp>
43
44using namespace std;
45
46#define INCHES_TO_METERS 0.02540005f
47
48const F32 POSITION_KEYFRAME_THRESHOLD = 0.03f;
49const F32 ROTATION_KEYFRAME_THRESHOLD = 0.01f;
50
51const F32 POSITION_MOTION_THRESHOLD = 0.001f;
52const F32 ROTATION_MOTION_THRESHOLD = 0.001f;
53
54char gInFile[1024]; /* Flawfinder: ignore */
55char gOutFile[1024]; /* Flawfinder: ignore */
56
57//------------------------------------------------------------------------
58// Status Codes
59//------------------------------------------------------------------------
60char *LLBVHLoader::ST_OK = "Ok";
61char *LLBVHLoader::ST_EOF = "Premature end of file.";
62char *LLBVHLoader::ST_NO_CONSTRAINT = "Can't read constraint definition.";
63char *LLBVHLoader::ST_NO_FILE = "Can't open BVH file.";
64char *LLBVHLoader::ST_NO_HIER = "Invalid HIERARCHY header.";
65char *LLBVHLoader::ST_NO_JOINT = "Can't find ROOT or JOINT.";
66char *LLBVHLoader::ST_NO_NAME = "Can't get JOINT name.";
67char *LLBVHLoader::ST_NO_OFFSET = "Can't find OFFSET.";
68char *LLBVHLoader::ST_NO_CHANNELS = "Can't find CHANNELS.";
69char *LLBVHLoader::ST_NO_ROTATION = "Can't get rotation order.";
70char *LLBVHLoader::ST_NO_AXIS = "Can't get rotation axis.";
71char *LLBVHLoader::ST_NO_MOTION = "Can't find MOTION.";
72char *LLBVHLoader::ST_NO_FRAMES = "Can't get number of frames.";
73char *LLBVHLoader::ST_NO_FRAME_TIME = "Can't get frame time.";
74char *LLBVHLoader::ST_NO_POS = "Can't get position values.";
75char *LLBVHLoader::ST_NO_ROT = "Can't get rotation values.";
76char *LLBVHLoader::ST_NO_XLT_FILE = "Can't open translation file.";
77char *LLBVHLoader::ST_NO_XLT_HEADER = "Can't read translation header.";
78char *LLBVHLoader::ST_NO_XLT_NAME = "Can't read translation names.";
79char *LLBVHLoader::ST_NO_XLT_IGNORE = "Can't read translation ignore value.";
80char *LLBVHLoader::ST_NO_XLT_RELATIVE = "Can't read translation relative value.";
81char *LLBVHLoader::ST_NO_XLT_OUTNAME = "Can't read translation outname value.";
82char *LLBVHLoader::ST_NO_XLT_MATRIX = "Can't read translation matrix.";
83char *LLBVHLoader::ST_NO_XLT_MERGECHILD = "Can't get mergechild name.";
84char *LLBVHLoader::ST_NO_XLT_MERGEPARENT = "Can't get mergeparent name.";
85char *LLBVHLoader::ST_NO_XLT_PRIORITY = "Can't get priority value.";
86char *LLBVHLoader::ST_NO_XLT_LOOP = "Can't get loop value.";
87char *LLBVHLoader::ST_NO_XLT_EASEIN = "Can't get easeIn values.";
88char *LLBVHLoader::ST_NO_XLT_EASEOUT = "Can't get easeOut values.";
89char *LLBVHLoader::ST_NO_XLT_HAND = "Can't get hand morph value.";
90char *LLBVHLoader::ST_NO_XLT_EMOTE = "Can't read emote name.";
91
92//------------------------------------------------------------------------
93// find_next_whitespace()
94//------------------------------------------------------------------------
95const char *find_next_whitespace(const char *p)
96{
97 while(*p && isspace(*p)) p++;
98 while(*p && !isspace(*p)) p++;
99 return p;
100}
101
102
103//------------------------------------------------------------------------
104// bvhStringToOrder()
105//
106// XYZ order in BVH files must be passed to mayaQ() as ZYX.
107// This function reverses the input string before passing it on
108// to StringToOrder().
109//------------------------------------------------------------------------
110LLQuaternion::Order bvhStringToOrder( char *str )
111{
112 char order[4]; /* Flawfinder: ignore */
113 order[0] = str[2];
114 order[1] = str[1];
115 order[2] = str[0];
116 order[3] = 0;
117 LLQuaternion::Order retVal = StringToOrder( order );
118 return retVal;
119}
120
121//-----------------------------------------------------------------------------
122// LLBVHLoader()
123//-----------------------------------------------------------------------------
124LLBVHLoader::LLBVHLoader(const char* buffer)
125{
126 reset();
127
128 mStatus = loadTranslationTable("anim.ini");
129
130 if (mStatus == LLBVHLoader::ST_NO_XLT_FILE)
131 {
132 llwarns << "NOTE: No translation table found." << llendl;
133 return;
134 }
135 else
136 {
137 if (mStatus != LLBVHLoader::ST_OK)
138 {
139 llwarns << "ERROR: [line: " << getLineNumber() << "] " << mStatus << llendl;
140 return;
141 }
142 }
143
144 char error_text[128]; /* Flawfinder: ignore */
145 S32 error_line;
146 mStatus = loadBVHFile(buffer, error_text, error_line);
147 if (mStatus != LLBVHLoader::ST_OK)
148 {
149 llwarns << "ERROR: [line: " << getLineNumber() << "] " << mStatus << llendl;
150 return;
151 }
152
153 applyTranslations();
154 optimize();
155
156 mInitialized = TRUE;
157}
158
159LLBVHLoader::~LLBVHLoader()
160{
161 std::for_each(mJoints.begin(),mJoints.end(),DeletePointer());
162}
163
164//------------------------------------------------------------------------
165// LLBVHLoader::loadTranslationTable()
166//------------------------------------------------------------------------
167LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName)
168{
169 mLineNumber = 0;
170 mTranslations.clear();
171 mConstraints.clear();
172
173 //--------------------------------------------------------------------
174 // open file
175 //--------------------------------------------------------------------
176 char path[LL_MAX_PATH]; /* Flawfinder: ignore */
177
178 snprintf( path, sizeof(path), "%s",
179 gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName).c_str()); /* Flawfinder: ignore */
180
181
182 apr_file_t *fp = ll_apr_file_open(path, LL_APR_R);
183 if (!fp)
184 return ST_NO_XLT_FILE;
185
186 llinfos << "NOTE: Loading translation table: " << fileName << llendl;
187
188 //--------------------------------------------------------------------
189 // register file to be closed on function exit
190 //--------------------------------------------------------------------
191 FileCloser fileCloser(fp);
192
193 //--------------------------------------------------------------------
194 // load header
195 //--------------------------------------------------------------------
196 if ( ! getLine(fp) )
197 return ST_EOF;
198 if ( strncmp(mLine, "Translations 1.0", 16) )
199 return ST_NO_XLT_HEADER;
200
201 //--------------------------------------------------------------------
202 // load data one line at a time
203 //--------------------------------------------------------------------
204 BOOL loadingGlobals = FALSE;
205 Translation *trans = NULL;
206 while ( getLine(fp) )
207 {
208 //----------------------------------------------------------------
209 // check the 1st token on the line to determine if it's empty or a comment
210 //----------------------------------------------------------------
211 char token[128]; /* Flawfinder: ignore */
212 if ( sscanf(mLine, " %127s", token) != 1 )
213 continue;
214
215 if (token[0] == '#')
216 continue;
217
218 //----------------------------------------------------------------
219 // check if a [jointName] or [GLOBALS] was specified.
220 //----------------------------------------------------------------
221 if (token[0] == '[')
222 {
223 char name[128]; /* Flawfinder: ignore */
224 if ( sscanf(mLine, " [%127[^]]", name) != 1 )
225 return ST_NO_XLT_NAME;
226
227 if (strcmp(name, "GLOBALS")==0)
228 {
229 loadingGlobals = TRUE;
230 continue;
231 }
232 else
233 {
234 loadingGlobals = FALSE;
235 Translation &newTrans = mTranslations[ name ];
236 trans = &newTrans;
237 continue;
238 }
239 }
240
241 //----------------------------------------------------------------
242 // check for optional emote
243 //----------------------------------------------------------------
244 if (loadingGlobals && LLString::compareInsensitive(token, "emote")==0)
245 {
246 char emote_str[1024]; /* Flawfinder: ignore */
247 if ( sscanf(mLine, " %*s = %1023s", emote_str) != 1 )
248 return ST_NO_XLT_EMOTE;
249
250 mEmoteName.assign( emote_str );
251// llinfos << "NOTE: Emote: " << mEmoteName.c_str() << llendl;
252 continue;
253 }
254
255
256 //----------------------------------------------------------------
257 // check for global priority setting
258 //----------------------------------------------------------------
259 if (loadingGlobals && LLString::compareInsensitive(token, "priority")==0)
260 {
261 S32 priority;
262 if ( sscanf(mLine, " %*s = %d", &priority) != 1 )
263 return ST_NO_XLT_PRIORITY;
264
265 mPriority = priority;
266// llinfos << "NOTE: Priority: " << mPriority << llendl;
267 continue;
268 }
269
270 //----------------------------------------------------------------
271 // check for global loop setting
272 //----------------------------------------------------------------
273 if (loadingGlobals && LLString::compareInsensitive(token, "loop")==0)
274 {
275 char trueFalse[128]; /* Flawfinder: ignore */
276 trueFalse[0] = '\0';
277
278 F32 loop_in = 0.f;
279 F32 loop_out = 1.f;
280
281 if ( sscanf(mLine, " %*s = %f %f", &loop_in, &loop_out) == 2 )
282 {
283 mLoop = TRUE;
284 }
285 else if ( sscanf(mLine, " %*s = %127s", trueFalse) == 1 )
286 {
287 mLoop = (LLString::compareInsensitive(trueFalse, "true")==0);
288 }
289 else
290 {
291 return ST_NO_XLT_LOOP;
292 }
293
294 mLoopInPoint = loop_in * mDuration;
295 mLoopOutPoint = loop_out * mDuration;
296
297 continue;
298 }
299
300 //----------------------------------------------------------------
301 // check for global easeIn setting
302 //----------------------------------------------------------------
303 if (loadingGlobals && LLString::compareInsensitive(token, "easein")==0)
304 {
305 F32 duration;
306 char type[128]; /* Flawfinder: ignore */
307 if ( sscanf(mLine, " %*s = %f %127s", &duration, type) != 2 )
308 return ST_NO_XLT_EASEIN;
309
310 mEaseIn = duration;
311 continue;
312 }
313
314 //----------------------------------------------------------------
315 // check for global easeOut setting
316 //----------------------------------------------------------------
317 if (loadingGlobals && LLString::compareInsensitive(token, "easeout")==0)
318 {
319 F32 duration;
320 char type[128];
321 if ( sscanf(mLine, " %*s = %f %127s", &duration, type) != 2 )
322 return ST_NO_XLT_EASEOUT;
323
324 mEaseOut = duration;
325 continue;
326 }
327
328 //----------------------------------------------------------------
329 // check for global handMorph setting
330 //----------------------------------------------------------------
331 if (loadingGlobals && LLString::compareInsensitive(token, "hand")==0)
332 {
333 S32 handMorph;
334 if (sscanf(mLine, " %*s = %d", &handMorph) != 1)
335 return ST_NO_XLT_HAND;
336
337 mHand = handMorph;
338 continue;
339 }
340
341 if (loadingGlobals && LLString::compareInsensitive(token, "constraint")==0)
342 {
343 Constraint constraint;
344
345 // try reading optional target direction
346 if(sscanf(
347 mLine,
348 " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f %f %f %f",
349 &constraint.mChainLength,
350 &constraint.mEaseInStart,
351 &constraint.mEaseInStop,
352 &constraint.mEaseOutStart,
353 &constraint.mEaseOutStop,
354 constraint.mSourceJointName,
355 &constraint.mSourceOffset.mV[VX],
356 &constraint.mSourceOffset.mV[VY],
357 &constraint.mSourceOffset.mV[VZ],
358 constraint.mTargetJointName,
359 &constraint.mTargetOffset.mV[VX],
360 &constraint.mTargetOffset.mV[VY],
361 &constraint.mTargetOffset.mV[VZ],
362 &constraint.mTargetDir.mV[VX],
363 &constraint.mTargetDir.mV[VY],
364 &constraint.mTargetDir.mV[VZ]) != 16)
365 {
366 if(sscanf(
367 mLine,
368 " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f",
369 &constraint.mChainLength,
370 &constraint.mEaseInStart,
371 &constraint.mEaseInStop,
372 &constraint.mEaseOutStart,
373 &constraint.mEaseOutStop,
374 constraint.mSourceJointName,
375 &constraint.mSourceOffset.mV[VX],
376 &constraint.mSourceOffset.mV[VY],
377 &constraint.mSourceOffset.mV[VZ],
378 constraint.mTargetJointName,
379 &constraint.mTargetOffset.mV[VX],
380 &constraint.mTargetOffset.mV[VY],
381 &constraint.mTargetOffset.mV[VZ]) != 13)
382 {
383 return ST_NO_CONSTRAINT;
384 }
385 }
386 else
387 {
388 // normalize direction
389 if (!constraint.mTargetDir.isExactlyZero())
390 {
391 constraint.mTargetDir.normVec();
392 }
393
394 }
395
396 constraint.mConstraintType = CONSTRAINT_TYPE_POINT;
397 mConstraints.push_back(constraint);
398 continue;
399 }
400
401 if (loadingGlobals && LLString::compareInsensitive(token, "planar_constraint")==0)
402 {
403 Constraint constraint;
404
405 // try reading optional target direction
406 if(sscanf(
407 mLine,
408 " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f %f %f %f",
409 &constraint.mChainLength,
410 &constraint.mEaseInStart,
411 &constraint.mEaseInStop,
412 &constraint.mEaseOutStart,
413 &constraint.mEaseOutStop,
414 constraint.mSourceJointName,
415 &constraint.mSourceOffset.mV[VX],
416 &constraint.mSourceOffset.mV[VY],
417 &constraint.mSourceOffset.mV[VZ],
418 constraint.mTargetJointName,
419 &constraint.mTargetOffset.mV[VX],
420 &constraint.mTargetOffset.mV[VY],
421 &constraint.mTargetOffset.mV[VZ],
422 &constraint.mTargetDir.mV[VX],
423 &constraint.mTargetDir.mV[VY],
424 &constraint.mTargetDir.mV[VZ]) != 16)
425 {
426 if(sscanf(
427 mLine,
428 " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f",
429 &constraint.mChainLength,
430 &constraint.mEaseInStart,
431 &constraint.mEaseInStop,
432 &constraint.mEaseOutStart,
433 &constraint.mEaseOutStop,
434 constraint.mSourceJointName,
435 &constraint.mSourceOffset.mV[VX],
436 &constraint.mSourceOffset.mV[VY],
437 &constraint.mSourceOffset.mV[VZ],
438 constraint.mTargetJointName,
439 &constraint.mTargetOffset.mV[VX],
440 &constraint.mTargetOffset.mV[VY],
441 &constraint.mTargetOffset.mV[VZ]) != 13)
442 {
443 return ST_NO_CONSTRAINT;
444 }
445 }
446 else
447 {
448 // normalize direction
449 if (!constraint.mTargetDir.isExactlyZero())
450 {
451 constraint.mTargetDir.normVec();
452 }
453
454 }
455
456 constraint.mConstraintType = CONSTRAINT_TYPE_PLANE;
457 mConstraints.push_back(constraint);
458 continue;
459 }
460
461
462 //----------------------------------------------------------------
463 // at this point there must be a valid trans pointer
464 //----------------------------------------------------------------
465 if ( ! trans )
466 return ST_NO_XLT_NAME;
467
468 //----------------------------------------------------------------
469 // check for ignore flag
470 //----------------------------------------------------------------
471 if ( LLString::compareInsensitive(token, "ignore")==0 )
472 {
473 char trueFalse[128]; /* Flawfinder: ignore */
474 if ( sscanf(mLine, " %*s = %127s", trueFalse) != 1 )
475 return ST_NO_XLT_IGNORE;
476
477 trans->mIgnore = (LLString::compareInsensitive(trueFalse, "true")==0);
478 continue;
479 }
480
481 //----------------------------------------------------------------
482 // check for relativepos flag
483 //----------------------------------------------------------------
484 if ( LLString::compareInsensitive(token, "relativepos")==0 )
485 {
486 F32 x, y, z;
487 char relpos[128]; /* Flawfinder: ignore */
488 if ( sscanf(mLine, " %*s = %f %f %f", &x, &y, &z) == 3 )
489 {
490 trans->mRelativePosition.setVec( x, y, z );
491 }
492 else if ( sscanf(mLine, " %*s = %127s", relpos) == 1 )
493 {
494 if ( LLString::compareInsensitive(relpos, "firstkey")==0 )
495 {
496 trans->mRelativePositionKey = TRUE;
497 }
498 else
499 {
500 return ST_NO_XLT_RELATIVE;
501 }
502 }
503 else
504 {
505 return ST_NO_XLT_RELATIVE;
506 }
507
508 continue;
509 }
510
511 //----------------------------------------------------------------
512 // check for relativerot flag
513 //----------------------------------------------------------------
514 if ( LLString::compareInsensitive(token, "relativerot")==0 )
515 {
516 //F32 x, y, z;
517 char relpos[128]; /* Flawfinder: ignore */
518 if ( sscanf(mLine, " %*s = %127s", relpos) == 1 )
519 {
520 if ( LLString::compareInsensitive(relpos, "firstkey")==0 )
521 {
522 trans->mRelativeRotationKey = TRUE;
523 }
524 else
525 {
526 return ST_NO_XLT_RELATIVE;
527 }
528 }
529 else
530 {
531 return ST_NO_XLT_RELATIVE;
532 }
533
534 continue;
535 }
536
537 //----------------------------------------------------------------
538 // check for outname value
539 //----------------------------------------------------------------
540 if ( LLString::compareInsensitive(token, "outname")==0 )
541 {
542 char outName[128]; /* Flawfinder: ignore */
543 if ( sscanf(mLine, " %*s = %127s", outName) != 1 )
544 return ST_NO_XLT_OUTNAME;
545
546 trans->mOutName = outName;
547 continue;
548 }
549
550 //----------------------------------------------------------------
551 // check for frame matrix value
552 //----------------------------------------------------------------
553 if ( LLString::compareInsensitive(token, "frame")==0 )
554 {
555 LLMatrix3 fm;
556 if ( sscanf(mLine, " %*s = %f %f %f, %f %f %f, %f %f %f",
557 &fm.mMatrix[0][0], &fm.mMatrix[0][1], &fm.mMatrix[0][2],
558 &fm.mMatrix[1][0], &fm.mMatrix[1][1], &fm.mMatrix[1][2],
559 &fm.mMatrix[2][0], &fm.mMatrix[2][1], &fm.mMatrix[2][2] ) != 9 )
560 return ST_NO_XLT_MATRIX;
561
562 trans->mFrameMatrix = fm;
563 continue;
564 }
565
566 //----------------------------------------------------------------
567 // check for offset matrix value
568 //----------------------------------------------------------------
569 if ( LLString::compareInsensitive(token, "offset")==0 )
570 {
571 LLMatrix3 om;
572 if ( sscanf(mLine, " %*s = %f %f %f, %f %f %f, %f %f %f",
573 &om.mMatrix[0][0], &om.mMatrix[0][1], &om.mMatrix[0][2],
574 &om.mMatrix[1][0], &om.mMatrix[1][1], &om.mMatrix[1][2],
575 &om.mMatrix[2][0], &om.mMatrix[2][1], &om.mMatrix[2][2] ) != 9 )
576 return ST_NO_XLT_MATRIX;
577
578 trans->mOffsetMatrix = om;
579 continue;
580 }
581
582 //----------------------------------------------------------------
583 // check for mergeparent value
584 //----------------------------------------------------------------
585 if ( LLString::compareInsensitive(token, "mergeparent")==0 )
586 {
587 char mergeParentName[128]; /* Flawfinder: ignore */
588 if ( sscanf(mLine, " %*s = %127s", mergeParentName) != 1 )
589 return ST_NO_XLT_MERGEPARENT;
590
591 trans->mMergeParentName = mergeParentName;
592 continue;
593 }
594
595 //----------------------------------------------------------------
596 // check for mergechild value
597 //----------------------------------------------------------------
598 if ( LLString::compareInsensitive(token, "mergechild")==0 )
599 {
600 char mergeChildName[128]; /* Flawfinder: ignore */
601 if ( sscanf(mLine, " %*s = %127s", mergeChildName) != 1 )
602 return ST_NO_XLT_MERGECHILD;
603
604 trans->mMergeChildName = mergeChildName;
605 continue;
606 }
607
608 //----------------------------------------------------------------
609 // check for per-joint priority
610 //----------------------------------------------------------------
611 if ( LLString::compareInsensitive(token, "priority")==0 )
612 {
613 S32 priority;
614 if ( sscanf(mLine, " %*s = %d", &priority) != 1 )
615 return ST_NO_XLT_PRIORITY;
616
617 trans->mPriorityModifier = priority;
618 continue;
619 }
620
621 }
622 return ST_OK;
623}
624
625
626//------------------------------------------------------------------------
627// LLBVHLoader::loadBVHFile()
628//------------------------------------------------------------------------
629LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &err_line)
630{
631 std::string line;
632
633 err_line = 0;
634 error_text[127] = '\0';
635
636 std::string str(buffer);
637 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
638 boost::char_separator<char> sep("\r\n");
639 tokenizer tokens(str, sep);
640 tokenizer::iterator iter = tokens.begin();
641
642 mLineNumber = 0;
643 mJoints.clear();
644
645 std::vector<S32> parent_joints;
646
647 //--------------------------------------------------------------------
648 // consume hierarchy
649 //--------------------------------------------------------------------
650 if (iter == tokens.end())
651 return ST_EOF;
652 line = (*(iter++));
653 err_line++;
654
655 if ( !strstr(line.c_str(), "HIERARCHY") )
656 {
657// llinfos << line << llendl;
658 return ST_NO_HIER;
659 }
660
661 //--------------------------------------------------------------------
662 // consume joints
663 //--------------------------------------------------------------------
664 while (TRUE)
665 {
666 //----------------------------------------------------------------
667 // get next line
668 //----------------------------------------------------------------
669 if (iter == tokens.end())
670 return ST_EOF;
671 line = (*(iter++));
672 err_line++;
673
674 //----------------------------------------------------------------
675 // consume }
676 //----------------------------------------------------------------
677 if ( strstr(line.c_str(), "}") )
678 {
679 if (parent_joints.size() > 0)
680 {
681 parent_joints.pop_back();
682 }
683 continue;
684 }
685
686 //----------------------------------------------------------------
687 // if MOTION, break out
688 //----------------------------------------------------------------
689 if ( strstr(line.c_str(), "MOTION") )
690 break;
691
692 //----------------------------------------------------------------
693 // it must be either ROOT or JOINT or EndSite
694 //----------------------------------------------------------------
695 if ( strstr(line.c_str(), "ROOT") )
696 {
697 }
698 else if ( strstr(line.c_str(), "JOINT") )
699 {
700 }
701 else if ( strstr(line.c_str(), "End Site") )
702 {
703 iter++; // {
704 iter++; // OFFSET
705 S32 depth = 0;
706 for (S32 j = (S32)parent_joints.size() - 1; j >= 0; j--)
707 {
708 Joint *joint = mJoints[parent_joints[j]];
709 if (depth > joint->mChildTreeMaxDepth)
710 {
711 joint->mChildTreeMaxDepth = depth;
712 }
713 depth++;
714 }
715 continue;
716 }
717 else
718 {
719 strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */
720 return ST_NO_JOINT;
721 }
722
723 //----------------------------------------------------------------
724 // get the joint name
725 //----------------------------------------------------------------
726 char jointName[80]; /* Flawfinder: ignore */
727 if ( sscanf(line.c_str(), "%*s %79s", jointName) != 1 )
728 {
729 strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */
730 return ST_NO_NAME;
731 }
732
733 //----------------------------------------------------------------
734 // add a set of keyframes for this joint
735 //----------------------------------------------------------------
736 mJoints.push_back( new Joint( jointName ) );
737 Joint *joint = mJoints.back();
738
739 S32 depth = 1;
740 for (S32 j = (S32)parent_joints.size() - 1; j >= 0; j--)
741 {
742 Joint *pjoint = mJoints[parent_joints[j]];
743 if (depth > pjoint->mChildTreeMaxDepth)
744 {
745 pjoint->mChildTreeMaxDepth = depth;
746 }
747 depth++;
748 }
749
750 //----------------------------------------------------------------
751 // get next line
752 //----------------------------------------------------------------
753 if (iter == tokens.end())
754 {
755 return ST_EOF;
756 }
757 line = (*(iter++));
758 err_line++;
759
760 //----------------------------------------------------------------
761 // it must be {
762 //----------------------------------------------------------------
763 if ( !strstr(line.c_str(), "{") )
764 {
765 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
766 return ST_NO_OFFSET;
767 }
768 else
769 {
770 parent_joints.push_back((S32)mJoints.size() - 1);
771 }
772
773 //----------------------------------------------------------------
774 // get next line
775 //----------------------------------------------------------------
776 if (iter == tokens.end())
777 {
778 return ST_EOF;
779 }
780 line = (*(iter++));
781 err_line++;
782
783 //----------------------------------------------------------------
784 // it must be OFFSET
785 //----------------------------------------------------------------
786 if ( !strstr(line.c_str(), "OFFSET") )
787 {
788 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
789 return ST_NO_OFFSET;
790 }
791
792 //----------------------------------------------------------------
793 // get next line
794 //----------------------------------------------------------------
795 if (iter == tokens.end())
796 {
797 return ST_EOF;
798 }
799 line = (*(iter++));
800 err_line++;
801
802 //----------------------------------------------------------------
803 // it must be CHANNELS
804 //----------------------------------------------------------------
805 if ( !strstr(line.c_str(), "CHANNELS") )
806 {
807 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
808 return ST_NO_CHANNELS;
809 }
810
811 //----------------------------------------------------------------
812 // get rotation order
813 //----------------------------------------------------------------
814 const char *p = line.c_str();
815 for (S32 i=0; i<3; i++)
816 {
817 p = strstr(p, "rotation");
818 if (!p)
819 {
820 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
821 return ST_NO_ROTATION;
822 }
823
824 const char axis = *(p - 1);
825 if ((axis != 'X') && (axis != 'Y') && (axis != 'Z'))
826 {
827 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
828 return ST_NO_AXIS;
829 }
830
831 joint->mOrder[i] = axis;
832
833 p++;
834 }
835 }
836
837 //--------------------------------------------------------------------
838 // consume motion
839 //--------------------------------------------------------------------
840 if ( !strstr(line.c_str(), "MOTION") )
841 {
842 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
843 return ST_NO_MOTION;
844 }
845
846 //--------------------------------------------------------------------
847 // get number of frames
848 //--------------------------------------------------------------------
849 if (iter == tokens.end())
850 {
851 return ST_EOF;
852 }
853 line = (*(iter++));
854 err_line++;
855
856 if ( !strstr(line.c_str(), "Frames:") )
857 {
858 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
859 return ST_NO_FRAMES;
860 }
861
862 if ( sscanf(line.c_str(), "Frames: %d", &mNumFrames) != 1 )
863 {
864 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
865 return ST_NO_FRAMES;
866 }
867
868 //--------------------------------------------------------------------
869 // get frame time
870 //--------------------------------------------------------------------
871 if (iter == tokens.end())
872 {
873 return ST_EOF;
874 }
875 line = (*(iter++));
876 err_line++;
877
878 if ( !strstr(line.c_str(), "Frame Time:") )
879 {
880 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
881 return ST_NO_FRAME_TIME;
882 }
883
884 if ( sscanf(line.c_str(), "Frame Time: %f", &mFrameTime) != 1 )
885 {
886 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
887 return ST_NO_FRAME_TIME;
888 }
889
890 mDuration = (F32)mNumFrames * mFrameTime;
891 if (!mLoop)
892 {
893 mLoopOutPoint = mDuration;
894 }
895
896 //--------------------------------------------------------------------
897 // load frames
898 //--------------------------------------------------------------------
899 for (S32 i=0; i<mNumFrames; i++)
900 {
901 // get next line
902 if (iter == tokens.end())
903 {
904 return ST_EOF;
905 }
906 line = (*(iter++));
907 err_line++;
908
909 // read and store values
910 const char *p = line.c_str();
911 for (U32 j=0; j<mJoints.size(); j++)
912 {
913 Joint *joint = mJoints[j];
914 joint->mKeys.push_back( Key() );
915 Key &key = joint->mKeys.back();
916
917 // get 3 pos values for root joint only
918 if (j==0)
919 {
920 if ( sscanf(p, "%f %f %f", key.mPos, key.mPos+1, key.mPos+2) != 3 )
921 {
922 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
923 return ST_NO_POS;
924 }
925 }
926
927 // skip to next 3 values in the line
928 p = find_next_whitespace(p);
929 if (!p)
930 {
931 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
932 return ST_NO_ROT;
933 }
934 p = find_next_whitespace(++p);
935 if (!p)
936 {
937 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
938 return ST_NO_ROT;
939 }
940 p = find_next_whitespace(++p);
941 if (!p)
942 {
943 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
944 return ST_NO_ROT;
945 }
946
947 // get 3 rot values for joint
948 F32 rot[3];
949 if ( sscanf(p, " %f %f %f", rot, rot+1, rot+2) != 3 )
950 {
951 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
952 return ST_NO_ROT;
953 }
954
955 p++;
956
957 key.mRot[ joint->mOrder[0]-'X' ] = rot[0];
958 key.mRot[ joint->mOrder[1]-'X' ] = rot[1];
959 key.mRot[ joint->mOrder[2]-'X' ] = rot[2];
960 }
961 }
962
963 return ST_OK;
964}
965
966
967//------------------------------------------------------------------------
968// LLBVHLoader::applyTranslation()
969//------------------------------------------------------------------------
970void LLBVHLoader::applyTranslations()
971{
972 JointVector::iterator ji;
973 for (ji = mJoints.begin(); ji != mJoints.end(); ++ji )
974 {
975 Joint *joint = *ji;
976 //----------------------------------------------------------------
977 // Look for a translation for this joint.
978 // If none, skip to next joint
979 //----------------------------------------------------------------
980 TranslationMap::iterator ti = mTranslations.find( joint->mName );
981 if ( ti == mTranslations.end() )
982 {
983 continue;
984 }
985
986 Translation &trans = ti->second;
987
988 //----------------------------------------------------------------
989 // Set the ignore flag if necessary
990 //----------------------------------------------------------------
991 if ( trans.mIgnore )
992 {
993 //llinfos << "NOTE: Ignoring " << joint->mName.c_str() << llendl;
994 joint->mIgnore = TRUE;
995 continue;
996 }
997
998 //----------------------------------------------------------------
999 // Set the output name
1000 //----------------------------------------------------------------
1001 if ( ! trans.mOutName.empty() )
1002 {
1003 //llinfos << "NOTE: Changing " << joint->mName.c_str() << " to " << trans.mOutName.c_str() << llendl;
1004 joint->mOutName = trans.mOutName;
1005 }
1006
1007 //----------------------------------------------------------------
1008 // Set the ignorepos flag if necessary
1009 //----------------------------------------------------------------
1010 if ( joint->mOutName == std::string("mPelvis") )
1011 {
1012 joint->mIgnorePositions = FALSE;
1013 }
1014
1015 //----------------------------------------------------------------
1016 // Set the relativepos flags if necessary
1017 //----------------------------------------------------------------
1018 if ( trans.mRelativePositionKey )
1019 {
1020// llinfos << "NOTE: Removing 1st position offset from all keys for " << joint->mOutName.c_str() << llendl;
1021 joint->mRelativePositionKey = TRUE;
1022 }
1023
1024 if ( trans.mRelativeRotationKey )
1025 {
1026// llinfos << "NOTE: Removing 1st rotation from all keys for " << joint->mOutName.c_str() << llendl;
1027 joint->mRelativeRotationKey = TRUE;
1028 }
1029
1030 if ( trans.mRelativePosition.magVec() > 0.0f )
1031 {
1032 joint->mRelativePosition = trans.mRelativePosition;
1033// llinfos << "NOTE: Removing " <<
1034// joint->mRelativePosition.mV[0] << " " <<
1035// joint->mRelativePosition.mV[1] << " " <<
1036// joint->mRelativePosition.mV[2] <<
1037// " from all position keys in " <<
1038// joint->mOutName.c_str() << llendl;
1039 }
1040
1041 //----------------------------------------------------------------
1042 // Set change of coordinate frame
1043 //----------------------------------------------------------------
1044 joint->mFrameMatrix = trans.mFrameMatrix;
1045 joint->mOffsetMatrix = trans.mOffsetMatrix;
1046
1047 //----------------------------------------------------------------
1048 // Set mergeparent name
1049 //----------------------------------------------------------------
1050 if ( ! trans.mMergeParentName.empty() )
1051 {
1052// llinfos << "NOTE: Merging " << joint->mOutName.c_str() <<
1053// " with parent " <<
1054// trans.mMergeParentName.c_str() << llendl;
1055 joint->mMergeParentName = trans.mMergeParentName;
1056 }
1057
1058 //----------------------------------------------------------------
1059 // Set mergechild name
1060 //----------------------------------------------------------------
1061 if ( ! trans.mMergeChildName.empty() )
1062 {
1063// llinfos << "NOTE: Merging " << joint->mName.c_str() <<
1064// " with child " << trans.mMergeChildName.c_str() << llendl;
1065 joint->mMergeChildName = trans.mMergeChildName;
1066 }
1067
1068 //----------------------------------------------------------------
1069 // Set joint priority
1070 //----------------------------------------------------------------
1071 joint->mPriority = mPriority + trans.mPriorityModifier;
1072
1073 }
1074}
1075
1076//-----------------------------------------------------------------------------
1077// LLBVHLoader::optimize()
1078//-----------------------------------------------------------------------------
1079void LLBVHLoader::optimize()
1080{
1081 //RN: assumes motion blend, which is the default now
1082 if (!mLoop && mEaseIn + mEaseOut > mDuration && mDuration != 0.f)
1083 {
1084 F32 factor = mDuration / (mEaseIn + mEaseOut);
1085 mEaseIn *= factor;
1086 mEaseOut *= factor;
1087 }
1088
1089 JointVector::iterator ji;
1090 for (ji = mJoints.begin(); ji != mJoints.end(); ++ji)
1091 {
1092 Joint *joint = *ji;
1093 BOOL pos_changed = FALSE;
1094 BOOL rot_changed = FALSE;
1095
1096 if ( ! joint->mIgnore )
1097 {
1098 joint->mNumPosKeys = 0;
1099 joint->mNumRotKeys = 0;
1100 LLQuaternion::Order order = bvhStringToOrder( joint->mOrder );
1101
1102 KeyVector::iterator first_key = joint->mKeys.begin();
1103
1104 // no keys?
1105 if (first_key == joint->mKeys.end())
1106 {
1107 joint->mIgnore = TRUE;
1108 continue;
1109 }
1110
1111 LLVector3 first_frame_pos(first_key->mPos);
1112 LLQuaternion first_frame_rot = mayaQ( first_key->mRot[0], first_key->mRot[1], first_key->mRot[2], order);
1113
1114 // skip first key
1115 KeyVector::iterator ki = joint->mKeys.begin();
1116 if (joint->mKeys.size() == 1)
1117 {
1118 // *FIX: use single frame to move pelvis
1119 // if only one keyframe force output for this joint
1120 rot_changed = TRUE;
1121 }
1122 else
1123 {
1124 // if more than one keyframe, use first frame as reference and skip to second
1125 first_key->mIgnorePos = TRUE;
1126 first_key->mIgnoreRot = TRUE;
1127 ++ki;
1128 }
1129
1130 KeyVector::iterator ki_prev = ki;
1131 KeyVector::iterator ki_last_good_pos = ki;
1132 KeyVector::iterator ki_last_good_rot = ki;
1133 S32 numPosFramesConsidered = 2;
1134 S32 numRotFramesConsidered = 2;
1135
1136 F32 rot_threshold = ROTATION_KEYFRAME_THRESHOLD / llmax((F32)joint->mChildTreeMaxDepth * 0.33f, 1.f);
1137
1138 for (; ki != joint->mKeys.end(); ++ki)
1139 {
1140 if (ki_prev == ki_last_good_pos)
1141 {
1142 joint->mNumPosKeys++;
1143 if (dist_vec(LLVector3(ki_prev->mPos), first_frame_pos) > POSITION_MOTION_THRESHOLD)
1144 {
1145 pos_changed = TRUE;
1146 }
1147 }
1148 else
1149 {
1150 //check position for noticeable effect
1151 LLVector3 test_pos(ki_prev->mPos);
1152 LLVector3 last_good_pos(ki_last_good_pos->mPos);
1153 LLVector3 current_pos(ki->mPos);
1154 LLVector3 interp_pos = lerp(current_pos, last_good_pos, 1.f / (F32)numPosFramesConsidered);
1155
1156 if (dist_vec(current_pos, first_frame_pos) > POSITION_MOTION_THRESHOLD)
1157 {
1158 pos_changed = TRUE;
1159 }
1160
1161 if (dist_vec(interp_pos, test_pos) < POSITION_KEYFRAME_THRESHOLD)
1162 {
1163 ki_prev->mIgnorePos = TRUE;
1164 numPosFramesConsidered++;
1165 }
1166 else
1167 {
1168 numPosFramesConsidered = 2;
1169 ki_last_good_pos = ki_prev;
1170 joint->mNumPosKeys++;
1171 }
1172 }
1173
1174 if (ki_prev == ki_last_good_rot)
1175 {
1176 joint->mNumRotKeys++;
1177 LLQuaternion test_rot = mayaQ( ki_prev->mRot[0], ki_prev->mRot[1], ki_prev->mRot[2], order);
1178 F32 x_delta = dist_vec(LLVector3::x_axis * first_frame_rot, LLVector3::x_axis * test_rot);
1179 F32 y_delta = dist_vec(LLVector3::y_axis * first_frame_rot, LLVector3::y_axis * test_rot);
1180 F32 rot_test = x_delta + y_delta;
1181
1182 if (rot_test > ROTATION_MOTION_THRESHOLD)
1183 {
1184 rot_changed = TRUE;
1185 }
1186 }
1187 else
1188 {
1189 //check rotation for noticeable effect
1190 LLQuaternion test_rot = mayaQ( ki_prev->mRot[0], ki_prev->mRot[1], ki_prev->mRot[2], order);
1191 LLQuaternion last_good_rot = mayaQ( ki_last_good_rot->mRot[0], ki_last_good_rot->mRot[1], ki_last_good_rot->mRot[2], order);
1192 LLQuaternion current_rot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order);
1193 LLQuaternion interp_rot = lerp(1.f / (F32)numRotFramesConsidered, current_rot, last_good_rot);
1194
1195 F32 x_delta;
1196 F32 y_delta;
1197 F32 rot_test;
1198
1199 x_delta = dist_vec(LLVector3::x_axis * first_frame_rot, LLVector3::x_axis * test_rot);
1200 y_delta = dist_vec(LLVector3::y_axis * first_frame_rot, LLVector3::y_axis * test_rot);
1201 rot_test = x_delta + y_delta;
1202
1203 if (rot_test > ROTATION_MOTION_THRESHOLD)
1204 {
1205 rot_changed = TRUE;
1206 }
1207
1208 x_delta = dist_vec(LLVector3::x_axis * interp_rot, LLVector3::x_axis * test_rot);
1209 y_delta = dist_vec(LLVector3::y_axis * interp_rot, LLVector3::y_axis * test_rot);
1210 rot_test = x_delta + y_delta;
1211
1212 if (rot_test < rot_threshold)
1213 {
1214 ki_prev->mIgnoreRot = TRUE;
1215 numRotFramesConsidered++;
1216 }
1217 else
1218 {
1219 numRotFramesConsidered = 2;
1220 ki_last_good_rot = ki_prev;
1221 joint->mNumRotKeys++;
1222 }
1223 }
1224
1225 ki_prev = ki;
1226 }
1227 }
1228
1229 // don't output joints with no motion
1230 if (!(pos_changed || rot_changed))
1231 {
1232 //llinfos << "Ignoring joint " << joint->mName << llendl;
1233 joint->mIgnore = TRUE;
1234 }
1235 }
1236}
1237
1238void LLBVHLoader::reset()
1239{
1240 mLineNumber = 0;
1241 mNumFrames = 0;
1242 mFrameTime = 0.0f;
1243 mDuration = 0.0f;
1244
1245 mPriority = 2;
1246 mLoop = FALSE;
1247 mLoopInPoint = 0.f;
1248 mLoopOutPoint = 0.f;
1249 mEaseIn = 0.3f;
1250 mEaseOut = 0.3f;
1251 mHand = 1;
1252 mInitialized = FALSE;
1253
1254 mEmoteName = "";
1255}
1256
1257//------------------------------------------------------------------------
1258// LLBVHLoader::getLine()
1259//------------------------------------------------------------------------
1260BOOL LLBVHLoader::getLine(apr_file_t* fp)
1261{
1262 if (apr_file_eof(fp) == APR_EOF)
1263 {
1264 return FALSE;
1265 }
1266 if ( apr_file_gets(mLine, BVH_PARSER_LINE_SIZE, fp) == APR_SUCCESS)
1267 {
1268 mLineNumber++;
1269 return TRUE;
1270 }
1271
1272 return FALSE;
1273}
1274
1275// returns required size of output buffer
1276U32 LLBVHLoader::getOutputSize()
1277{
1278 LLDataPackerBinaryBuffer dp;
1279 serialize(dp);
1280
1281 return dp.getCurrentSize();
1282}
1283
1284// writes contents to datapacker
1285BOOL LLBVHLoader::serialize(LLDataPacker& dp)
1286{
1287 JointVector::iterator ji;
1288 KeyVector::iterator ki;
1289 F32 time;
1290
1291 // count number of non-ignored joints
1292 S32 numJoints = 0;
1293 for (ji=mJoints.begin(); ji!=mJoints.end(); ++ji)
1294 {
1295 Joint *joint = *ji;
1296 if ( ! joint->mIgnore )
1297 numJoints++;
1298 }
1299
1300 // print header
1301 dp.packU16(KEYFRAME_MOTION_VERSION, "version");
1302 dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version");
1303 dp.packS32(mPriority, "base_priority");
1304 dp.packF32(mDuration, "duration");
1305 dp.packString(mEmoteName.c_str(), "emote_name");
1306 dp.packF32(mLoopInPoint, "loop_in_point");
1307 dp.packF32(mLoopOutPoint, "loop_out_point");
1308 dp.packS32(mLoop, "loop");
1309 dp.packF32(mEaseIn, "ease_in_duration");
1310 dp.packF32(mEaseOut, "ease_out_duration");
1311 dp.packU32(mHand, "hand_pose");
1312 dp.packU32(numJoints, "num_joints");
1313
1314 for ( ji = mJoints.begin();
1315 ji != mJoints.end();
1316 ++ji )
1317 {
1318 Joint *joint = *ji;
1319 // if ignored, skip it
1320 if ( joint->mIgnore )
1321 continue;
1322
1323 LLQuaternion first_frame_rot;
1324 LLQuaternion fixup_rot;
1325
1326 dp.packString(joint->mOutName.c_str(), "joint_name");
1327 dp.packS32(joint->mPriority, "joint_priority");
1328
1329 // compute coordinate frame rotation
1330 LLQuaternion frameRot( joint->mFrameMatrix );
1331 LLQuaternion frameRotInv = ~frameRot;
1332
1333 LLQuaternion offsetRot( joint->mOffsetMatrix );
1334
1335 // find mergechild and mergeparent joints, if specified
1336 LLQuaternion mergeParentRot;
1337 LLQuaternion mergeChildRot;
1338 Joint *mergeParent = NULL;
1339 Joint *mergeChild = NULL;
1340
1341 JointVector::iterator mji;
1342 for (mji=mJoints.begin(); mji!=mJoints.end(); ++mji)
1343 {
1344 Joint *mjoint = *mji;
1345 if ( !joint->mMergeParentName.empty() && (mjoint->mName == joint->mMergeParentName) )
1346 {
1347 mergeParent = *mji;
1348 }
1349 if ( !joint->mMergeChildName.empty() && (mjoint->mName == joint->mMergeChildName) )
1350 {
1351 mergeChild = *mji;
1352 }
1353 }
1354
1355 dp.packS32(joint->mNumRotKeys, "num_rot_keys");
1356
1357 LLQuaternion::Order order = bvhStringToOrder( joint->mOrder );
1358 S32 outcount = 0;
1359 S32 frame = 1;
1360 for ( ki = joint->mKeys.begin();
1361 ki != joint->mKeys.end();
1362 ++ki )
1363 {
1364 if ((frame == 1) && joint->mRelativeRotationKey)
1365 {
1366 first_frame_rot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order);
1367
1368 fixup_rot.shortestArc(LLVector3::z_axis * first_frame_rot * frameRot, LLVector3::z_axis);
1369 }
1370
1371 if (ki->mIgnoreRot)
1372 {
1373 frame++;
1374 continue;
1375 }
1376
1377 time = (F32)frame * mFrameTime;
1378
1379 if (mergeParent)
1380 {
1381 mergeParentRot = mayaQ( mergeParent->mKeys[frame-1].mRot[0],
1382 mergeParent->mKeys[frame-1].mRot[1],
1383 mergeParent->mKeys[frame-1].mRot[2],
1384 bvhStringToOrder(mergeParent->mOrder) );
1385 LLQuaternion parentFrameRot( mergeParent->mFrameMatrix );
1386 LLQuaternion parentOffsetRot( mergeParent->mOffsetMatrix );
1387 mergeParentRot = ~parentFrameRot * mergeParentRot * parentFrameRot * parentOffsetRot;
1388 }
1389 else
1390 {
1391 mergeParentRot.loadIdentity();
1392 }
1393
1394 if (mergeChild)
1395 {
1396 mergeChildRot = mayaQ( mergeChild->mKeys[frame-1].mRot[0],
1397 mergeChild->mKeys[frame-1].mRot[1],
1398 mergeChild->mKeys[frame-1].mRot[2],
1399 bvhStringToOrder(mergeChild->mOrder) );
1400 LLQuaternion childFrameRot( mergeChild->mFrameMatrix );
1401 LLQuaternion childOffsetRot( mergeChild->mOffsetMatrix );
1402 mergeChildRot = ~childFrameRot * mergeChildRot * childFrameRot * childOffsetRot;
1403
1404 }
1405 else
1406 {
1407 mergeChildRot.loadIdentity();
1408 }
1409
1410 LLQuaternion inRot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order);
1411
1412 LLQuaternion outRot = frameRotInv* mergeChildRot * inRot * mergeParentRot * ~first_frame_rot * frameRot * offsetRot;
1413
1414 U16 time_short = F32_to_U16(time, 0.f, mDuration);
1415 dp.packU16(time_short, "time");
1416 U16 x, y, z;
1417 LLVector3 rot_vec = outRot.packToVector3();
1418 rot_vec.quantize16(-1.f, 1.f, -1.f, 1.f);
1419 x = F32_to_U16(rot_vec.mV[VX], -1.f, 1.f);
1420 y = F32_to_U16(rot_vec.mV[VY], -1.f, 1.f);
1421 z = F32_to_U16(rot_vec.mV[VZ], -1.f, 1.f);
1422 dp.packU16(x, "rot_angle_x");
1423 dp.packU16(y, "rot_angle_y");
1424 dp.packU16(z, "rot_angle_z");
1425 outcount++;
1426 frame++;
1427 }
1428
1429 // output position keys (only for 1st joint)
1430 if ( ji == mJoints.begin() && !joint->mIgnorePositions )
1431 {
1432 dp.packS32(joint->mNumPosKeys, "num_pos_keys");
1433
1434 LLVector3 relPos = joint->mRelativePosition;
1435 LLVector3 relKey;
1436
1437 frame = 1;
1438 for ( ki = joint->mKeys.begin();
1439 ki != joint->mKeys.end();
1440 ++ki )
1441 {
1442 if ((frame == 1) && joint->mRelativePositionKey)
1443 {
1444 relKey.setVec(ki->mPos);
1445 }
1446
1447 if (ki->mIgnorePos)
1448 {
1449 frame++;
1450 continue;
1451 }
1452
1453 time = (F32)frame * mFrameTime;
1454
1455 LLVector3 inPos = (LLVector3(ki->mPos) - relKey) * ~first_frame_rot;// * fixup_rot;
1456 LLVector3 outPos = inPos * frameRot * offsetRot;
1457
1458 outPos *= INCHES_TO_METERS;
1459
1460 outPos -= relPos;
1461 outPos.clamp(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1462
1463 U16 time_short = F32_to_U16(time, 0.f, mDuration);
1464 dp.packU16(time_short, "time");
1465
1466 U16 x, y, z;
1467 outPos.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1468 x = F32_to_U16(outPos.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1469 y = F32_to_U16(outPos.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1470 z = F32_to_U16(outPos.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1471 dp.packU16(x, "pos_x");
1472 dp.packU16(y, "pos_y");
1473 dp.packU16(z, "pos_z");
1474
1475 frame++;
1476 }
1477 }
1478 else
1479 {
1480 dp.packS32(0, "num_pos_keys");
1481 }
1482 }
1483
1484 S32 num_constraints = (S32)mConstraints.size();
1485 dp.packS32(num_constraints, "num_constraints");
1486
1487 for (ConstraintVector::iterator constraint_it = mConstraints.begin();
1488 constraint_it != mConstraints.end();
1489 constraint_it++)
1490 {
1491 U8 byte = constraint_it->mChainLength;
1492 dp.packU8(byte, "chain_lenght");
1493
1494 byte = constraint_it->mConstraintType;
1495 dp.packU8(byte, "constraint_type");
1496 dp.packBinaryDataFixed((U8*)constraint_it->mSourceJointName, 16, "source_volume");
1497 dp.packVector3(constraint_it->mSourceOffset, "source_offset");
1498 dp.packBinaryDataFixed((U8*)constraint_it->mTargetJointName, 16, "target_volume");
1499 dp.packVector3(constraint_it->mTargetOffset, "target_offset");
1500 dp.packVector3(constraint_it->mTargetDir, "target_dir");
1501 dp.packF32(constraint_it->mEaseInStart, "ease_in_start");
1502 dp.packF32(constraint_it->mEaseInStop, "ease_in_stop");
1503 dp.packF32(constraint_it->mEaseOutStart, "ease_out_start");
1504 dp.packF32(constraint_it->mEaseOutStop, "ease_out_stop");
1505 }
1506
1507 return TRUE;
1508}