PageRenderTime 175ms CodeModel.GetById 15ms app.highlight 144ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llcharacter/llbvhloader.cpp

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