diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcharacter/llbvhloader.cpp | |
parent | README.txt (diff) | |
download | meta-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.cpp | 1508 |
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 | |||
44 | using namespace std; | ||
45 | |||
46 | #define INCHES_TO_METERS 0.02540005f | ||
47 | |||
48 | const F32 POSITION_KEYFRAME_THRESHOLD = 0.03f; | ||
49 | const F32 ROTATION_KEYFRAME_THRESHOLD = 0.01f; | ||
50 | |||
51 | const F32 POSITION_MOTION_THRESHOLD = 0.001f; | ||
52 | const F32 ROTATION_MOTION_THRESHOLD = 0.001f; | ||
53 | |||
54 | char gInFile[1024]; /* Flawfinder: ignore */ | ||
55 | char gOutFile[1024]; /* Flawfinder: ignore */ | ||
56 | |||
57 | //------------------------------------------------------------------------ | ||
58 | // Status Codes | ||
59 | //------------------------------------------------------------------------ | ||
60 | char *LLBVHLoader::ST_OK = "Ok"; | ||
61 | char *LLBVHLoader::ST_EOF = "Premature end of file."; | ||
62 | char *LLBVHLoader::ST_NO_CONSTRAINT = "Can't read constraint definition."; | ||
63 | char *LLBVHLoader::ST_NO_FILE = "Can't open BVH file."; | ||
64 | char *LLBVHLoader::ST_NO_HIER = "Invalid HIERARCHY header."; | ||
65 | char *LLBVHLoader::ST_NO_JOINT = "Can't find ROOT or JOINT."; | ||
66 | char *LLBVHLoader::ST_NO_NAME = "Can't get JOINT name."; | ||
67 | char *LLBVHLoader::ST_NO_OFFSET = "Can't find OFFSET."; | ||
68 | char *LLBVHLoader::ST_NO_CHANNELS = "Can't find CHANNELS."; | ||
69 | char *LLBVHLoader::ST_NO_ROTATION = "Can't get rotation order."; | ||
70 | char *LLBVHLoader::ST_NO_AXIS = "Can't get rotation axis."; | ||
71 | char *LLBVHLoader::ST_NO_MOTION = "Can't find MOTION."; | ||
72 | char *LLBVHLoader::ST_NO_FRAMES = "Can't get number of frames."; | ||
73 | char *LLBVHLoader::ST_NO_FRAME_TIME = "Can't get frame time."; | ||
74 | char *LLBVHLoader::ST_NO_POS = "Can't get position values."; | ||
75 | char *LLBVHLoader::ST_NO_ROT = "Can't get rotation values."; | ||
76 | char *LLBVHLoader::ST_NO_XLT_FILE = "Can't open translation file."; | ||
77 | char *LLBVHLoader::ST_NO_XLT_HEADER = "Can't read translation header."; | ||
78 | char *LLBVHLoader::ST_NO_XLT_NAME = "Can't read translation names."; | ||
79 | char *LLBVHLoader::ST_NO_XLT_IGNORE = "Can't read translation ignore value."; | ||
80 | char *LLBVHLoader::ST_NO_XLT_RELATIVE = "Can't read translation relative value."; | ||
81 | char *LLBVHLoader::ST_NO_XLT_OUTNAME = "Can't read translation outname value."; | ||
82 | char *LLBVHLoader::ST_NO_XLT_MATRIX = "Can't read translation matrix."; | ||
83 | char *LLBVHLoader::ST_NO_XLT_MERGECHILD = "Can't get mergechild name."; | ||
84 | char *LLBVHLoader::ST_NO_XLT_MERGEPARENT = "Can't get mergeparent name."; | ||
85 | char *LLBVHLoader::ST_NO_XLT_PRIORITY = "Can't get priority value."; | ||
86 | char *LLBVHLoader::ST_NO_XLT_LOOP = "Can't get loop value."; | ||
87 | char *LLBVHLoader::ST_NO_XLT_EASEIN = "Can't get easeIn values."; | ||
88 | char *LLBVHLoader::ST_NO_XLT_EASEOUT = "Can't get easeOut values."; | ||
89 | char *LLBVHLoader::ST_NO_XLT_HAND = "Can't get hand morph value."; | ||
90 | char *LLBVHLoader::ST_NO_XLT_EMOTE = "Can't read emote name."; | ||
91 | |||
92 | //------------------------------------------------------------------------ | ||
93 | // find_next_whitespace() | ||
94 | //------------------------------------------------------------------------ | ||
95 | const 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 | //------------------------------------------------------------------------ | ||
110 | LLQuaternion::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 | //----------------------------------------------------------------------------- | ||
124 | LLBVHLoader::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 | |||
159 | LLBVHLoader::~LLBVHLoader() | ||
160 | { | ||
161 | std::for_each(mJoints.begin(),mJoints.end(),DeletePointer()); | ||
162 | } | ||
163 | |||
164 | //------------------------------------------------------------------------ | ||
165 | // LLBVHLoader::loadTranslationTable() | ||
166 | //------------------------------------------------------------------------ | ||
167 | LLBVHLoader::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 | //------------------------------------------------------------------------ | ||
629 | LLBVHLoader::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 | //------------------------------------------------------------------------ | ||
970 | void 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 | //----------------------------------------------------------------------------- | ||
1079 | void 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 | |||
1238 | void 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 | //------------------------------------------------------------------------ | ||
1260 | BOOL 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 | ||
1276 | U32 LLBVHLoader::getOutputSize() | ||
1277 | { | ||
1278 | LLDataPackerBinaryBuffer dp; | ||
1279 | serialize(dp); | ||
1280 | |||
1281 | return dp.getCurrentSize(); | ||
1282 | } | ||
1283 | |||
1284 | // writes contents to datapacker | ||
1285 | BOOL 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 | } | ||