diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 21:25:21 +0200 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 22:40:26 +0300 |
commit | e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch) | |
tree | 1bb897489ce524986f6196201c10ac0d8861aa5f /indra/llappearance/llpolymesh.cpp | |
parent | 069ea06848f766466f1a281144c82a0f2bd79f3a (diff) |
Fix line endlings
Diffstat (limited to 'indra/llappearance/llpolymesh.cpp')
-rw-r--r-- | indra/llappearance/llpolymesh.cpp | 2080 |
1 files changed, 1040 insertions, 1040 deletions
diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp index 6c56b192ed..b70e5af69f 100644 --- a/indra/llappearance/llpolymesh.cpp +++ b/indra/llappearance/llpolymesh.cpp @@ -1,1040 +1,1040 @@ -/**
- * @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();
-}
-
-// compare_int is used by the qsort function to sort the index array
-S32 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())
- {
- LL_ERRS() << "Filename is Empty!" << LL_ENDL;
- return false;
- }
- LLFILE* fp = LLFile::fopen(fileName, "rb"); /*Flawfinder: ignore*/
- if (!fp)
- {
- LL_ERRS() << "can't open: " << fileName << LL_ENDL;
- return false;
- }
-
- //-------------------------------------------------------------------------
- // Read a chunk
- //-------------------------------------------------------------------------
- char header[128]; /*Flawfinder: ignore*/
- if (fread(header, sizeof(char), 128, fp) != 128)
- {
- LL_WARNS() << "Short read" << LL_ENDL;
- }
-
- //-------------------------------------------------------------------------
- // Check for proper binary header
- //-------------------------------------------------------------------------
- bool status = false;
- if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 ) /*Flawfinder: ignore*/
- {
- LL_DEBUGS() << "Loading " << fileName << LL_ENDL;
-
- //----------------------------------------------------------------
- // 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)
- {
- LL_ERRS() << "can't read HasWeights flag from " << fileName << LL_ENDL;
- return false;
- }
- if (!isLOD())
- {
- mHasWeights = hasWeights > 0;
- }
-
- //----------------------------------------------------------------
- // HasDetailTexCoords
- //----------------------------------------------------------------
- U8 hasDetailTexCoords;
- numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp);
- if (numRead != 1)
- {
- LL_ERRS() << "can't read HasDetailTexCoords flag from " << fileName << LL_ENDL;
- return false;
- }
-
- //----------------------------------------------------------------
- // Position
- //----------------------------------------------------------------
- LLVector3 position;
- numRead = fread(position.mV, sizeof(float), 3, fp);
- llendianswizzle(position.mV, sizeof(float), 3);
- if (numRead != 3)
- {
- LL_ERRS() << "can't read Position from " << fileName << LL_ENDL;
- return false;
- }
- setPosition( position );
-
- //----------------------------------------------------------------
- // Rotation
- //----------------------------------------------------------------
- LLVector3 rotationAngles;
- numRead = fread(rotationAngles.mV, sizeof(float), 3, fp);
- llendianswizzle(rotationAngles.mV, sizeof(float), 3);
- if (numRead != 3)
- {
- LL_ERRS() << "can't read RotationAngles from " << fileName << LL_ENDL;
- return false;
- }
-
- U8 rotationOrder;
- numRead = fread(&rotationOrder, sizeof(U8), 1, fp);
-
- if (numRead != 1)
- {
- LL_ERRS() << "can't read RotationOrder from " << fileName << LL_ENDL;
- 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)
- {
- LL_ERRS() << "can't read Scale from " << fileName << LL_ENDL;
- 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)
- {
- LL_ERRS() << "can't read NumVertices from " << fileName << LL_ENDL;
- 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)
- {
- LL_ERRS() << "can't read Coordinates from " << fileName << LL_ENDL;
- 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)
- {
- LL_ERRS() << " can't read Normals from " << fileName << LL_ENDL;
- 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)
- {
- LL_ERRS() << " can't read Binormals from " << fileName << LL_ENDL;
- return false;
- }
- }
-
- //----------------------------------------------------------------
- // TexCoords
- //----------------------------------------------------------------
- numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp);
- llendianswizzle(mTexCoords, sizeof(float), 2*numVertices);
- if (numRead != numVertices)
- {
- LL_ERRS() << "can't read TexCoords from " << fileName << LL_ENDL;
- return false;
- }
-
- //----------------------------------------------------------------
- // DetailTexCoords
- //----------------------------------------------------------------
- if (mHasDetailTexCoords)
- {
- numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp);
- llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices);
- if (numRead != numVertices)
- {
- LL_ERRS() << "can't read DetailTexCoords from " << fileName << LL_ENDL;
- return false;
- }
- }
-
- //----------------------------------------------------------------
- // Weights
- //----------------------------------------------------------------
- if (mHasWeights)
- {
- numRead = fread(mWeights, sizeof(float), numVertices, fp);
- llendianswizzle(mWeights, sizeof(float), numVertices);
- if (numRead != numVertices)
- {
- LL_ERRS() << "can't read Weights from " << fileName << LL_ENDL;
- return false;
- }
- }
- }
-
- //----------------------------------------------------------------
- // NumFaces
- //----------------------------------------------------------------
- U16 numFaces;
- numRead = fread(&numFaces, sizeof(U16), 1, fp);
- llendianswizzle(&numFaces, sizeof(U16), 1);
- if (numRead != 1)
- {
- LL_ERRS() << "can't read NumFaces from " << fileName << LL_ENDL;
- 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)
- {
- LL_ERRS() << "can't read Face[" << i << "] from " << fileName << LL_ENDL;
- 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++)
-// {
-// std::vector<S32> *face_list = mVertFaceMap.getIfThere(face[j]);
-// if (!face_list)
-// {
-// face_list = new std::vector<S32>;
-// mVertFaceMap.addData(face[j], face_list);
-// }
-// face_list->put(i);
-// }
-
- numTris++;
- }
-
- LL_DEBUGS() << "verts: " << numVertices
- << ", faces: " << numFaces
- << ", tris: " << numTris
- << LL_ENDL;
-
- //----------------------------------------------------------------
- // NumSkinJoints
- //----------------------------------------------------------------
- if (!isLOD())
- {
- U16 numSkinJoints = 0;
- if ( mHasWeights )
- {
- numRead = fread(&numSkinJoints, sizeof(U16), 1, fp);
- llendianswizzle(&numSkinJoints, sizeof(U16), 1);
- if (numRead != 1)
- {
- LL_ERRS() << "can't read NumSkinJoints from " << fileName << LL_ENDL;
- 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)
- {
- LL_ERRS() << "can't read Skin[" << i << "].Name from " << fileName << LL_ENDL;
- 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;
- }
- std::string morph_name(morphName);
- LLPolyMorphData* morph_data = new LLPolyMorphData(morph_name);
-
- bool result = morph_data->loadBinary(fp, this);
-
- if (!result)
- {
- LL_WARNS() << "Failure loading " << morph_name << " from " << fileName << LL_ENDL;
- 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)
- {
- LL_ERRS() << "can't read source vertex in vertex remap data" << LL_ENDL;
- break;
- }
- if (fread(&remapDst, sizeof(S32), 1, fp) != 1)
- {
- LL_ERRS() << "can't read destination vertex in vertex remap data" << LL_ENDL;
- break;
- }
- llendianswizzle(&remapSrc, sizeof(S32), 1);
- llendianswizzle(&remapDst, sizeof(S32), 1);
-
- mSharedVerts[remapSrc] = remapDst;
- }
- }
- }
-
- status = true;
- }
- else
- {
- LL_ERRS() << "invalid mesh file header: " << fileName << LL_ENDL;
- 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;
-
- 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()
-{
- delete_and_clear(mJointRenderData);
- 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)
- {
-// LL_INFOS() << "Polymesh " << name << " found in global mesh table." << LL_ENDL;
- 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);
-
-// LL_INFOS() << "Polymesh " << name << " added to global mesh table." << LL_ENDL;
- sGlobalSharedMeshList[name] = poly_mesh->mSharedData;
-
- return poly_mesh;
-}
-
-//-----------------------------------------------------------------------------
-// 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()
-{
- // keep track of totals
- U32 total_verts = 0;
- U32 total_faces = 0;
- U32 total_kb = 0;
-
- std::string buf;
-
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
- LL_INFOS() << " Global PolyMesh Table (DEBUG only)" << LL_ENDL;
- LL_INFOS() << " Verts Faces Mem(KB) Name" << LL_ENDL;
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
-
- // print each loaded mesh, and it's memory usage
- for(const LLPolyMeshSharedDataTable::value_type& mesh_pair : sGlobalSharedMeshList)
- {
- const std::string& mesh_name = mesh_pair.first;
- LLPolyMeshSharedData* mesh = mesh_pair.second;
-
- S32 num_verts = mesh->mNumVertices;
- S32 num_faces = mesh->mNumFaces;
- U32 num_kb = mesh->getNumKB();
-
- buf = llformat("%8d %8d %8d %s", num_verts, num_faces, num_kb, mesh_name.c_str());
- LL_INFOS() << buf << LL_ENDL;
-
- total_verts += num_verts;
- total_faces += num_faces;
- total_kb += num_kb;
- }
-
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
- buf = llformat("%8d %8d %8d TOTAL", total_verts, total_faces, total_kb );
- LL_INFOS() << buf << LL_ENDL;
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
-}
-
-//-----------------------------------------------------------------------------
-// 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()
-{
- 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 < mSharedData->mNumVertices; ++i)
- {
- mClothingWeights[i].clear();
- }
-}
-
-//-----------------------------------------------------------------------------
-// getMorphData()
-//-----------------------------------------------------------------------------
-LLPolyMorphData* LLPolyMesh::getMorphData(const std::string& morph_name)
-{
- if (!mSharedData)
- return NULL;
- for (LLPolyMorphData* morph_data : mSharedData->mMorphData)
- {
- 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
+/** + * @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(); +} + +// compare_int is used by the qsort function to sort the index array +S32 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()) + { + LL_ERRS() << "Filename is Empty!" << LL_ENDL; + return false; + } + LLFILE* fp = LLFile::fopen(fileName, "rb"); /*Flawfinder: ignore*/ + if (!fp) + { + LL_ERRS() << "can't open: " << fileName << LL_ENDL; + return false; + } + + //------------------------------------------------------------------------- + // Read a chunk + //------------------------------------------------------------------------- + char header[128]; /*Flawfinder: ignore*/ + if (fread(header, sizeof(char), 128, fp) != 128) + { + LL_WARNS() << "Short read" << LL_ENDL; + } + + //------------------------------------------------------------------------- + // Check for proper binary header + //------------------------------------------------------------------------- + bool status = false; + if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 ) /*Flawfinder: ignore*/ + { + LL_DEBUGS() << "Loading " << fileName << LL_ENDL; + + //---------------------------------------------------------------- + // 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) + { + LL_ERRS() << "can't read HasWeights flag from " << fileName << LL_ENDL; + return false; + } + if (!isLOD()) + { + mHasWeights = hasWeights > 0; + } + + //---------------------------------------------------------------- + // HasDetailTexCoords + //---------------------------------------------------------------- + U8 hasDetailTexCoords; + numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp); + if (numRead != 1) + { + LL_ERRS() << "can't read HasDetailTexCoords flag from " << fileName << LL_ENDL; + return false; + } + + //---------------------------------------------------------------- + // Position + //---------------------------------------------------------------- + LLVector3 position; + numRead = fread(position.mV, sizeof(float), 3, fp); + llendianswizzle(position.mV, sizeof(float), 3); + if (numRead != 3) + { + LL_ERRS() << "can't read Position from " << fileName << LL_ENDL; + return false; + } + setPosition( position ); + + //---------------------------------------------------------------- + // Rotation + //---------------------------------------------------------------- + LLVector3 rotationAngles; + numRead = fread(rotationAngles.mV, sizeof(float), 3, fp); + llendianswizzle(rotationAngles.mV, sizeof(float), 3); + if (numRead != 3) + { + LL_ERRS() << "can't read RotationAngles from " << fileName << LL_ENDL; + return false; + } + + U8 rotationOrder; + numRead = fread(&rotationOrder, sizeof(U8), 1, fp); + + if (numRead != 1) + { + LL_ERRS() << "can't read RotationOrder from " << fileName << LL_ENDL; + 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) + { + LL_ERRS() << "can't read Scale from " << fileName << LL_ENDL; + 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) + { + LL_ERRS() << "can't read NumVertices from " << fileName << LL_ENDL; + 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) + { + LL_ERRS() << "can't read Coordinates from " << fileName << LL_ENDL; + 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) + { + LL_ERRS() << " can't read Normals from " << fileName << LL_ENDL; + 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) + { + LL_ERRS() << " can't read Binormals from " << fileName << LL_ENDL; + return false; + } + } + + //---------------------------------------------------------------- + // TexCoords + //---------------------------------------------------------------- + numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp); + llendianswizzle(mTexCoords, sizeof(float), 2*numVertices); + if (numRead != numVertices) + { + LL_ERRS() << "can't read TexCoords from " << fileName << LL_ENDL; + return false; + } + + //---------------------------------------------------------------- + // DetailTexCoords + //---------------------------------------------------------------- + if (mHasDetailTexCoords) + { + numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp); + llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices); + if (numRead != numVertices) + { + LL_ERRS() << "can't read DetailTexCoords from " << fileName << LL_ENDL; + return false; + } + } + + //---------------------------------------------------------------- + // Weights + //---------------------------------------------------------------- + if (mHasWeights) + { + numRead = fread(mWeights, sizeof(float), numVertices, fp); + llendianswizzle(mWeights, sizeof(float), numVertices); + if (numRead != numVertices) + { + LL_ERRS() << "can't read Weights from " << fileName << LL_ENDL; + return false; + } + } + } + + //---------------------------------------------------------------- + // NumFaces + //---------------------------------------------------------------- + U16 numFaces; + numRead = fread(&numFaces, sizeof(U16), 1, fp); + llendianswizzle(&numFaces, sizeof(U16), 1); + if (numRead != 1) + { + LL_ERRS() << "can't read NumFaces from " << fileName << LL_ENDL; + 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) + { + LL_ERRS() << "can't read Face[" << i << "] from " << fileName << LL_ENDL; + 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++) +// { +// std::vector<S32> *face_list = mVertFaceMap.getIfThere(face[j]); +// if (!face_list) +// { +// face_list = new std::vector<S32>; +// mVertFaceMap.addData(face[j], face_list); +// } +// face_list->put(i); +// } + + numTris++; + } + + LL_DEBUGS() << "verts: " << numVertices + << ", faces: " << numFaces + << ", tris: " << numTris + << LL_ENDL; + + //---------------------------------------------------------------- + // NumSkinJoints + //---------------------------------------------------------------- + if (!isLOD()) + { + U16 numSkinJoints = 0; + if ( mHasWeights ) + { + numRead = fread(&numSkinJoints, sizeof(U16), 1, fp); + llendianswizzle(&numSkinJoints, sizeof(U16), 1); + if (numRead != 1) + { + LL_ERRS() << "can't read NumSkinJoints from " << fileName << LL_ENDL; + 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) + { + LL_ERRS() << "can't read Skin[" << i << "].Name from " << fileName << LL_ENDL; + 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; + } + std::string morph_name(morphName); + LLPolyMorphData* morph_data = new LLPolyMorphData(morph_name); + + bool result = morph_data->loadBinary(fp, this); + + if (!result) + { + LL_WARNS() << "Failure loading " << morph_name << " from " << fileName << LL_ENDL; + 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) + { + LL_ERRS() << "can't read source vertex in vertex remap data" << LL_ENDL; + break; + } + if (fread(&remapDst, sizeof(S32), 1, fp) != 1) + { + LL_ERRS() << "can't read destination vertex in vertex remap data" << LL_ENDL; + break; + } + llendianswizzle(&remapSrc, sizeof(S32), 1); + llendianswizzle(&remapDst, sizeof(S32), 1); + + mSharedVerts[remapSrc] = remapDst; + } + } + } + + status = true; + } + else + { + LL_ERRS() << "invalid mesh file header: " << fileName << LL_ENDL; + 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; + + 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() +{ + delete_and_clear(mJointRenderData); + 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) + { +// LL_INFOS() << "Polymesh " << name << " found in global mesh table." << LL_ENDL; + 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); + +// LL_INFOS() << "Polymesh " << name << " added to global mesh table." << LL_ENDL; + sGlobalSharedMeshList[name] = poly_mesh->mSharedData; + + return poly_mesh; +} + +//----------------------------------------------------------------------------- +// 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() +{ + // keep track of totals + U32 total_verts = 0; + U32 total_faces = 0; + U32 total_kb = 0; + + std::string buf; + + LL_INFOS() << "-----------------------------------------------------" << LL_ENDL; + LL_INFOS() << " Global PolyMesh Table (DEBUG only)" << LL_ENDL; + LL_INFOS() << " Verts Faces Mem(KB) Name" << LL_ENDL; + LL_INFOS() << "-----------------------------------------------------" << LL_ENDL; + + // print each loaded mesh, and it's memory usage + for(const LLPolyMeshSharedDataTable::value_type& mesh_pair : sGlobalSharedMeshList) + { + const std::string& mesh_name = mesh_pair.first; + LLPolyMeshSharedData* mesh = mesh_pair.second; + + S32 num_verts = mesh->mNumVertices; + S32 num_faces = mesh->mNumFaces; + U32 num_kb = mesh->getNumKB(); + + buf = llformat("%8d %8d %8d %s", num_verts, num_faces, num_kb, mesh_name.c_str()); + LL_INFOS() << buf << LL_ENDL; + + total_verts += num_verts; + total_faces += num_faces; + total_kb += num_kb; + } + + LL_INFOS() << "-----------------------------------------------------" << LL_ENDL; + buf = llformat("%8d %8d %8d TOTAL", total_verts, total_faces, total_kb ); + LL_INFOS() << buf << LL_ENDL; + LL_INFOS() << "-----------------------------------------------------" << LL_ENDL; +} + +//----------------------------------------------------------------------------- +// 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() +{ + 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 < mSharedData->mNumVertices; ++i) + { + mClothingWeights[i].clear(); + } +} + +//----------------------------------------------------------------------------- +// getMorphData() +//----------------------------------------------------------------------------- +LLPolyMorphData* LLPolyMesh::getMorphData(const std::string& morph_name) +{ + if (!mSharedData) + return NULL; + for (LLPolyMorphData* morph_data : mSharedData->mMorphData) + { + 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 |