diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 16877c345e82b94ab7725f1f083cd02505b50729..4ba81047f54eb06aa1cab51930ae01a65b488220 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -541,6 +541,7 @@ set(viewer_SOURCE_FILES llsidepaneliteminfo.cpp llsidepaneltaskinfo.cpp llsidetraypanelcontainer.cpp + llskinningutil.cpp llsky.cpp llslurl.cpp llsnapshotlivepreview.cpp @@ -1147,6 +1148,7 @@ set(viewer_HEADER_FILES llsidepaneliteminfo.h llsidepaneltaskinfo.h llsidetraypanelcontainer.h + llskinningutil.h llsky.h llslurl.h llsnapshotlivepreview.h diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index fbf2a04bcc82c732f8008d2d9c6946f07c47040d..04758ef839fcebf640d81d998b4a2fcdef30e573 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -101,6 +101,7 @@ #include "llscenemonitor.h" #include "llavatarrenderinfoaccountant.h" #include "lllocalbitmaps.h" +#include "llskinningutil.h" // Linden library includes #include "llavatarnamecache.h" @@ -794,6 +795,9 @@ bool LLAppViewer::init() LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; + // initialize skinning util + LLSkinningUtil::initClass(); + //set the max heap size. initMaxHeapSize() ; LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize")); diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index dff6cada9abea4a9fe251d66939525cedbf07da3..89233b8e325c23ad40826eea195edec2a7f26a9e 100755 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "lldrawpoolavatar.h" +#include "llskinningutil.h" #include "llrender.h" #include "llvoavatar.h" @@ -1537,282 +1538,6 @@ void LLDrawPoolAvatar::getRiggedGeometry( buffer->flush(); } -// static -U32 LLDrawPoolAvatar::getMaxJointCount() -{ - return llmin(LL_MAX_JOINTS_PER_MESH_OBJECT, gSavedSettings.getU32("MaxJointsPerMeshObject")); -} - -// static -U32 LLDrawPoolAvatar::getMeshJointCount(const LLMeshSkinInfo *skin) -{ - return llmin((U32)getMaxJointCount(), (U32)skin->mJointNames.size()); -} - -bool getNameIndex(const std::string& name, std::vector<std::string>& names, U32& result) -{ - std::vector<std::string>::const_iterator find_it = - std::find(names.begin(), names.end(), name); - if (find_it != names.end()) - { - result = find_it - names.begin(); - return true; - } - else - { - return false; - } -} - -// Find a name table index that is also a valid joint on the -// avatar. Order of preference is: requested name, mPelvis, first -// valid match in names table. -U32 getValidJointIndex(const std::string& name, LLVOAvatar *avatar, std::vector<std::string>& joint_names) -{ - U32 result; - if (avatar->getJoint(name) && getNameIndex(name,joint_names,result)) - { - return result; - } - if (getNameIndex("mPelvis",joint_names,result)) - { - return result; - } - for (U32 j=0; j<joint_names.size(); j++) - { - if (avatar->getJoint(joint_names[j])) - { - return j; - } - } - // BENTO how to handle? - LL_ERRS() << "no valid joints in joint_names" << LL_ENDL; - return 0; -} - -// Which joint will stand in for this joint? -U32 getProxyJointIndex(U32 joint_index, LLVOAvatar *avatar, std::vector<std::string>& joint_names) -{ - bool include_enhanced = gSavedSettings.getBOOL("IncludeEnhancedSkeleton"); - U32 j_proxy = getValidJointIndex(joint_names[joint_index], avatar, joint_names); - LLJoint *joint = avatar->getJoint(joint_names[j_proxy]); - llassert(joint); - // BENTO - test of simple push-to-base-ancestor - // complexity reduction scheme. Find the first - // ancestor that's not flagged as extended, or the - // last ancestor that's rigged in this mesh, whichever - // comes first. - while (1) - { - if (include_enhanced || - joint->getSupport()==LLJoint::SUPPORT_BASE) - break; - LLJoint *parent = joint->getParent(); - if (!parent) - break; - if (!getNameIndex(parent->getName(), joint_names, j_proxy)) - { - break; - } - joint = parent; - } - return j_proxy; -} - -// static - -// Destructively remap the joints in skin info based on what joints -// are known in the avatar, and which are currently supported. This -// will also populate mJointRemap[] in the skin, which can be used to -// make the corresponding changes to the integer part of vertex -// weights. -// -// This will throw away joint info for any joints that are not known -// in the avatar, or not currently flagged to support based on the -// debug setting for IncludeEnhancedSkeleton. -// -// static -void LLDrawPoolAvatar::remapSkinInfoJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin) -{ - // skip if already done. - if (!skin->mJointRemap.empty()) - { - return; - } - - // Compute the remap - std::vector<U32> j_proxy(skin->mJointNames.size()); - for (U32 j = 0; j < skin->mJointNames.size(); ++j) - { - U32 j_rep = getProxyJointIndex(j, avatar, skin->mJointNames); - j_proxy[j] = j_rep; - } - S32 top = 0; - std::vector<U32> j_remap(skin->mJointNames.size()); - // Fill in j_remap for all joints that will make the cut. - for (U32 j = 0; j < skin->mJointNames.size(); ++j) - { - if (j_proxy[j] == j) - { - // Joint will be included - j_remap[j] = top++; - } - } - // Then use j_proxy to fill in j_remap for the joints that will be discarded - for (U32 j = 0; j < skin->mJointNames.size(); ++j) - { - if (j_proxy[j] != j) - { - j_remap[j] = j_remap[j_proxy[j]]; - } - } - - - // Apply the remap to mJointNames, mInvBindMatrix, and mAlternateBindMatrix - std::vector<std::string> new_joint_names; - std::vector<LLMatrix4> new_inv_bind_matrix; - std::vector<LLMatrix4> new_alternate_bind_matrix; - - for (U32 j = 0; j < skin->mJointNames.size(); ++j) - { - if (j_proxy[j] == j) - { - new_joint_names.push_back(skin->mJointNames[j]); - new_inv_bind_matrix.push_back(skin->mInvBindMatrix[j]); - if (!skin->mAlternateBindMatrix.empty()) - { - new_alternate_bind_matrix.push_back(skin->mAlternateBindMatrix[j]); - } - } - } - - for (U32 j = 0; j < skin->mJointNames.size(); ++j) - { - LL_INFOS() << "Starting joint[" << j << "] = " << skin->mJointNames[j] << " j_remap " << j_remap[j] << " ==> " << new_joint_names[j_remap[j]] << LL_ENDL; - } - - skin->mJointNames = new_joint_names; - skin->mInvBindMatrix = new_inv_bind_matrix; - skin->mAlternateBindMatrix = new_alternate_bind_matrix; - skin->mJointRemap = j_remap; -} - -// static -void LLDrawPoolAvatar::initSkinningMatrixPalette( - LLMatrix4* mat, - S32 count, - const LLMeshSkinInfo* skin, - LLVOAvatar *avatar) -{ - // BENTO - switching to use Matrix4a and SSE might speed this up. - // Note that we are mostly passing Matrix4a's to this routine anyway, just dubiously casted. - for (U32 j = 0; j < count; ++j) - { - LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); - mat[j] = skin->mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } -} - -// Transform the weights based on the remap info stored in skin. Note -// that this is destructive and non-idempotent, so we need to keep -// track of whether we've done it already. If the desired remapping -// changes, the viewer must be restarted. -// -// static -void LLDrawPoolAvatar::remapSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) -{ - llassert(skin->mJointRemap.size()>0); // Must call remapSkinInfoJoints() first, which this checks for. - const U32* remap = &skin->mJointRemap[0]; - const S32 max_joints = skin->mJointNames.size(); - for (U32 j=0; j<num_vertices; j++) - { - F32 *w = weights[j].getF32ptr(); - - for (U32 k=0; k<4; ++k) - { - S32 i = llfloor(w[k]); - F32 f = w[k]-i; - i = llclamp(i,0,max_joints-1); - w[k] = remap[i] + f; - } - } -} - -// static -void LLDrawPoolAvatar::checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) -{ - if (skin->mJointRemap.size()>0) - { - // Check the weights are consistent with the current remap. - const S32 max_joints = skin->mJointNames.size(); - for (U32 j=0; j<num_vertices; j++) - { - F32 *w = weights[j].getF32ptr(); - - for (U32 k=0; k<4; ++k) - { - S32 i = llfloor(w[k]); - llassert(i>=0); - llassert(i<max_joints); - } - } - } -} - -// static -void LLDrawPoolAvatar::getPerVertexSkinMatrix( - F32* weights, - LLMatrix4a* mat, - bool handle_bad_scale, - LLMatrix4a& final_mat, - U32 max_joints) -{ - - final_mat.clear(); - - S32 idx[4]; - - LLVector4 wght; - - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weights[k]; - - // BENTO potential optimizations - // - Do clamping in unpackVolumeFaces() (once instead of every time) - // - int vs floor: if we know w is - // >= 0.0, we can use int instead of floorf; the latter - // allegedly has a lot of overhead due to ieeefp error - // checking which we should not need. - idx[k] = llclamp((S32) floorf(w), (S32)0, (S32)max_joints-1); - - wght[k] = w - floorf(w); - scale += wght[k]; - } - if (handle_bad_scale && scale <= 0.f) - { - wght = LLVector4(1.0f, 0.0f, 0.0f, 0.0f); - } - else - { - // This is enforced in unpackVolumeFaces() - llassert(scale>0.f); - wght *= 1.f/scale; - } - - for (U32 k = 0; k < 4; k++) - { - F32 w = wght[k]; - - LLMatrix4a src; - src.setMul(mat[idx[k]], w); - - final_mat.add(src); - } -} - void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( LLVOAvatar* avatar, LLFace* face, @@ -1826,7 +1551,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( return; } // BENTO ugly const cast - remapSkinInfoJoints(avatar, const_cast<LLMeshSkinInfo*>(skin)); + LLSkinningUtil::remapSkinInfoJoints(avatar, const_cast<LLMeshSkinInfo*>(skin)); LLPointer<LLVertexBuffer> buffer = face->getVertexBuffer(); LLDrawable* drawable = face->getDrawable(); @@ -1835,7 +1560,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( if (!vol_face.mWeightsRemapped) { - remapSkinWeights(weight, vol_face.mNumVertices, skin); + LLSkinningUtil::remapSkinWeights(weight, vol_face.mNumVertices, skin); vol_face.mWeightsRemapped = TRUE; } @@ -1890,18 +1615,18 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( //build matrix palette LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; - U32 count = getMeshJointCount(skin); - initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar); - checkSkinWeights(weight, buffer->getNumVerts(), skin); + U32 count = LLSkinningUtil::getMeshJointCount(skin); + LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar); + LLSkinningUtil::checkSkinWeights(weight, buffer->getNumVerts(), skin); LLMatrix4a bind_shape_matrix; bind_shape_matrix.loadu(skin->mBindShapeMatrix); - const U32 max_joints = getMaxJointCount(); + const U32 max_joints = LLSkinningUtil::getMaxJointCount(); for (U32 j = 0; j < buffer->getNumVerts(); ++j) { LLMatrix4a final_mat; - getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints); + LLSkinningUtil::getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints); LLVector4a& v = vol_face.mPositions[j]; LLVector4a t; @@ -1984,8 +1709,8 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) { // upload matrix palette to shader LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; - U32 count = getMeshJointCount(skin); - initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar); + U32 count = LLSkinningUtil::getMeshJointCount(skin); + LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar); stop_glerror(); diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index 8d6e95ba1ab90be1d9b22819cca3c44d6ddc4ab9..b9d220405211c0a8119bde65932ebf652dc434f3 100755 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -134,13 +134,6 @@ class LLDrawPoolAvatar : public LLFacePool void endDeferredRiggedBump(); void getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer>& buffer, U32 data_mask, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face); - static U32 getMaxJointCount(); - static U32 getMeshJointCount(const LLMeshSkinInfo *skin); - static void remapSkinInfoJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin); - static void initSkinningMatrixPalette(LLMatrix4* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar); - static void checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); - static void remapSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); - static void getPerVertexSkinMatrix(F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints); void updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* facep, const LLMeshSkinInfo* skin, diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index c971faac5f9df6282113f9bfcc3623a943b5efb9..3cad7badadfe568d800ee048ebbfd87f1ae33f7b 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -42,7 +42,6 @@ #include "llcombobox.h" #include "lldatapacker.h" #include "lldrawable.h" -#include "lldrawpoolavatar.h" #include "llrender.h" #include "llface.h" #include "lleconomy.h" @@ -54,6 +53,7 @@ #include "llmeshrepository.h" #include "llnotificationsutil.h" #include "llsdutil_math.h" +#include "llskinningutil.h" #include "lltextbox.h" #include "lltoolmgr.h" #include "llui.h" @@ -4031,17 +4031,17 @@ BOOL LLModelPreview::render() LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; const LLMeshSkinInfo *skin = &model->mSkinInfo; - U32 count = LLDrawPoolAvatar::getMeshJointCount(skin); - LLDrawPoolAvatar::initSkinningMatrixPalette((LLMatrix4*)mat, count, + U32 count = LLSkinningUtil::getMeshJointCount(skin); + LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, getPreviewAvatar()); LLMatrix4a bind_shape_matrix; bind_shape_matrix.loadu(skin->mBindShapeMatrix); - U32 max_joints = LLDrawPoolAvatar::getMaxJointCount(); + U32 max_joints = LLSkinningUtil::getMaxJointCount(); for (U32 j = 0; j < buffer->getNumVerts(); ++j) { LLMatrix4a final_mat; F32 *wptr = weight[j].mV; - LLDrawPoolAvatar::getPerVertexSkinMatrix(wptr, mat, true, final_mat, max_joints); + LLSkinningUtil::getPerVertexSkinMatrix(wptr, mat, true, final_mat, max_joints); //VECTORIZE THIS LLVector4a& v = face.mPositions[j]; diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp new file mode 100644 index 0000000000000000000000000000000000000000..23bbbdcf90fc6fe4a03bc4b137213591623fdee3 --- /dev/null +++ b/indra/newview/llskinningutil.cpp @@ -0,0 +1,329 @@ +/** +* @file llskinningutil.cpp +* @brief Functions for mesh object skinning +* @author vir@lindenlab.com +* +* $LicenseInfo:firstyear=2015&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2015, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llskinningutil.h" +#include "llvoavatar.h" +#include "llviewercontrol.h" +#include "llmeshrepository.h" + +bool LLSkinningUtil::sIncludeEnhancedSkeleton = true; +U32 LLSkinningUtil::sMaxJointsPerMeshObject = LL_MAX_JOINTS_PER_MESH_OBJECT; + +namespace { + +bool get_name_index(const std::string& name, std::vector<std::string>& names, U32& result) +{ + std::vector<std::string>::const_iterator find_it = + std::find(names.begin(), names.end(), name); + if (find_it != names.end()) + { + result = find_it - names.begin(); + return true; + } + else + { + return false; + } +} + +// Find a name table index that is also a valid joint on the +// avatar. Order of preference is: requested name, mPelvis, first +// valid match in names table. +U32 get_valid_joint_index(const std::string& name, LLVOAvatar *avatar, std::vector<std::string>& joint_names) +{ + U32 result; + if (avatar->getJoint(name) && get_name_index(name,joint_names,result)) + { + return result; + } + if (get_name_index("mPelvis",joint_names,result)) + { + return result; + } + for (U32 j=0; j<joint_names.size(); j++) + { + if (avatar->getJoint(joint_names[j])) + { + return j; + } + } + // BENTO how to handle? + LL_ERRS() << "no valid joints in joint_names" << LL_ENDL; + return 0; +} + +// Which joint will stand in for this joint? +U32 get_proxy_joint_index(U32 joint_index, LLVOAvatar *avatar, std::vector<std::string>& joint_names) +{ + bool include_enhanced = LLSkinningUtil::sIncludeEnhancedSkeleton; + U32 j_proxy = get_valid_joint_index(joint_names[joint_index], avatar, joint_names); + LLJoint *joint = avatar->getJoint(joint_names[j_proxy]); + llassert(joint); + // BENTO - test of simple push-to-base-ancestor + // complexity reduction scheme. Find the first + // ancestor that's not flagged as extended, or the + // last ancestor that's rigged in this mesh, whichever + // comes first. + while (1) + { + if (include_enhanced || + joint->getSupport()==LLJoint::SUPPORT_BASE) + break; + LLJoint *parent = joint->getParent(); + if (!parent) + break; + if (!get_name_index(parent->getName(), joint_names, j_proxy)) + { + break; + } + joint = parent; + } + return j_proxy; +} + +} + +// static +void LLSkinningUtil::initClass() +{ + sIncludeEnhancedSkeleton = gSavedSettings.getBOOL("IncludeEnhancedSkeleton"); + sMaxJointsPerMeshObject = gSavedSettings.getU32("MaxJointsPerMeshObject"); +} + +// static +U32 LLSkinningUtil::getMaxJointCount() +{ + U32 result = llmin(LL_MAX_JOINTS_PER_MESH_OBJECT, sMaxJointsPerMeshObject); + if (!sIncludeEnhancedSkeleton) + { + result = llmin(result,(U32)52); // BENTO replace with LLAvatarAppearance::getBaseJointCount()) or equivalent + } + return result; +} + +// static +U32 LLSkinningUtil::getMeshJointCount(const LLMeshSkinInfo *skin) +{ + return llmin((U32)getMaxJointCount(), (U32)skin->mJointNames.size()); +} + +// static + +// Destructively remap the joints in skin info based on what joints +// are known in the avatar, and which are currently supported. This +// will also populate mJointRemap[] in the skin, which can be used to +// make the corresponding changes to the integer part of vertex +// weights. +// +// This will throw away joint info for any joints that are not known +// in the avatar, or not currently flagged to support based on the +// debug setting for IncludeEnhancedSkeleton. +// +// static +void LLSkinningUtil::remapSkinInfoJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin) +{ + // skip if already done. + if (!skin->mJointRemap.empty()) + { + return; + } + + // Compute the remap + std::vector<U32> j_proxy(skin->mJointNames.size()); + for (U32 j = 0; j < skin->mJointNames.size(); ++j) + { + U32 j_rep = get_proxy_joint_index(j, avatar, skin->mJointNames); + j_proxy[j] = j_rep; + } + S32 top = 0; + std::vector<U32> j_remap(skin->mJointNames.size()); + // Fill in j_remap for all joints that will make the cut. + for (U32 j = 0; j < skin->mJointNames.size(); ++j) + { + if (j_proxy[j] == j) + { + // Joint will be included + j_remap[j] = top++; + } + } + // Then use j_proxy to fill in j_remap for the joints that will be discarded + for (U32 j = 0; j < skin->mJointNames.size(); ++j) + { + if (j_proxy[j] != j) + { + j_remap[j] = j_remap[j_proxy[j]]; + } + } + + + // Apply the remap to mJointNames, mInvBindMatrix, and mAlternateBindMatrix + std::vector<std::string> new_joint_names; + std::vector<LLMatrix4> new_inv_bind_matrix; + std::vector<LLMatrix4> new_alternate_bind_matrix; + + for (U32 j = 0; j < skin->mJointNames.size(); ++j) + { + if (j_proxy[j] == j) + { + new_joint_names.push_back(skin->mJointNames[j]); + new_inv_bind_matrix.push_back(skin->mInvBindMatrix[j]); + if (!skin->mAlternateBindMatrix.empty()) + { + new_alternate_bind_matrix.push_back(skin->mAlternateBindMatrix[j]); + } + } + } + + for (U32 j = 0; j < skin->mJointNames.size(); ++j) + { + LL_DEBUGS("Avatar") << "Starting joint[" << j << "] = " << skin->mJointNames[j] << " j_remap " << j_remap[j] << " ==> " << new_joint_names[j_remap[j]] << LL_ENDL; + } + + skin->mJointNames = new_joint_names; + skin->mInvBindMatrix = new_inv_bind_matrix; + skin->mAlternateBindMatrix = new_alternate_bind_matrix; + skin->mJointRemap = j_remap; +} + +// static +void LLSkinningUtil::initSkinningMatrixPalette( + LLMatrix4* mat, + S32 count, + const LLMeshSkinInfo* skin, + LLVOAvatar *avatar) +{ + // BENTO - switching to use Matrix4a and SSE might speed this up. + // Note that we are mostly passing Matrix4a's to this routine anyway, just dubiously casted. + for (U32 j = 0; j < count; ++j) + { + LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); + mat[j] = skin->mInvBindMatrix[j]; + mat[j] *= joint->getWorldMatrix(); + } +} + +// Transform the weights based on the remap info stored in skin. Note +// that this is destructive and non-idempotent, so we need to keep +// track of whether we've done it already. If the desired remapping +// changes, the viewer must be restarted. +// +// static +void LLSkinningUtil::remapSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) +{ + llassert(skin->mJointRemap.size()>0); // Must call remapSkinInfoJoints() first, which this checks for. + const U32* remap = &skin->mJointRemap[0]; + const S32 max_joints = skin->mJointNames.size(); + for (U32 j=0; j<num_vertices; j++) + { + F32 *w = weights[j].getF32ptr(); + + for (U32 k=0; k<4; ++k) + { + S32 i = llfloor(w[k]); + F32 f = w[k]-i; + i = llclamp(i,0,max_joints-1); + w[k] = remap[i] + f; + } + } +} + +// static +void LLSkinningUtil::checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) +{ + if (skin->mJointRemap.size()>0) + { + // Check the weights are consistent with the current remap. + const S32 max_joints = skin->mJointNames.size(); + for (U32 j=0; j<num_vertices; j++) + { + F32 *w = weights[j].getF32ptr(); + + for (U32 k=0; k<4; ++k) + { + S32 i = llfloor(w[k]); + llassert(i>=0); + llassert(i<max_joints); + } + } + } +} + +// static +void LLSkinningUtil::getPerVertexSkinMatrix( + F32* weights, + LLMatrix4a* mat, + bool handle_bad_scale, + LLMatrix4a& final_mat, + U32 max_joints) +{ + + final_mat.clear(); + + S32 idx[4]; + + LLVector4 wght; + + F32 scale = 0.f; + for (U32 k = 0; k < 4; k++) + { + F32 w = weights[k]; + + // BENTO potential optimizations + // - Do clamping in unpackVolumeFaces() (once instead of every time) + // - int vs floor: if we know w is + // >= 0.0, we can use int instead of floorf; the latter + // allegedly has a lot of overhead due to ieeefp error + // checking which we should not need. + idx[k] = llclamp((S32) floorf(w), (S32)0, (S32)max_joints-1); + + wght[k] = w - floorf(w); + scale += wght[k]; + } + if (handle_bad_scale && scale <= 0.f) + { + wght = LLVector4(1.0f, 0.0f, 0.0f, 0.0f); + } + else + { + // This is enforced in unpackVolumeFaces() + llassert(scale>0.f); + wght *= 1.f/scale; + } + + for (U32 k = 0; k < 4; k++) + { + F32 w = wght[k]; + + LLMatrix4a src; + src.setMul(mat[idx[k]], w); + + final_mat.add(src); + } +} + diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h new file mode 100644 index 0000000000000000000000000000000000000000..813d4015355663ac41af720c3a0b7ab534cc7e14 --- /dev/null +++ b/indra/newview/llskinningutil.h @@ -0,0 +1,51 @@ +/** +* @file llskinningutil.h +* @brief Functions for mesh object skinning +* @author vir@lindenlab.com +* +* $LicenseInfo:firstyear=2015&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2015, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LLSKINNINGUTIL_H +#define LLSKINNINGUTIL_H + +class LLVOAvatar; +class LLMeshSkinInfo; +class LLMatrix4a; + +class LLSkinningUtil +{ +public: + static void initClass(); + static U32 getMaxJointCount(); + static U32 getMeshJointCount(const LLMeshSkinInfo *skin); + static void remapSkinInfoJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin); + static void initSkinningMatrixPalette(LLMatrix4* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar); + static void checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); + static void remapSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); + static void getPerVertexSkinMatrix(F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints); + + // This is initialized from gSavedSettings at startup and then left alone. + static bool sIncludeEnhancedSkeleton; + static U32 sMaxJointsPerMeshObject; +}; + +#endif diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 466edb19b25bee8cb73f150828c433e616b04cc7..4e4aaf5f8ee382e96de1c6d8e9bf27123a96b250 100755 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -67,6 +67,7 @@ #include "llvowlsky.h" #include "llrender.h" #include "llnavigationbar.h" +#include "llnotificationsutil.h" #include "llfloatertools.h" #include "llpaneloutfitsinventory.h" #include "llpanellogin.h" @@ -119,6 +120,12 @@ static bool handleTerrainDetailChanged(const LLSD& newvalue) } +static bool handleDeferredDebugSettingChanged(const LLSD& newvalue) +{ + LLNotificationsUtil::add("ChangeDeferredDebugSetting"); + return true; +} + static bool handleSetShaderChanged(const LLSD& newvalue) { // changing shader level may invalidate existing cached bump maps, as the shader type determines the format of the bump map it expects - clear and repopulate the bump cache @@ -761,7 +768,8 @@ void settings_setup_listeners() gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&handleSpellCheckChanged)); gSavedSettings.getControl("SpellCheckDictionary")->getSignal()->connect(boost::bind(&handleSpellCheckChanged)); gSavedSettings.getControl("LoginLocation")->getSignal()->connect(boost::bind(&handleLoginLocationChanged)); - gSavedSettings.getControl("MaxJointsPerMeshObject")->getCommitSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("MaxJointsPerMeshObject")->getCommitSignal()->connect(boost::bind(&handleDeferredDebugSettingChanged, _2)); + gSavedSettings.getControl("IncludeEnhancedSkeleton")->getCommitSignal()->connect(boost::bind(&handleDeferredDebugSettingChanged, _2)); } #if TEST_CACHED_CONTROL diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index b1e521f193cc8d348a20e43afd79e653f5a18c27..3e0cec0f0999e7fb19b05ae4141f28bd03789070 100755 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -44,7 +44,7 @@ #include "llvosky.h" #include "llrender.h" #include "lljoint.h" -#include "lldrawpoolavatar.h" +#include "llskinningutil.h" #ifdef LL_RELEASE_FOR_DOWNLOAD #define UNIFORM_ERRS LL_WARNS_ONCE("Shader") @@ -876,7 +876,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders() boost::unordered_map<std::string, std::string> attribs; attribs["MAX_JOINTS_PER_MESH_OBJECT"] = - boost::lexical_cast<std::string>(LLDrawPoolAvatar::getMaxJointCount()); + boost::lexical_cast<std::string>(LLSkinningUtil::getMaxJointCount()); // We no longer have to bind the shaders to global glhandles, they are automatically added to a map now. for (U32 i = 0; i < shaders.size(); i++) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 5d8558cb4630a2ed66e77959d495f2a2810a619d..9b2e9db59a26b10b22eaece6b2bfaa4c5d316a9f 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -54,6 +54,7 @@ #include "llspatialpartition.h" #include "llhudmanager.h" #include "llflexibleobject.h" +#include "llskinningutil.h" #include "llsky.h" #include "lltexturefetch.h" #include "llvector4a.h" @@ -4179,8 +4180,8 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons static const size_t kMaxJoints = LL_MAX_JOINTS_PER_MESH_OBJECT; LLMatrix4a mat[kMaxJoints]; - U32 maxJoints = LLDrawPoolAvatar::getMeshJointCount(skin); - LLDrawPoolAvatar::initSkinningMatrixPalette((LLMatrix4*)mat, maxJoints, skin, avatar); + U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin); + LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, maxJoints, skin, avatar); for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { @@ -4192,7 +4193,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons if ( weight ) { - LLDrawPoolAvatar::checkSkinWeights(weight, dst_face.mNumVertices, skin); + LLSkinningUtil::checkSkinWeights(weight, dst_face.mNumVertices, skin); LLMatrix4a bind_shape_matrix; bind_shape_matrix.loadu(skin->mBindShapeMatrix); @@ -4202,11 +4203,11 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons { LL_RECORD_BLOCK_TIME(FTM_SKIN_RIGGED); - U32 max_joints = LLDrawPoolAvatar::getMaxJointCount(); + U32 max_joints = LLSkinningUtil::getMaxJointCount(); for (U32 j = 0; j < dst_face.mNumVertices; ++j) { LLMatrix4a final_mat; - LLDrawPoolAvatar::getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints); + LLSkinningUtil::getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints); LLVector4a& v = vol_face.mPositions[j]; LLVector4a t; diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 70ba4d5077580d39bb4bf95d8b0a6051b2c18cea..ab027ac6006ede120c597452afff579ac0a48208 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -1422,6 +1422,13 @@ Note: This will clear the cache. Port settings take effect after you restart [APP_NAME]. </notification> + <notification + icon="alertmodal.tga" + name="ChangeDeferredDebugSetting" + type="alertmodal"> +This debug setting change will take effect after you restart [APP_NAME]. + </notification> + <notification icon="alertmodal.tga" name="ChangeSkin"