diff options
| -rwxr-xr-x | indra/newview/CMakeLists.txt | 2 | ||||
| -rwxr-xr-x | indra/newview/llappviewer.cpp | 4 | ||||
| -rwxr-xr-x | indra/newview/lldrawpoolavatar.cpp | 295 | ||||
| -rwxr-xr-x | indra/newview/lldrawpoolavatar.h | 7 | ||||
| -rwxr-xr-x | indra/newview/llfloatermodelpreview.cpp | 10 | ||||
| -rw-r--r-- | indra/newview/llskinningutil.cpp | 329 | ||||
| -rw-r--r-- | indra/newview/llskinningutil.h | 51 | ||||
| -rwxr-xr-x | indra/newview/llviewercontrol.cpp | 10 | ||||
| -rwxr-xr-x | indra/newview/llviewershadermgr.cpp | 4 | ||||
| -rwxr-xr-x | indra/newview/llvovolume.cpp | 11 | ||||
| -rwxr-xr-x | indra/newview/skins/default/xui/en/notifications.xml | 7 | 
11 files changed, 425 insertions, 305 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 16877c345e..4ba81047f5 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 fbf2a04bcc..04758ef839 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 dff6cada9a..89233b8e32 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 8d6e95ba1a..b9d2204052 100755 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -134,13 +134,6 @@ public:  	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 c971faac5f..3cad7badad 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 0000000000..23bbbdcf90 --- /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 0000000000..813d401535 --- /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 466edb19b2..4e4aaf5f8e 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 b1e521f193..3e0cec0f09 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 5d8558cb46..9b2e9db59a 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 70ba4d5077..ab027ac600 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -1424,6 +1424,13 @@ Port settings take effect after you restart [APP_NAME].    <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"     type="alertmodal">  The new skin will appear after you restart [APP_NAME].  | 
