summaryrefslogtreecommitdiff
path: root/indra/newview/llpolymesh.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llpolymesh.cpp')
-rw-r--r--indra/newview/llpolymesh.cpp1117
1 files changed, 1117 insertions, 0 deletions
diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp
new file mode 100644
index 0000000000..593a502b37
--- /dev/null
+++ b/indra/newview/llpolymesh.cpp
@@ -0,0 +1,1117 @@
+/**
+ * @file llpolymesh.cpp
+ * @brief Implementation of LLPolyMesh class
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "llviewerprecompiledheaders.h"
+
+#include "llpolymesh.h"
+
+#include "llviewercontrol.h"
+#include "llxmltree.h"
+#include "llvoavatar.h"
+#include "lldir.h"
+#include "llvolume.h"
+#include "llendianswizzle.h"
+
+#include "llfasttimer.h"
+
+#define HEADER_ASCII "Linden Mesh 1.0"
+#define HEADER_BINARY "Linden Binary Mesh 1.0"
+
+extern LLControlGroup gSavedSettings; // read only
+
+//-----------------------------------------------------------------------------
+// Global table of loaded LLPolyMeshes
+//-----------------------------------------------------------------------------
+LLPolyMesh::LLPolyMeshSharedDataTable LLPolyMesh::sGlobalSharedMeshList;
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData()
+//-----------------------------------------------------------------------------
+LLPolyMeshSharedData::LLPolyMeshSharedData()
+{
+ mNumVertices = 0;
+ mBaseCoords = NULL;
+ mBaseNormals = NULL;
+ mBaseBinormals = NULL;
+ mTexCoords = NULL;
+ mDetailTexCoords = NULL;
+ mWeights = NULL;
+ mHasWeights = FALSE;
+ mHasDetailTexCoords = FALSE;
+
+ mNumFaces = 0;
+ mFaces = NULL;
+
+ mNumJointNames = 0;
+ mJointNames = NULL;
+
+ mTriangleIndices = NULL;
+ mNumTriangleIndices = 0;
+
+ mReferenceData = NULL;
+
+ mLastIndexOffset = -1;
+}
+
+//-----------------------------------------------------------------------------
+// ~LLPolyMeshSharedData()
+//-----------------------------------------------------------------------------
+LLPolyMeshSharedData::~LLPolyMeshSharedData()
+{
+ freeMeshData();
+ mMorphData.deleteAllData();
+}
+
+//-----------------------------------------------------------------------------
+// setupLOD()
+//-----------------------------------------------------------------------------
+void LLPolyMeshSharedData::setupLOD(LLPolyMeshSharedData* reference_data)
+{
+ mReferenceData = reference_data;
+
+ if (reference_data)
+ {
+ mBaseCoords = reference_data->mBaseCoords;
+ mBaseNormals = reference_data->mBaseNormals;
+ mBaseBinormals = reference_data->mBaseBinormals;
+ mTexCoords = reference_data->mTexCoords;
+ mDetailTexCoords = reference_data->mDetailTexCoords;
+ mWeights = reference_data->mWeights;
+ mHasWeights = reference_data->mHasWeights;
+ mHasDetailTexCoords = reference_data->mHasDetailTexCoords;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData::freeMeshData()
+//-----------------------------------------------------------------------------
+void LLPolyMeshSharedData::freeMeshData()
+{
+ if (!mReferenceData)
+ {
+ mNumVertices = 0;
+
+ delete [] mBaseCoords;
+ mBaseCoords = NULL;
+
+ delete [] mBaseNormals;
+ mBaseNormals = NULL;
+
+ delete [] mBaseBinormals;
+ mBaseBinormals = NULL;
+
+ delete [] mTexCoords;
+ mTexCoords = NULL;
+
+ delete [] mDetailTexCoords;
+ mDetailTexCoords = NULL;
+
+ delete [] mWeights;
+ mWeights = NULL;
+ }
+
+ mNumFaces = 0;
+ delete [] mFaces;
+ mFaces = NULL;
+
+ mNumJointNames = 0;
+ delete [] mJointNames;
+ mJointNames = NULL;
+
+ delete [] mTriangleIndices;
+ mTriangleIndices = NULL;
+
+// mVertFaceMap.deleteAllData();
+}
+
+// compate_int is used by the qsort function to sort the index array
+int compare_int(const void *a, const void *b);
+
+//-----------------------------------------------------------------------------
+// genIndices()
+//-----------------------------------------------------------------------------
+void LLPolyMeshSharedData::genIndices(S32 index_offset)
+{
+ if (index_offset == mLastIndexOffset)
+ {
+ return;
+ }
+
+ delete []mTriangleIndices;
+ mTriangleIndices = new U32[mNumTriangleIndices];
+
+ S32 cur_index = 0;
+ for (S32 i = 0; i < mNumFaces; i++)
+ {
+ mTriangleIndices[cur_index] = mFaces[i][0] + index_offset;
+ cur_index++;
+ mTriangleIndices[cur_index] = mFaces[i][1] + index_offset;
+ cur_index++;
+ mTriangleIndices[cur_index] = mFaces[i][2] + index_offset;
+ cur_index++;
+ }
+
+ mLastIndexOffset = index_offset;
+}
+
+//--------------------------------------------------------------------
+// LLPolyMeshSharedData::getNumKB()
+//--------------------------------------------------------------------
+U32 LLPolyMeshSharedData::getNumKB()
+{
+ U32 num_kb = sizeof(LLPolyMesh);
+
+ if (!isLOD())
+ {
+ num_kb += mNumVertices *
+ ( sizeof(LLVector3) + // coords
+ sizeof(LLVector3) + // normals
+ sizeof(LLVector2) ); // texCoords
+ }
+
+ if (mHasDetailTexCoords && !isLOD())
+ {
+ num_kb += mNumVertices * sizeof(LLVector2); // detailTexCoords
+ }
+
+ if (mHasWeights && !isLOD())
+ {
+ num_kb += mNumVertices * sizeof(float); // weights
+ }
+
+ num_kb += mNumFaces * sizeof(LLPolyFace); // faces
+
+ num_kb /= 1024;
+ return num_kb;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData::allocateVertexData()
+//-----------------------------------------------------------------------------
+BOOL LLPolyMeshSharedData::allocateVertexData( U32 numVertices )
+{
+ U32 i;
+ mBaseCoords = new LLVector3[ numVertices ];
+ mBaseNormals = new LLVector3[ numVertices ];
+ mBaseBinormals = new LLVector3[ numVertices ];
+ mTexCoords = new LLVector2[ numVertices ];
+ mDetailTexCoords = new LLVector2[ numVertices ];
+ mWeights = new F32[ numVertices ];
+ for (i = 0; i < numVertices; i++)
+ {
+ mWeights[i] = 0.f;
+ }
+ mNumVertices = numVertices;
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData::allocateFaceData()
+//-----------------------------------------------------------------------------
+BOOL LLPolyMeshSharedData::allocateFaceData( U32 numFaces )
+{
+ mFaces = new LLPolyFace[ numFaces ];
+ mNumFaces = numFaces;
+ mNumTriangleIndices = mNumFaces * 3;
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData::allocateJointNames()
+//-----------------------------------------------------------------------------
+BOOL LLPolyMeshSharedData::allocateJointNames( U32 numJointNames )
+{
+ mJointNames = new std::string[ numJointNames ];
+ mNumJointNames = numJointNames;
+ return TRUE;
+}
+
+//--------------------------------------------------------------------
+// LLPolyMeshSharedData::loadMesh()
+//--------------------------------------------------------------------
+BOOL LLPolyMeshSharedData::loadMesh( const char *fileName )
+{
+ //-------------------------------------------------------------------------
+ // Open the file
+ //-------------------------------------------------------------------------
+ FILE *fp = LLFile::fopen(fileName, "rb");
+ if (!fp)
+ {
+ llerrs << "can't open: " << fileName << llendl;
+ return FALSE;
+ }
+
+ //-------------------------------------------------------------------------
+ // Read a chunk
+ //-------------------------------------------------------------------------
+ char header[128];
+ fread(header, sizeof(char), 128, fp);
+
+ //-------------------------------------------------------------------------
+ // Check for proper binary header
+ //-------------------------------------------------------------------------
+ BOOL status = FALSE;
+ if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 )
+ {
+ lldebugs << "Loading " << fileName << llendl;
+
+ //----------------------------------------------------------------
+ // File Header (seek past it)
+ //----------------------------------------------------------------
+ fseek(fp, 24, SEEK_SET);
+
+ //----------------------------------------------------------------
+ // HasWeights
+ //----------------------------------------------------------------
+ U8 hasWeights;
+ size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp);
+ if (numRead != 1)
+ {
+ llerrs << "can't read HasWeights flag from " << fileName << llendl;
+ }
+ if (!isLOD())
+ {
+ mHasWeights = (hasWeights==0) ? FALSE : TRUE;
+ }
+
+ //----------------------------------------------------------------
+ // HasDetailTexCoords
+ //----------------------------------------------------------------
+ U8 hasDetailTexCoords;
+ numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp);
+ if (numRead != 1)
+ {
+ llerrs << "can't read HasDetailTexCoords flag from " << fileName << llendl;
+ }
+
+ //----------------------------------------------------------------
+ // Position
+ //----------------------------------------------------------------
+ LLVector3 position;
+ numRead = fread(position.mV, sizeof(float), 3, fp);
+ llendianswizzle(position.mV, sizeof(float), 3);
+ if (numRead != 3)
+ {
+ llerrs << "can't read Position from " << fileName << llendl;
+ }
+ setPosition( position );
+
+ //----------------------------------------------------------------
+ // Rotation
+ //----------------------------------------------------------------
+ LLVector3 rotationAngles;
+ numRead = fread(rotationAngles.mV, sizeof(float), 3, fp);
+ llendianswizzle(rotationAngles.mV, sizeof(float), 3);
+ if (numRead != 3)
+ {
+ llerrs << "can't read RotationAngles from " << fileName << llendl;
+ }
+
+ U8 rotationOrder;
+ numRead = fread(&rotationOrder, 1, 1, fp);
+
+ if (numRead != 1)
+ {
+ llerrs << "can't read RotationOrder from " << fileName << llendl;
+ }
+
+ rotationOrder = 0;
+
+ setRotation( mayaQ( rotationAngles.mV[0],
+ rotationAngles.mV[1],
+ rotationAngles.mV[2],
+ (LLQuaternion::Order)rotationOrder ) );
+
+ //----------------------------------------------------------------
+ // Scale
+ //----------------------------------------------------------------
+ LLVector3 scale;
+ numRead = fread(scale.mV, sizeof(float), 3, fp);
+ llendianswizzle(scale.mV, sizeof(float), 3);
+ if (numRead != 3)
+ {
+ llerrs << "can't read Scale from " << fileName << llendl;
+ }
+ setScale( scale );
+
+ //-------------------------------------------------------------------------
+ // Release any existing mesh geometry
+ //-------------------------------------------------------------------------
+ freeMeshData();
+
+ U16 numVertices = 0;
+
+ //----------------------------------------------------------------
+ // NumVertices
+ //----------------------------------------------------------------
+ if (!isLOD())
+ {
+ numRead = fread(&numVertices, sizeof(U16), 1, fp);
+ llendianswizzle(&numVertices, sizeof(U16), 1);
+ if (numRead != 1)
+ {
+ llerrs << "can't read NumVertices from " << fileName << llendl;
+ }
+
+ allocateVertexData( numVertices );
+
+ //----------------------------------------------------------------
+ // Coords
+ //----------------------------------------------------------------
+ numRead = fread(mBaseCoords, 3*sizeof(float), numVertices, fp);
+ llendianswizzle(mBaseCoords, sizeof(float), 3*numVertices);
+ if (numRead != numVertices)
+ {
+ llerrs << "can't read Coordinates from " << fileName << llendl;
+ }
+
+ //----------------------------------------------------------------
+ // Normals
+ //----------------------------------------------------------------
+ numRead = fread(mBaseNormals, 3*sizeof(float), numVertices, fp);
+ llendianswizzle(mBaseNormals, sizeof(float), 3*numVertices);
+ if (numRead != numVertices)
+ {
+ llerrs << " can't read Normals from " << fileName << llendl;
+ }
+
+ //----------------------------------------------------------------
+ // Binormals
+ //----------------------------------------------------------------
+ numRead = fread(mBaseBinormals, 3*sizeof(float), numVertices, fp);
+ llendianswizzle(mBaseBinormals, sizeof(float), 3*numVertices);
+ if (numRead != numVertices)
+ {
+ llerrs << " can't read Binormals from " << fileName << llendl;
+ }
+
+
+ //----------------------------------------------------------------
+ // TexCoords
+ //----------------------------------------------------------------
+ numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp);
+ llendianswizzle(mTexCoords, sizeof(float), 2*numVertices);
+ if (numRead != numVertices)
+ {
+ llerrs << "can't read TexCoords from " << fileName << llendl;
+ }
+
+ //----------------------------------------------------------------
+ // DetailTexCoords
+ //----------------------------------------------------------------
+ if (mHasDetailTexCoords)
+ {
+ numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp);
+ llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices);
+ if (numRead != numVertices)
+ {
+ llerrs << "can't read DetailTexCoords from " << fileName << llendl;
+ }
+ }
+
+ //----------------------------------------------------------------
+ // Weights
+ //----------------------------------------------------------------
+ if (mHasWeights)
+ {
+ numRead = fread(mWeights, sizeof(float), numVertices, fp);
+ llendianswizzle(mWeights, sizeof(float), numVertices);
+ if (numRead != numVertices)
+ {
+ llerrs << "can't read Weights from " << fileName << llendl;
+ }
+ }
+ }
+
+ //----------------------------------------------------------------
+ // NumFaces
+ //----------------------------------------------------------------
+ U16 numFaces;
+ numRead = fread(&numFaces, sizeof(U16), 1, fp);
+ llendianswizzle(&numFaces, sizeof(U16), 1);
+ if (numRead != 1)
+ {
+ llerrs << "can't read NumFaces from " << fileName << llendl;
+ }
+ allocateFaceData( numFaces );
+
+
+ //----------------------------------------------------------------
+ // Faces
+ //----------------------------------------------------------------
+ U32 i;
+ U32 numTris = 0;
+ for (i = 0; i < numFaces; i++)
+ {
+ S16 face[3];
+ numRead = fread(face, sizeof(U16), 3, fp);
+ llendianswizzle(face, sizeof(U16), 3);
+ if (numRead != 3)
+ {
+ llerrs << "can't read Face[" << i << "] from " << fileName << llendl;
+ }
+ if (mReferenceData)
+ {
+ llassert(face[0] < mReferenceData->mNumVertices);
+ llassert(face[1] < mReferenceData->mNumVertices);
+ llassert(face[2] < mReferenceData->mNumVertices);
+ }
+
+ if (isLOD())
+ {
+ // store largest index in case of LODs
+ for (S32 j = 0; j < 3; j++)
+ {
+ if (face[j] > mNumVertices - 1)
+ {
+ mNumVertices = face[j] + 1;
+ }
+ }
+ }
+ mFaces[i][0] = face[0];
+ mFaces[i][1] = face[1];
+ mFaces[i][2] = face[2];
+
+// S32 j;
+// for(j = 0; j < 3; j++)
+// {
+// LLDynamicArray<S32> *face_list = mVertFaceMap.getIfThere(face[j]);
+// if (!face_list)
+// {
+// face_list = new LLDynamicArray<S32>;
+// mVertFaceMap.addData(face[j], face_list);
+// }
+// face_list->put(i);
+// }
+
+ numTris++;
+ }
+
+ lldebugs << "verts: " << numVertices
+ << ", faces: " << numFaces
+ << ", tris: " << numTris
+ << llendl;
+
+ //----------------------------------------------------------------
+ // NumSkinJoints
+ //----------------------------------------------------------------
+ if (!isLOD())
+ {
+ U16 numSkinJoints = 0;
+ if ( mHasWeights )
+ {
+ numRead = fread(&numSkinJoints, sizeof(U16), 1, fp);
+ llendianswizzle(&numSkinJoints, sizeof(U16), 1);
+ if (numRead != 1)
+ {
+ llerrs << "can't read NumSkinJoints from " << fileName << llendl;
+ }
+ allocateJointNames( numSkinJoints );
+ }
+
+ //----------------------------------------------------------------
+ // SkinJoints
+ //----------------------------------------------------------------
+ for (i=0; i < numSkinJoints; i++)
+ {
+ char jointName[64];
+ numRead = fread(jointName, sizeof(jointName), 1, fp);
+ if (numRead != 1)
+ {
+ llerrs << "can't read Skin[" << i << "].Name from " << fileName << llendl;
+ }
+
+ std::string *jn = &mJointNames[i];
+ *jn = jointName;
+ }
+
+ //-------------------------------------------------------------------------
+ // look for morph section
+ //-------------------------------------------------------------------------
+ char morphName[64];
+ while(fread(&morphName, sizeof(char), 64, fp) == 64)
+ {
+ if (!strcmp(morphName, "End Morphs"))
+ {
+ // we reached the end of the morphs
+ break;
+ }
+ LLPolyMorphData* morph_data = new LLPolyMorphData(morphName);
+
+ BOOL result = morph_data->loadBinary(fp, this);
+
+ if (!result)
+ {
+ delete morph_data;
+ continue;
+ }
+
+ mMorphData.addData(morph_data);
+ }
+
+ S32 numRemaps;
+ if (fread(&numRemaps, sizeof(S32), 1, fp) == 1)
+ {
+ llendianswizzle(&numRemaps, sizeof(S32), 1);
+ for (S32 i = 0; i < numRemaps; i++)
+ {
+ S32 remapSrc;
+ S32 remapDst;
+ if (fread(&remapSrc, sizeof(S32), 1, fp) != 1)
+ {
+ llerrs << "can't read source vertex in vertex remap data" << llendl;
+ break;
+ }
+ if (fread(&remapDst, sizeof(S32), 1, fp) != 1)
+ {
+ llerrs << "can't read destination vertex in vertex remap data" << llendl;
+ break;
+ }
+ llendianswizzle(&remapSrc, sizeof(S32), 1);
+ llendianswizzle(&remapDst, sizeof(S32), 1);
+
+ mSharedVerts[remapSrc] = remapDst;
+ }
+ }
+ }
+
+ status = TRUE;
+ }
+ else
+ {
+ llerrs << "invalid mesh file header: " << fileName << llendl;
+ status = FALSE;
+ }
+
+ if (0 == mNumJointNames)
+ {
+ allocateJointNames(1);
+ }
+
+ fclose( fp );
+
+ return status;
+}
+
+//-----------------------------------------------------------------------------
+// getSharedVert()
+//-----------------------------------------------------------------------------
+const S32 *LLPolyMeshSharedData::getSharedVert(S32 vert)
+{
+ if (mSharedVerts.count(vert) > 0)
+ {
+ return &mSharedVerts[vert];
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// getUV()
+//-----------------------------------------------------------------------------
+const LLVector2 &LLPolyMeshSharedData::getUVs(U32 index)
+{
+ // TODO: convert all index variables to S32
+ llassert((S32)index < mNumVertices);
+
+ return mTexCoords[index];
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh)
+{
+ llassert(shared_data);
+
+ mSharedData = shared_data;
+ mReferenceMesh = reference_mesh;
+ mAvatarp = NULL;
+ mVertexData = NULL;
+
+ if (shared_data->isLOD() && reference_mesh)
+ {
+ mCoords = reference_mesh->mCoords;
+ mNormals = reference_mesh->mNormals;
+ mScaledNormals = reference_mesh->mScaledNormals;
+ mBinormals = reference_mesh->mBinormals;
+ mScaledBinormals = reference_mesh->mScaledBinormals;
+ mTexCoords = reference_mesh->mTexCoords;
+ mClothingWeights = reference_mesh->mClothingWeights;
+ }
+ else
+ {
+#if 1 // Allocate memory without initializing every vector
+ // NOTE: This makes asusmptions about the size of LLVector[234]
+ int nverts = mSharedData->mNumVertices;
+ int nfloats = nverts * (3*5 + 2 + 4);
+ mVertexData = new F32[nfloats];
+ int offset = 0;
+ mCoords = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
+ mNormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
+ mScaledNormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
+ mBinormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
+ mScaledBinormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
+ mTexCoords = (LLVector2*)(mVertexData + offset); offset += 2*nverts;
+ mClothingWeights = (LLVector4*)(mVertexData + offset); offset += 4*nverts;
+#else
+ mCoords = new LLVector3[mSharedData->mNumVertices];
+ mNormals = new LLVector3[mSharedData->mNumVertices];
+ mScaledNormals = new LLVector3[mSharedData->mNumVertices];
+ mBinormals = new LLVector3[mSharedData->mNumVertices];
+ mScaledBinormals = new LLVector3[mSharedData->mNumVertices];
+ mTexCoords = new LLVector2[mSharedData->mNumVertices];
+ mClothingWeights = new LLVector4[mSharedData->mNumVertices];
+ memset(mClothingWeights, 0, sizeof(LLVector4) * mSharedData->mNumVertices);
+#endif
+ initializeForMorph();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// ~LLPolyMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh::~LLPolyMesh()
+{
+ S32 i;
+ for (i = 0; i < mJointRenderData.count(); i++)
+ {
+ delete mJointRenderData[i];
+ mJointRenderData[i] = NULL;
+ }
+#if 0 // These are now allocated as one big uninitialized chunk
+ delete [] mCoords;
+ delete [] mNormals;
+ delete [] mScaledNormals;
+ delete [] mBinormals;
+ delete [] mScaledBinormals;
+ delete [] mClothingWeights;
+ delete [] mTexCoords;
+#else
+ delete [] mVertexData;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// LLPolyMesh::getMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh *LLPolyMesh::getMesh(const LLString &name, LLPolyMesh* reference_mesh)
+{
+ //-------------------------------------------------------------------------
+ // search for an existing mesh by this name
+ //-------------------------------------------------------------------------
+ LLPolyMeshSharedData **meshSharedData = sGlobalSharedMeshList.getValue(name);
+ if (meshSharedData)
+ {
+// llinfos << "Polymesh " << name << " found in global mesh table." << llendl;
+ LLPolyMesh *poly_mesh = new LLPolyMesh(*meshSharedData, reference_mesh);
+ return poly_mesh;
+ }
+
+ //-------------------------------------------------------------------------
+ // if not found, create a new one, add it to the list
+ //-------------------------------------------------------------------------
+ char full_path[LL_MAX_PATH];
+ sprintf(full_path, "%s", (gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,name.c_str())).c_str());
+
+ LLPolyMeshSharedData *mesh_data = new LLPolyMeshSharedData();
+ if (reference_mesh)
+ {
+ mesh_data->setupLOD(reference_mesh->getSharedData());
+ }
+ if ( ! mesh_data->loadMesh( full_path ) )
+ {
+ delete mesh_data;
+ return NULL;
+ }
+
+ LLPolyMesh *poly_mesh = new LLPolyMesh(mesh_data, reference_mesh);
+
+// llinfos << "Polymesh " << name << " added to global mesh table." << llendl;
+ sGlobalSharedMeshList.addToTail(name, poly_mesh->mSharedData);
+
+ return poly_mesh;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMesh::freeAllMeshes()
+//-----------------------------------------------------------------------------
+void LLPolyMesh::freeAllMeshes()
+{
+ U32 i;
+
+ // delete each item in the global lists
+ for (i=0; i<sGlobalSharedMeshList.length(); i++)
+ {
+ // returns a pointer to the value, which is the pointer
+ // to the mesh
+ LLPolyMeshSharedData **shared_mesh_pp = sGlobalSharedMeshList.getValueAt(i);
+
+ // delete the mesh
+ delete *shared_mesh_pp;
+ }
+
+ // empty the lists
+ sGlobalSharedMeshList.removeAll();
+}
+
+LLPolyMeshSharedData *LLPolyMesh::getSharedData() const
+{
+ return mSharedData;
+}
+
+
+//--------------------------------------------------------------------
+// LLPolyMesh::dumpDiagInfo()
+//--------------------------------------------------------------------
+void LLPolyMesh::dumpDiagInfo()
+{
+ // keep track of totals
+ U32 total_verts = 0;
+ U32 total_faces = 0;
+ U32 total_kb = 0;
+
+ char buf[1024];
+
+ llinfos << "-----------------------------------------------------" << llendl;
+ llinfos << " Global PolyMesh Table (DEBUG only)" << llendl;
+ llinfos << " Verts Faces Mem(KB) Name" << llendl;
+ llinfos << "-----------------------------------------------------" << llendl;
+
+ // print each loaded mesh, and it's memory usage
+ for (U32 i=0; i<sGlobalSharedMeshList.length(); i++)
+ {
+ std::string *mesh_name_p = sGlobalSharedMeshList.getIndexAt(i);
+
+ LLPolyMeshSharedData **mesh_pp = sGlobalSharedMeshList.getValueAt(i);
+ LLPolyMeshSharedData &mesh = **mesh_pp;
+
+ S32 num_verts = mesh.mNumVertices;
+ S32 num_faces = mesh.mNumFaces;
+ U32 num_kb = mesh.getNumKB();
+
+ sprintf(buf, "%8d %8d %8d %s", num_verts, num_faces, num_kb, mesh_name_p->c_str());
+ llinfos << buf << llendl;
+
+ total_verts += num_verts;
+ total_faces += num_faces;
+ total_kb += num_kb;
+ }
+
+ llinfos << "-----------------------------------------------------" << llendl;
+ sprintf(buf, "%8d %8d %8d TOTAL", total_verts, total_faces, total_kb );
+ llinfos << buf << llendl;
+ llinfos << "-----------------------------------------------------" << llendl;
+}
+
+//-----------------------------------------------------------------------------
+// getCoords()
+//-----------------------------------------------------------------------------
+const LLVector3 *LLPolyMesh::getCoords() const
+{
+ return mCoords;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableCoords()
+//-----------------------------------------------------------------------------
+LLVector3 *LLPolyMesh::getWritableCoords()
+{
+ return mCoords;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableNormals()
+//-----------------------------------------------------------------------------
+LLVector3 *LLPolyMesh::getWritableNormals()
+{
+ return mNormals;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableBinormals()
+//-----------------------------------------------------------------------------
+LLVector3 *LLPolyMesh::getWritableBinormals()
+{
+ return mBinormals;
+}
+
+
+//-----------------------------------------------------------------------------
+// getWritableClothingWeights()
+//-----------------------------------------------------------------------------
+LLVector4 *LLPolyMesh::getWritableClothingWeights()
+{
+ return mClothingWeights;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableTexCoords()
+//-----------------------------------------------------------------------------
+LLVector2 *LLPolyMesh::getWritableTexCoords()
+{
+ return mTexCoords;
+}
+
+//-----------------------------------------------------------------------------
+// getScaledNormals()
+//-----------------------------------------------------------------------------
+LLVector3 *LLPolyMesh::getScaledNormals()
+{
+ return mScaledNormals;
+}
+
+//-----------------------------------------------------------------------------
+// getScaledBinormals()
+//-----------------------------------------------------------------------------
+LLVector3 *LLPolyMesh::getScaledBinormals()
+{
+ return mScaledBinormals;
+}
+
+
+//-----------------------------------------------------------------------------
+// initializeForMorph()
+//-----------------------------------------------------------------------------
+void LLPolyMesh::initializeForMorph()
+{
+ if (!mSharedData)
+ return;
+
+ memcpy(mCoords, mSharedData->mBaseCoords, sizeof(LLVector3) * mSharedData->mNumVertices);
+ memcpy(mNormals, mSharedData->mBaseNormals, sizeof(LLVector3) * mSharedData->mNumVertices);
+ memcpy(mScaledNormals, mSharedData->mBaseNormals, sizeof(LLVector3) * mSharedData->mNumVertices);
+ memcpy(mBinormals, mSharedData->mBaseBinormals, sizeof(LLVector3) * mSharedData->mNumVertices);
+ memcpy(mScaledBinormals, mSharedData->mBaseBinormals, sizeof(LLVector3) * mSharedData->mNumVertices);
+ memcpy(mTexCoords, mSharedData->mTexCoords, sizeof(LLVector2) * mSharedData->mNumVertices);
+ memset(mClothingWeights, 0, sizeof(LLVector4) * mSharedData->mNumVertices);
+}
+
+//-----------------------------------------------------------------------------
+// getMorphData()
+//-----------------------------------------------------------------------------
+LLPolyMorphData* LLPolyMesh::getMorphData(const char *morph_name)
+{
+ if (!mSharedData) return NULL;
+ for (LLPolyMorphData *morph_data = mSharedData->mMorphData.getFirstData();
+ morph_data;
+ morph_data = mSharedData->mMorphData.getNextData())
+ {
+ if (!strcmp(morph_data->getName(), morph_name))
+ {
+ return morph_data;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// removeMorphData()
+//-----------------------------------------------------------------------------
+void LLPolyMesh::removeMorphData(LLPolyMorphData *morph_target)
+{
+ if (!mSharedData) return;
+
+ mSharedData->mMorphData.removeData(morph_target);
+}
+
+//-----------------------------------------------------------------------------
+// deleteAllMorphData()
+//-----------------------------------------------------------------------------
+void LLPolyMesh::deleteAllMorphData()
+{
+ if (!mSharedData) return;
+
+ mSharedData->mMorphData.deleteAllData();
+}
+
+//-----------------------------------------------------------------------------
+// getWeights()
+//-----------------------------------------------------------------------------
+const F32* LLPolyMesh::getWeights() const
+{
+ return mSharedData->mWeights;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableWeights()
+//-----------------------------------------------------------------------------
+F32* LLPolyMesh::getWritableWeights() const
+{
+ return mSharedData->mWeights;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolySkeletalDistortionInfo()
+//-----------------------------------------------------------------------------
+LLPolySkeletalDistortionInfo::LLPolySkeletalDistortionInfo()
+{
+}
+
+BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
+{
+ llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) );
+
+ if (!LLViewerVisualParamInfo::parseXml(node))
+ return FALSE;
+
+ LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton");
+
+ for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() )
+ {
+ if (bone->hasName("bone"))
+ {
+ LLString name;
+ LLVector3 scale;
+ LLVector3 pos;
+ BOOL haspos = FALSE;
+
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!bone->getFastAttributeString(name_string, name))
+ {
+ llwarns << "No bone name specified for skeletal param." << llendl;
+ continue;
+ }
+
+ static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
+ if (!bone->getFastAttributeVector3(scale_string, scale))
+ {
+ llwarns << "No scale specified for bone " << name << "." << llendl;
+ continue;
+ }
+
+ // optional offset deformation (translation)
+ static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset");
+ if (bone->getFastAttributeVector3(offset_string, pos))
+ {
+ haspos = TRUE;
+ }
+ mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos));
+ }
+ else
+ {
+ llwarns << "Unrecognized element " << bone->getName() << " in skeletal distortion" << llendl;
+ continue;
+ }
+ }
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolySkeletalDistortion()
+//-----------------------------------------------------------------------------
+LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLVOAvatar *avatarp)
+{
+ mAvatar = avatarp;
+ mDefaultVec.setVec(0.001f, 0.001f, 0.001f);
+}
+
+//-----------------------------------------------------------------------------
+// ~LLPolySkeletalDistortion()
+//-----------------------------------------------------------------------------
+LLPolySkeletalDistortion::~LLPolySkeletalDistortion()
+{
+}
+
+BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
+{
+ llassert(mInfo == NULL);
+ if (info->mID < 0)
+ return FALSE;
+ mInfo = info;
+ mID = info->mID;
+ setWeight(getDefaultWeight(), FALSE );
+
+ LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;
+ for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++)
+ {
+ LLPolySkeletalBoneInfo *bone_info = &(*iter);
+ LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName);
+ if (!joint)
+ {
+ llwarns << "Joint " << bone_info->mBoneName << " not found." << llendl;
+ continue;
+ }
+
+ if (mJointScales.find(joint) != mJointScales.end())
+ {
+ llwarns << "Scale deformation already supplied for joint " << joint->getName() << "." << llendl;
+ }
+
+ // store it
+ mJointScales[joint] = bone_info->mScaleDeformation;
+
+ // apply to children that need to inherit it
+ for ( LLViewerJoint *child_joint = (LLViewerJoint *)joint->mChildren.getFirstData();
+ child_joint != NULL;
+ child_joint = (LLViewerJoint *)joint->mChildren.getNextData() )
+ {
+ if (child_joint->inheritScale())
+ {
+ LLVector3 childDeformation = LLVector3(child_joint->getScale());
+ childDeformation.scaleVec(bone_info->mScaleDeformation);
+ mJointScales[child_joint] = childDeformation;
+ }
+ }
+
+ if (bone_info->mHasPositionDeformation)
+ {
+ if (mJointOffsets.find(joint) != mJointOffsets.end())
+ {
+ llwarns << "Offset deformation already supplied for joint " << joint->getName() << "." << llendl;
+ }
+ mJointOffsets[joint] = bone_info->mPositionDeformation;
+ }
+ }
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// apply()
+//-----------------------------------------------------------------------------
+void LLPolySkeletalDistortion::apply( ESex avatar_sex )
+{
+ F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
+
+ LLJoint* joint;
+ joint_vec_map_t::iterator iter;
+
+ for (iter = mJointScales.begin();
+ iter != mJointScales.end();
+ iter++)
+ {
+ joint = iter->first;
+ LLVector3 newScale = joint->getScale();
+ LLVector3 scaleDelta = iter->second;
+ newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
+ joint->setScale(newScale);
+ }
+
+ for (iter = mJointOffsets.begin();
+ iter != mJointOffsets.end();
+ iter++)
+ {
+ joint = iter->first;
+ LLVector3 newPosition = joint->getPosition();
+ LLVector3 positionDelta = iter->second;
+ newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
+ joint->setPosition(newPosition);
+ }
+
+ if (mLastWeight != mCurWeight && !mIsAnimating)
+ {
+ mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1);
+ }
+ mLastWeight = mCurWeight;
+}
+
+// End