Backout fcb3339cfe08 (mesh deformer) for testing; might cause memory leak

meow-7.2.2
Ansariel 2013-08-10 01:15:44 +02:00
parent 852fcc3c98
commit 992118ffc9
25 changed files with 18 additions and 1734 deletions

View File

@ -1280,15 +1280,6 @@ LLPolyMesh* LLAvatarAppearance::getHeadMesh()
return mMeshLOD[MESH_ID_HEAD]->mMeshParts[0]->getMesh();
}
// <FS:CR> Qarl's mesh deformer
//-----------------------------------------------------------------------------
// LLAvatarAppearance::getMesh()
//-----------------------------------------------------------------------------
LLPolyMesh* LLAvatarAppearance::getMesh(S32 which)
{
return mMeshLOD[which]->mMeshParts[0]->getMesh();
}
// </FS:CR>
//-----------------------------------------------------------------------------
// LLAvatarAppearance::getUpperBodyMesh()

View File

@ -95,7 +95,6 @@ public:
/*virtual*/ S32 getCollisionVolumeID(std::string &name);
/*virtual*/ LLPolyMesh* getHeadMesh();
/*virtual*/ LLPolyMesh* getUpperBodyMesh();
/*virtual*/ LLPolyMesh* getMesh(S32 which); // <FS:CR> Qarl's mesh deformer
/** Inherited
** **

View File

@ -167,7 +167,6 @@ int compare_int(const void *a, const void *b);
//-----------------------------------------------------------------------------
// genIndices()
//-----------------------------------------------------------------------------
#if 0 // <FS:CR> Dead code
void LLPolyMeshSharedData::genIndices(S32 index_offset)
{
if (index_offset == mLastIndexOffset)
@ -191,7 +190,6 @@ void LLPolyMeshSharedData::genIndices(S32 index_offset)
mLastIndexOffset = index_offset;
}
#endif //0 // </FS:CR>
//--------------------------------------------------------------------
// LLPolyMeshSharedData::getNumKB()

View File

@ -133,8 +133,7 @@ private:
BOOL loadMesh( const std::string& fileName );
public:
// <FS:CR> Comment out dead code
//void genIndices(S32 offset);
void genIndices(S32 offset);
const LLVector2 &getUVs(U32 index);

View File

@ -314,251 +314,6 @@ BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, cons
}
}
// <FS:CR> Qarl's mesh deformer
// find the point on a triangle closest to a given target point
// algorithm derived from: www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf
// (returns distance squared and barycentric coordinates)
F32 LLTriangleClosestPoint(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& target,
F32& closest_a, F32& closest_b)
{
// edges of triangle
LLVector3 edge0 = vert1 - vert0;
LLVector3 edge1 = vert2 - vert0;
LLVector3 delta = vert0 - target;
// length of triangle edges
F32 a00 = edge0.lengthSquared();
F32 a01 = edge0 * edge1;
F32 a11 = edge1.lengthSquared();
F32 b0 = delta * edge0;
F32 b1 = delta * edge1;
F32 c = delta.lengthSquared();
F32 det = fabs(a00*a11-a01*a01);
F32 s = a01*b1-a11*b0;
F32 t = a01*b0-a00*b1;
F32 dist_squared;
if ( s + t <= det )
{
if ( s < 0.0f )
{
if ( t < 0.0f ) // region 4
{
if ( b0 < 0.0f )
{
t = 0.0f;
if ( -b0 >= a00 )
{
s = 1.0f;
dist_squared = a00+(2.0f)*b0+c;
}
else
{
s = -b0/a00;
dist_squared = b0*s+c;
}
}
else
{
s = 0.0f;
if ( b1 >= 0.0f )
{
t = 0.0f;
dist_squared = c;
}
else if ( -b1 >= a11 )
{
t = 1.0f;
dist_squared = a11+(2.0f)*b1+c;
}
else
{
t = -b1/a11;
dist_squared = b1*t+c;
}
}
}
else // region 3
{
s = 0.0f;
if ( b1 >= 0.0f )
{
t = 0.0f;
dist_squared = c;
}
else if ( -b1 >= a11 )
{
t = 1.0f;
dist_squared = a11+(2.0f)*b1+c;
}
else
{
t = -b1/a11;
dist_squared = b1*t+c;
}
}
}
else if ( t < 0.0f ) // region 5
{
t = 0.0f;
if ( b0 >= 0.0f )
{
s = 0.0f;
dist_squared = c;
}
else if ( -b0 >= a00 )
{
s = 1.0f;
dist_squared = a00+(2.0f)*b0+c;
}
else
{
s = -b0/a00;
dist_squared = b0*s+c;
}
}
else // region 0
{
// minimum at interior point
F32 det_inv = (1.0f)/det;
s *= det_inv;
t *= det_inv;
dist_squared = s*(a00*s+a01*t+(2.0f)*b0) +
t*(a01*s+a11*t+(2.0f)*b1)+c;
}
}
else
{
F32 tmp0, tmp1, numerator, denominator;
if ( s < 0.0f ) // region 2
{
tmp0 = a01 + b0;
tmp1 = a11 + b1;
if ( tmp1 > tmp0 )
{
numerator = tmp1 - tmp0;
denominator = a00-2.0f*a01+a11;
if ( numerator >= denominator )
{
s = 1.0f;
t = 0.0f;
dist_squared = a00+(2.0f)*b0+c;
}
else
{
s = numerator/denominator;
t = 1.0f - s;
dist_squared = s*(a00*s+a01*t+2.0f*b0) +
t*(a01*s+a11*t+(2.0f)*b1)+c;
}
}
else
{
s = 0.0f;
if ( tmp1 <= 0.0f )
{
t = 1.0f;
dist_squared = a11+(2.0f)*b1+c;
}
else if ( b1 >= 0.0f )
{
t = 0.0f;
dist_squared = c;
}
else
{
t = -b1/a11;
dist_squared = b1*t+c;
}
}
}
else if ( t < 0.0f ) // region 6
{
tmp0 = a01 + b1;
tmp1 = a00 + b0;
if ( tmp1 > tmp0 )
{
numerator = tmp1 - tmp0;
denominator = a00-(2.0f)*a01+a11;
if ( numerator >= denominator )
{
t = 1.0f;
s = 0.0f;
dist_squared = a11+(2.0f)*b1+c;
}
else
{
t = numerator/denominator;
s = 1.0f - t;
dist_squared = s*(a00*s+a01*t+(2.0f)*b0) +
t*(a01*s+a11*t+(2.0f)*b1)+c;
}
}
else
{
t = 0.0f;
if ( tmp1 <= 0.0f )
{
s = 1.0f;
dist_squared = a00+(2.0f)*b0+c;
}
else if ( b0 >= 0.0f )
{
s = 0.0f;
dist_squared = c;
}
else
{
s = -b0/a00;
dist_squared = b0*s+c;
}
}
}
else // region 1
{
numerator = a11 + b1 - a01 - b0;
if ( numerator <= 0.0f )
{
s = 0.0f;
t = 1.0f;
dist_squared = a11+(2.0f)*b1+c;
}
else
{
denominator = a00-2.0f*a01+a11;
if ( numerator >= denominator )
{
s = 1.0f;
t = 0.0f;
dist_squared = a00+(2.0f)*b0+c;
}
else
{
s = numerator/denominator;
t = 1.0f - s;
dist_squared = s*(a00*s+a01*t+(2.0f)*b0) +
t*(a01*s+a11*t+(2.0f)*b1)+c;
}
}
}
}
closest_a = s;
closest_b = t;
return fabs(dist_squared);
}
// </FS:CR>
class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle>
{
public:
@ -2329,7 +2084,7 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
generate();
if ((mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE) || mParams.getSculptType() == LL_SCULPT_TYPE_MESH)
if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE || mParams.getSculptType() == LL_SCULPT_TYPE_MESH)
{
createVolumeFaces();
}

View File

@ -1100,11 +1100,7 @@ BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, co
F32& intersection_a, F32& intersection_b, F32& intersection_t);
BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
F32& intersection_a, F32& intersection_b, F32& intersection_t);
// <FS:CR> Qarl's mesh deformer
F32 LLTriangleClosestPoint(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& target,
F32& closest_a, F32& closest_b);
// </FS:CR>
#endif

View File

@ -274,67 +274,6 @@ const LLMatrix4& LLMatrix4::invert(void)
return *this;
}
// <FS:CR> Qarl's mesh deformer
// does an actual inversion
const LLMatrix4& LLMatrix4::invert_real()
{
F32* m = &mMatrix[0][0];
F32 inv[16];
F32 det;
inv[0] = m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15]
+ m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10];
inv[4] = -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15]
- m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10];
inv[8] = m[4]*m[9]*m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15]
+ m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9];
inv[12] = -m[4]*m[9]*m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14]
- m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9];
inv[1] = -m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15]
- m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10];
inv[5] = m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15]
+ m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10];
inv[9] = -m[0]*m[9]*m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15]
- m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9];
inv[13] = m[0]*m[9]*m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14]
+ m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9];
inv[2] = m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15]
+ m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6];
inv[6] = -m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15]
- m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6];
inv[10] = m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15]
+ m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5];
inv[14] = -m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14]
- m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5];
inv[3] = -m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11]
- m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6];
inv[7] = m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11]
+ m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6];
inv[11] = -m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11]
- m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5];
inv[15] = m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10]
+ m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5];
det = m[0]*inv[0] + m[1]*inv[4] + m[2]*inv[8] + m[3]*inv[12];
if (det == 0)
{
setZero();
}
else
{
det = 1.0 / det;
for (int i = 0; i < 16; i++)
m[i] = inv[i] * det;
}
return *this;
}
// </FS:CR>
LLVector4 LLMatrix4::getFwdRow4() const
{
return LLVector4(mMatrix[VX][VX], mMatrix[VX][VY], mMatrix[VX][VZ], mMatrix[VX][VW]);

View File

@ -203,9 +203,6 @@ public:
const LLMatrix4& transpose(); // Transpose LLMatrix4
const LLMatrix4& invert(); // Invert LLMatrix4
// <FS:CR> Qarl's mesh deformer
const LLMatrix4& invert_real(); // Invert LLMatrix4 - works for all matrices
// Rotate existing matrix
// These are really, really, inefficient as implemented! - djs

View File

@ -2201,18 +2201,6 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
{
mPelvisOffset = skin["pelvis_offset"].asReal();
}
// <FS:CR> Qarl's mesh deformer
if (skin.has("deform"))
{
mDeform = skin["deform"];
}
else
{
mDeform = LLSD();
}
// <FS:CR> Qarl's mesh deformer
}
LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const
@ -2256,8 +2244,6 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const
ret["pelvis_offset"] = mPelvisOffset;
}
ret["deform"] = mDeform; // <FS:CR> Qarl's mesh deformer
return ret;
}

View File

@ -46,7 +46,6 @@ public:
std::vector<LLMatrix4> mInvBindMatrix;
std::vector<LLMatrix4> mAlternateBindMatrix;
std::map<std::string, U32> mJointMap;
LLSD mDeform; // <FS:CR> Qarl's mesh deformer
LLMeshSkinInfo() { }
LLMeshSkinInfo(LLSD& data);

View File

@ -247,7 +247,6 @@ set(viewer_SOURCE_FILES
lldaycyclemanager.cpp
lldebugmessagebox.cpp
lldebugview.cpp
lldeformerworker.cpp
lldeferredsounds.cpp
lldelayedgestureerror.cpp
lldirpicker.cpp
@ -451,7 +450,6 @@ set(viewer_SOURCE_FILES
llmediadataclient.cpp
llmenuoptionpathfindingrebakenavmesh.cpp
llmeshrepository.cpp
llmeshsearch.cpp
llmimetypes.cpp
llmorphview.cpp
llmoveview.cpp
@ -937,7 +935,6 @@ set(viewer_HEADER_FILES
lldaycyclemanager.h
lldebugmessagebox.h
lldebugview.h
lldeformerworker.h
lldeferredsounds.h
lldelayedgestureerror.h
lldirpicker.h
@ -1140,7 +1137,6 @@ set(viewer_HEADER_FILES
llmediadataclient.h
llmenuoptionpathfindingrebakenavmesh.h
llmeshrepository.h
llmeshsearch.h
llmimetypes.h
llmorphview.h
llmoveview.h

View File

@ -1,212 +0,0 @@
/**
* @file lldeformerworker.h
* @brief Threaded worker to compute deformation tables
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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 "lldrawable.h"
#include "llvoavatar.h"
#include "llvovolume.h"
#include "llviewerobjectlist.h"
#include "lldeformerworker.h"
// timer to watch the completed queue and process completed requests
// (needs to be done on main thread, hence this timer on 1 sec repeat.)
LLDeformerWorker::CompletedTimer::CompletedTimer() : LLEventTimer(1.0)
{
}
BOOL LLDeformerWorker::CompletedTimer::tick()
{
LLDeformerWorker::processCompletedQ();
return FALSE;
}
// yes, global instance -
// LLSingleton appears to be incompatible with LLThread - they both keep track of the instance and
// want to delete it.
LLDeformerWorker* gDeformerWorker;
LLDeformerWorker::LLDeformerWorker()
: LLThread("Deformer Worker")
{
mQuitting = false;
mSignal = new LLCondition(NULL);
mMutex = new LLMutex(NULL);
}
LLDeformerWorker::~LLDeformerWorker()
{
shutdown();
if (mSignal)
{
delete mSignal;
mSignal = NULL;
}
if (mMutex)
{
delete mMutex;
mMutex = NULL;
}
}
void LLDeformerWorker::shutdown()
{
if (mSignal)
{
mQuitting = true;
mSignal->signal();
while (!isStopped())
{
apr_sleep(10);
}
}
}
// static
void LLDeformerWorker::submitRequest(LLPointer<Request> request)
{
if (!gDeformerWorker)
{
gDeformerWorker = new LLDeformerWorker;
}
gDeformerWorker->instanceSubmitRequest(request);
}
void LLDeformerWorker::instanceSubmitRequest(LLPointer<Request> request)
{
if (isStopped())
{
start();
}
LLMutexLock lock(mMutex);
mRequestQ.push_back(request);
mSignal->signal();
}
// static
BOOL LLDeformerWorker::alreadyQueued(LLPointer<Request> request)
{
if (!gDeformerWorker)
{
return FALSE;
}
for (request_queue::iterator iterator = gDeformerWorker->mRequestQ.begin();
iterator != gDeformerWorker->mRequestQ.end();
iterator++)
{
// the request is already here if we match MeshID, VertexCount, and Face
LLPointer<LLDeformerWorker::Request> old_request = *iterator;
if ((request->mMeshID == old_request->mMeshID) &&
(request->mFace == old_request->mFace) &&
(request->mVertexCount == old_request->mVertexCount))
{
return TRUE;
}
}
return FALSE;
}
void LLDeformerWorker::buildDeformation(LLPointer<Request> request)
{
request->mDeformedVolume->computeDeformTable(request);
}
void LLDeformerWorker::run()
{
while (!mQuitting)
{
mSignal->wait();
while (!mQuitting && !mRequestQ.empty())
{
LLPointer<Request> request;
{
// alter Q while locked
LLMutexLock lock(mMutex);
request = mRequestQ.front();
mRequestQ.pop_front();
}
buildDeformation(request);
{
// alter Q while locked
LLMutexLock lock(mMutex);
mCompletedQ.push_back(request);
}
}
}
}
// static
void LLDeformerWorker::processCompletedQ()
{
if (!gDeformerWorker)
{
return;
}
while ( !gDeformerWorker->mCompletedQ.empty())
{
LLPointer<Request> request;
{
// alter Q while locked
LLMutexLock lock(gDeformerWorker->mMutex);
request = gDeformerWorker->mCompletedQ.front();
gDeformerWorker->mCompletedQ.pop_front();
}
// tag the drawable for rebuild
request->mDrawable->setState(LLDrawable::REBUILD_ALL);
}
}

View File

@ -1,122 +0,0 @@
/**
* @file lldeformerworker.h
* @brief Threaded worker to compute deformation tables
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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 LL_DEFORMER_WORKER_H
#define LL_DEFORMER_WORKER_H
#include "llthread.h"
#include "llsingleton.h"
#include "llpointer.h"
#include "llrefcount.h"
#include "lleventtimer.h"
#include "m4math.h"
#include <vector>
#include <list>
class LLDeformedVolume;
class LLDrawable;
class LLDeformerWorker : LLThread
{
public:
// request that the worker compute a deform table:
class Request : public LLRefCount
{
public:
LLPointer<LLDeformedVolume> mDeformedVolume;
LLPointer<LLDrawable> mDrawable;
LLUUID mMeshID;
S32 mFace;
S32 mVertexCount;
// positions/normals of the volume vertices
std::vector< LLVector3 > mVolumePositions;
std::vector< LLVector3 > mVolumeNormals;
// positions/normals/indices of the base avatar vertices
std::vector<std::vector< LLVector3 > > mAvatarPositions;
std::vector<std::vector< LLVector3 > > mAvatarNormals;
std::vector<std::vector< S32 > > mAvatarIndices;
LLMatrix4 mBindShapeMatrix;
F32 mScale;
};
// timer handles completed requests on main thread
class CompletedTimer : public LLEventTimer
{
public:
CompletedTimer();
BOOL tick();
};
LLDeformerWorker();
virtual ~LLDeformerWorker();
// add a request to the Q (called from main thread)
static void submitRequest(LLPointer<Request> request);
// see if request is already on queue
static BOOL alreadyQueued(LLPointer<Request> request);
// do the work of building the deformation table
void buildDeformation(LLPointer<Request> request);
// do the necessary work on the completed queue (on the main thread)
static void processCompletedQ();
void shutdown();
virtual void run();
CompletedTimer mTimer;
private:
void instanceSubmitRequest(LLPointer<Request> request);
LLCondition* mSignal;
LLMutex* mMutex;
BOOL mQuitting;
typedef std::list< LLPointer<Request> > request_queue;
request_queue mRequestQ;
request_queue mCompletedQ;
};
extern LLDeformerWorker* gDeformerWorker;
#endif

View File

@ -49,7 +49,6 @@
#include "llappviewer.h"
#include "llrendersphere.h"
#include "llviewerpartsim.h"
#include "llviewernetwork.h" // <FS:CR> Qarl's mesh deformer - for hopefully temporary grid checks
static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK;
static U32 sBufferUsage = GL_STREAM_DRAW_ARB;
@ -1445,12 +1444,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
}
}
// <FS:CR> Qarl's mesh deformer
//void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face)
void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face,
const LLMeshSkinInfo* skin, LLVolume* volume,
const LLVolumeFace& vol_face, LLVOVolume* vobj)
// </FS:CR>
void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face)
{
LLVector4a* weight = vol_face.mWeights;
if (!weight)
@ -1459,17 +1453,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
}
LLPointer<LLVertexBuffer> buffer = face->getVertexBuffer();
// <FS:CR> Qarl's mesh deformer
//LLDrawable* drawable = face->getDrawable();
LLPointer<LLDrawable> drawable = face->getDrawable();
// NOTE: Remove this next bit as well as the rest of the grid checking if LL ever gets their act together
// and adds the deformer <FS:CR>
bool is_opensim = false;
#if OPENSIM
is_opensim = LLGridManager::getInstance()->isInOpenSim();
#endif // OPENSIM
// </FS:CR>
LLDrawable* drawable = face->getDrawable();
U32 data_mask = face->getRiggedVertexBufferDataMask();
@ -1530,21 +1514,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
face->setPoolType(LLDrawPool::POOL_AVATAR);
}
// <FS:CR> Qarl's mesh deformer
//face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
// swap in deformed volume if conditions are met:
LLVolume* which_volume = volume;
if (skin->mDeform["version"].asInteger() != 0//)
&& is_opensim) // <FS:CR> Remove the grid check if LL ever gets it together
// </FS:CR>
{
LLDeformedVolume* deformed_volume = vobj->getDeformedVolume();
deformed_volume->deform(volume, avatar, skin, face->getTEOffset(), drawable);
which_volume = deformed_volume;
}
face->getGeometryVolume(*which_volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
buffer->flush();
}
@ -1583,19 +1553,6 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
LLMatrix4a bind_shape_matrix;
bind_shape_matrix.loadu(skin->mBindShapeMatrix);
// <FS:CR> Qarl's mesh deformer
// swap in deformed volume if conditions are met:
LLVolume* which_volume = volume;
if (skin->mDeform["version"].asInteger() != 0//)
&& is_opensim) // NOTE: Remove the grid check if LL ever gets it together
{
which_volume = vobj->getDeformedVolume();
}
LLVector4a* positions = which_volume->getVolumeFace(face->getTEOffset()).mPositions;
LLVector4a* normals = which_volume->getVolumeFace(face->getTEOffset()).mNormals;
// </FS:CR>
for (U32 j = 0; j < buffer->getNumVerts(); ++j)
{
LLMatrix4a final_mat;
@ -1627,10 +1584,8 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
final_mat.add(src);
}
// <FS:CR> Qarl's mesh deformer
//LLVector4a& v = vol_face.mPositions[j];
LLVector4a& v = positions[j];
// </FS:CR>
LLVector4a& v = vol_face.mPositions[j];
LLVector4a t;
LLVector4a dst;
bind_shape_matrix.affineTransform(v, t);
@ -1639,15 +1594,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
if (norm)
{
// <FS:CR> Qarl's mesh deformer
//LLVector4a& n = vol_face.mNormals[j];
// normals are not transformed by the same math as points.
// you need the inverse transpose.
// these matrices are non-uniformly scaled (by a lot) so this
// math is wrong. (i think.) -qarl
LLVector4a& n = normals[j];
// </FS:CR>
LLVector4a& n = vol_face.mNormals[j];
bind_shape_matrix.rotate(n, t);
final_mat.rotate(t, dst);
norm[j] = dst;
@ -1895,10 +1842,7 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
stop_glerror();
const LLVolumeFace& vol_face = volume->getVolumeFace(te);
// <FS:CR> Qarl's mesh deformer
//updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face);
updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face, vobj);
// </FS:CR>
updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face);
}
}
}

View File

@ -35,7 +35,6 @@ class LLFace;
class LLMeshSkinInfo;
class LLVolume;
class LLVolumeFace;
class LLVOVolume; // <FS:CR> Qarl's mesh deformer
class LLDrawPoolAvatar : public LLFacePool
@ -138,8 +137,7 @@ public:
LLFace* facep,
const LLMeshSkinInfo* skin,
LLVolume* volume,
const LLVolumeFace& vol_face,
LLVOVolume* vobj); // <FS:CR> Qarl's mesh deformer
const LLVolumeFace& vol_face);
void updateRiggedVertexBuffers(LLVOAvatar* avatar);
void renderRigged(LLVOAvatar* avatar, U32 type, bool glow = false);

View File

@ -146,10 +146,7 @@ public:
LLFacePool* getPool() const { return mDrawPoolp; }
U32 getPoolType() const { return mPoolType; }
// <FS:CR> Qarl's mesh deformer
//LLDrawable* getDrawable() const { return mDrawablep; }
LLPointer<LLDrawable> getDrawable() const { return mDrawablep; }
// </FS:CR>
LLDrawable* getDrawable() const { return mDrawablep; }
LLViewerObject* getViewerObject() const { return mVObjp; }
S32 getLOD() const { return mVObjp.notNull() ? mVObjp->getLOD() : 0; }
void setPoolType(U32 type) { mPoolType = type; }

View File

@ -459,10 +459,6 @@ BOOL LLFloaterModelPreview::postBuild()
childSetCommitCallback("import_scale", onImportScaleCommit, this);
childSetCommitCallback("pelvis_offset", onPelvisOffsetCommit, this);
// <FS:CR> Qarl's mesh deformer
childSetCommitCallback("deform", onDeformCommit, this);
childSetCommitCallback("deform_base", onDeformCommit, this);
// </FS:CR>
getChild<LLCheckBoxCtrl>("show_edges")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
getChild<LLCheckBoxCtrl>("show_physics")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
@ -472,13 +468,6 @@ BOOL LLFloaterModelPreview::postBuild()
childDisable("upload_skin");
childDisable("upload_joints");
// <FS:CR> Qarls' mesh deformer
childDisable("deform");
childDisable("deform_base");
// initialize base radio buttons
getChild<LLUICtrl>("deform_base")->setValue(LLSD(0));
// </FS:CR>
initDecompControls();
@ -707,25 +696,6 @@ void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata )
fp->mModelPreview->refresh();
}
// <FS:CR> Qarl's mesh deformer
//static
void LLFloaterModelPreview::onDeformCommit( LLUICtrl*, void* userdata )
{
LLFloaterModelPreview *fp =(LLFloaterModelPreview*)userdata;
if (!fp->mModelPreview)
{
return;
}
fp->mModelPreview->mDirty = true;
fp->toggleCalculateButton(true);
fp->mModelPreview->refresh();
}
// </FS:CR>
//static
void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata)
{
@ -3294,45 +3264,6 @@ LLModelPreview::~LLModelPreview()
//glodShutdown();
}
// <FS:CR> Qarl's mesh deformer
// map the base deformation type to it's corresponding LLSD
// if a person wanted to add standard sizing parameters, here
// is where they'd do it.
LLSD deformation_parameters(BOOL deform, S32 base_type)
{
if (!deform)
return LLSD();
LLSD parameters;
parameters = LLSD::emptyMap();
parameters["version"] = 1;
parameters["visual_params"] = LLSD::emptyMap();
if (base_type == 0) // male
{
parameters["visual_params"]["male"] = 1.0f;
}
if (base_type == 1) // female
{
// female base needs no modifications
}
// example stub for how one might implement standard sizing parameters
if (base_type == 2) // male - scrawny
{
parameters["visual_params"]["male"] = 1.0f;
parameters["visual_params"]["Love_Handles"] = -1.0f;
parameters["visual_params"]["Leg Muscles"] = 0.0f;
}
return parameters;
}
// </FS:CR>
U32 LLModelPreview::calcResourceCost()
{
assert_main_thread();
@ -3355,7 +3286,6 @@ U32 LLModelPreview::calcResourceCost()
F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f;
mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 3.0f;
BOOL deform = mFMP ? mFMP->childGetValue("deform").asBoolean() : FALSE; // <FS:CR> Qarl's mesh deformer
if ( mFMP && mFMP->childGetValue("upload_joints").asBoolean() )
{
@ -3377,16 +3307,12 @@ U32 LLModelPreview::calcResourceCost()
instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics :
instance.mModel->mPhysics;
//update instance skin info for each lods pelvisZoffset and deform
//update instance skin info for each lods pelvisZoffset
for ( int j=0; j<LLModel::NUM_LODS; ++j )
{
if ( instance.mLOD[j] )
{
instance.mLOD[j]->mSkinInfo.mPelvisOffset = mPelvisZOffset;
// <FS:CR> Qarl's mesh deformer
instance.mLOD[j]->mSkinInfo.mDeform =
deformation_parameters(deform, mFMP->childGetValue("deform_base").asInteger());
// </FS:CR>
}
}
@ -5184,7 +5110,6 @@ BOOL LLModelPreview::render()
bool has_skin_weights = false;
bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean();
bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean();
bool deform = mFMP->childGetValue("deform").asBoolean(); // <FS:CR> Qarl's mesh deformer
if ( upload_joints != mLastJointUpdate )
{
@ -5212,21 +5137,11 @@ BOOL LLModelPreview::render()
fmp->enableViewOption("show_skin_weight");
fmp->setViewOptionEnabled("show_joint_positions", skin_weight);
mFMP->childEnable("upload_skin");
// <FS:CR> Qarl's mesh deformer
mFMP->childEnable("deform");
mFMP->childEnable("deform_base");
// </FS:CR>
}
}
else
{
mFMP->childDisable("upload_skin");
// <FS:CR> Qarl's mesh deformer
mFMP->childDisable("deform");
mFMP->childDisable("deform_base");
// </FS:CR>
if (fmp)
{
mViewOption["show_skin_weight"] = false;
@ -5248,26 +5163,12 @@ BOOL LLModelPreview::render()
upload_joints = false;
}
// <FS:CR> Qarl's mesh deformer
if (!upload_skin && deform)
{ // can't deform if model has no skin weights
mFMP->childSetValue("deform", false);
deform = false;
}
// </FS:CR>
//Only enable joint offsets if it passed the earlier critiquing
if ( isRigValidForJointPositionUpload() )
{
mFMP->childSetEnabled("upload_joints", upload_skin);
}
// <FS:CR> Qarl's mesh deformer
// Only enable deform if skins are enabled
mFMP->childSetEnabled("deform", upload_skin);
mFMP->childSetEnabled("deform_base", upload_skin);
// </FS:CR>
F32 explode = mFMP->childGetValue("physics_explode").asReal();
glClear(GL_DEPTH_BUFFER_BIT);

View File

@ -217,7 +217,6 @@ protected:
static void onImportScaleCommit(LLUICtrl*, void*);
static void onPelvisOffsetCommit(LLUICtrl*, void*);
static void onDeformCommit(LLUICtrl*, void*); // <FS:CR> Qarl's mesh deformer
static void onUploadJointsCommit(LLUICtrl*,void*);
static void onUploadSkinCommit(LLUICtrl*,void*);

View File

@ -1,230 +0,0 @@
/**
* @file llmeshsearch.cpp
* @brief Search meshes efficiently
* @author Karl Stiefvater <qarl@qarl.com>
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* InWorldz Viewer Source Code
* Copyright (C) 2013, InWorldz, LLC.
*
* 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 or later.
*
* 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
*
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llmeshsearch.h"
#include "llrand.h"
#include "llvolume.h"
LLMeshSearch::LLMeshSearch(std::vector<LLVector3>& positions, std::vector<S32>& indices) :
mPositions(positions), mIndices(indices)
{
// compute bounding box
mBBox.setMin(mPositions[0]);
mBBox.setMax(mPositions[0]);
for (S32 i = 0; i < mPositions.size(); i++)
{
mBBox.addPoint(mPositions[i]);
}
// size of each voxel - emperically determined to give good performance
mVoxelSize = 0.05;
mWidth = (S32)ceil(mBBox.getExtent().mV[VX] / mVoxelSize);
mHeight = (S32)ceil(mBBox.getExtent().mV[VY] / mVoxelSize);
mDepth = (S32)ceil(mBBox.getExtent().mV[VZ] / mVoxelSize);
// the voxel table
mVoxels.resize(mWidth * mHeight * mDepth, NULL);
// insert triangles into voxel table
for (S32 triangle_index = 0; triangle_index < mIndices.size(); triangle_index += 3)
{
S32 index0 = mIndices[triangle_index];
S32 index1 = mIndices[triangle_index+1];
S32 index2 = mIndices[triangle_index+2];
LLVector3& position0 = mPositions[index0];
LLVector3& position1 = mPositions[index1];
LLVector3& position2 = mPositions[index2];
S32 x, y, z;
cellLocation(position0, x, y, z);
insertTriangle(triangle_index, x, y, z);
cellLocation(position1, x, y, z);
insertTriangle(triangle_index, x, y, z);
cellLocation(position2, x, y, z);
insertTriangle(triangle_index, x, y, z);
}
}
LLMeshSearch::~LLMeshSearch()
{
for (S32 i = 0; i < mVoxels.size(); i++)
{
if (mVoxels[i])
{
delete mVoxels[i];
}
}
}
// given a point in space, find it's entry coordinates in the voxel table
void LLMeshSearch::cellLocation(LLVector3& position, S32& x, S32& y, S32& z)
{
LLVector3 local_position = position - mBBox.getMin();
x = (S32)floor(local_position.mV[VX] / mVoxelSize);
y = (S32)floor(local_position.mV[VY] / mVoxelSize);
z = (S32)floor(local_position.mV[VZ] / mVoxelSize);
}
// insert a new triangle into the voxel table
void LLMeshSearch::insertTriangle(S32 triangle_index, S32 x, S32 y, S32 z)
{
S32 voxel_index = (x * mHeight + y) * mDepth + z;
std::vector<S32>* vector_pointer = mVoxels[voxel_index];
if (!vector_pointer)
{
vector_pointer = new std::vector<S32>;
mVoxels[voxel_index] = vector_pointer;
}
// don't insert dupes (which will only appear sequentially so this test catches them all)
if ((vector_pointer->size() == 0) || (vector_pointer->back() != triangle_index))
{
vector_pointer->push_back(triangle_index);
}
}
// find point on mesh which is closest to target mesh, within a given distance, return TRUE if found
BOOL LLMeshSearch::findClosestPoint(LLVector3 target, F32 within,
F32& distance, S32& index0, S32& index1, S32& index2, F32& bary_a, F32& bary_b)
{
BOOL found = FALSE;
F32 closest_distance_squared = powf(within, 2.0f);
S32 target_x, target_y, target_z;
cellLocation(target, target_x, target_y, target_z);
// cycle over all voxels
for (S32 x = 0; x < mWidth; x++)
{
F32 delta_x = llmax(abs(x-target_x)-1, 0) * mVoxelSize;
F32 delta_x_squared = delta_x * delta_x;
// if this plane is too far away, skip it
if ((delta_x_squared) > closest_distance_squared)
continue;
for (S32 y = 0; y < mHeight; y++)
{
F32 delta_y = llmax(abs(y-target_y)-1, 0) * mVoxelSize;
F32 delta_y_squared = delta_y * delta_y;
// if this line is too far away, skip it
if ((delta_x_squared + delta_y_squared) > closest_distance_squared)
continue;
for (S32 z = 0; z < mDepth; z++)
{
F32 delta_z = llmax(abs(z-target_z)-1, 0) * mVoxelSize;
F32 delta_z_squared = delta_z * delta_z;
// if this voxel is too far away, skip it
if ((delta_x_squared + delta_y_squared + delta_z_squared) > closest_distance_squared)
continue;
S32 voxel_index = (x * mHeight + y) * mDepth + z;
std::vector<S32>* vector_pointer = mVoxels[voxel_index];
// if the voxel is empty, skip it
if (!vector_pointer)
continue;
// cycle over all triangles
for (S32 j = 0; j < vector_pointer->size(); j++)
{
S32 triangle_index = (*vector_pointer)[j];
// indices for triangle corners
S32 this_index0 = mIndices[triangle_index+0];
S32 this_index1 = mIndices[triangle_index+1];
S32 this_index2 = mIndices[triangle_index+2];
// positions of triangle corners
LLVector3 this_position0 = mPositions[this_index0];
LLVector3 this_position1 = mPositions[this_index1];
LLVector3 this_position2 = mPositions[this_index2];
// barycentric coord of closest point
F32 this_bary_a;
F32 this_bary_b;
F32 this_distance_squared = LLTriangleClosestPoint(this_position0, this_position1, this_position2,
target, this_bary_a, this_bary_b);
if (this_distance_squared < closest_distance_squared)
{
found = TRUE;
// record corner indices of this triangle
index0 = this_index0;
index1 = this_index1;
index2 = this_index2;
// compute weights from barycentric coordinates
bary_a = this_bary_a;
bary_b = this_bary_b;
closest_distance_squared = this_distance_squared;
}
}
}
}
}
if (found)
{
distance = sqrt(closest_distance_squared);
}
return found;
}

View File

@ -1,68 +0,0 @@
/**
* @file llmeshsearch.cpp
* @brief Search meshes efficiently
* @author Karl Stiefvater <qarl@qarl.com>
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* InWorldz Viewer Source Code
* Copyright (C) 2013, InWorldz, LLC.
*
* 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 or later.
*
* 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
*
* $/LicenseInfo$
*/
class LLVector3;
class LLBBox;
#ifndef LL_MESHSEARCH_H
#define LL_MESHSEARCH_H
class LLMeshSearch
{
std::vector<LLVector3> mPositions;
std::vector<S32> mIndices;
LLBBoxLocal mBBox;
// voxel table
F32 mVoxelSize;
U32 mWidth;
U32 mHeight;
U32 mDepth;
std::vector<std::vector<S32>* > mVoxels;
public:
LLMeshSearch(std::vector<LLVector3>& positions, std::vector<S32>& indices);
~LLMeshSearch();
void cellLocation(LLVector3& position, S32& x, S32& y, S32& z);
void insertTriangle(S32 triangle_index, S32 x, S32 y, S32 z);
BOOL findClosestPoint(LLVector3 target, F32 within, F32& distance, S32& index0, S32& index1, S32& index2, F32& bary_a, F32& bary_b);
};
#endif // LL_MESHSEARCH_H

