Files
SingularityViewer/indra/llappearance/llpolymesh.cpp
2012-12-20 02:55:34 -06:00

1773 lines
54 KiB
C++

/**
* @file llpolymesh.cpp
* @brief Implementation of LLPolyMesh class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "linden_common.h"
#include "llpolymesh.h"
#include "llfasttimer.h"
#include "llmemory.h"
//#include "llviewercontrol.h"
#include "llxmltree.h"
#include "llavatarappearance.h"
//#include "llwearable.h"
#include "lldir.h"
#include "llvolume.h"
#include "llendianswizzle.h"
#define HEADER_ASCII "Linden Mesh 1.0"
#define HEADER_BINARY "Linden Binary Mesh 1.0"
//extern LLControlGroup gSavedSettings; // read only
LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
const std::string &name);
LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
const LLVector3 &direction,
const std::string &name);
LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
F32 scale,
const std::string &name);
//-----------------------------------------------------------------------------
// 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();
for_each(mMorphData.begin(), mMorphData.end(), DeletePointer());
mMorphData.clear();
}
//-----------------------------------------------------------------------------
// 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;
ll_aligned_free_16(mBaseCoords);
mBaseCoords = NULL;
ll_aligned_free_16(mBaseNormals);
mBaseNormals = NULL;
ll_aligned_free_16(mBaseBinormals);
mBaseBinormals = NULL;
ll_aligned_free_16(mTexCoords);
mTexCoords = NULL;
ll_aligned_free_16(mDetailTexCoords);
mDetailTexCoords = NULL;
ll_aligned_free_16(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 = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
mBaseNormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
mBaseBinormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
mTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2));
mDetailTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2));
mWeights = (F32*) ll_aligned_malloc_16(numVertices*sizeof(F32));
for (i = 0; i < numVertices; i++)
{
mBaseCoords[i].clear();
mBaseNormals[i].clear();
mBaseBinormals[i].clear();
mTexCoords[i].clear();
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 std::string& fileName )
{
//-------------------------------------------------------------------------
// Open the file
//-------------------------------------------------------------------------
if(fileName.empty())
{
llerrs << "Filename is Empty!" << llendl;
return FALSE;
}
LLFILE* fp = LLFile::fopen(fileName, "rb"); /*Flawfinder: ignore*/
if (!fp)
{
llerrs << "can't open: " << fileName << llendl;
return FALSE;
}
//-------------------------------------------------------------------------
// Read a chunk
//-------------------------------------------------------------------------
char header[128]; /*Flawfinder: ignore*/
if (fread(header, sizeof(char), 128, fp) != 128)
{
llwarns << "Short read" << llendl;
}
//-------------------------------------------------------------------------
// Check for proper binary header
//-------------------------------------------------------------------------
BOOL status = FALSE;
if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 ) /*Flawfinder: ignore*/
{
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;
return FALSE;
}
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;
return FALSE;
}
//----------------------------------------------------------------
// 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;
return FALSE;
}
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;
return FALSE;
}
U8 rotationOrder;
numRead = fread(&rotationOrder, sizeof(U8), 1, fp);
if (numRead != 1)
{
llerrs << "can't read RotationOrder from " << fileName << llendl;
return FALSE;
}
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;
return FALSE;
}
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;
return FALSE;
}
allocateVertexData( numVertices );
for (U16 i = 0; i < numVertices; ++i)
{
//----------------------------------------------------------------
// Coords
//----------------------------------------------------------------
numRead = fread(&mBaseCoords[i], sizeof(float), 3, fp);
llendianswizzle(&mBaseCoords[i], sizeof(float), 3);
if (numRead != 3)
{
llerrs << "can't read Coordinates from " << fileName << llendl;
return FALSE;
}
}
for (U16 i = 0; i < numVertices; ++i)
{
//----------------------------------------------------------------
// Normals
//----------------------------------------------------------------
numRead = fread(&mBaseNormals[i], sizeof(float), 3, fp);
llendianswizzle(&mBaseNormals[i], sizeof(float), 3);
if (numRead != 3)
{
llerrs << " can't read Normals from " << fileName << llendl;
return FALSE;
}
}
for (U16 i = 0; i < numVertices; ++i)
{
//----------------------------------------------------------------
// Binormals
//----------------------------------------------------------------
numRead = fread(&mBaseBinormals[i], sizeof(float), 3, fp);
llendianswizzle(&mBaseBinormals[i], sizeof(float), 3);
if (numRead != 3)
{
llerrs << " can't read Binormals from " << fileName << llendl;
return FALSE;
}
}
//----------------------------------------------------------------
// 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;
return FALSE;
}
//----------------------------------------------------------------
// 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;
return FALSE;
}
}
//----------------------------------------------------------------
// 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;
return FALSE;
}
}
}
//----------------------------------------------------------------
// 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;
return FALSE;
}
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;
return FALSE;
}
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;
return FALSE;
}
allocateJointNames( numSkinJoints );
}
//----------------------------------------------------------------
// SkinJoints
//----------------------------------------------------------------
for (i=0; i < numSkinJoints; i++)
{
char jointName[64+1];
numRead = fread(jointName, sizeof(jointName)-1, 1, fp);
jointName[sizeof(jointName)-1] = '\0'; // ensure nul-termination
if (numRead != 1)
{
llerrs << "can't read Skin[" << i << "].Name from " << fileName << llendl;
return FALSE;
}
std::string *jn = &mJointNames[i];
*jn = jointName;
}
//-------------------------------------------------------------------------
// look for morph section
//-------------------------------------------------------------------------
char morphName[64+1];
morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination
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(std::string(morphName));
BOOL result = morph_data->loadBinary(fp, this);
if (!result)
{
delete morph_data;
continue;
}
mMorphData.insert(morph_data);
if (!strcmp(morphName, "Breast_Female_Cleavage"))
{
mMorphData.insert(clone_morph_param_cleavage(morph_data,
.75f,
"Breast_Physics_LeftRight_Driven"));
}
if (!strcmp(morphName, "Breast_Female_Cleavage"))
{
mMorphData.insert(clone_morph_param_duplicate(morph_data,
"Breast_Physics_InOut_Driven"));
}
if (!strcmp(morphName, "Breast_Gravity"))
{
mMorphData.insert(clone_morph_param_duplicate(morph_data,
"Breast_Physics_UpDown_Driven"));
}
if (!strcmp(morphName, "Big_Belly_Torso"))
{
mMorphData.insert(clone_morph_param_direction(morph_data,
LLVector3(0,0,0.05f),
"Belly_Physics_Torso_UpDown_Driven"));
}
if (!strcmp(morphName, "Big_Belly_Legs"))
{
mMorphData.insert(clone_morph_param_direction(morph_data,
LLVector3(0,0,0.05f),
"Belly_Physics_Legs_UpDown_Driven"));
}
if (!strcmp(morphName, "skirt_belly"))
{
mMorphData.insert(clone_morph_param_direction(morph_data,
LLVector3(0,0,0.05f),
"Belly_Physics_Skirt_UpDown_Driven"));
}
if (!strcmp(morphName, "Small_Butt"))
{
mMorphData.insert(clone_morph_param_direction(morph_data,
LLVector3(0,0,0.05f),
"Butt_Physics_UpDown_Driven"));
}
if (!strcmp(morphName, "Small_Butt"))
{
mMorphData.insert(clone_morph_param_direction(morph_data,
LLVector3(0,0.03f,0),
"Butt_Physics_LeftRight_Driven"));
}
}
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)
{
LLMemType mt(LLMemType::MTYPE_AVATAR_MESH);
llassert(shared_data);
mSharedData = shared_data;
mReferenceMesh = reference_mesh;
mAvatarp = NULL;
mVertexData = NULL;
mCurVertexCount = 0;
mFaceIndexCount = 0;
mFaceIndexOffset = 0;
mFaceVertexCount = 0;
mFaceVertexOffset = 0;
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
{
// Allocate memory without initializing every vector
// NOTE: This makes asusmptions about the size of LLVector[234]
S32 nverts = mSharedData->mNumVertices;
//make sure it's an even number of verts for alignment
nverts += nverts%2;
S32 nfloats = nverts * (
4 + //coords
4 + //normals
4 + //weights
2 + //coords
4 + //scaled normals
4 + //binormals
4); //scaled binormals
//use 16 byte aligned vertex data to make LLPolyMesh SSE friendly
mVertexData = (F32*) ll_aligned_malloc_16(nfloats*4);
S32 offset = 0;
mCoords = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
mNormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
mClothingWeights = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
mTexCoords = (LLVector2*)(mVertexData + offset); offset += 2*nverts;
mScaledNormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
mBinormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
mScaledBinormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
initializeForMorph();
}
}
//-----------------------------------------------------------------------------
// ~LLPolyMesh()
//-----------------------------------------------------------------------------
LLPolyMesh::~LLPolyMesh()
{
S32 i;
for (i = 0; i < mJointRenderData.count(); i++)
{
delete mJointRenderData[i];
mJointRenderData[i] = NULL;
}
ll_aligned_free_16(mVertexData);
}
//-----------------------------------------------------------------------------
// LLPolyMesh::getMesh()
//-----------------------------------------------------------------------------
LLPolyMesh *LLPolyMesh::getMesh(const std::string &name, LLPolyMesh* reference_mesh)
{
//-------------------------------------------------------------------------
// search for an existing mesh by this name
//-------------------------------------------------------------------------
LLPolyMeshSharedData* meshSharedData = get_if_there(sGlobalSharedMeshList, name, (LLPolyMeshSharedData*)NULL);
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
//-------------------------------------------------------------------------
std::string full_path;
full_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,name);
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[name] = poly_mesh->mSharedData;
return poly_mesh;
}
//-----------------------------------------------------------------------------
// LLPolyMesh::getMeshData()
//-----------------------------------------------------------------------------
LLPolyMeshSharedData *LLPolyMesh::getMeshData(const std::string &name)
{
//-------------------------------------------------------------------------
// search for an existing mesh by this name
//-------------------------------------------------------------------------
LLPolyMeshSharedData* mesh_shared_data = get_if_there(sGlobalSharedMeshList, name, (LLPolyMeshSharedData*)NULL);
return mesh_shared_data;
}
//-----------------------------------------------------------------------------
// LLPolyMesh::saveLLM()
//-----------------------------------------------------------------------------
BOOL LLPolyMesh::saveLLM(LLFILE *fp)
{
if (!fp)
return FALSE;
//-------------------------------------------------------------------------
// Write a header
//-------------------------------------------------------------------------
if (fwrite(HEADER_BINARY, 1, strlen(HEADER_BINARY), fp) != strlen(HEADER_BINARY))
{
llwarns << "Short write" << llendl;
}
if (strlen(HEADER_BINARY) < 24)
{
char padding[24] = {}; // zeroes
int pad = 24 - strlen(HEADER_BINARY);
if (fwrite(&padding, 1, pad, fp) != pad)
{
llwarns << "Short write" << llendl;
}
}
//----------------------------------------------------------------
// HasWeights
//----------------------------------------------------------------
U8 hasWeights = (U8) mSharedData->mHasWeights;
if (fwrite(&hasWeights, sizeof(U8), 1, fp) != 1)
{
llwarns << "Short write" << llendl;
}
//----------------------------------------------------------------
// HasDetailTexCoords
//----------------------------------------------------------------
U8 hasDetailTexCoords = (U8) mSharedData->mHasDetailTexCoords;
if (fwrite(&hasDetailTexCoords, sizeof(U8), 1, fp) != 1)
{
llwarns << "Short write" << llendl;
}
//----------------------------------------------------------------
// Position
//----------------------------------------------------------------
LLVector3 position = mSharedData->mPosition;
llendianswizzle(position.mV, sizeof(float), 3);
if (fwrite(position.mV, sizeof(float), 3, fp) != 3)
{
llwarns << "Short write" << llendl;
}
//----------------------------------------------------------------
// Rotation
//----------------------------------------------------------------
LLQuaternion rotation = mSharedData->mRotation;
F32 roll;
F32 pitch;
F32 yaw;
rotation.getEulerAngles(&roll, &pitch, &yaw);
roll *= RAD_TO_DEG;
pitch *= RAD_TO_DEG;
yaw *= RAD_TO_DEG;
LLVector3 rotationAngles (roll, pitch, yaw);
llendianswizzle(rotationAngles.mV, sizeof(float), 3);
if (fwrite(rotationAngles.mV, sizeof(float), 3, fp) != 3)
{
llwarns << "Short write" << llendl;
}
U8 rotationOrder = 0;
if (fwrite(&rotationOrder, sizeof(U8), 1, fp) != 1)
{
llwarns << "Short write" << llendl;
}
//----------------------------------------------------------------
// Scale
//----------------------------------------------------------------
LLVector3 scale = mSharedData->mScale;
llendianswizzle(scale.mV, sizeof(float), 3);
if (fwrite(scale.mV, sizeof(float), 3, fp) != 3)
{
llwarns << "Short write" << llendl;
}
//----------------------------------------------------------------
// NumVertices
//----------------------------------------------------------------
U16 numVertices = mSharedData->mNumVertices;
if (!isLOD())
{
llendianswizzle(&numVertices, sizeof(U16), 1);
if (fwrite(&numVertices, sizeof(U16), 1, fp) != 1)
{
llwarns << "Short write" << llendl;
}
numVertices = mSharedData->mNumVertices; // without the swizzle again
//----------------------------------------------------------------
// Coords
//----------------------------------------------------------------
for (U16 i = 0; i < numVertices; ++i)
{
LLVector4a& coords = mSharedData->mBaseCoords[i];
llendianswizzle(coords.getF32ptr(), sizeof(float), 3);
if (fwrite(coords.getF32ptr(), 3*sizeof(float), 1, fp) != 1)
{
llwarns << "Short write" << llendl;
}
llendianswizzle(coords.getF32ptr(), sizeof(float), 3);
}
//----------------------------------------------------------------
// Normals
//----------------------------------------------------------------
for (U16 i = 0; i < numVertices; ++i)
{
LLVector4a& normals = mSharedData->mBaseNormals[i];
llendianswizzle(normals.getF32ptr(), sizeof(float), 3);
if (fwrite(normals.getF32ptr(), 3*sizeof(float), 1, fp) != 1)
{
llwarns << "Short write" << llendl;
}
llendianswizzle(normals.getF32ptr(), sizeof(float), 3);
}
//----------------------------------------------------------------
// Binormals
//----------------------------------------------------------------
for (U16 i = 0; i < numVertices; ++i)
{
LLVector4a& binormals = mSharedData->mBaseBinormals[i];
llendianswizzle(binormals.getF32ptr(), sizeof(float), 3);
if (fwrite(binormals.getF32ptr(), 3*sizeof(float), 1, fp) != 1)
{
llwarns << "Short write" << llendl;
}
llendianswizzle(binormals.getF32ptr(), sizeof(float), 3);
}
//----------------------------------------------------------------
// TexCoords
//----------------------------------------------------------------
LLVector2* tex = mSharedData->mTexCoords;
llendianswizzle(tex, sizeof(float), 2*numVertices);
if (fwrite(tex, 2*sizeof(float), numVertices, fp) != numVertices)
{
llwarns << "Short write" << llendl;
}
llendianswizzle(tex, sizeof(float), 2*numVertices);
//----------------------------------------------------------------
// DetailTexCoords
//----------------------------------------------------------------
if (hasDetailTexCoords)
{
LLVector2* detail = mSharedData->mDetailTexCoords;
llendianswizzle(detail, sizeof(float), 2*numVertices);
if (fwrite(detail, 2*sizeof(float), numVertices, fp) != numVertices)
{
llwarns << "Short write" << llendl;
}
llendianswizzle(detail, sizeof(float), 2*numVertices);
}
//----------------------------------------------------------------
// Weights
//----------------------------------------------------------------
if (hasWeights)
{
F32* weights = mSharedData->mWeights;
llendianswizzle(weights, sizeof(float), numVertices);
if (fwrite(weights, sizeof(float), numVertices, fp) != numVertices)
{
llwarns << "Short write" << llendl;
}
llendianswizzle(weights, sizeof(float), numVertices);
}
}
//----------------------------------------------------------------
// NumFaces
//----------------------------------------------------------------
U16 numFaces = mSharedData->mNumFaces;
llendianswizzle(&numFaces, sizeof(U16), 1);
if (fwrite(&numFaces, sizeof(U16), 1, fp) != 1)
{
llwarns << "Short write" << llendl;
}
numFaces = mSharedData->mNumFaces; // without the swizzle again
//----------------------------------------------------------------
// Faces
//----------------------------------------------------------------
LLPolyFace* faces = mSharedData->mFaces;
S16 face[3];
U32 i;
for (i = 0; i < numFaces; i++)
{
face[0] = faces[i][0];
face[1] = faces[i][1];
face[2] = faces[i][2];
llendianswizzle(face, sizeof(U16), 3);
if (fwrite(face, sizeof(U16), 3, fp) != 3)
{
llwarns << "Short write" << llendl;
}
}
//----------------------------------------------------------------
// NumSkinJoints
//----------------------------------------------------------------
// When reading LOD mesh files, we stop here, but the actual Linden
// .llm files have data with zero items for these, so we do the same.
U16 numSkinJoints = mSharedData->mNumJointNames;
// At least one element is always allocated but it may be empty
std::string *jn = &mSharedData->mJointNames[0];
if ((numSkinJoints == 1)
&& (jn->length() == 0))
{
numSkinJoints = 0;
}
if ( hasWeights )
{
llendianswizzle(&numSkinJoints, sizeof(U16), 1);
if (fwrite(&numSkinJoints, sizeof(U16), 1, fp) != 1)
{
llwarns << "Short write" << llendl;
}
llendianswizzle(&numSkinJoints, sizeof(U16), 1);
//----------------------------------------------------------------
// SkinJoints
//----------------------------------------------------------------
char padding[64] = {}; // zeroes
for (i=0; i < numSkinJoints; i++)
{
jn = &mSharedData->mJointNames[i];
if (fwrite(jn->c_str(), 1, jn->length(), fp) != jn->length())
{
llwarns << "Short write" << llendl;
}
if (jn->length() < 64)
{
int pad = 64 - jn->length();
if (fwrite(&padding, 1, pad, fp) != pad)
{
llwarns << "Short write" << llendl;
}
}
}
}
//-------------------------------------------------------------------------
// look for morph section
//-------------------------------------------------------------------------
LLPolyMeshSharedData::morphdata_list_t::iterator iter = mSharedData->mMorphData.begin();
LLPolyMeshSharedData::morphdata_list_t::iterator end = mSharedData->mMorphData.end();
// Sort them
morph_list_t morph_list;
for (; iter != end; ++iter)
{
LLPolyMorphData *morph_data = *iter;
std::string morph_name = morph_data->getName();
morph_list.insert(std::pair<std::string,LLPolyMorphData*>(morph_name, morph_data));
}
char padding[64] = {}; // zeroes
for (morph_list_t::iterator morph_iter = morph_list.begin();
morph_iter != morph_list.end(); ++morph_iter)
{
const std::string& morph_name = morph_iter->first;
LLPolyMorphData* morph_data = morph_iter->second;
if (fwrite(morph_name.c_str(), 1, morph_name.length(), fp) != morph_name.length())
{
llwarns << "Short write" << llendl;
}
if (morph_name.length() < 64)
{
int pad = 64 - morph_name.length();
if (fwrite(&padding, 1, pad, fp) != pad)
{
llwarns << "Short write" << llendl;
}
}
if (!morph_data->saveLLM(fp))
{
llwarns << "Problem writing morph" << llendl;
}
}
char end_morphs[64] = "End Morphs"; // padded with zeroes
if (fwrite(end_morphs, sizeof(char), 64, fp) != 64)
{
llwarns << "Short write" << llendl;
}
//-------------------------------------------------------------------------
// Remaps
//-------------------------------------------------------------------------
S32 numRemaps = mSharedData->mSharedVerts.size();
llendianswizzle(&numRemaps, sizeof(S32), 1);
if (fwrite(&numRemaps, sizeof(S32), 1, fp) != 1)
{
llwarns << "Short write" << llendl;
}
std::map<S32, S32>::iterator remap_iter = mSharedData->mSharedVerts.begin();
std::map<S32, S32>::iterator remap_end = mSharedData->mSharedVerts.end();
for (; remap_iter != remap_end; ++remap_iter)
{
S32 remapSrc = remap_iter->first;
llendianswizzle(&remapSrc, sizeof(S32), 1);
if (fwrite(&remapSrc, sizeof(S32), 1, fp) != 1)
{
llwarns << "Short write" << llendl;
}
S32 remapDst = remap_iter->second;
llendianswizzle(&remapDst, sizeof(S32), 1);
if (fwrite(&remapDst, sizeof(S32), 1, fp) != 1)
{
llwarns << "Short write" << llendl;
}
}
return TRUE;
}
//-----------------------------------------------------------------------------
// LLPolyMesh::saveOBJ()
//-----------------------------------------------------------------------------
BOOL LLPolyMesh::saveOBJ(LLFILE *fp)
{
if (!fp)
return FALSE;
// If it's an LOD mesh, the LOD vertices are usually at the start of the
// list of vertices, so the number of vertices is just that subset.
// We could also write out the rest of the vertices in case someone wants
// to choose new vertices for the LOD mesh, but that may confuse some people.
int nverts = mSharedData->mNumVertices;
int nfaces = mSharedData->mNumFaces;
int i;
LLVector4a* coords = getWritableCoords();
for ( i=0; i<nverts; i++) {
std::string outstring = llformat("v %f %f %f\n",
coords[i].getF32ptr()[0],
coords[i].getF32ptr()[1],
coords[i].getF32ptr()[2]);
if (fwrite(outstring.c_str(), 1, outstring.length(), fp) != outstring.length())
{
llwarns << "Short write" << llendl;
}
}
LLVector4a* normals = getWritableNormals();
for ( i=0; i<nverts; i++) {
std::string outstring = llformat("vn %f %f %f\n",
normals[i].getF32ptr()[0],
normals[i].getF32ptr()[1],
normals[i].getF32ptr()[2]);
if (fwrite(outstring.c_str(), 1, outstring.length(), fp) != outstring.length())
{
llwarns << "Short write" << llendl;
}
}
LLVector2* tex = getWritableTexCoords();
for ( i=0; i<nverts; i++) {
std::string outstring = llformat("vt %f %f\n",
tex[i][0],
tex[i][1]);
if (fwrite(outstring.c_str(), 1, outstring.length(), fp) != outstring.length())
{
llwarns << "Short write" << llendl;
}
}
LLPolyFace* faces = getFaces();
for ( i=0; i<nfaces; i++) {
S32 f1 = faces[i][0] + 1;
S32 f2 = faces[i][1] + 1;
S32 f3 = faces[i][2] + 1;
std::string outstring = llformat("f %d/%d/%d %d/%d/%d %d/%d/%d\n",
f1, f1, f1,
f2, f2, f2,
f3, f3, f3);
if (fwrite(outstring.c_str(), 1, outstring.length(), fp) != outstring.length())
{
llwarns << "Short write" << llendl;
}
}
return TRUE;
}
//-----------------------------------------------------------------------------
// LLPolyMesh::loadOBJ()
//-----------------------------------------------------------------------------
BOOL LLPolyMesh::loadOBJ(LLFILE *fp)
{
if (!fp)
return FALSE;
int nverts = mSharedData->mNumVertices;
int ntris = mSharedData->mNumFaces;
int nfaces = 0;
int ncoords = 0;
int nnormals = 0;
int ntexcoords = 0;
LLVector4a* coords = getWritableCoords();
LLVector4a* normals = getWritableNormals();
LLVector4a* binormals = getWritableBinormals();
LLVector2* tex = getWritableTexCoords();
LLPolyFace* faces = getFaces();
const S32 BUFSIZE = 16384;
char buffer[BUFSIZE];
// *NOTE: changing the size or type of these buffers will require
// changing the sscanf below.
char keyword[256];
keyword[0] = 0;
F32 tempX;
F32 tempY;
F32 tempZ;
S32 values;
while (!feof(fp))
{
if (fgets(buffer, BUFSIZE, fp) == NULL)
{
buffer[0] = '\0';
}
if (sscanf (buffer," %255s", keyword) != 1)
{
// blank line
continue;
}
if (!strcmp("v", keyword))
{
values = sscanf (buffer," %255s %f %f %f", keyword, &tempX, &tempY, &tempZ);
if (values != 4)
{
llwarns << "Expecting v x y z, but found: " << buffer <<llendl;
continue;
}
if (ncoords == nverts)
{
llwarns << "Too many vertices. Ignoring from: " << buffer <<llendl;
}
if (ncoords < nverts)
{
coords[ncoords].set (tempX, tempY, tempZ);
}
ncoords++;
}
else if (!strcmp("vn",keyword))
{
values = sscanf (buffer," %255s %f %f %f", keyword, &tempX, &tempY, &tempZ);
if (values != 4)
{
llwarns << "Expecting vn x y z, but found: " << buffer <<llendl;
continue;
}
if (nnormals == nverts)
{
llwarns << "Too many normals. Ignoring from: " << buffer <<llendl;
}
if (nnormals < nverts)
{
normals[nnormals].set (tempX, tempY, tempZ);
}
nnormals++;
}
else if (!strcmp("vt", keyword))
{
values = sscanf (buffer," %255s %f %f", keyword, &tempX, &tempY);
if (values != 3)
{
llwarns << "Expecting vt x y, but found: " << buffer <<llendl;
continue;
}
if (ntexcoords == nverts)
{
llwarns << "Too many texture vertices. Ignoring from: " << buffer <<llendl;
}
if (ntexcoords < nverts)
{
tex[ntexcoords].set (tempX, tempY);
}
ntexcoords++;
}
else if (!strcmp("f",keyword))
{
if (nfaces == 0)
{
llwarns << "Ignoring face keywords for now." <<llendl;
}
nfaces++;
}
else
{
llinfos << "Unrecognized keyword. Ignoring: " << buffer << llendl;
}
}
// Compute the binormals
// This computation is close, but not exactly what is being used in the
// original meshes.
int v;
for ( v=0; v<nverts; v++)
{
binormals[v].clear();
}
int f;
for ( f=0; f<ntris; f++)
{
S32 f0 = faces[f][0];
S32 f1 = faces[f][1];
S32 f2 = faces[f][2];
LLVector4a binorm;
calc_binormal_from_triangle(binorm, coords[f0], tex[f0], coords[f1], tex[f1], coords[f2], tex[f2]);
binorm.normalize3fast();
binormals[f0].add(binorm);
binormals[f1].add(binorm);
binormals[f2].add(binorm);
}
for ( v=0; v<nverts; v++)
{
binormals[v].normalize3();
}
return TRUE;
}
//-----------------------------------------------------------------------------
// LLPolyMesh::setSharedFromCurrent()
//-----------------------------------------------------------------------------
BOOL LLPolyMesh::setSharedFromCurrent()
{
// Because meshes are set by continually updating morph weights
// there is no easy way to reapply the morphs, so we just compute
// the change in the base mesh and apply that.
LLPolyMesh delta(mSharedData, NULL);
U32 nverts = delta.getNumVertices();
LLVector4a *delta_coords = delta.getWritableCoords();
LLVector4a *delta_normals = delta.getWritableNormals();
LLVector4a *delta_binormals = delta.getWritableBinormals();
LLVector2 *delta_tex_coords = delta.getWritableTexCoords();
U32 vert_index;
for( vert_index = 0; vert_index < nverts; vert_index++)
{
delta_coords[vert_index].sub( mCoords[vert_index]);
delta_normals[vert_index].sub( mNormals[vert_index]);
delta_binormals[vert_index].sub( mBinormals[vert_index]);
delta_tex_coords[vert_index] -= mTexCoords[vert_index];
}
// Now copy the new base mesh
LLVector4a::memcpyNonAliased16((F32*) mSharedData->mBaseCoords, (F32*) mCoords, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mSharedData->mBaseNormals, (F32*) mNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mSharedData->mBaseBinormals, (F32*) mBinormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mSharedData->mTexCoords, (F32*) mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2));
// Update all avatars by applying the delta
std::vector< LLCharacter* >::iterator avatar_it;
for(avatar_it = LLCharacter::sInstances.begin(); avatar_it != LLCharacter::sInstances.end(); ++avatar_it)
{
LLAvatarAppearance* avatarp = (LLAvatarAppearance*)*avatar_it;
LLPolyMesh* mesh = avatarp->getMesh(mSharedData);
if (mesh)
{
LLVector4a *mesh_coords = mesh->getWritableCoords();
LLVector4a *mesh_normals = mesh->getWritableNormals();
LLVector4a *mesh_binormals = mesh->getWritableBinormals();
LLVector2 *mesh_tex_coords = mesh->getWritableTexCoords();
LLVector4a *mesh_scaled_normals = mesh->getScaledNormals();
LLVector4a *mesh_scaled_binormals = mesh->getScaledBinormals();
for( vert_index = 0; vert_index < nverts; vert_index++)
{
mesh_coords[vert_index].sub(delta_coords[vert_index]);
mesh_tex_coords[vert_index] -= delta_tex_coords[vert_index];
mesh_scaled_normals[vert_index].sub(delta_normals[vert_index]);
LLVector4a normalized_normal = mesh_scaled_normals[vert_index];
normalized_normal.normalize3();
mesh_normals[vert_index] = normalized_normal;
mesh_scaled_binormals[vert_index].sub(delta_binormals[vert_index]);
LLVector4a tangent;
tangent.setCross3(mesh_scaled_binormals[vert_index], normalized_normal);
LLVector4a normalized_binormal;
normalized_binormal.setCross3(normalized_normal, tangent);
normalized_binormal.normalize3();
mesh_binormals[vert_index] = normalized_binormal;
}
avatarp->dirtyMesh();
}
}
return TRUE;
}
//-----------------------------------------------------------------------------
// LLPolyMesh::getSharedMeshName()
//-----------------------------------------------------------------------------
std::string const* LLPolyMesh::getSharedMeshName(LLPolyMeshSharedData* shared)
{
//-------------------------------------------------------------------------
// search for an existing mesh with this shared data
//-------------------------------------------------------------------------
for(LLPolyMeshSharedDataTable::iterator iter = sGlobalSharedMeshList.begin(); iter != sGlobalSharedMeshList.end(); ++iter)
{
std::string const* mesh_name = &iter->first;
LLPolyMeshSharedData* mesh = iter->second;
if (mesh == shared)
return mesh_name;
}
return NULL;
}
//-----------------------------------------------------------------------------
// LLPolyMesh::freeAllMeshes()
//-----------------------------------------------------------------------------
void LLPolyMesh::freeAllMeshes()
{
// delete each item in the global lists
for_each(sGlobalSharedMeshList.begin(), sGlobalSharedMeshList.end(), DeletePairedPointer());
sGlobalSharedMeshList.clear();
}
LLPolyMeshSharedData *LLPolyMesh::getSharedData() const
{
return mSharedData;
}
//--------------------------------------------------------------------
// LLPolyMesh::dumpDiagInfo()
//--------------------------------------------------------------------
void LLPolyMesh::dumpDiagInfo(void*)
{
// keep track of totals
U32 total_verts = 0;
U32 total_faces = 0;
U32 total_kb = 0;
std::string buf;
llinfos << "-----------------------------------------------------" << llendl;
llinfos << " Global PolyMesh Table (DEBUG only)" << llendl;
llinfos << " Verts Faces Mem(KB) Type Name" << llendl;
llinfos << "-----------------------------------------------------" << llendl;
// print each loaded mesh, and it's memory usage
for(LLPolyMeshSharedDataTable::iterator iter = sGlobalSharedMeshList.begin();
iter != sGlobalSharedMeshList.end(); ++iter)
{
const std::string& mesh_name = iter->first;
LLPolyMeshSharedData* mesh = iter->second;
S32 num_verts = mesh->mNumVertices;
S32 num_faces = mesh->mNumFaces;
U32 num_kb = mesh->getNumKB();
std::string type;
if (mesh->isLOD()) {
type = "LOD ";
} else {
type = "base";
}
buf = llformat("%8d %8d %8d %s %s", num_verts, num_faces, num_kb, type.c_str(), mesh_name.c_str());
llinfos << buf << llendl;
total_verts += num_verts;
total_faces += num_faces;
total_kb += num_kb;
}
llinfos << "-----------------------------------------------------" << llendl;
buf = llformat("%8d %8d %8d TOTAL", total_verts, total_faces, total_kb );
llinfos << buf << llendl;
llinfos << "-----------------------------------------------------" << llendl;
}
//-----------------------------------------------------------------------------
// getWritableCoords()
//-----------------------------------------------------------------------------
LLVector4a *LLPolyMesh::getWritableCoords()
{
return mCoords;
}
//-----------------------------------------------------------------------------
// getWritableNormals()
//-----------------------------------------------------------------------------
LLVector4a *LLPolyMesh::getWritableNormals()
{
return mNormals;
}
//-----------------------------------------------------------------------------
// getWritableBinormals()
//-----------------------------------------------------------------------------
LLVector4a *LLPolyMesh::getWritableBinormals()
{
return mBinormals;
}
//-----------------------------------------------------------------------------
// getWritableClothingWeights()
//-----------------------------------------------------------------------------
LLVector4a *LLPolyMesh::getWritableClothingWeights()
{
return mClothingWeights;
}
//-----------------------------------------------------------------------------
// getWritableTexCoords()
//-----------------------------------------------------------------------------
LLVector2 *LLPolyMesh::getWritableTexCoords()
{
return mTexCoords;
}
//-----------------------------------------------------------------------------
// getScaledNormals()
//-----------------------------------------------------------------------------
LLVector4a *LLPolyMesh::getScaledNormals()
{
return mScaledNormals;
}
//-----------------------------------------------------------------------------
// getScaledBinormals()
//-----------------------------------------------------------------------------
LLVector4a *LLPolyMesh::getScaledBinormals()
{
return mScaledBinormals;
}
//-----------------------------------------------------------------------------
// initializeForMorph()
//-----------------------------------------------------------------------------
void LLPolyMesh::initializeForMorph()
{
if (!mSharedData)
return;
LLVector4a::memcpyNonAliased16((F32*) mCoords, (F32*) mSharedData->mBaseCoords, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mScaledNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mScaledBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2));
for (U32 i = 0; i < (U32)mSharedData->mNumVertices; ++i)
{
mClothingWeights[i].clear();
}
}
//-----------------------------------------------------------------------------
// getMorphList()
//-----------------------------------------------------------------------------
void LLPolyMesh::getMorphList (const std::string& mesh_name, morph_list_t* morph_list)
{
if (!morph_list)
return;
LLPolyMeshSharedData* mesh_shared_data = get_if_there(sGlobalSharedMeshList, mesh_name, (LLPolyMeshSharedData*)NULL);
if (!mesh_shared_data)
return;
LLPolyMeshSharedData::morphdata_list_t::iterator iter = mesh_shared_data->mMorphData.begin();
LLPolyMeshSharedData::morphdata_list_t::iterator end = mesh_shared_data->mMorphData.end();
for (; iter != end; ++iter)
{
LLPolyMorphData *morph_data = *iter;
std::string morph_name = morph_data->getName();
morph_list->insert(std::pair<std::string,LLPolyMorphData*>(morph_name, morph_data));
}
return;
}
//-----------------------------------------------------------------------------
// getMorphData()
//-----------------------------------------------------------------------------
LLPolyMorphData* LLPolyMesh::getMorphData(const std::string& morph_name)
{
if (!mSharedData)
return NULL;
for (LLPolyMeshSharedData::morphdata_list_t::iterator iter = mSharedData->mMorphData.begin();
iter != mSharedData->mMorphData.end(); ++iter)
{
LLPolyMorphData *morph_data = *iter;
if (morph_data->getName() == morph_name)
{
return morph_data;
}
}
return NULL;
}
//-----------------------------------------------------------------------------
// removeMorphData()
//-----------------------------------------------------------------------------
// // erasing but not deleting seems bad, but fortunately we don't actually use this...
// void LLPolyMesh::removeMorphData(LLPolyMorphData *morph_target)
// {
// if (!mSharedData)
// return;
// mSharedData->mMorphData.erase(morph_target);
// }
//-----------------------------------------------------------------------------
// deleteAllMorphData()
//-----------------------------------------------------------------------------
// void LLPolyMesh::deleteAllMorphData()
// {
// if (!mSharedData)
// return;
// for_each(mSharedData->mMorphData.begin(), mSharedData->mMorphData.end(), DeletePointer());
// mSharedData->mMorphData.clear();
// }
//-----------------------------------------------------------------------------
// getWritableWeights()
//-----------------------------------------------------------------------------
F32* LLPolyMesh::getWritableWeights() const
{
return mSharedData->mWeights;
}
// End