summaryrefslogtreecommitdiff
path: root/indra/llcharacter
diff options
context:
space:
mode:
authorBrad Kittenbrink <brad@lindenlab.com>2022-11-28 14:33:27 -0800
committerBrad Kittenbrink <brad@lindenlab.com>2022-11-28 14:33:27 -0800
commit0b188ac04ecdb1d620a427eacbf5fc089e0accc8 (patch)
tree76f6afe9424d79bab8d30060d49aec3166d96ec8 /indra/llcharacter
parente9cd2b320ea2ecaab88e4904f7c81746ea617fea (diff)
parentc8f08f232a28f4e08b4acf525f0d316a101a0e27 (diff)
Merge remote-tracking branch 'origin/main' into DRTVWR-528
Diffstat (limited to 'indra/llcharacter')
-rw-r--r--indra/llcharacter/llbvhloader.cpp26
-rw-r--r--indra/llcharacter/llkeyframemotion.cpp45
-rw-r--r--indra/llcharacter/llkeyframemotion.h7
3 files changed, 63 insertions, 15 deletions
diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp
index e906d81ce1..c38614b0b4 100644
--- a/indra/llcharacter/llbvhloader.cpp
+++ b/indra/llcharacter/llbvhloader.cpp
@@ -44,6 +44,14 @@ using namespace std;
#define INCHES_TO_METERS 0.02540005f
+/// The .bvh does not have a formal spec, and different readers interpret things in their own way.
+/// In OUR usage, frame 0 is used in optimization and is not considered to be part of the animation.
+const S32 NUMBER_OF_IGNORED_FRAMES_AT_START = 1;
+/// In our usage, the last frame is used only to indicate what the penultimate frame should be interpolated towards.
+/// I.e., the animation only plays up to the start of the last frame. There is no hold or exptrapolation past that point..
+/// Thus there are two frame of the total that do not contribute to the total running time of the animation.
+const S32 NUMBER_OF_UNPLAYED_FRAMES = NUMBER_OF_IGNORED_FRAMES_AT_START + 1;
+
const F32 POSITION_KEYFRAME_THRESHOLD_SQUARED = 0.03f * 0.03f;
const F32 ROTATION_KEYFRAME_THRESHOLD = 0.01f;
@@ -865,7 +873,10 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &
return E_ST_NO_FRAME_TIME;
}
- mDuration = (F32)mNumFrames * mFrameTime;
+ // If the user only supplies one animation frame (after the ignored reference frame 0), hold for mFrameTime.
+ // If the user supples exactly one total frame, it isn't clear if that is a pose or reference frame, and the
+ // behavior is not defined. In this case, retain historical undefined behavior.
+ mDuration = llmax((F32)(mNumFrames - NUMBER_OF_UNPLAYED_FRAMES), 1.0f) * mFrameTime;
if (!mLoop)
{
mLoopOutPoint = mDuration;
@@ -1355,12 +1366,13 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
LLQuaternion::Order order = bvhStringToOrder( joint->mOrder );
S32 outcount = 0;
- S32 frame = 1;
+ S32 frame = 0;
for ( ki = joint->mKeys.begin();
ki != joint->mKeys.end();
++ki )
{
- if ((frame == 1) && joint->mRelativeRotationKey)
+
+ if ((frame == 0) && joint->mRelativeRotationKey)
{
first_frame_rot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order);
@@ -1373,7 +1385,7 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
continue;
}
- time = (F32)frame * mFrameTime;
+ time = llmax((F32)(frame - NUMBER_OF_IGNORED_FRAMES_AT_START), 0.0f) * mFrameTime; // Time elapsed before this frame starts.
if (mergeParent)
{
@@ -1433,12 +1445,12 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
LLVector3 relPos = joint->mRelativePosition;
LLVector3 relKey;
- frame = 1;
+ frame = 0;
for ( ki = joint->mKeys.begin();
ki != joint->mKeys.end();
++ki )
{
- if ((frame == 1) && joint->mRelativePositionKey)
+ if ((frame == 0) && joint->mRelativePositionKey)
{
relKey.setVec(ki->mPos);
}
@@ -1449,7 +1461,7 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
continue;
}
- time = (F32)frame * mFrameTime;
+ time = llmax((F32)(frame - NUMBER_OF_IGNORED_FRAMES_AT_START), 0.0f) * mFrameTime; // Time elapsed before this frame starts.
LLVector3 inPos = (LLVector3(ki->mPos) - relKey) * ~first_frame_rot;// * fixup_rot;
LLVector3 outPos = inPos * frameRot * offsetRot;
diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index a25ff16786..ebf7454a61 100644
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -1222,8 +1222,11 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
//-----------------------------------------------------------------------------
// deserialize()
+//
+// allow_invalid_joints should be true when handling existing content, to avoid breakage.
+// During upload, we should be more restrictive and reject such animations.
//-----------------------------------------------------------------------------
-BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
+BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, bool allow_invalid_joints)
{
BOOL old_version = FALSE;
mJointMotionList = new LLKeyframeMotion::JointMotionList;
@@ -1344,6 +1347,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
return FALSE;
}
+ //SL-17206 hack to alter Female_land loop setting, while current behavior won't be changed serverside
+ LLUUID const female_land_anim("ca1baf4d-0a18-5a1f-0330-e4bd1e71f09e");
+ LLUUID const formal_female_land_anim("6a9a173b-61fa-3ad5-01fa-a851cfc5f66a");
+ if (female_land_anim == asset_id || formal_female_land_anim == asset_id)
+ {
+ LL_WARNS() << "Animation(" << asset_id << ") won't be looped." << LL_ENDL;
+ mJointMotionList->mLoop = FALSE;
+ }
+
//-------------------------------------------------------------------------
// get easeIn and easeOut
//-------------------------------------------------------------------------
@@ -1443,6 +1455,7 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
if (joint)
{
S32 joint_num = joint->getJointNum();
+ joint_name = joint->getName(); // canonical name in case this is an alias.
// LL_INFOS() << " joint: " << joint_name << LL_ENDL;
if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0))
{
@@ -1457,7 +1470,10 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
{
LL_WARNS() << "invalid joint name: " << joint_name
<< " for animation " << asset_id << LL_ENDL;
- //return FALSE;
+ if (!allow_invalid_joints)
+ {
+ return FALSE;
+ }
}
joint_motion->mJointName = joint_name;
@@ -2096,8 +2112,9 @@ U32 LLKeyframeMotion::getFileSize()
//-----------------------------------------------------------------------------
// dumpToFile()
//-----------------------------------------------------------------------------
-void LLKeyframeMotion::dumpToFile(const std::string& name)
+bool LLKeyframeMotion::dumpToFile(const std::string& name)
{
+ bool succ = false;
if (isLoaded())
{
std::string outfile_base;
@@ -2114,10 +2131,24 @@ void LLKeyframeMotion::dumpToFile(const std::string& name)
const LLUUID& id = getID();
outfile_base = id.asString();
}
- std::string outfilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfile_base + ".anim");
+
+ if (gDirUtilp->getExtension(outfile_base).empty())
+ {
+ outfile_base += ".anim";
+ }
+ std::string outfilename;
+ if (gDirUtilp->getDirName(outfile_base).empty())
+ {
+ outfilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfile_base);
+ }
+ else
+ {
+ outfilename = outfile_base;
+ }
if (LLFile::isfile(outfilename))
{
- return;
+ LL_WARNS() << outfilename << " already exists, write failed" << LL_ENDL;
+ return false;
}
S32 file_size = getFileSize();
@@ -2131,11 +2162,13 @@ void LLKeyframeMotion::dumpToFile(const std::string& name)
outfile.open(outfilename, LL_APR_WPB);
if (outfile.getFileHandle())
{
- outfile.write(buffer, file_size);
+ S32 wrote_bytes = outfile.write(buffer, file_size);
+ succ = (wrote_bytes == file_size);
}
}
delete [] buffer;
}
+ return succ;
}
//-----------------------------------------------------------------------------
diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h
index 9a927ede9a..96746f57c9 100644
--- a/indra/llcharacter/llkeyframemotion.h
+++ b/indra/llcharacter/llkeyframemotion.h
@@ -156,9 +156,9 @@ public:
public:
U32 getFileSize();
BOOL serialize(LLDataPacker& dp) const;
- BOOL deserialize(LLDataPacker& dp, const LLUUID& asset_id);
+ BOOL deserialize(LLDataPacker& dp, const LLUUID& asset_id, bool allow_invalid_joints = true);
BOOL isLoaded() { return mJointMotionList != NULL; }
- void dumpToFile(const std::string& name);
+ bool dumpToFile(const std::string& name);
// setters for modifying a keyframe animation
@@ -432,6 +432,9 @@ protected:
F32 mLastUpdateTime;
F32 mLastLoopedTime;
AssetStatus mAssetStatus;
+
+public:
+ void setCharacter(LLCharacter* character) { mCharacter = character; }
};
class LLKeyframeDataCache