View File

@ -5609,7 +5609,6 @@ void LLVOAvatar::updateVisualParams()
dirtyMesh();
updateHeadOffset();
rebuildRiggedAttachments(); // <FS:CR> Qarl's mesh deformer
}
//-----------------------------------------------------------------------------

View File

@ -82,10 +82,6 @@
#include "rlvhandler.h"
#include "rlvlocks.h"
// [/RLVa:KB]
// <FS:CR> Qarl's mesh deformer
#include "lldeformerworker.h"
#include "llmeshsearch.h"
// </FS:CR>
const S32 MIN_QUIET_FRAMES_COALESCE = 30;
const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
@ -4015,9 +4011,8 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
LLVector4a* weight = vol_face.mWeights;
// <FS:CR> Qarl's mesh deformer
//if ( weight )
//{
if ( weight )
{
LLMatrix4a bind_shape_matrix;
bind_shape_matrix.loadu(skin->mBindShapeMatrix);
@ -4062,8 +4057,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
LLVector4a& v = vol_face.mPositions[j];
LLVector4a t;
LLVector4a dst;
bind_shape_matrix.affineTransform(v, t); // shouldn't this matrix be premultiplied into the matrix palette? this is expensive.
bind_shape_matrix.affineTransform(v, t);
final_mat.affineTransform(t, dst);
pos[j] = dst;
}
@ -4101,456 +4095,10 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
dst_face.createOctree(1.f);
}
//} // <FS:CR> Qarl's mesh deformer
}
}
}
// <FS:CR> Qarl's mesh deformer
LLDeformedVolume* LLVOVolume::getDeformedVolume()
{
if (!mDeformedVolume)
{
// doesn't exist yet - make it
mDeformedVolume = new LLDeformedVolume;
}
return mDeformedVolume;
}
static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED_DEFORM("Deform");
// these are the meshes we follow
static S32 MORPH_MESHES[] = { LLAvatarAppearanceDefines::MESH_ID_HEAD,
LLAvatarAppearanceDefines::MESH_ID_UPPER_BODY,
LLAvatarAppearanceDefines::MESH_ID_LOWER_BODY };
// attempt to find the cached deform table. if not found, generate request for it to be built and
// send to deform worker
LLDeformedVolume::LLDeformTable* LLDeformedVolume::getDeformTable(LLVolume* source, LLVOAvatar* avatar2,
const LLMeshSkinInfo* skin, S32 face,
LLPointer<LLDrawable> drawable)
{
// see if we can find this deform table in the cache
LLDeformTableCacheIndex cache_index(source->getParams().getSculptID(), face,
source->getVolumeFace(face).mNumVertices);
deform_cache_t::iterator i = mDeformCache.find(cache_index);
if (i != mDeformCache.end())
{
// found it, return it
return &(i->second);
}
// doesn't exist in cache, must create
// send a request to the deformer worker.
LLPointer<LLDeformerWorker::Request> request = new LLDeformerWorker::Request;
// pack the request
request->mDeformedVolume = this;
request->mDrawable = drawable;
request->mMeshID = source->getParams().getSculptID();
request->mFace = face;
request->mVertexCount = source->getVolumeFace(face).mNumVertices;
// before we do any more work, see if this request is already on the queue
if (LLDeformerWorker::alreadyQueued(request))
{
// no more to be done here, return NULL
return NULL;
}
// we copy this data now so that when we do the work in
// the second thread, there's no chance it will be clobbered
//
// fill volume vertex positions/normals
//
const LLVolumeFace& source_face = source->getVolumeFace(face);
request->mVolumePositions.resize(source_face.mNumVertices);
request->mVolumeNormals.resize(source_face.mNumVertices);
for (S32 i = 0; i < source_face.mNumVertices; i++)
{
LLVector3 position(source_face.mPositions[i].getF32ptr());
request->mVolumePositions[i] = position;
LLVector3 normal(source_face.mNormals[i].getF32ptr());
normal.normalize();
request->mVolumeNormals[i] = normal;
}
// scale and matrix constants
// maps volume space to object (avatar) space
LLMatrix4a bind_shape_matrix_a;
request->mBindShapeMatrix = skin->mBindShapeMatrix;
// skeleton scaling factor - assumes all joints have same scale and that the scale is uniform in XYZ (currently true)
request->mScale = powf(skin->mInvBindMatrix[0].determinant(), 1.0f / 3.0f);
//
// compute the base avatar shape for this deformed volume
//
// create default avatar
LLPointer<LLVOAvatar> avatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion());
avatar->mIsDummy = TRUE;
avatar->mSpecialRenderMode = 2;
avatar->updateJointLODs();
// apply base visual_params
LLSD visual_params = skin->mDeform["visual_params"];
// at this point i planned to loop over the map and set the parameters it
// specified. but i learned that LLSD does not implement LLSD::mapBegin() and
// LLSD::mapEnd(). (they are defined, just not implemented. yay.) so instead
// i loop over all the possible visual params in the avatar, and see if they are
// present in the map.
LLVisualParam* this_param = avatar->getFirstVisualParam();
while(this_param != NULL)
{
std::string name = this_param->getName();
if (visual_params.has(name))
{
avatar->setVisualParamWeight(name.c_str(), visual_params[name].asReal());
}
this_param = avatar->getNextVisualParam();
}
// and apply this parameters
avatar->updateVisualParams();
// extract the data from this avatar, store it in the request
S32 num_meshes = sizeof(MORPH_MESHES)/sizeof(S32);
request->mAvatarIndices.resize(num_meshes);
request->mAvatarPositions.resize(num_meshes);
request->mAvatarNormals.resize(num_meshes);
for (S32 j = 0; j < num_meshes; j++)
{
S32 mesh_id = MORPH_MESHES[j];
LLPolyMesh* avatar_mesh = avatar->getMesh(mesh_id);
LLPolyFace* faces = avatar_mesh->getFaces();
// store avatar indices (LLPolyFaces are triangles)
S32 num_triangles = avatar_mesh->getNumFaces();
request->mAvatarIndices[j].resize(num_triangles * 3);
for (S32 k = 0; k < num_triangles; k++)
{
// indices for triangle corners
S32 index0 = faces[k][0];
S32 index1 = faces[k][1];
S32 index2 = faces[k][2];
request->mAvatarIndices[j][k * 3 + 0] = index0;
request->mAvatarIndices[j][k * 3 + 1] = index1;
request->mAvatarIndices[j][k * 3 + 2] = index2;
}
// store avatar vertices/normals
const LLVector4a* base_positions = avatar_mesh->getCoords();
const LLVector4a* base_normals = avatar_mesh->getNormals();
S32 num_vertices = avatar_mesh->getNumVertices();
request->mAvatarPositions[j].resize(num_vertices);
request->mAvatarNormals[j].resize(num_vertices);
for (S32 k = 0; k < num_vertices; k++)
{
request->mAvatarPositions[j][k] = LLVector3(base_positions[k].getF32ptr());
request->mAvatarNormals[j][k] = LLVector3(base_normals[k].getF32ptr());
request->mAvatarNormals[j][k].normalize();
}
// clean-up avatar
avatar->markDead();
}
// submit request to deformer worker
LLDeformerWorker::submitRequest(request);
return NULL;
}
void LLDeformedVolume::computeDeformTable(LLPointer<LLDeformerWorker::Request> request)
{
// see if this table is already in the cache. if so, return (no work needed)
LLDeformTableCacheIndex cache_index(request->mMeshID, request->mFace, request->mVertexCount);
deform_cache_t::iterator i = mDeformCache.find(cache_index);
if (i != mDeformCache.end())
{
// found it, nothing more to do here
return;
}
// tables are fairly small, we keep them around in case the user is switching between meshes for poorman's animation
// one entry per face per LOD per sculpt_ID
U32 MAX_CACHE_SIZE = 20;
if (mDeformCache.size() > MAX_CACHE_SIZE)
{
// this table will very infrequently fill - so make space in simple way:
// delete element at random
U32 random = ll_rand(MAX_CACHE_SIZE-1);
deform_cache_t::iterator iterator = mDeformCache.begin();
for (int i = 0; i < random; i++)
{
iterator++;
}
mDeformCache.erase(iterator);
}
LLDeformTable deform_table;
// table is a mapping from verts on the volume to verts on the avatar mesh.
// currently we take closest point - but may want to modify this in favor
// verts with similar skin weights and/or normals (so verts on the left leg
// don't move with the right leg by accident.)
// build mapping
deform_table.mMap.resize(request->mVertexCount);
// find matrices (vert and normal)
LLMatrix4a vertex_matrix;
vertex_matrix.loadu(request->mBindShapeMatrix);
LLMatrix4 normal_matrix_noA = request->mBindShapeMatrix;
normal_matrix_noA.invert_real(); // normals are transformed by inverse transpose
normal_matrix_noA.transpose();
LLMatrix4a normal_matrix;
normal_matrix.loadu(normal_matrix_noA);
// build optimized mesh searchers - one for each avatar mesh
LLMeshSearch* search[sizeof(MORPH_MESHES)/sizeof(S32)];
for (S32 i = 0; i < sizeof(MORPH_MESHES)/sizeof(S32); i++)
{
search[i] = new LLMeshSearch(request->mAvatarPositions[i], request->mAvatarIndices[i]);
}
// for each vertex in the volume, find the closest point on the avatar mesh(es)
// "closest" is defined to be a mixture of spatial position and distance between
// normals.
for (S32 i = 0; i < request->mVertexCount; i++)
{
// position to get closest to
LLVector4a source_position;
source_position.load3(request->mVolumePositions[i].mV);
LLVector4a source_position_transformed;
vertex_matrix.affineTransform(source_position, source_position_transformed);
source_position_transformed.mul(request->mScale);
LLVector3 target_position(source_position_transformed.getF32ptr());
F32 closest_distance = F32_MAX;
S32 closest_mesh = 0;
// corners of the triangle containing the closest point;
S32 closest_vertex[LL_DEFORMER_WEIGHT_COUNT];
// weights of those corners (barycentric coordinates)
F32 closest_vertex_weights[LL_DEFORMER_WEIGHT_COUNT];
for (S32 k = 0; k < sizeof(MORPH_MESHES)/sizeof(S32); k++)
{
F32 this_distance;
S32 index0, index1, index2;
F32 bary_a, bary_b;
BOOL found = search[k]->findClosestPoint(target_position, closest_distance,
this_distance, index0, index1, index2, bary_a, bary_b);
if (found)
{
// record corner indices of this triangle
closest_vertex[0] = index0;
closest_vertex[1] = index1;
closest_vertex[2] = index2;
// compute weights from barycentric coordinates
closest_vertex_weights[0] = 1.0f - bary_a - bary_b;
closest_vertex_weights[1] = bary_a;
closest_vertex_weights[2] = bary_b;
// and closest mesh
closest_mesh = k;
closest_distance = this_distance;
}
}
// create entry for found vertices
for (S32 k = 0; k < LL_DEFORMER_WEIGHT_COUNT; k++)
{
deform_table.mMap[i].mMesh[k] = (U8)closest_mesh;
deform_table.mMap[i].mVertex[k] = closest_vertex[k];
deform_table.mMap[i].mWeight[k] = closest_vertex_weights[k];
}
}
// free mesh searchers
for (S32 i = 0; i < sizeof(MORPH_MESHES)/sizeof(S32); i++)
{
delete search[i];
}
// store base positions for avatar verts
deform_table.mBasePositions = request->mAvatarPositions;
// now put it in the cache
mDeformCache[cache_index] = deform_table;
return;
}
BOOL LLDeformedVolume::deform(LLVolume* source, LLVOAvatar* avatar,
const LLMeshSkinInfo* skin, S32 face, LLPointer<LLDrawable> drawable)
{
LLFastTimer t(FTM_SKIN_RIGGED_DEFORM);
// first copy the source volume
bool copy = false;
if (source->getNumVolumeFaces() != getNumVolumeFaces())
{
copy = true;
}
for (S32 i = 0; i < source->getNumVolumeFaces() && !copy; ++i)
{
const LLVolumeFace& src_face = source->getVolumeFace(i);
const LLVolumeFace& dst_face = getVolumeFace(i);
if (src_face.mNumIndices != dst_face.mNumIndices ||
src_face.mNumVertices != dst_face.mNumVertices)
{
copy = true;
}
}
if (copy)
{
copyVolumeFaces(source);
}
// get the deform table
LLDeformTable* deform_table = getDeformTable(source, avatar, skin, face, drawable);
// if it's not available, fail
if (!deform_table)
{
return FALSE;
}
const LLVolumeFace& source_face = source->getVolumeFace(face);
const LLVolumeFace& destination_face = getVolumeFace(face);
// transforms volume space to avatar space
LLMatrix4a bind_shape_matrix_a;
bind_shape_matrix_a.loadu(skin->mBindShapeMatrix);
// transforms back again
LLMatrix4 bind_shape_matrix_inverse = skin->mBindShapeMatrix;
bind_shape_matrix_inverse.invert_real();
LLMatrix4a bind_shape_matrix_inverse_a;
bind_shape_matrix_inverse_a.loadu(bind_shape_matrix_inverse);
// skeleton scaling factor - assumes all joints have same scale and that the scale is uniform in XYZ (currently true)
F32 scale = powf(skin->mInvBindMatrix[0].determinant(), 1.0f / 3.0f);
for (S32 i = 0; i < source_face.mNumVertices; i++)
{
LLVector4a weighted_morph_delta;
weighted_morph_delta.clear();
F32 total_weight = 0;
for (S32 j = 0; j < LL_DEFORMER_WEIGHT_COUNT; j++)
{
U16 closest_vertex = deform_table->mMap[i].mVertex[j];
S32 closest_mesh = deform_table->mMap[i].mMesh[j];
F32 closest_weight = deform_table->mMap[i].mWeight[j];
// find the current mesh
LLPolyMesh* avatar_mesh = avatar->getMesh(MORPH_MESHES[closest_mesh]);
// and get positions for and morphed vertices
const LLVector4a* morph_positions = avatar_mesh->getCoords();
// find the movement of this vertex due to morphing
LLVector4a base_position;
base_position.load3(deform_table->mBasePositions[closest_mesh][closest_vertex].mV);
LLVector4a morph_delta;
morph_delta.setSub(morph_positions[closest_vertex], base_position);
// weight this delta and add to total
morph_delta.mul(closest_weight);
weighted_morph_delta.add(morph_delta);
total_weight += closest_weight;
}
// normalize
weighted_morph_delta.mul(1.0f/total_weight);
// source position mapped to avatar space
LLVector4a source_position = source_face.mPositions[i];
LLVector4a source_position_transformed;
bind_shape_matrix_a.affineTransform(source_position, source_position_transformed);
source_position_transformed.mul(scale);
// modify by movement delta
LLVector4a destination_position_transformed;
destination_position_transformed.setAdd(source_position_transformed, weighted_morph_delta);
// map back to volume space
destination_position_transformed.mul(1.0f / scale);
LLVector4a destination_position;
bind_shape_matrix_inverse_a.affineTransform(destination_position_transformed, destination_position);
destination_face.mPositions[i] = destination_position;
}
return TRUE; // success!
}
// </FS:CR>
U32 LLVOVolume::getPartitionType() const
{
if (isHUDAttachment())

View File

@ -35,7 +35,6 @@
#include "m3math.h" // LLMatrix3
#include "m4math.h" // LLMatrix4
#include <map>
#include "lldeformerworker.h" // <FS:CR> Qarl's mesh deformer
class LLViewerTextureAnim;
class LLDrawPool;
@ -65,92 +64,6 @@ public:
void update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* src_volume);
};
// <FS:CR> Qarl's mesh deformer
const S32 LL_DEFORMER_WEIGHT_COUNT = 3;
class LLDeformedVolume : public LLVolume
{
public:
LLDeformedVolume()
: LLVolume(LLVolumeParams(), 0.f)
{
}
// used as a key for the deform table cache
class LLDeformTableCacheIndex
{
public:
LLDeformTableCacheIndex(const LLUUID& id, S32 face, S32 vertex_count) :
mID(id), mFace(face), mVertexCount(vertex_count) {}
S32 mBaseShape;
LLUUID mID;
S32 mFace;
S32 mVertexCount;
bool operator<(const LLDeformTableCacheIndex& lhs) const
{
if (mID < lhs.mID)
return TRUE;
if (mID > lhs.mID)
return FALSE;
if (mFace < lhs.mFace)
return TRUE;
if (mFace > lhs.mFace)
return FALSE;
if (mVertexCount < lhs.mVertexCount)
return TRUE;
return FALSE;
}
};
// these are entries in the deformer table.
// they map vertices on the volume mesh to
// vertices on the avatar mesh(es).
struct LLDeformMap
{
U8 mMesh[LL_DEFORMER_WEIGHT_COUNT];
U16 mVertex[LL_DEFORMER_WEIGHT_COUNT];
F32 mWeight[LL_DEFORMER_WEIGHT_COUNT];
};
// the deform table contains precomputed information
// necessary to perform deformation on a volume face in
// realtime.
class LLDeformTable
{
public:
std::vector<struct LLDeformMap> mMap;
std::vector<std::vector< LLVector3 > > mBasePositions;
};
// the deform table cache holds tables for each face and mesh asset ID
typedef std::map<LLDeformTableCacheIndex, LLDeformTable> deform_cache_t;
deform_cache_t mDeformCache;
// apply deformation to source volume and store it in this volume
BOOL deform(LLVolume* source, LLVOAvatar* avatar, const LLMeshSkinInfo* skin, S32 face, LLPointer<LLDrawable> drawable);
// look-up the cached deform table
LLDeformTable* getDeformTable(LLVolume* source, LLVOAvatar* avatar, const LLMeshSkinInfo* skin,
S32 face, LLPointer<LLDrawable> drawable);
// compute the cached deform table
void computeDeformTable(LLPointer<LLDeformerWorker::Request> request);
};
// </FS:CR>
// Base class for implementations of the volume - Primitive, Flexible Object, etc.
class LLVolumeInterface
{
@ -419,11 +332,6 @@ public:
//clear out rigged volume and revert back to non-rigged state for picking/LOD/distance updates
void clearRiggedVolume();
// <FS:CR> Qarl's mesh deformer
// deformed volume (rigged attachments follow avatar morph shape changes
LLDeformedVolume* getDeformedVolume();
// </FS:CR>
protected:
S32 computeLODDetail(F32 distance, F32 radius);
BOOL calcLOD();
@ -469,7 +377,6 @@ private:
S32 mMDCImplCount;
LLPointer<LLRiggedVolume> mRiggedVolume;
LLPointer<LLDeformedVolume> mDeformedVolume; // <FS:CR> Qarl's mesh deformer
// statics
public:

View File

@ -275,7 +275,7 @@ Additional code generously contributed to Firestorm by:
top_pad="4"
width="420"
wrap="true">
Albatroz Hird, Alexie Birman, Andromeda Rage, Armin Weatherwax, Casper Warden, Chalice Yao, Cron Stardust, Damian Zhaoying, Dawa Gurbux, Felyza Wishbringer, f0rbidden, Fractured Crystal, Geenz Spad, Hitomi Tiponi, Inworldz LLC, Karl Stiefvater, Katharine Berry, Kittin Ninetails, Kool Koolhoven, Lance Corrimal, Magne Metaverse LLC, Magus Freston, Manami Hokkigai, MartinRJ Fayray, Melancholy Lemon, Miguael Liamano, Mimika Oh, Mister Acacia, Mysty Saunders, Nagi Michinaga, Name Short, nhede Core, NiranV Dean, Nogardrevlis Lectar, paperwork, Peyton Menges, programmtest, Qwerty Venom, Revolution Smythe, Sahkolihaa Contepomi, sal Kaligawa, Satomi Ahn, Sei Lisa, Shin Wasp, Shyotl Kuhr, Sione Lomu, Skills Hak, StarlightShining, Sunset Faulkes, Thickbrick Sleaford, Vaalith Jinn, Whirly Fizzle, Zwagoth Klaar and others.
Albatroz Hird, Alexie Birman, Andromeda Rage, Armin Weatherwax, Casper Warden, Chalice Yao, Cron Stardust, Damian Zhaoying, Dawa Gurbux, Felyza Wishbringer, f0rbidden, Fractured Crystal, Geenz Spad, Hitomi Tiponi, Katharine Berry, Kittin Ninetails, Kool Koolhoven, Lance Corrimal, Magne Metaverse LLC, Magus Freston, Manami Hokkigai, MartinRJ Fayray, Melancholy Lemon, Miguael Liamano, Mimika Oh, Mister Acacia, Mysty Saunders, Nagi Michinaga, Name Short, nhede Core, NiranV Dean, Nogardrevlis Lectar, paperwork, Peyton Menges, programmtest, Qwerty Venom, Revolution Smythe, Sahkolihaa Contepomi, sal Kaligawa, Satomi Ahn, Sei Lisa, Shin Wasp, Shyotl Kuhr, Sione Lomu, Skills Hak, StarlightShining, Sunset Faulkes, Thickbrick Sleaford, Vaalith Jinn, Whirly Fizzle, Zwagoth Klaar and others.
</text>
<text
follows="top|left"

View File

@ -1190,38 +1190,6 @@
label_text.text_color="White"
name="upload_joints"
top_pad="15"/>
<check_box
follows="top|left"
height="15"
label="Deform to avatar shape"
label_text.text_color="White"
name="deform"
top_pad="15"/>
<radio_group
draw_border="false"
follows="left|top"
width="221"
height="50"
name="deform_base">
<radio_item
height="15"
label="Male"
follows="left|top"
name="0"
width="200"/>
<radio_item
height="15"
follows="left|top"
label="Female"
name="1"
width="200" />
<radio_item
height="15"
label="Male - scrawny"
follows="left|top"
name="2"
width="200"/>
</radio_group>
<text
follows="top|left"
height="15"