From 5d75b3b223e4c7b5374083384c3cf4f8fbde7a90 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 9 Mar 2019 01:51:50 -0600 Subject: [PATCH] Prep for animesh. --- etc/message.xml | 8 + indra/llappearance/llavatarappearance.cpp | 36 ++- indra/llappearance/llavatarappearance.h | 5 +- indra/llcharacter/llcharacter.h | 2 +- indra/llcharacter/lljoint.h | 11 + indra/llcharacter/llkeyframemotion.cpp | 201 +++++++++------ indra/llcharacter/llkeyframemotion.h | 2 +- indra/llcharacter/llmotioncontroller.cpp | 13 +- indra/llcharacter/llmotioncontroller.h | 7 +- indra/llmath/CMakeLists.txt | 2 + indra/llmath/llmatrix4a.h | 8 + indra/llmath/llvector4a.h | 5 + indra/llmath/llvolume.cpp | 287 +++++++++++++++------- indra/llmath/llvolume.h | 12 +- indra/llprimitive/llmodel.cpp | 66 ++--- indra/llprimitive/llmodel.h | 6 +- indra/llprimitive/llmodelloader.h | 1 + indra/llprimitive/llprimitive.cpp | 80 +++++- indra/llprimitive/llprimitive.h | 31 ++- indra/newview/CMakeLists.txt | 1 + indra/newview/floaterlocalassetbrowse.cpp | 2 +- indra/newview/lldrawpoolavatar.cpp | 24 +- indra/newview/llfloaterbvhpreview.cpp | 4 +- indra/newview/llfloaterimagepreview.cpp | 2 +- indra/newview/llfloatermodelpreview.cpp | 18 ++ indra/newview/llskinningutil.cpp | 161 +++++++----- indra/newview/llskinningutil.h | 21 +- indra/newview/llvovolume.cpp | 17 +- 28 files changed, 700 insertions(+), 333 deletions(-) diff --git a/etc/message.xml b/etc/message.xml index fd019aa70..5f2c3aa06 100644 --- a/etc/message.xml +++ b/etc/message.xml @@ -236,6 +236,14 @@ false + ObjectAnimation + + flavor + template + trusted-sender + false + + AvatarAppearance flavor diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 121c00601..87898d4dc 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -185,8 +185,9 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mHeadOffset(), mRoot(NULL), mWearableData(wearable_data), - mNumBones(0), - mIsBuilt(FALSE) + mNumBones(0), + mIsBuilt(FALSE), + mInitFlags(0) { llassert_always(mWearableData); mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES); @@ -282,6 +283,8 @@ void LLAvatarAppearance::initInstance() } buildCharacter(); + mInitFlags |= 1<<0; + } // virtual @@ -1370,12 +1373,12 @@ LLVector3 LLAvatarAppearance::getVolumePos(S32 joint_index, LLVector3& volume_of //----------------------------------------------------------------------------- // findCollisionVolume() //----------------------------------------------------------------------------- -LLJoint* LLAvatarAppearance::findCollisionVolume(U32 volume_id) +LLJoint* LLAvatarAppearance::findCollisionVolume(S32 volume_id) { //SNOW-488: As mNumCollisionVolumes is a S32 and we are casting from a U32 to a S32 //to compare we also need to be sure of the wrap around case producing (S32) <0 //or in terms of the U32 an out of bounds index in the array. - if ((S32)volume_id > (S32)mCollisionVolumes.size() || (S32)volume_id<0) + if ((S32)volume_id > (S32)mCollisionVolumes.size() || volume_id<0) { return NULL; } @@ -1828,13 +1831,34 @@ const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases { LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter; - for (iter = sAvatarSkeletonInfo->mBoneInfoList.begin(); iter != sAvatarSkeletonInfo->mBoneInfoList.end(); ++iter) + for (iter = sAvatarSkeletonInfo->mBoneInfoList.begin(); + iter != sAvatarSkeletonInfo->mBoneInfoList.end(); + ++iter) { //LLAvatarBoneInfo *bone_info = *iter; makeJointAliases( *iter ); } + + LLAvatarXmlInfo::attachment_info_list_t::iterator attach_iter; + for (attach_iter = sAvatarXmlInfo->mAttachmentInfoList.begin(); + attach_iter != sAvatarXmlInfo->mAttachmentInfoList.end(); + ++attach_iter) + { + LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *attach_iter; + std::string bone_name = info->mName; + + // Also accept the name with spaces substituted with + // underscores. This gives a mechanism for referencing such joints + // in daes, which don't allow spaces. + std::string sub_space_to_underscore = bone_name; + LLStringUtil::replaceChar(sub_space_to_underscore, ' ', '_'); + if (sub_space_to_underscore != bone_name) + { + mJointAliasMap[sub_space_to_underscore] = bone_name; + } + } } - + return mJointAliasMap; } diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index aaee5ed13..2651106ca 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -71,6 +71,7 @@ public: static void initClass(); // initializes static members static void cleanupClass(); // Cleanup data that's only init'd once per class. virtual void initInstance(); // Called after construction to initialize the instance. + S32 mInitFlags; virtual BOOL loadSkeletonNode(); BOOL loadMeshNodes(); BOOL loadLayersets(); @@ -93,7 +94,7 @@ public: /*virtual*/ const char* getAnimationPrefix() { return "avatar"; } /*virtual*/ LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset); - /*virtual*/ LLJoint* findCollisionVolume(U32 volume_id); + /*virtual*/ LLJoint* findCollisionVolume(S32 volume_id); /*virtual*/ S32 getCollisionVolumeID(std::string &name); /*virtual*/ LLPolyMesh* getHeadMesh(); /*virtual*/ LLPolyMesh* getUpperBodyMesh(); @@ -234,7 +235,7 @@ protected: ** RENDERING **/ public: - BOOL mIsDummy; // for special views + BOOL mIsDummy; // for special views and animated object controllers; local to viewer //-------------------------------------------------------------------- // Morph masks diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index 2bcd2d28d..93cf461c9 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -182,7 +182,7 @@ public: virtual LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset) { return LLVector3::zero; } - virtual LLJoint* findCollisionVolume(U32 volume_id) { return NULL; } + virtual LLJoint* findCollisionVolume(S32 volume_id) { return NULL; } virtual S32 getCollisionVolumeID(std::string &name) { return -1; } diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 238e49e9f..6beffc9f6 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -69,6 +69,17 @@ public: private: map_type m_map; }; + +inline bool operator==(const LLVector3OverrideMap& a, const LLVector3OverrideMap& b) +{ + return a.getMap() == b.getMap(); +} + +inline bool operator!=(const LLVector3OverrideMap& a, const LLVector3OverrideMap& b) +{ + return !(a == b); +} + //----------------------------------------------------------------------------- // class LLJoint //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index d5e5eb585..ed9167f74 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -623,7 +623,7 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact LLDataPackerBinaryBuffer dp(anim_data, anim_file_size); - if (!deserialize(dp)) + if (!deserialize(dp, getID())) { LL_WARNS() << "Failed to decode asset for animation " << getName() << ":" << getID() << LL_ENDL; mAssetStatus = ASSET_FETCH_FAILED; @@ -1291,7 +1291,7 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8 //----------------------------------------------------------------------------- // deserialize() //----------------------------------------------------------------------------- -BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) +BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id) { BOOL old_version = FALSE; @@ -1324,13 +1324,13 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (!dp.unpackU16(version, "version")) { - LL_WARNS() << "can't read version number" << LL_ENDL; + LL_WARNS() << "can't read version number for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackU16(sub_version, "sub_version")) { - LL_WARNS() << "can't read sub version number" << LL_ENDL; + LL_WARNS() << "can't read sub version number for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1341,28 +1341,32 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) else if (version != KEYFRAME_MOTION_VERSION || sub_version != KEYFRAME_MOTION_SUBVERSION) { #if LL_RELEASE - LL_WARNS() << "Bad animation version " << version << "." << sub_version << LL_ENDL; + LL_WARNS() << "Bad animation version " << version << "." << sub_version + << " for animation " << asset_id << LL_ENDL; return FALSE; #else - LL_ERRS() << "Bad animation version " << version << "." << sub_version << LL_ENDL; + LL_ERRS() << "Bad animation version " << version << "." << sub_version + << " for animation " << asset_id << LL_ENDL; #endif } if (!dp.unpackS32(temp_priority, "base_priority")) { - LL_WARNS() << "can't read animation base_priority" << LL_ENDL; + LL_WARNS() << "can't read animation base_priority" + << " for animation " << asset_id << LL_ENDL; return FALSE; } mJointMotionList->mBasePriority = (LLJoint::JointPriority) temp_priority; if (mJointMotionList->mBasePriority >= LLJoint::ADDITIVE_PRIORITY) { - mJointMotionList->mBasePriority = (LLJoint::JointPriority)((int)LLJoint::ADDITIVE_PRIORITY-1); + mJointMotionList->mBasePriority = (LLJoint::JointPriority)((S32)LLJoint::ADDITIVE_PRIORITY-1); mJointMotionList->mMaxPriority = mJointMotionList->mBasePriority; } else if (mJointMotionList->mBasePriority < LLJoint::USE_MOTION_PRIORITY) { - LL_WARNS() << "bad animation base_priority " << mJointMotionList->mBasePriority << LL_ENDL; + LL_WARNS() << "bad animation base_priority " << mJointMotionList->mBasePriority + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1371,14 +1375,16 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) //------------------------------------------------------------------------- if (!dp.unpackF32(mJointMotionList->mDuration, "duration")) { - LL_WARNS() << "can't read duration" << LL_ENDL; + LL_WARNS() << "can't read duration" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (mJointMotionList->mDuration > MAX_ANIM_DURATION || !std::isfinite(mJointMotionList->mDuration)) { - LL_WARNS() << "invalid animation duration" << LL_ENDL; + LL_WARNS() << "invalid animation duration" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1387,13 +1393,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) //------------------------------------------------------------------------- if (!dp.unpackString(mJointMotionList->mEmoteName, "emote_name")) { - LL_WARNS() << "can't read optional_emote_animation" << LL_ENDL; + LL_WARNS() << "can't read optional_emote_animation" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if(mJointMotionList->mEmoteName==mID.asString()) { - LL_WARNS() << "Malformed animation mEmoteName==mID" << LL_ENDL; + LL_WARNS() << "Malformed animation mEmoteName==mID" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1403,20 +1411,23 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (!dp.unpackF32(mJointMotionList->mLoopInPoint, "loop_in_point") || !std::isfinite(mJointMotionList->mLoopInPoint)) { - LL_WARNS() << "can't read loop point" << LL_ENDL; + LL_WARNS() << "can't read loop point" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackF32(mJointMotionList->mLoopOutPoint, "loop_out_point") || !std::isfinite(mJointMotionList->mLoopOutPoint)) { - LL_WARNS() << "can't read loop point" << LL_ENDL; + LL_WARNS() << "can't read loop point" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackS32(mJointMotionList->mLoop, "loop")) { - LL_WARNS() << "can't read loop" << LL_ENDL; + LL_WARNS() << "can't read loop" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1426,14 +1437,16 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (!dp.unpackF32(mJointMotionList->mEaseInDuration, "ease_in_duration") || !std::isfinite(mJointMotionList->mEaseInDuration)) { - LL_WARNS() << "can't read easeIn" << LL_ENDL; + LL_WARNS() << "can't read easeIn" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackF32(mJointMotionList->mEaseOutDuration, "ease_out_duration") || !std::isfinite(mJointMotionList->mEaseOutDuration)) { - LL_WARNS() << "can't read easeOut" << LL_ENDL; + LL_WARNS() << "can't read easeOut" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1443,13 +1456,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) U32 word; if (!dp.unpackU32(word, "hand_pose")) { - LL_WARNS() << "can't read hand pose" << LL_ENDL; + LL_WARNS() << "can't read hand pose" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if(word > LLHandMotion::NUM_HAND_POSES) { - LL_WARNS() << "invalid LLHandMotion::eHandPose index: " << word << LL_ENDL; + LL_WARNS() << "invalid LLHandMotion::eHandPose index: " << word + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1461,18 +1476,21 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) U32 num_motions = 0; if (!dp.unpackU32(num_motions, "num_joints")) { - LL_WARNS() << "can't read number of joints" << LL_ENDL; + LL_WARNS() << "can't read number of joints" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (num_motions == 0) { - LL_WARNS() << "no joints in animation" << LL_ENDL; + LL_WARNS() << "no joints" + << " for animation " << asset_id << LL_ENDL; return FALSE; } else if (num_motions > LL_CHARACTER_MAX_ANIMATED_JOINTS) { - LL_WARNS() << "too many joints in animation" << LL_ENDL; + LL_WARNS() << "too many joints" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1500,13 +1518,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) std::string joint_name; if (!dp.unpackString(joint_name, "joint_name")) { - LL_WARNS() << "can't read joint name" << LL_ENDL; + LL_WARNS() << "can't read joint name" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (joint_name == "mScreen" || joint_name == "mRoot") { - LL_WARNS() << "attempted to animate special " << joint_name << " joint" << LL_ENDL; + LL_WARNS() << "attempted to animate special " << joint_name << " joint" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1520,10 +1540,12 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) // LL_INFOS() << " joint: " << joint_name << LL_ENDL; if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0)) { - LL_WARNS() << "Joint will be omitted from animation: joint_num " << joint_num << " is outside of legal range [0-" - << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << joint->getName() << LL_ENDL; - joint = NULL; - } + LL_WARNS() << "Joint will be omitted from animation: joint_num " << joint_num + << " is outside of legal range [0-" + << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << joint->getName() + << " for animation " << asset_id << LL_ENDL; + joint = NULL; + } } else { @@ -1539,7 +1561,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) i++; } // - LL_WARNS() << "joint not found: " << joint_name << LL_ENDL; + LL_WARNS() << "invalid joint name: " << joint_name + << " for animation " << asset_id << LL_ENDL; //return FALSE; } @@ -1556,13 +1579,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) S32 joint_priority; if (!dp.unpackS32(joint_priority, "joint_priority")) { - LL_WARNS() << "can't read joint priority." << LL_ENDL; + LL_WARNS() << "can't read joint priority." + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (joint_priority < LLJoint::USE_MOTION_PRIORITY) { - LL_WARNS() << "joint priority unknown - too low." << LL_ENDL; + LL_WARNS() << "joint priority unknown - too low." + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1580,7 +1605,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) //--------------------------------------------------------------------- if (!dp.unpackS32(joint_motion->mRotationCurve.mNumKeys, "num_rot_keys") || joint_motion->mRotationCurve.mNumKeys < 0) { - LL_WARNS() << "can't read number of rotation keys" << LL_ENDL; + LL_WARNS() << "can't read number of rotation keys" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1605,7 +1631,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (!dp.unpackF32(time, "time") || !std::isfinite(time)) { - LL_WARNS() << "can't read rotation key (" << k << ")" << LL_ENDL; + LL_WARNS() << "can't read rotation key (" << k << ")" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1614,7 +1641,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) { if (!dp.unpackU16(time_short, "time")) { - LL_WARNS() << "can't read rotation key (" << k << ")" << LL_ENDL; + LL_WARNS() << "can't read rotation key (" << k << ")" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1622,7 +1650,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (time < 0 || time > mJointMotionList->mDuration) { - LL_WARNS() << "invalid frame time" << LL_ENDL; + LL_WARNS() << "invalid frame time" + << " for animation " << asset_id << LL_ENDL; return FALSE; } } @@ -1656,13 +1685,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if( !(rot_key.mRotation.isFinite()) ) { - LL_WARNS() << "non-finite angle in rotation key" << LL_ENDL; + LL_WARNS() << "non-finite angle in rotation key" + << " for animation " << asset_id << LL_ENDL; success = FALSE; } if (!success) { - LL_WARNS() << "can't read rotation key (" << k << ")" << LL_ENDL; + LL_WARNS() << "can't read rotation key (" << k << ")" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1674,7 +1705,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) //--------------------------------------------------------------------- if (!dp.unpackS32(joint_motion->mPositionCurve.mNumKeys, "num_pos_keys") || joint_motion->mPositionCurve.mNumKeys < 0) { - LL_WARNS() << "can't read number of position keys" << LL_ENDL; + LL_WARNS() << "can't read number of position keys" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1699,7 +1731,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (!dp.unpackF32(pos_key.mTime, "time") || !std::isfinite(pos_key.mTime)) { - LL_WARNS() << "can't read position key (" << k << ")" << LL_ENDL; + LL_WARNS() << "can't read position key (" << k << ")" + << " for animation " << asset_id << LL_ENDL; return FALSE; } } @@ -1707,7 +1740,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) { if (!dp.unpackU16(time_short, "time")) { - LL_WARNS() << "can't read position key (" << k << ")" << LL_ENDL; + LL_WARNS() << "can't read position key (" << k << ")" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1741,13 +1775,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if( !(pos_key.mPosition.isFinite()) ) { - LL_WARNS() << "non-finite position in key" << LL_ENDL; + LL_WARNS() << "non-finite position in key" + << " for animation " << asset_id << LL_ENDL; success = FALSE; } if (!success) { - LL_WARNS() << "can't read position key (" << k << ")" << LL_ENDL; + LL_WARNS() << "can't read position key (" << k << ")" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1768,13 +1804,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) S32 num_constraints = 0; if (!dp.unpackS32(num_constraints, "num_constraints")) { - LL_WARNS() << "can't read number of constraints" << LL_ENDL; + LL_WARNS() << "can't read number of constraints" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (num_constraints > MAX_CONSTRAINTS || num_constraints < 0) { - LL_WARNS() << "Bad number of constraints... ignoring: " << num_constraints << LL_ENDL; + LL_WARNS() << "Bad number of constraints... ignoring: " << num_constraints + << " for animation " << asset_id << LL_ENDL; } else { @@ -1791,26 +1829,30 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (!dp.unpackU8(byte, "chain_length")) { - LL_WARNS() << "can't read constraint chain length" << LL_ENDL; + LL_WARNS() << "can't read constraint chain length" + << " for animation " << asset_id << LL_ENDL; return FALSE; } constraintp->mChainLength = (S32) byte; if((U32)constraintp->mChainLength > mJointMotionList->getNumJointMotions()) { - LL_WARNS() << "invalid constraint chain length" << LL_ENDL; + LL_WARNS() << "invalid constraint chain length" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackU8(byte, "constraint_type")) { - LL_WARNS() << "can't read constraint type" << LL_ENDL; + LL_WARNS() << "can't read constraint type" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if( byte >= NUM_CONSTRAINT_TYPES ) { - LL_WARNS() << "invalid constraint type" << LL_ENDL; + LL_WARNS() << "invalid constraint type" + << " for animation " << asset_id << LL_ENDL; return FALSE; } constraintp->mConstraintType = (EConstraintType)byte; @@ -1819,37 +1861,39 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) U8 bin_data[BIN_DATA_LENGTH+1]; if (!dp.unpackBinaryDataFixed(bin_data, BIN_DATA_LENGTH, "source_volume")) { - LL_WARNS() << "can't read source volume name" << LL_ENDL; + LL_WARNS() << "can't read source volume name" + << " for animation " << asset_id << LL_ENDL; return FALSE; } bin_data[BIN_DATA_LENGTH] = 0; // Ensure null termination str = (char*)bin_data; constraintp->mSourceConstraintVolume = mCharacter->getCollisionVolumeID(str); - - // - if(constraintp->mSourceConstraintVolume == -1) + if (constraintp->mSourceConstraintVolume == -1) { - LL_WARNS() << "can't get source constraint volume" << LL_ENDL; + LL_WARNS() << "not a valid source constraint volume " << str + << " for animation " << asset_id << LL_ENDL; return FALSE; } - // if (!dp.unpackVector3(constraintp->mSourceConstraintOffset, "source_offset")) { - LL_WARNS() << "can't read constraint source offset" << LL_ENDL; + LL_WARNS() << "can't read constraint source offset" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if( !(constraintp->mSourceConstraintOffset.isFinite()) ) { - LL_WARNS() << "non-finite constraint source offset" << LL_ENDL; + LL_WARNS() << "non-finite constraint source offset" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackBinaryDataFixed(bin_data, BIN_DATA_LENGTH, "target_volume")) { - LL_WARNS() << "can't read target volume name" << LL_ENDL; + LL_WARNS() << "can't read target volume name" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1864,29 +1908,39 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) { constraintp->mConstraintTargetType = CONSTRAINT_TARGET_TYPE_BODY; constraintp->mTargetConstraintVolume = mCharacter->getCollisionVolumeID(str); + if (constraintp->mTargetConstraintVolume == -1) + { + LL_WARNS() << "not a valid target constraint volume " << str + << " for animation " << asset_id << LL_ENDL; + return FALSE; + } } if (!dp.unpackVector3(constraintp->mTargetConstraintOffset, "target_offset")) { - LL_WARNS() << "can't read constraint target offset" << LL_ENDL; + LL_WARNS() << "can't read constraint target offset" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if( !(constraintp->mTargetConstraintOffset.isFinite()) ) { - LL_WARNS() << "non-finite constraint target offset" << LL_ENDL; + LL_WARNS() << "non-finite constraint target offset" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackVector3(constraintp->mTargetConstraintDir, "target_dir")) { - LL_WARNS() << "can't read constraint target direction" << LL_ENDL; + LL_WARNS() << "can't read constraint target direction" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if( !(constraintp->mTargetConstraintDir.isFinite()) ) { - LL_WARNS() << "non-finite constraint target direction" << LL_ENDL; + LL_WARNS() << "non-finite constraint target direction" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1898,25 +1952,29 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (!dp.unpackF32(constraintp->mEaseInStartTime, "ease_in_start") || !std::isfinite(constraintp->mEaseInStartTime)) { - LL_WARNS() << "can't read constraint ease in start time" << LL_ENDL; + LL_WARNS() << "can't read constraint ease in start time" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackF32(constraintp->mEaseInStopTime, "ease_in_stop") || !std::isfinite(constraintp->mEaseInStopTime)) { - LL_WARNS() << "can't read constraint ease in stop time" << LL_ENDL; + LL_WARNS() << "can't read constraint ease in stop time" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackF32(constraintp->mEaseOutStartTime, "ease_out_start") || !std::isfinite(constraintp->mEaseOutStartTime)) { - LL_WARNS() << "can't read constraint ease out start time" << LL_ENDL; + LL_WARNS() << "can't read constraint ease out start time" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackF32(constraintp->mEaseOutStopTime, "ease_out_stop") || !std::isfinite(constraintp->mEaseOutStopTime)) { - LL_WARNS() << "can't read constraint ease out stop time" << LL_ENDL; + LL_WARNS() << "can't read constraint ease out stop time" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1939,7 +1997,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (!parent) { LL_WARNS() << "Joint with no parent: " << joint->getName() - << " Emote: " << mJointMotionList->mEmoteName << LL_ENDL; + << " Emote: " << mJointMotionList->mEmoteName + << " for animation " << asset_id << LL_ENDL; return FALSE; } joint = parent; @@ -1950,7 +2009,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if ( !constraint_joint ) { - LL_WARNS() << "Invalid joint " << j << LL_ENDL; + LL_WARNS() << "Invalid joint " << j + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1962,7 +2022,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) } if (constraintp->mJointStateIndices[i] < 0 ) { - LL_WARNS() << "No joint index for constraint " << i << LL_ENDL; + LL_WARNS() << "No joint index for constraint " << i + << " for animation " << asset_id << LL_ENDL; return FALSE; } } @@ -2318,7 +2379,7 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs, LL_DEBUGS("Animation") << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << LL_ENDL; LLDataPackerBinaryBuffer dp(buffer, size); - if (motionp->deserialize(dp)) + if (motionp->deserialize(dp, asset_uuid)) { motionp->mAssetStatus = ASSET_LOADED; } diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index 4c54d5500..c68243bd4 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -266,7 +266,7 @@ public: public: U32 getFileSize(); BOOL serialize(LLDataPacker& dp) const; - BOOL deserialize(LLDataPacker& dp); + BOOL deserialize(LLDataPacker& dp, const LLUUID& asset_id); BOOL isLoaded() { return !!mJointMotionList; } diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 7a9fb29ee..7ff348d81 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -126,22 +126,22 @@ LLMotion* LLMotionRegistry::createMotion(LLUUID const& id, LLMotionController* c // Class Constructor //----------------------------------------------------------------------------- LLMotionController::LLMotionController() - : mIsSelf(FALSE), - mTimeFactor(sCurrentTimeFactor), + : mTimeFactor(sCurrentTimeFactor), mCharacter(NULL), + mAnimTime(0.f), mActiveMask(0), mDisableSyncing(0), mHidden(false), mHaveVisibleSyncedMotions(false), mPrevTimerElapsed(0.f), - mAnimTime(0.f), mLastTime(0.0f), mHasRunOnce(FALSE), mPaused(FALSE), - mPauseTime(0.f), + mPausedFrame(0), mTimeStep(0.f), mTimeStepCount(0), - mLastInterp(0.f) + mLastInterp(0.f), + mIsSelf(FALSE) { } @@ -467,7 +467,7 @@ BOOL LLMotionController::stopMotionLocally(const LLUUID &id, BOOL stop_immediate { // if already inactive, return false LLMotion *motion = findMotion(id); - return stopMotionInstance(motion, stop_immediate); + return stopMotionInstance(motion, stop_immediate||mPaused); } BOOL LLMotionController::stopMotionInstance(LLMotion* motion, BOOL stop_immediate) @@ -1312,6 +1312,7 @@ void LLMotionController::pauseAllMotions() { //LL_INFOS() << "Pausing animations..." << LL_ENDL; mPaused = TRUE; + mPausedFrame = LLFrameTimer::getFrameCount(); } } diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index 76d8b99b4..2a2ca4b33 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -162,16 +162,20 @@ public: void pauseAllMotions(); void unpauseAllMotions(); BOOL isPaused() const { return mPaused; } + S32 getPausedFrame() const { return mPausedFrame; } // void requestPause(std::vector& avatar_pause_handles); void pauseAllSyncedCharacters(std::vector& avatar_pause_handles); // void setTimeStep(F32 step); + F32 getTimeStep() const { return mTimeStep; } void setTimeFactor(F32 time_factor); F32 getTimeFactor() const { return mTimeFactor; } + F32 getAnimTime() const { return mAnimTime; } + motion_list_t& getActiveMotions() { return mActiveMotions; } void incMotionCounts(S32& num_motions, S32& num_loading_motions, S32& num_loaded_motions, S32& num_active_motions, S32& num_deprecated_motions); @@ -248,7 +252,7 @@ protected: F32 mLastTime; BOOL mHasRunOnce; BOOL mPaused; - F32 mPauseTime; + S32 mPausedFrame; F32 mTimeStep; S32 mTimeStepCount; F32 mLastInterp; @@ -263,7 +267,6 @@ public: bool syncing_disabled(void) const { return mDisableSyncing >= 100; } // Accessors needed for synchronization. - F32 getAnimTime(void) const { return mAnimTime; } bool isHidden(void) const { return mHidden; } // Called often. Should return false if we still need to keep updating our motions even if we're not visible. diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index ff174112a..41d1fdee9 100644 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -22,6 +22,7 @@ set(llmath_SOURCE_FILES llperlin.cpp llquaternion.cpp llrect.cpp + llrigginginfo.cpp llsdutil_math.cpp llsphere.cpp llvector4a.cpp @@ -67,6 +68,7 @@ set(llmath_HEADER_FILES llquaternion2.h llquaternion2.inl llrect.h + llrigginginfo.h llsdutil_math.h llsimdmath.h llsimdtypes.h diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h index 14f89b4af..7dab479bd 100644 --- a/indra/llmath/llmatrix4a.h +++ b/indra/llmath/llmatrix4a.h @@ -700,4 +700,12 @@ public: } } LL_ALIGN_POSTFIX(16); + +inline std::ostream& operator<<(std::ostream& s, const LLMatrix4a& m) +{ + s << "[" << m.getF32ptr()[0] << ", " << m.getF32ptr()[1] << ", " << m.getF32ptr()[2] << ", " << m.getF32ptr()[3] << "]"; + return s; +} + +void matMulBoundBox(const LLMatrix4a &a, const LLVector4a *in_extents, LLVector4a *out_extents); #endif diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h index 2e958b308..a34e3ec88 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -336,4 +336,9 @@ inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p max.setMax(max, p); } +inline std::ostream& operator<<(std::ostream& s, const LLVector4a& v) +{ + s << "(" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << ")"; + return s; +} #endif diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index e531c9d89..a0906af1a 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1301,7 +1301,7 @@ S32 LLPath::getNumNGonPoints(const LLPathParams& params, S32 sides, F32 startOff void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) { // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane. - const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; + static const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; F32 revolutions = params.getRevolutions(); F32 skew = params.getSkew(); @@ -1599,6 +1599,7 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, if (is_sculpted) sides = llmax(sculpt_size, 1); + if (0 < sides) genNGon(params, sides); } break; @@ -2081,6 +2082,7 @@ void LLVolume::resizePath(S32 length) { mPathp->resizePath(length); mVolumeFaces.clear(); + setDirty(); } void LLVolume::regen() @@ -2138,19 +2140,22 @@ BOOL LLVolume::generate() F32 profile_detail = mDetail; F32 path_detail = mDetail; - - U8 path_type = mParams.getPathParams().getCurveType(); - U8 profile_type = mParams.getProfileParams().getCurveType(); - - if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) - { //cylinders don't care about Z-Axis - mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); + + if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) + { + U8 path_type = mParams.getPathParams().getCurveType(); + U8 profile_type = mParams.getProfileParams().getCurveType(); + if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) + { + //cylinders don't care about Z-Axis + mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); + } + else if (path_type == LL_PCODE_PATH_CIRCLE) + { + mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); + } } - else if (path_type == LL_PCODE_PATH_CIRCLE) - { - mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); - } - + BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split); BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split); @@ -2906,15 +2911,41 @@ F32 LLVolume::sculptGetSurfaceArea() return area; } -// create placeholder shape -void LLVolume::sculptGeneratePlaceholder() +// create empty placeholder shape +void LLVolume::sculptGenerateEmptyPlaceholder() { S32 sizeS = mPathp->mPath.size(); S32 sizeT = mProfilep->mProfile.size(); - + + S32 line = 0; + + for (S32 s = 0; s < sizeS; s++) + { + for (S32 t = 0; t < sizeT; t++) + { + S32 i = t + line; + LLVector4a& pt = mMesh[i]; + + F32* p = pt.getF32ptr(); + + p[0] = 0; + p[1] = 0; + p[2] = 0; + + llassert(pt.isFinite3()); + } + line += sizeT; + } +} + +// create sphere placeholder shape +void LLVolume::sculptGenerateSpherePlaceholder() +{ + S32 sizeS = mPathp->mPath.size(); + S32 sizeT = mProfilep->mProfile.size(); + S32 line = 0; - // for now, this is a sphere. for (S32 s = 0; s < sizeS; s++) { for (S32 t = 0; t < sizeT; t++) @@ -3123,7 +3154,7 @@ bool sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32 } // sculpt replaces generate() for sculpted surfaces -void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level) +void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level, bool visible_placeholder) { U8 sculpt_type = mParams.getSculptType(); @@ -3187,13 +3218,22 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, if (area < SCULPT_MIN_AREA || area > SCULPT_MAX_AREA) { data_is_empty = TRUE; + visible_placeholder = true; } } } if (data_is_empty) { - sculptGeneratePlaceholder(); + if (visible_placeholder) + { + // Object should be visible since there will be nothing else to display + sculptGenerateSpherePlaceholder(); + } + else + { + sculptGenerateEmptyPlaceholder(); + } } @@ -3723,10 +3763,46 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, continue; } - if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { + if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) + { + LLVector4a* v = (LLVector4a*)face.mPositions; + LLVector4a* n = (LLVector4a*)face.mNormals; + + for (U32 j = 0; j < (U32)face.mNumIndices / 3; j++) + { + for (S32 k = 0; k < 3; k++) + { + S32 index = face.mEdge[j * 3 + k]; + + if (index == -1) + { + // silhouette edge, currently only cubes, so no other conditions + + S32 v1 = face.mIndices[j * 3 + k]; + S32 v2 = face.mIndices[j * 3 + ((k + 1) % 3)]; + + LLVector4a t; + mat.affineTransform(v[v1], t); + vertices.push_back(LLVector3(t[0], t[1], t[2])); + + norm_mat.rotate(n[v1], t); + + t.normalize3fast(); + normals.push_back(LLVector3(t[0], t[1], t[2])); + + mat.affineTransform(v[v2], t); + vertices.push_back(LLVector3(t[0], t[1], t[2])); + + norm_mat.rotate(n[v2], t); + t.normalize3fast(); + normals.push_back(LLVector3(t[0], t[1], t[2])); + } + } + } } - else { + else + { //============================================== //DEBUG draw edge map instead of silhouette edge @@ -4709,6 +4785,7 @@ LLVolumeFace::~LLVolumeFace() { ll_aligned_free_16(mExtents); mExtents = NULL; + mCenter = NULL; freeData(); } @@ -5556,10 +5633,17 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) if (!partial_build) { resizeIndices(grid_size*grid_size*6); + if (!volume->isMeshAssetLoaded()) + { + mEdge.resize(grid_size*grid_size * 6); + } U16* out = mIndices; S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; + + int cur_edge = 0; + for(S32 gx = 0;gx=0;i--) { *out++ = ((gy*(grid_size+1))+gx+idxs[i]); - } + } + + S32 edge_value = grid_size * 2 * gy + gx * 2; + + if (gx > 0) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; // Mark face to higlight it + } + + if (gy < grid_size - 1) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + mEdge[cur_edge++] = edge_value; + + if (gx < grid_size - 1) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + if (gy > 0) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + mEdge[cur_edge++] = edge_value; } else { @@ -5578,6 +5704,48 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) { *out++ = ((gy*(grid_size+1))+gx+idxs[i]); } + + S32 edge_value = grid_size * 2 * gy + gx * 2; + + if (gy > 0) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + if (gx < grid_size - 1) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + mEdge[cur_edge++] = edge_value; + + if (gy < grid_size - 1) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + if (gx > 0) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + mEdge[cur_edge++] = edge_value; } } } @@ -6056,6 +6224,9 @@ void LLVolumeFace::resizeVertices(S32 num_verts) allocateTangents(0); allocateVertices(num_verts); mNumVertices = num_verts; + + // Force update + mJointRiggingInfoTab.clear(); } void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv) @@ -6201,78 +6372,6 @@ void LLVolumeFace::fillFromLegacyData(std::vector& v, } } -void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in) -{ - U16 offset = mNumVertices; - - S32 new_count = face.mNumVertices + mNumVertices; - - if (new_count > 65536) - { - LL_ERRS() << "Cannot append face -- 16-bit overflow will occur." << LL_ENDL; - } - - if (face.mNumVertices == 0) - { - LL_ERRS() << "Cannot append empty face." << LL_ENDL; - } - - allocateVertices(new_count, true); - mNumVertices = new_count; - - //get destination address of appended face - LLVector4a* dst_pos = mPositions+offset; - LLVector2* dst_tc = mTexCoords+offset; - LLVector4a* dst_norm = mNormals+offset; - - //get source addresses of appended face - const LLVector4a* src_pos = face.mPositions; - const LLVector2* src_tc = face.mTexCoords; - const LLVector4a* src_norm = face.mNormals; - - //load aligned matrices - LLMatrix4a mat, norm_mat; - mat.loadu(mat_in); - norm_mat.loadu(norm_mat_in); - - for (U32 i = 0; i < (U32)face.mNumVertices; ++i) - { - //transform appended face position and store - mat.affineTransform(src_pos[i], dst_pos[i]); - - //transform appended face normal and store - norm_mat.rotate(src_norm[i], dst_norm[i]); - dst_norm[i].normalize3fast(); - - //copy appended face texture coordinate - dst_tc[i] = src_tc[i]; - - if (offset == 0 && i == 0) - { //initialize bounding box - mExtents[0] = mExtents[1] = dst_pos[i]; - } - else - { - //stretch bounding box - update_min_max(mExtents[0], mExtents[1], dst_pos[i]); - } - } - - - new_count = mNumIndices + face.mNumIndices; - - allocateIndices(mNumIndices + face.mNumIndices, true); - - //get destination address into new index buffer - U16* dst_idx = mIndices+mNumIndices; - mNumIndices = new_count; - - for (U32 i = 0; i < (U32)face.mNumIndices; ++i) - { //copy indices, offsetting by old vertex count - dst_idx[i] = face.mIndices[i]+offset; - } -} - BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { BOOL flat = mTypeMask & FLAT_MASK; diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index ad819b8ff..1181fb40f 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -60,6 +60,7 @@ class LLVolumeTriangle; #include "llpointer.h" #include "llfile.h" #include "llalignedarray.h" +#include "llrigginginfo.h" //============================================================================ @@ -870,8 +871,6 @@ public: BOOL create(LLVolume* volume, BOOL partial_build = FALSE); void createTangents(); - - void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform); void resizeVertices(S32 num_verts); void allocateTangents(S32 num_verts); @@ -961,6 +960,10 @@ public: mutable BOOL mWeightsScrubbed; + // Which joints are rigged to, and the bounding box of any rigged + // vertices per joint. + LLJointRiggingInfoTab mJointRiggingInfoTab; + LLOctreeNode* mOctree; //whether or not face has been cache optimized @@ -1059,7 +1062,7 @@ public: U32 mFaceMask; // bit array of which faces exist in this volume LLVector3 mLODScaleBias; // vector for biasing LOD based on scale - void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level); + void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level, bool visible_placeholder); void copyVolumeFaces(const LLVolume* volume); void copyFacesTo(std::vector &faces) const; void copyFacesFrom(const std::vector &faces); @@ -1068,7 +1071,8 @@ public: private: void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); F32 sculptGetSurfaceArea(); - void sculptGeneratePlaceholder(); + void sculptGenerateEmptyPlaceholder(); + void sculptGenerateSpherePlaceholder(); void sculptCalcMeshResolution(U16 width, U16 height, U8 type, S32& s, S32& t); diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 8b3a9c2a5..74bbcd793 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -110,9 +110,9 @@ void LLModel::optimizeVolumeFaces() { for (U32 i = 0; i < (U32)getNumVolumeFaces(); ++i) { - validate_face(mVolumeFaces[i]); + //validate_face(mVolumeFaces[i]); mVolumeFaces[i].optimize(); - validate_face(mVolumeFaces[i]); + //validate_face(mVolumeFaces[i]); } } @@ -161,11 +161,11 @@ void LLModel::sortVolumeFacesByMaterialName() mVolumeFaces = new_faces; } -void LLModel::trimVolumeFacesToSize(S32 new_count, LLVolume::face_list_t* remainder) +void LLModel::trimVolumeFacesToSize(U32 new_count, LLVolume::face_list_t* remainder) { llassert(new_count <= LL_SCULPT_MESH_MAX_FACES); - if (new_count && (getNumVolumeFaces() > new_count)) + if (new_count && ((U32)getNumVolumeFaces() > new_count)) { // Copy out remaining volume faces for alternative handling, if provided // @@ -407,40 +407,6 @@ void LLModel::setVolumeFaceData( LLVector4a::memcpyNonAliased16((F32*) face.mIndices, (F32*) ind.get(), size); } -void LLModel::appendFaces(LLModel *model, LLMatrix4 &transform, LLMatrix4& norm_mat) -{ - if (mVolumeFaces.empty()) - { - setNumVolumeFaces(1); - } - - LLVolumeFace& face = mVolumeFaces[mVolumeFaces.size()-1]; - - - for (S32 i = 0; i < model->getNumFaces(); ++i) - { - face.appendFace(model->getVolumeFace(i), transform, norm_mat); - } - -} - -void LLModel::appendFace(const LLVolumeFace& src_face, std::string src_material, LLMatrix4& mat, LLMatrix4& norm_mat) -{ - S32 rindex = getNumVolumeFaces()-1; - if (rindex == -1 || - mVolumeFaces[rindex].mNumVertices + src_face.mNumVertices >= 65536) - { //empty or overflow will occur, append new face - LLVolumeFace cur_face; - cur_face.appendFace(src_face, mat, norm_mat); - addFace(cur_face); - mMaterialList.push_back(src_material); - } - else - { //append to existing end face - mVolumeFaces.rbegin()->appendFace(src_face, mat, norm_mat); - } -} - void LLModel::addFace(const LLVolumeFace& face) { if (face.mNumVertices == 0) @@ -523,9 +489,9 @@ void LLModel::generateNormals(F32 angle_cutoff) } //weld vertices in temporary face, respecting angle_cutoff (step 2) - validate_face(faceted); + //validate_face(faceted); faceted.optimize(angle_cutoff); - validate_face(faceted); + //validate_face(faceted); //generate normals for welded face based on new topology (step 3) @@ -657,9 +623,9 @@ void LLModel::generateNormals(F32 angle_cutoff) } //remove redundant vertices from new face (step 6) - validate_face(new_face); + //validate_face(new_face); new_face.optimize(); - validate_face(new_face); + //validate_face(new_face); mVolumeFaces[j] = new_face; } @@ -1043,12 +1009,14 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos) { //no exact match found, get closest point const F32 epsilon = 1e-5f; weight_map::iterator iter_up = mSkinWeights.lower_bound(pos); - weight_map::iterator iter_down = ++iter_up; - + weight_map::iterator iter_down = iter_up; + if (iter_up != mSkinWeights.end()) + { + iter_down = ++iter_up; + } weight_map::iterator best = iter_up; - // iter == mSkinWeights.end()... - F32 min_dist = (iter_up->first - pos).magVec(); + F32 min_dist = (iter->first - pos).magVec(); bool done = false; while (!done) @@ -1399,14 +1367,16 @@ bool LLModel::loadDecomposition(LLSD& header, std::istream& is) LLMeshSkinInfo::LLMeshSkinInfo(): mPelvisOffset(0.0), mLockScaleIfJointPosition(false), - mInvalidJointsScrubbed(false) + mInvalidJointsScrubbed(false), + mJointNumsInitialized(false) { } LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin): mPelvisOffset(0.0), mLockScaleIfJointPosition(false), - mInvalidJointsScrubbed(false) + mInvalidJointsScrubbed(false), + mJointNumsInitialized(false) { fromLLSD(skin); } diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index 0eb358696..9b1df2a0e 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -57,6 +57,7 @@ public: float mPelvisOffset; bool mLockScaleIfJointPosition; bool mInvalidJointsScrubbed; + bool mJointNumsInitialized; }; class LLModel : public LLVolume @@ -158,9 +159,6 @@ public: EModelStatus getStatus() const {return mStatus;} static std::string getStatusString(U32 status) ; - void appendFaces(LLModel* model, LLMatrix4& transform, LLMatrix4& normal_transform); - void appendFace(const LLVolumeFace& src_face, std::string src_material, LLMatrix4& mat, LLMatrix4& norm_mat); - void setNumVolumeFaces(S32 count); void setVolumeFaceData( S32 f, @@ -177,7 +175,7 @@ public: void sortVolumeFacesByMaterialName(); void normalizeVolumeFaces(); - void trimVolumeFacesToSize(S32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL); + void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL); void optimizeVolumeFaces(); void offsetMesh( const LLVector3& pivotPoint ); void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out); diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h index 18651ed73..5a382e408 100644 --- a/indra/llprimitive/llmodelloader.h +++ b/indra/llprimitive/llmodelloader.h @@ -81,6 +81,7 @@ public: GENERATING_VERTEX_BUFFERS, GENERATING_LOD, DONE, + WARNING_BIND_SHAPE_ORIENTATION, ERROR_PARSING, //basically loading failed ERROR_MATERIALS, ERROR_PASSWORD_REQUIRED, diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index e30f49493..d952f3c67 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -175,7 +175,7 @@ LLPrimitive::~LLPrimitive() { clearTextureList(); // Cleanup handled by volume manager - if (mVolumep) + if (mVolumep && sVolumeManager) { sVolumeManager->unrefVolume(mVolumep); } @@ -586,7 +586,7 @@ U8 LLPrimitive::pCodeToLegacy(const LLPCode pcode) // static -// Don't crash or llerrs here! This function is used for debug strings. +// Don't crash or LL_ERRS() here! This function is used for debug strings. std::string LLPrimitive::pCodeToString(const LLPCode pcode) { std::string pcode_string; @@ -729,6 +729,16 @@ S32 face_index_from_id(LLFaceID face_ID, const std::vector& fac BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume) { + if (NO_LOD == detail) + { + // build the new object + setChanged(GEOMETRY); + sVolumeManager->unrefVolume(mVolumep); + mVolumep = new LLVolume(volume_params, 1, TRUE, TRUE); + setNumTEs(mVolumep->getNumFaces()); + return FALSE; + } + LLVolume *volumep; if (unique_volume) { @@ -1577,6 +1587,8 @@ BOOL LLNetworkData::isValid(U16 param_type, U32 size) return (size == 17); case PARAMS_LIGHT_IMAGE: return (size == 28); + case PARAMS_EXTENDED_MESH: + return (size == 4); } return FALSE; @@ -2004,3 +2016,67 @@ bool LLLightImageParams::fromLLSD(LLSD& sd) return false; } + +//============================================================================ + +LLExtendedMeshParams::LLExtendedMeshParams() +{ + mType = PARAMS_EXTENDED_MESH; + mFlags = 0; +} + +BOOL LLExtendedMeshParams::pack(LLDataPacker &dp) const +{ + dp.packU32(mFlags, "flags"); + + return TRUE; +} + +BOOL LLExtendedMeshParams::unpack(LLDataPacker &dp) +{ + dp.unpackU32(mFlags, "flags"); + + return TRUE; +} + +bool LLExtendedMeshParams::operator==(const LLNetworkData& data) const +{ + if (data.mType != PARAMS_EXTENDED_MESH) + { + return false; + } + + const LLExtendedMeshParams *param = (const LLExtendedMeshParams*)&data; + if ( (param->mFlags != mFlags) ) + { + return false; + } + + return true; +} + +void LLExtendedMeshParams::copy(const LLNetworkData& data) +{ + const LLExtendedMeshParams *param = (LLExtendedMeshParams*)&data; + mFlags = param->mFlags; +} + +LLSD LLExtendedMeshParams::asLLSD() const +{ + LLSD sd; + + sd["flags"] = LLSD::Integer(mFlags); + + return sd; +} + +bool LLExtendedMeshParams::fromLLSD(LLSD& sd) +{ + if (sd.has("flags")) + { + setFlags( sd["flags"].asInteger()); + return true; + } + + return false; +} diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 85fb2233e..7999d2b0f 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -106,6 +106,7 @@ public: PARAMS_LIGHT_IMAGE = 0x40, PARAMS_RESERVED = 0x50, // Used on server-side PARAMS_MESH = 0x60, + PARAMS_EXTENDED_MESH = 0x70, }; public: @@ -288,6 +289,27 @@ public: }; +class LLExtendedMeshParams : public LLNetworkData +{ +protected: + U32 mFlags; + +public: + static const U32 ANIMATED_MESH_ENABLED_FLAG = 0x1 << 0; + + LLExtendedMeshParams(); + /*virtual*/ BOOL pack(LLDataPacker &dp) const; + /*virtual*/ BOOL unpack(LLDataPacker &dp); + /*virtual*/ bool operator==(const LLNetworkData& data) const; + /*virtual*/ void copy(const LLNetworkData& data); + LLSD asLLSD() const; + operator LLSD() const { return asLLSD(); } + bool fromLLSD(LLSD& sd); + + void setFlags(const U32& flags) { mFlags = flags; } + U32 getFlags() const { return mFlags; } + +}; // This code is not naming-standards compliant. Leaving it like this for // now to make the connection to code in @@ -308,9 +330,9 @@ struct LLTEContents S16 image_rot[MAX_TES]; U8 bump[MAX_TES]; U8 media_flags[MAX_TES]; - U8 glow[MAX_TES]; + U8 glow[MAX_TES]; LLMaterialID material_ids[MAX_TES]; - + static const U32 MAX_TE_BUFFER = 4096; U8 packed_buffer[MAX_TE_BUFFER]; @@ -483,6 +505,11 @@ protected: U32 mMiscFlags; // home for misc bools static LLVolumeMgr* sVolumeManager; + + enum + { + NO_LOD = -1 + }; }; inline BOOL LLPrimitive::isAvatar() const diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index d49eb8a29..261e3f67f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1554,6 +1554,7 @@ if (WINDOWS) ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py generate_viewer_version stage_third_party_libs + llcommon ${COPY_INPUT_DEPENDENCIES} COMMENT "Performing viewer_manifest copy" ) diff --git a/indra/newview/floaterlocalassetbrowse.cpp b/indra/newview/floaterlocalassetbrowse.cpp index c53705cf9..3c8e4fae7 100644 --- a/indra/newview/floaterlocalassetbrowse.cpp +++ b/indra/newview/floaterlocalassetbrowse.cpp @@ -653,7 +653,7 @@ void LocalAssetBrowser::PerformSculptUpdates(LocalBitmap& unit) { LLImageRaw* rawimage = gTextureList.findImage(unit.getID())->getCachedRawImage(); - aobj.object->getVolume()->sculpt(rawimage->getWidth(), rawimage->getHeight(), rawimage->getComponents(), rawimage->getData(), 0); + aobj.object->getVolume()->sculpt(rawimage->getWidth(), rawimage->getHeight(), rawimage->getComponents(), rawimage->getData(), 0, true); unit.volume_dirty = false; } diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index f2800e3d7..8843dad39 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -1403,6 +1403,16 @@ void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer } //LL_INFOS() << "Rebuilt face " << face->getTEOffset() << " of " << face->getDrawable() << " at " << gFrameTimeSeconds << LL_ENDL; + + // Let getGeometryVolume know if a texture matrix is in play + if (face->mTextureMatrix) + { + face->setState(LLFace::TEXTURE_ANIM); + } + else + { + face->clearState(LLFace::TEXTURE_ANIM); + } face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_inv_trans, offset, true); buffer->flush(); @@ -1410,16 +1420,24 @@ void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face) { - LLVector4a* weight = vol_face.mWeights; - if (!weight) + LLVector4a* weights = vol_face.mWeights; + if (!weights) { return; } + // FIXME ugly const cast + LLSkinningUtil::scrubInvalidJoints(avatar, const_cast(skin)); LLPointer buffer = face->getVertexBuffer(); LLDrawable* drawable = face->getDrawable(); U32 data_mask = face->getRiggedVertexBufferDataMask(); + + if (!vol_face.mWeightsScrubbed) + { + LLSkinningUtil::scrubSkinWeights(weights, vol_face.mNumVertices, skin); + vol_face.mWeightsScrubbed = TRUE; + } if (buffer.isNull() || buffer->getTypeMask() != data_mask || @@ -1452,7 +1470,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* if (sShaderLevel <= 0 && face->mLastSkinTime < avatar->getLastSkinTime()) { - avatar->updateSoftwareSkinnedVertices(skin, weight, vol_face, buffer); + avatar->updateSoftwareSkinnedVertices(skin, weights, vol_face, buffer); } } diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index 00a00a855..c16c5739f 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -352,7 +352,7 @@ BOOL LLFloaterBvhPreview::postBuild() // pass animation data through memory buffer loaderp->serialize(dp); dp.reset(); - success = motionp && motionp->deserialize(dp); + success = motionp && motionp->deserialize(dp, mMotionID); } else { @@ -411,7 +411,7 @@ BOOL LLFloaterBvhPreview::postBuild() motionp = (LLKeyframeMotion*)mAnimPreview->getDummyAvatar()->createMotion(mMotionID); LLDataPackerBinaryBuffer dp((U8*)file_buffer, file_size); dp.reset(); - success = motionp && motionp->deserialize(dp); + success = motionp && motionp->deserialize(dp, mMotionID); } raw_animatn.close(); diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 05964fb81..283ecb157 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -849,7 +849,7 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance) if (imagep) { - mVolume->sculpt(imagep->getWidth(), imagep->getHeight(), imagep->getComponents(), imagep->getData(), 0); + mVolume->sculpt(imagep->getWidth(), imagep->getHeight(), imagep->getComponents(), imagep->getData(), 0, false); } const LLVolumeFace &vf = mVolume->getVolumeFace(0); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 84b19e252..9f798c68c 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -672,6 +672,11 @@ void LLFloaterModelPreview::draw() childSetTextArg("status", "[STATUS]", getString("status_parse_error")); toggleCalculateButton(false); } + else + if (mModelPreview->getLoadState() == LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION) + { + childSetTextArg("status", "[STATUS]", getString("status_bind_shape_orientation")); + } else { childSetTextArg("status", "[STATUS]", getString("status_idle")); @@ -1588,6 +1593,19 @@ void LLModelPreview::rebuildUploadData() mFMP->childDisable( "calculate_btn" ); } } + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) mFMP; + bool upload_skinweights = fmp && fmp->childGetValue("upload_skin").asBoolean(); + if (upload_skinweights && high_lod_model->mSkinInfo.mJointNames.size() > 0) + { + LLQuaternion bind_rot = LLSkinningUtil::getUnscaledQuaternion(high_lod_model->mSkinInfo.mBindShapeMatrix); + LLQuaternion identity; + if (!bind_rot.isEqualEps(identity,0.01)) + { + LL_WARNS() << "non-identity bind shape rot. mat is " << high_lod_model->mSkinInfo.mBindShapeMatrix + << " bind_rot " << bind_rot << LL_ENDL; + setLoadState( LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION ); + } + } } instance.mTransform = mat; mUploadData.push_back(instance); diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index b0280d45b..842d5a137 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -37,20 +37,17 @@ void LLSkinningUtil::initClass() { } -// static U32 LLSkinningUtil::getMaxJointCount() { U32 result = LL_MAX_JOINTS_PER_MESH_OBJECT; return result; } -// static U32 LLSkinningUtil::getMeshJointCount(const LLMeshSkinInfo *skin) { return llmin((U32)getMaxJointCount(), (U32)skin->mJointNames.size()); } -// static void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin) { if (skin->mInvalidJointsScrubbed) @@ -64,8 +61,10 @@ void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin // needed for handling of any legacy bad data. if (!avatar->getJoint(skin->mJointNames[j])) { - LL_DEBUGS("Avatar") << "Mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL; + LL_DEBUGS("Avatar") << avatar->getFullname() << " mesh rigged to invalid joint " << skin->mJointNames[j] << LL_ENDL; + LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL; skin->mJointNames[j] = "mPelvis"; + skin->mJointNumsInitialized = false; // force update after names change. } } skin->mInvalidJointsScrubbed = true; @@ -77,69 +76,43 @@ void LLSkinningUtil::initSkinningMatrixPalette( S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar, - bool relative_to_avatar) + bool relative_to_avatar) { - for (U32 j = 0; j < (U32)count; ++j) - { - LLJoint *joint = NULL; - if( skin->mJointNums[j] <= -50 ) - { - // Give up silently. - mat[j].loadu((F32*)skin->mInvBindMatrix[j].mMatrix); - continue; - } - else if (skin->mJointNums[j] < 0 ) - { - joint = avatar->getJoint(skin->mJointNames[j]); - if (!joint) - { - LL_WARNS_ONCE("Avatar") << "Rigged to invalid joint name " << skin->mJointNames[j] << " Using 'root' fallback." << LL_ENDL; - joint = avatar->getJoint("mRoot"); - } - if (joint) - { - //LL_INFOS() << "Found joint " << skin->mJointNames[j] << " Id = " << joint->getJointNum() << LL_ENDL; - skin->mJointNums[j] = joint->getJointNum(); - } - else - { - --skin->mJointNums[j]; - } - } - else - { - joint = avatar->getJoint(skin->mJointNums[j]); - if (!joint) - { - LL_WARNS_ONCE() << "Joint not found: " << skin->mJointNames[j] << " Id = " << skin->mJointNums[j] << LL_ENDL; - } - } - if (joint) - { - LLMatrix4a bind; - bind.loadu((F32*)skin->mInvBindMatrix[j].mMatrix); - if (relative_to_avatar) - { - LLMatrix4a trans = joint->getWorldMatrix(); - trans.translate_affine(avatar->getPosition() * -1.f); - mat[j].setMul(trans, bind); - } - else - mat[j].setMul(joint->getWorldMatrix(), bind); - } - else - { - mat[j].loadu((F32*)skin->mInvBindMatrix[j].mMatrix); - // This shouldn't happen - in mesh upload, skinned - // rendering should be disabled unless all joints are - // valid. In other cases of skinned rendering, invalid - // joints should already have been removed during scrubInvalidJoints(). - LL_WARNS_ONCE("Avatar") << "Rigged to invalid joint name " << skin->mJointNames[j] << LL_ENDL; - } - } + initJointNums(const_cast(skin), avatar); + for (U32 j = 0; j < (U32)count; ++j) + { + LLJoint *joint = avatar->getJoint(skin->mJointNums[j]); + if (joint) + { + LLMatrix4a bind; + bind.loadu((F32*)skin->mInvBindMatrix[j].mMatrix); + if (relative_to_avatar) + { + LLMatrix4a trans = joint->getWorldMatrix(); + trans.translate_affine(avatar->getPosition() * -1.f); + mat[j].setMul(trans, bind); + } + else + mat[j].setMul(joint->getWorldMatrix(), bind); + } + else + { + mat[j].loadu((F32*)skin->mInvBindMatrix[j].mMatrix); + // This shouldn't happen - in mesh upload, skinned + // rendering should be disabled unless all joints are + // valid. In other cases of skinned rendering, invalid + // joints should already have been removed during scrubInvalidJoints(). + LL_WARNS_ONCE("Avatar") << avatar->getFullname() + << " rigged to invalid joint name " << skin->mJointNames[j] + << " num " << skin->mJointNums[j] << LL_ENDL; + LL_WARNS_ONCE("Avatar") << avatar->getFullname() + << " avatar build state: isBuilt() " << avatar->isBuilt() + << " mInitFlags " << avatar->mInitFlags << LL_ENDL; + } + } } -// static + void LLSkinningUtil::checkSkinWeights(const LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) { #ifndef LL_RELEASE_FOR_DOWNLOAD @@ -179,7 +152,6 @@ void LLSkinningUtil::scrubSkinWeights(LLVector4a* weights, U32 num_vertices, con checkSkinWeights(weights, num_vertices, skin); } -// static void LLSkinningUtil::getPerVertexSkinMatrix( const F32* weights, LLMatrix4a* mat, @@ -231,3 +203,62 @@ void LLSkinningUtil::getPerVertexSkinMatrix( llassert(valid_weights); } +void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar) +{ + if (!skin->mJointNumsInitialized) + { + for (U32 j = 0; j < skin->mJointNames.size(); ++j) + { + LLJoint *joint = NULL; + if (skin->mJointNums[j] == -1) + { + joint = avatar->getJoint(skin->mJointNames[j]); + if (joint) + { + skin->mJointNums[j] = joint->getJointNum(); + if (skin->mJointNums[j] < 0) + { + LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " joint has unusual number " << skin->mJointNames[j] << ": " << skin->mJointNums[j] << LL_ENDL; + LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " avatar build state: isBuilt() " << avatar->isBuilt() << " mInitFlags " << avatar->mInitFlags << LL_ENDL; + } + } + else + { + LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " unable to find joint " << skin->mJointNames[j] << LL_ENDL; + LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " avatar build state: isBuilt() " << avatar->isBuilt() << " mInitFlags " << avatar->mInitFlags << LL_ENDL; +#if 0 + dump_avatar_and_skin_state("initJointNums joint not found", avatar, skin); +#endif + } + } + } + skin->mJointNumsInitialized = true; + } +} + +// This is used for extracting rotation from a bind shape matrix that +// already has scales baked in +LLQuaternion LLSkinningUtil::getUnscaledQuaternion(const LLMatrix4& mat4) +{ + LLMatrix3 bind_mat = mat4.getMat3(); + for (auto i = 0; i < 3; i++) + { + F32 len = 0.0f; + for (auto j = 0; j < 3; j++) + { + len += bind_mat.mMatrix[i][j] * bind_mat.mMatrix[i][j]; + } + if (len > 0.0f) + { + len = sqrt(len); + for (auto j = 0; j < 3; j++) + { + bind_mat.mMatrix[i][j] /= len; + } + } + } + bind_mat.invert(); + LLQuaternion bind_rot = bind_mat.quaternion(); + bind_rot.normalize(); + return bind_rot; +} diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h index e8d9afa65..c57050ded 100644 --- a/indra/newview/llskinningutil.h +++ b/indra/newview/llskinningutil.h @@ -31,17 +31,18 @@ class LLVOAvatar; class LLMeshSkinInfo; class LLMatrix4a; -class LLSkinningUtil +namespace LLSkinningUtil { -public: - static void initClass(); - static U32 getMaxJointCount(); - static U32 getMeshJointCount(const LLMeshSkinInfo *skin); - static void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin); - static void initSkinningMatrixPalette(LLMatrix4a* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar, bool relative_to_avatar = false); - static void checkSkinWeights(const LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); - static void scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); - static void getPerVertexSkinMatrix(const F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints); + void initClass(); + U32 getMaxJointCount(); + U32 getMeshJointCount(const LLMeshSkinInfo *skin); + void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin); + void initSkinningMatrixPalette(LLMatrix4a* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar, bool relative_to_avatar = false); + void checkSkinWeights(const LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); + void scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); + void getPerVertexSkinMatrix(const F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints); + void initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar); + LLQuaternion getUnscaledQuaternion(const LLMatrix4& mat4); }; #endif diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index f606549e1..880e4bb9e 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1193,7 +1193,7 @@ void LLVOVolume::sculpt() sculpt_data = raw_image->getData(); } - getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level); + getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level, mSculptTexture->isMissingAsset()); //notify rebuild any other VOVolumes that reference this sculpty volume for (S32 i = 0; i < mSculptTexture->getNumVolumes(); ++i) @@ -4111,6 +4111,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin); LLSkinningUtil::initSkinningMatrixPalette(mat, maxJoints, skin, avatar, true); + LLMatrix4a bind_shape_matrix; + bind_shape_matrix.loadu(skin->mBindShapeMatrix); + LLVector4a av_pos; av_pos.load3(avatar->getPosition().mV); @@ -4127,8 +4130,6 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons continue; } LLSkinningUtil::checkSkinWeights(weight, dst_face.mNumVertices, skin); - LLMatrix4a bind_shape_matrix; - bind_shape_matrix.loadu(skin->mBindShapeMatrix); LLVector4a* pos = dst_face.mPositions; @@ -4143,11 +4144,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons LLSkinningUtil::getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints); LLVector4a& v = vol_face.mPositions[j]; - LLVector4a t; - LLVector4a dst; - bind_shape_matrix.affineTransform(v, t); - final_mat.affineTransform(t, dst); - pos[j] = dst; + + final_mat.mul(bind_shape_matrix); + final_mat.affineTransform(v, pos[j]); pos[j].add(av_pos); } @@ -6166,7 +6165,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac if (material_pass) { - U32 pass[] = + static const U32 pass[] = { LLRenderPass::PASS_MATERIAL, LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_MATERIAL_ALPHA,