summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorBrad Payne (Vir Linden) <vir@lindenlab.com>2015-10-21 16:47:03 -0400
committerBrad Payne (Vir Linden) <vir@lindenlab.com>2015-10-21 16:47:03 -0400
commitd365aa10f16c022970cefbfac8651fe01b5a9de8 (patch)
tree0549a07f81aada34f098ec66ce3397602efa6ee8 /indra
parentbfa3f83a2cf5d4ca408e7f045cd806a7f5133d9f (diff)
SL-234 WIP - moved LLSkinningUtil funcs to separate class/files. Remap weights where needed. Warn that related debug settings require restart to take effect.
Diffstat (limited to 'indra')
-rwxr-xr-xindra/newview/CMakeLists.txt2
-rwxr-xr-xindra/newview/llappviewer.cpp4
-rwxr-xr-xindra/newview/lldrawpoolavatar.cpp295
-rwxr-xr-xindra/newview/lldrawpoolavatar.h7
-rwxr-xr-xindra/newview/llfloatermodelpreview.cpp10
-rw-r--r--indra/newview/llskinningutil.cpp329
-rw-r--r--indra/newview/llskinningutil.h51
-rwxr-xr-xindra/newview/llviewercontrol.cpp10
-rwxr-xr-xindra/newview/llviewershadermgr.cpp4
-rwxr-xr-xindra/newview/llvovolume.cpp11
-rwxr-xr-xindra/newview/skins/default/xui/en/notifications.xml7
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].