diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index cfa10734e..807d7bf2a 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -2324,6 +2324,8 @@ void LLMenuGL::arrange( void ) (*item_iter)->buildDrawLabel(); } } + + cleanupSpilloverBranch(); } if (mKeepFixedSize) { @@ -2540,6 +2542,11 @@ BOOL LLMenuGL::append( LLMenuItemGL* item ) // Its added as a fix to a viewer 1.23 bug that has already been address by skinning work. BOOL LLMenuGL::appendNoArrange( LLMenuItemGL* item ) { + if (mSpilloverMenu) + { + return mSpilloverMenu->append(item); + } + mItems.push_back( item ); addChild( item ); return TRUE; @@ -4411,6 +4418,9 @@ BOOL LLMenuHolderGL::hideMenus() { return FALSE; } + + sItemActivationTimer.stop(); + BOOL menu_visible = hasVisibleMenu(); if (menu_visible) { diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp index a23c199c9..3a82e7304 100644 --- a/indra/newview/llpolymesh.cpp +++ b/indra/newview/llpolymesh.cpp @@ -863,6 +863,687 @@ LLPolyMesh *LLPolyMesh::getMesh(const std::string &name, LLPolyMesh* reference_m 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 + //---------------------------------------------------------------- + LLVector3* coords = mSharedData->mBaseCoords; + + llendianswizzle(coords, sizeof(float), 3*numVertices); + if (fwrite(coords, 3*sizeof(float), numVertices, fp) != numVertices) + { + llwarns << "Short write" << llendl; + } + llendianswizzle(coords, sizeof(float), 3*numVertices); + + //---------------------------------------------------------------- + // Normals + //---------------------------------------------------------------- + LLVector3* normals = mSharedData->mBaseNormals; + + llendianswizzle(normals, sizeof(float), 3*numVertices); + if (fwrite(normals, 3*sizeof(float), numVertices, fp) != numVertices) + { + llwarns << "Short write" << llendl; + } + llendianswizzle(normals, sizeof(float), 3*numVertices); + + //---------------------------------------------------------------- + // Binormals + //---------------------------------------------------------------- + LLVector3* binormals = mSharedData->mBaseBinormals; + + llendianswizzle(binormals, sizeof(float), 3*numVertices); + if (fwrite(binormals, 3*sizeof(float), numVertices, fp) != numVertices) + { + llwarns << "Short write" << llendl; + } + llendianswizzle(binormals, sizeof(float), 3*numVertices); + + //---------------------------------------------------------------- + // 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(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::iterator remap_iter = mSharedData->mSharedVerts.begin(); + std::map::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; + + LLVector3* coords = getWritableCoords(); + for ( i=0; imNumVertices; + int ntris = mSharedData->mNumFaces; + + int nfaces = 0; + int ncoords = 0; + int nnormals = 0; + int ntexcoords = 0; + + LLVector3* coords = getWritableCoords(); + LLVector3* normals = getWritableNormals(); + LLVector3* 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 <mBaseCoords, mCoords, sizeof(LLVector3) * mSharedData->mNumVertices); + memcpy(mSharedData->mBaseNormals, mNormals, sizeof(LLVector3) * mSharedData->mNumVertices); + memcpy(mSharedData->mBaseBinormals, mBinormals, sizeof(LLVector3) * mSharedData->mNumVertices); + memcpy(mSharedData->mTexCoords, mTexCoords, sizeof(LLVector2) * mSharedData->mNumVertices); + + // 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) + { + LLVOAvatar* avatarp = (LLVOAvatar*)*avatar_it; + LLPolyMesh* mesh = avatarp->getMesh(mSharedData); + if (mesh) + { + LLVector3 *mesh_coords = mesh->getWritableCoords(); + LLVector3 *mesh_normals = mesh->getWritableNormals(); + LLVector3 *mesh_binormals = mesh->getWritableBinormals(); + LLVector2 *mesh_tex_coords = mesh->getWritableTexCoords(); + LLVector3 *mesh_scaled_normals = mesh->getScaledNormals(); + LLVector3 *mesh_scaled_binormals = mesh->getScaledBinormals(); + + for( vert_index = 0; vert_index < nverts; vert_index++) + { + mesh_coords[vert_index] -= delta_coords[vert_index]; + mesh_tex_coords[vert_index] -= delta_tex_coords[vert_index]; + + mesh_scaled_normals[vert_index] -= delta_normals[vert_index]; + LLVector3 normalized_normal = mesh_scaled_normals[vert_index]; + normalized_normal.normVec(); + mesh_normals[vert_index] = normalized_normal; + + mesh_scaled_binormals[vert_index] -= delta_binormals[vert_index]; + LLVector3 tangent = mesh_scaled_binormals[vert_index] % normalized_normal; + LLVector3 normalized_binormal = normalized_normal % tangent; + normalized_binormal.normVec(); + 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() //----------------------------------------------------------------------------- @@ -882,7 +1563,7 @@ LLPolyMeshSharedData *LLPolyMesh::getSharedData() const //-------------------------------------------------------------------- // LLPolyMesh::dumpDiagInfo() //-------------------------------------------------------------------- -void LLPolyMesh::dumpDiagInfo() +void LLPolyMesh::dumpDiagInfo(void*) { // keep track of totals U32 total_verts = 0; @@ -893,7 +1574,7 @@ void LLPolyMesh::dumpDiagInfo() llinfos << "-----------------------------------------------------" << llendl; llinfos << " Global PolyMesh Table (DEBUG only)" << llendl; - llinfos << " Verts Faces Mem(KB) Name" << llendl; + llinfos << " Verts Faces Mem(KB) Type Name" << llendl; llinfos << "-----------------------------------------------------" << llendl; // print each loaded mesh, and it's memory usage @@ -907,7 +1588,14 @@ void LLPolyMesh::dumpDiagInfo() 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()); + 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; @@ -996,6 +1684,32 @@ void LLPolyMesh::initializeForMorph() memset(mClothingWeights, 0, sizeof(LLVector4) * mSharedData->mNumVertices); } +//----------------------------------------------------------------------------- +// 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(morph_name, morph_data)); + } + return; +} + //----------------------------------------------------------------------------- // getMorphData() //----------------------------------------------------------------------------- diff --git a/indra/newview/llpolymesh.h b/indra/newview/llpolymesh.h index c23617749..15c284a1a 100644 --- a/indra/newview/llpolymesh.h +++ b/indra/newview/llpolymesh.h @@ -174,6 +174,24 @@ public: // otherwise it is loaded from file, added to the table, and returned. static LLPolyMesh *getMesh( const std::string &name, LLPolyMesh* reference_mesh = NULL); + // Saves the mesh information as a binary Linden Lab Mesh file. + BOOL saveLLM(LLFILE *fp); + + // Saves the mesh information as an OBJ file. + BOOL saveOBJ(LLFILE *fp); + + // Loads new mesh information from an OBJ file. + BOOL loadOBJ(LLFILE *fp); + + // Copies the current mesh to the base mesh. + BOOL setSharedFromCurrent(); + + // Gets the name of the mesh corresponding to the shared data + static const std::string* getSharedMeshName(LLPolyMeshSharedData* shared); + + // Requests mesh data by name. Returns null if not found. + static LLPolyMeshSharedData *getMeshData( const std::string &name ); + // Frees all loaded meshes. // This should only be called once you know there are no outstanding // references to these objects. Generally, upon exit of the application. @@ -312,6 +330,9 @@ public: return mSharedData->mJointNames; } + typedef std::map morph_list_t; + static void getMorphList (const std::string& mesh_name, morph_list_t* morph_list); + LLPolyMorphData* getMorphData(const std::string& morph_name); // void removeMorphData(LLPolyMorphData *morph_target); // void deleteAllMorphData(); @@ -334,11 +355,12 @@ public: U32 mFaceIndexOffset; U32 mFaceIndexCount; U32 mCurVertexCount; -private: - void initializeForMorph(); // Dumps diagnostic information about the global mesh table - static void dumpDiagInfo(); + static void dumpDiagInfo(void*); + +private: + void initializeForMorph(); protected: // mesh data shared across all instances of a given mesh diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp index 72a332440..4cf59a209 100644 --- a/indra/newview/llpolymorph.cpp +++ b/indra/newview/llpolymorph.cpp @@ -43,6 +43,7 @@ //#include "../tools/imdebug/imdebug.h" const F32 NORMAL_SOFTEN_FACTOR = 0.65f; +const F32 SIGNIFICANT_DELTA = 0.0001f; //----------------------------------------------------------------------------- // LLPolyMorphData() @@ -210,6 +211,297 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh) return TRUE; } +//----------------------------------------------------------------------------- +// LLPolyMesh::saveLLM() +//----------------------------------------------------------------------------- +BOOL LLPolyMorphData::saveLLM(LLFILE *fp) +{ + if (!fp) + return FALSE; + + S32 numVertices = mNumIndices; + + llendianswizzle(&numVertices, sizeof(S32), 1); + if (fwrite(&numVertices, sizeof(S32), 1, fp) != 1) + { + llwarns << "Short write" << llendl; + } + numVertices = mNumIndices; // without the swizzle again + + //------------------------------------------------------------------------- + // write vertices + //------------------------------------------------------------------------- + for(S32 v = 0; v < numVertices; v++) + { + llendianswizzle(&mVertexIndices[v], sizeof(U32), 1); + if (fwrite(&mVertexIndices[v], sizeof(U32), 1, fp) != 1) + { + llwarns << "Short write" << llendl; + } + llendianswizzle(&mVertexIndices[v], sizeof(U32), 1); + + llendianswizzle(&mCoords[v].mV, sizeof(F32), 3); + if (fwrite(&mCoords[v].mV, sizeof(F32), 3, fp) != 3) + { + llwarns << "Short write" << llendl; + } + llendianswizzle(&mCoords[v].mV, sizeof(F32), 3); + + llendianswizzle(&mNormals[v].mV, sizeof(F32), 3); + if (fwrite(&mNormals[v].mV, sizeof(F32), 3, fp) != 3) + { + llwarns << "Short write" << llendl; + } + llendianswizzle(&mNormals[v].mV, sizeof(F32), 3); + + llendianswizzle(&mBinormals[v].mV, sizeof(F32), 3); + if (fwrite(&mBinormals[v].mV, sizeof(F32), 3, fp) != 3) + { + llwarns << "Short write" << llendl; + } + llendianswizzle(&mBinormals[v].mV, sizeof(F32), 3); + + llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2); + if (fwrite(&mTexCoords[v].mV, sizeof(F32), 2, fp) != 2) + { + llwarns << "Short write" << llendl; + } + llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2); + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// saveOBJ() +//----------------------------------------------------------------------------- +BOOL LLPolyMorphData::saveOBJ(LLFILE *fp) +{ + if (!fp) + return FALSE; + + LLPolyMesh mesh(mMesh, NULL); + + LLVector3 *coords = mesh.getWritableCoords(); + LLVector3 *normals = mesh.getWritableNormals(); + LLVector2 *tex_coords = mesh.getWritableTexCoords(); + + for(U32 vert_index_morph = 0; vert_index_morph < mNumIndices; vert_index_morph++) + { + S32 vert_index_mesh = mVertexIndices[vert_index_morph]; + + coords[vert_index_mesh] += mCoords[vert_index_morph]; + normals[vert_index_mesh] += mNormals[vert_index_morph]; + normals[vert_index_mesh].normVec(); + tex_coords[vert_index_mesh] += mTexCoords[vert_index_morph]; + } + + return mesh.saveOBJ(fp); +} + +//----------------------------------------------------------------------------- +// setMorphFromMesh() +//----------------------------------------------------------------------------- +BOOL LLPolyMorphData::setMorphFromMesh(LLPolyMesh *morph) +{ + if (!morph) + return FALSE; + + LLVector3 *morph_coords = morph->getWritableCoords(); + LLVector3 *morph_normals = morph->getWritableNormals(); + LLVector3 *morph_binormals = morph->getWritableBinormals(); + LLVector2 *morph_tex_coords = morph->getWritableTexCoords(); + + // We now have the morph loaded as a mesh. We have to subtract the + // base mesh to get the delta morph. + + LLPolyMesh delta(mMesh, NULL); + U32 nverts = delta.getNumVertices(); + + LLVector3 *delta_coords = delta.getWritableCoords(); + LLVector3 *delta_normals = delta.getWritableNormals(); + LLVector3 *delta_binormals = delta.getWritableBinormals(); + LLVector2 *delta_tex_coords = delta.getWritableTexCoords(); + + U32 num_significant = 0; + U32 vert_index; + for( vert_index = 0; vert_index < nverts; vert_index++) + { + delta_coords[vert_index] = morph_coords[vert_index] - delta_coords[vert_index]; + delta_normals[vert_index] = morph_normals[vert_index] - delta_normals[vert_index]; + delta_binormals[vert_index] = morph_binormals[vert_index] - delta_binormals[vert_index]; + delta_tex_coords[vert_index] = morph_tex_coords[vert_index] - delta_tex_coords[vert_index]; + + // For the normals and binormals, we really want the deltas + // to be perpendicular to the mesh (bi)normals in the plane + // that contains both the mesh and morph (bi)normals, such + // that the morph (bi)normals form the hypotenuses of right + // triangles. Right now, we just compute the difference vector. + + if (delta_coords[vert_index].length() > SIGNIFICANT_DELTA + || delta_normals[vert_index].length() > SIGNIFICANT_DELTA + || delta_binormals[vert_index].length() > SIGNIFICANT_DELTA + || delta_tex_coords[vert_index].length() > SIGNIFICANT_DELTA) + { + num_significant++; + } + } + + //------------------------------------------------------------------------- + // compute new morph + //------------------------------------------------------------------------- + + // If the morph matches the base mesh, we store one vertex to prevent + // zero length vectors. + + U32 nindices = num_significant; + if (num_significant == 0) + nindices = 1; + + LLVector3* new_coords = new LLVector3[nindices]; + LLVector3* new_normals = new LLVector3[nindices]; + LLVector3* new_binormals = new LLVector3[nindices]; + LLVector2* new_tex_coords = new LLVector2[nindices]; + U32* new_vertex_indices = new U32[nindices]; + + // We'll set the distortion directly + mTotalDistortion = 0.f; + mMaxDistortion = 0.f; + mAvgDistortion.zeroVec(); + + U32 morph_index = 0; + for( vert_index = 0; vert_index < nverts; vert_index++) + { + if (delta_coords[vert_index].length() > SIGNIFICANT_DELTA + || delta_normals[vert_index].length() > SIGNIFICANT_DELTA + || delta_binormals[vert_index].length() > SIGNIFICANT_DELTA + || delta_tex_coords[vert_index].length() > SIGNIFICANT_DELTA + || num_significant == 0) + { + new_vertex_indices[morph_index] = vert_index; + + new_coords[morph_index] = delta_coords[vert_index]; + new_normals[morph_index] = delta_normals[vert_index]; + new_binormals[morph_index] = delta_binormals[vert_index]; + new_tex_coords[morph_index] = delta_tex_coords[vert_index]; + + F32 magnitude = new_coords[morph_index].magVec(); + + mTotalDistortion += magnitude; + mAvgDistortion.mV[VX] += fabs(new_coords[morph_index].mV[VX]); + mAvgDistortion.mV[VY] += fabs(new_coords[morph_index].mV[VY]); + mAvgDistortion.mV[VZ] += fabs(new_coords[morph_index].mV[VZ]); + + if (magnitude > mMaxDistortion) + { + mMaxDistortion = magnitude; + } + + morph_index++; + num_significant = 1; + } + } + + mAvgDistortion = mAvgDistortion * (1.f/(F32)nindices); + mAvgDistortion.normVec(); + + //------------------------------------------------------------------------- + // compute the change in the morph + //------------------------------------------------------------------------- + + // 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 this morph and apply that appropriately weighted. + + for( morph_index = 0; morph_index < mNumIndices; morph_index++) + { + vert_index = mVertexIndices[morph_index]; + + delta_coords[vert_index] -= mCoords[morph_index]; + delta_normals[vert_index] -= mNormals[morph_index]; + delta_binormals[vert_index] -= mBinormals[morph_index]; + delta_tex_coords[vert_index] -= mTexCoords[morph_index]; + } + + //------------------------------------------------------------------------- + // Update all avatars + //------------------------------------------------------------------------- + + std::vector< LLCharacter* >::iterator avatar_it; + for(avatar_it = LLCharacter::sInstances.begin(); avatar_it != LLCharacter::sInstances.end(); ++avatar_it) + { + LLVOAvatar* avatarp = (LLVOAvatar*)*avatar_it; + + LLPolyMorphTarget* param = (LLPolyMorphTarget*) avatarp->getVisualParam(mName.c_str()); + if (!param) + { + continue; + } + + F32 weight = param->getLastWeight(); + if (weight == 0.0f) + { + continue; + } + + LLPolyMesh* mesh = avatarp->getMesh(mMesh); + if (!mesh) + { + continue; + } + + // If we have a vertex mask, just remove it. It will be recreated. + if (param->undoMask(TRUE)) + { + continue; + } + + LLVector3 *mesh_coords = mesh->getWritableCoords(); + LLVector3 *mesh_normals = mesh->getWritableNormals(); + LLVector3 *mesh_binormals = mesh->getWritableBinormals(); + LLVector2 *mesh_tex_coords = mesh->getWritableTexCoords(); + LLVector3 *mesh_scaled_normals = mesh->getScaledNormals(); + LLVector3 *mesh_scaled_binormals = mesh->getScaledBinormals(); + + for( vert_index = 0; vert_index < nverts; vert_index++) + { + mesh_coords[vert_index] += delta_coords[vert_index] * weight; + mesh_tex_coords[vert_index] += delta_tex_coords[vert_index] * weight; + + mesh_scaled_normals[vert_index] += delta_normals[vert_index] * weight * NORMAL_SOFTEN_FACTOR; + LLVector3 normalized_normal = mesh_scaled_normals[vert_index]; + normalized_normal.normVec(); + mesh_normals[vert_index] = normalized_normal; + + mesh_scaled_binormals[vert_index] += delta_binormals[vert_index] * weight * NORMAL_SOFTEN_FACTOR; + LLVector3 tangent = mesh_scaled_binormals[vert_index] % normalized_normal; + LLVector3 normalized_binormal = normalized_normal % tangent; + normalized_binormal.normVec(); + mesh_binormals[vert_index] = normalized_binormal; + } + + avatarp->dirtyMesh(); + } + + //------------------------------------------------------------------------- + // reallocate vertices + //------------------------------------------------------------------------- + delete [] mVertexIndices; + delete [] mCoords; + delete [] mNormals; + delete [] mBinormals; + delete [] mTexCoords; + + mVertexIndices = new_vertex_indices; + mCoords = new_coords; + mNormals = new_normals; + mBinormals = new_binormals; + mTexCoords = new_tex_coords; + mNumIndices = nindices; + + return TRUE; +} + //----------------------------------------------------------------------------- // LLPolyMorphTargetInfo() //----------------------------------------------------------------------------- @@ -588,10 +880,32 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3 else { // remove effect of previous mask - F32 *maskWeights = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL; + undoMask(FALSE); + } - if (maskWeights) + mLastWeight = 0.f; + + mVertMask->generateMask(maskTextureData, width, height, num_components, invert, clothing_weights); + + apply(mLastSex); +} + +//----------------------------------------------------------------------------- +// undoMask() +//----------------------------------------------------------------------------- +BOOL LLPolyMorphTarget::undoMask(BOOL delete_mask) +{ + if (!mVertMask) { + return FALSE; + } + + // remove effect of previous mask + + LLVector4 *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL; + + F32 *mask_weights = mVertMask->getMorphMaskWeights(); + LLVector3 *coords = mMesh->getWritableCoords(); LLVector3 *scaled_normals = mMesh->getScaledNormals(); LLVector3 *scaled_binormals = mMesh->getScaledBinormals(); @@ -599,33 +913,42 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3 for(U32 vert = 0; vert < mMorphData->mNumIndices; vert++) { - F32 lastMaskWeight = mLastWeight * maskWeights[vert]; + F32 mask_weight = 1.f; + if (mask_weights) + { + mask_weight = mask_weights[vert]; + } + + F32 last_mask_weight = mLastWeight * mask_weight; S32 out_vert = mMorphData->mVertexIndices[vert]; // remove effect of existing masked morph - coords[out_vert] -= mMorphData->mCoords[vert] * lastMaskWeight; - scaled_normals[out_vert] -= mMorphData->mNormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR; - scaled_binormals[out_vert] -= mMorphData->mBinormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR; - tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight; + coords[out_vert] -= mMorphData->mCoords[vert] * last_mask_weight; + scaled_normals[out_vert] -= mMorphData->mNormals[vert] * last_mask_weight * NORMAL_SOFTEN_FACTOR; + scaled_binormals[out_vert] -= mMorphData->mBinormals[vert] * last_mask_weight * NORMAL_SOFTEN_FACTOR; + tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * last_mask_weight; if (clothing_weights) { - LLVector3 clothing_offset = mMorphData->mCoords[vert] * lastMaskWeight; + LLVector3 clothing_offset = mMorphData->mCoords[vert] * last_mask_weight; LLVector4* clothing_weight = &clothing_weights[out_vert]; clothing_weight->mV[VX] -= clothing_offset.mV[VX]; clothing_weight->mV[VY] -= clothing_offset.mV[VY]; clothing_weight->mV[VZ] -= clothing_offset.mV[VZ]; } } - } - } // set last weight to 0, since we've removed the effect of this morph mLastWeight = 0.f; - mVertMask->generateMask(maskTextureData, width, height, num_components, invert, clothing_weights); + if (delete_mask) + { + delete mVertMask; + mVertMask = NULL; + addPendingMorphMask(); + } - apply(mLastSex); + return TRUE; } diff --git a/indra/newview/llpolymorph.h b/indra/newview/llpolymorph.h index 3fdaf3785..5137fc1fc 100644 --- a/indra/newview/llpolymorph.h +++ b/indra/newview/llpolymorph.h @@ -56,6 +56,10 @@ public: BOOL loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh); const std::string& getName() { return mName; } + BOOL saveLLM(LLFILE *fp); + BOOL saveOBJ(LLFILE *fp); + BOOL setMorphFromMesh(LLPolyMesh *morph); + public: std::string mName; @@ -167,6 +171,7 @@ public: /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); void applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert); + BOOL undoMask(BOOL delete_mask); void addPendingMorphMask() { mNumMorphMasksPending++; } protected: diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index d541a8cb8..9aa484907 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -182,7 +182,7 @@ #include "llparcel.h" - +#include "llpolymesh.h" #include "llprimitive.h" #include "llresmgr.h" #include "llselectmgr.h" @@ -572,6 +572,13 @@ void handle_toggle_pg(void*); void handle_dump_attachments(void *); void handle_show_overlay_title(void*); void handle_dump_avatar_local_textures(void*); +void handle_meshes_and_morphs(void*); +void handle_mesh_save_llm(void* data); +void handle_mesh_save_current_obj(void*); +void handle_mesh_save_obj(void*); +void handle_mesh_load_obj(void*); +void handle_morph_save_obj(void*); +void handle_morph_load_obj(void*); void handle_debug_avatar_textures(void*); void handle_grab_texture(void*); BOOL enable_grab_texture(void*); @@ -1626,6 +1633,11 @@ void init_debug_avatar_menu(LLMenuGL* menu) // //#endif // + + LLMenuItemCallGL* mesh_item = new LLMenuItemCallGL("Meshes And Morphs...", handle_meshes_and_morphs); + mesh_item->setUserData((void*)mesh_item); // So we can remove it later + menu->append(mesh_item); + menu->createJumpKeys(); } @@ -8391,6 +8403,410 @@ void handle_dump_avatar_local_textures(void*) } } +void handle_meshes_and_morphs(void* menu_item) +{ + LLMenuItemCallGL* item = (LLMenuItemCallGL*) menu_item; + LLMenuGL* parent_menu = (LLMenuGL*) item->getParent(); + parent_menu->remove(item); + + LLMenuGL* menu = new LLMenuGL("Meshes And Morphs"); + menu->append(new LLMenuItemCallGL("Dump Avatar Mesh Info", &LLPolyMesh::dumpDiagInfo)); + menu->appendSeparator(); + + LLVOAvatar::mesh_info_t mesh_info; + LLVOAvatar::getMeshInfo(&mesh_info); + + for(LLVOAvatar::mesh_info_t::iterator info_iter = mesh_info.begin(); + info_iter != mesh_info.end(); ++info_iter) + { + const std::string& type = info_iter->first; + LLVOAvatar::lod_mesh_map_t& lod_mesh = info_iter->second; + + LLMenuGL* type_menu = new LLMenuGL(type); + + for(LLVOAvatar::lod_mesh_map_t::iterator lod_iter = lod_mesh.begin(); + lod_iter != lod_mesh.end(); ++lod_iter) + { + S32 lod = lod_iter->first; + std::string& mesh = lod_iter->second; + + std::string caption = llformat ("%s LOD %d", type.c_str(), lod); + + if (lod == 0) + { + caption = type; + } + + LLPolyMeshSharedData* mesh_shared = LLPolyMesh::getMeshData(mesh); + + LLPolyMesh::morph_list_t morph_list; + LLPolyMesh::getMorphList(mesh, &morph_list); + + LLMenuGL* lod_menu = new LLMenuGL(caption); + lod_menu->append(new LLMenuItemCallGL("Save LLM", handle_mesh_save_llm, NULL, (void*) mesh_shared)); + + LLMenuGL* action_menu = new LLMenuGL("Base Mesh"); + action_menu->append(new LLMenuItemCallGL("Save OBJ", handle_mesh_save_obj, NULL, (void*) mesh_shared)); + + if (lod == 0) + { + // Since an LOD mesh has only faces, we won't enable this for + // LOD meshes until we add code for processing the face commands. + + action_menu->append(new LLMenuItemCallGL("Load OBJ", handle_mesh_load_obj, NULL, (void*) mesh_shared)); + } + + action_menu->createJumpKeys(); + lod_menu->appendMenu(action_menu); + + action_menu = new LLMenuGL("Current Mesh"); + + action_menu->append(new LLMenuItemCallGL("Save OBJ", handle_mesh_save_current_obj, NULL, (void*) mesh_shared)); + + action_menu->createJumpKeys(); + lod_menu->appendMenu(action_menu); + + lod_menu->appendSeparator(); + + for(LLPolyMesh::morph_list_t::iterator morph_iter = morph_list.begin(); + morph_iter != morph_list.end(); ++morph_iter) + { + std::string const& morph_name = morph_iter->first; + LLPolyMorphData* morph_data = morph_iter->second; + + action_menu = new LLMenuGL(morph_name); + + action_menu->append(new LLMenuItemCallGL("Save OBJ", handle_morph_save_obj, NULL, (void*) morph_data)); + action_menu->append(new LLMenuItemCallGL("Load OBJ", handle_morph_load_obj, NULL, (void*) morph_data)); + + action_menu->createJumpKeys(); + lod_menu->appendMenu(action_menu); + } + + lod_menu->createJumpKeys(); + type_menu->appendMenu(lod_menu); + } + type_menu->createJumpKeys(); + menu->appendMenu(type_menu); + } + + menu->createJumpKeys(); + menu->updateParent(LLMenuGL::sMenuContainer); + parent_menu->appendMenu(menu); + + LLMenuGL::sMenuContainer->hideMenus(); + LLFloater* tear_off_menu = LLTearOffMenu::create(menu); + tear_off_menu->setFocus(TRUE); +} + +static void handle_mesh_save_llm_continued(void* data, AIFilePicker* filepicker); +void handle_mesh_save_llm(void* data) +{ + LLPolyMeshSharedData* mesh_shared = (LLPolyMeshSharedData*) data; + std::string const* mesh_name = LLPolyMesh::getSharedMeshName(mesh_shared); + std::string default_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER, ""); + + if (!mesh_name) + { + llwarns << "LPolyMesh::getSharedMeshName returned NULL" << llendl; + return; + } + + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(*mesh_name, FFSAVE_ALL, default_path, "mesh_llm"); + filepicker->run(boost::bind(&handle_mesh_save_llm_continued, data, filepicker)); +} + +static void handle_mesh_save_llm_continued(void* data, AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + { + llwarns << "No file" << llendl; + return; + } + std::string selected_filename = filepicker->getFilename(); + LLPolyMeshSharedData* mesh_shared = (LLPolyMeshSharedData*) data; + std::string const* mesh_name = LLPolyMesh::getSharedMeshName(mesh_shared); + + llinfos << "Selected " << selected_filename << " for mesh " << *mesh_name <getExpandedFilename(LL_PATH_CHARACTER, ""); + + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(file_name, FFSAVE_ALL, default_path, "mesh_obj"); + filepicker->run(boost::bind(&handle_mesh_save_current_obj_continued, data, filepicker)); +} + +static void handle_mesh_save_current_obj_continued(void* data, AIFilePicker* filepicker) +{ + if(!filepicker->hasFilename()) + { + llwarns << "No file" << llendl; + return; + } + std::string selected_filename = filepicker->getFilename(); + LLPolyMeshSharedData* mesh_shared = (LLPolyMeshSharedData*)data; + std::string const* mesh_name = LLPolyMesh::getSharedMeshName(mesh_shared); + + llinfos << "Selected " << selected_filename << " for mesh " << *mesh_name <getMesh (mesh_shared); + mesh->saveOBJ(fp); + } + fclose(fp); +} + +static void handle_mesh_save_obj_continued(void* data, AIFilePicker* filepicker); +void handle_mesh_save_obj(void* data) +{ + LLPolyMeshSharedData* mesh_shared = (LLPolyMeshSharedData*) data; + std::string const* mesh_name = LLPolyMesh::getSharedMeshName(mesh_shared); + + if (!mesh_name) + { + llwarns << "LPolyMesh::getSharedMeshName returned NULL" << llendl; + return; + } + + std::string file_name = *mesh_name + ".obj"; + std::string default_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER, ""); + + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(file_name, FFSAVE_ALL, default_path, "mesh_obj"); + filepicker->run(boost::bind(&handle_mesh_save_obj_continued, data, filepicker)); +} + +static void handle_mesh_save_obj_continued(void* data, AIFilePicker* filepicker) +{ + if(!filepicker->hasFilename()) + { + llwarns << "No file" << llendl; + return; + } + std::string selected_filename = filepicker->getFilename(); + LLPolyMeshSharedData* mesh_shared = (LLPolyMeshSharedData*) data; + std::string const* mesh_name = LLPolyMesh::getSharedMeshName(mesh_shared); + + llinfos << "Selected " << selected_filename << " for mesh " << *mesh_name <getExpandedFilename(LL_PATH_CHARACTER, ""); + + if (!mesh_name) + { + llwarns << "LPolyMesh::getSharedMeshName returned NULL" << llendl; + return; + } + + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_ALL, default_path, "mesh_obj"); + filepicker->run(boost::bind(&handle_mesh_load_obj_continued, data, filepicker)); +} + +static void handle_mesh_load_obj_continued(void* data, AIFilePicker* filepicker) +{ + if(!filepicker->hasFilename()) + { + llwarns << "No file" << llendl; + return; + } + std::string selected_filename = filepicker->getFilename(); + LLPolyMeshSharedData* mesh_shared = (LLPolyMeshSharedData*) data; + std::string const* mesh_name = LLPolyMesh::getSharedMeshName(mesh_shared); + + llinfos << "Selected " << selected_filename << " for mesh " << *mesh_name <mMesh; + std::string const* mesh_name = LLPolyMesh::getSharedMeshName(mesh_shared); + std::string const& morph_name = morph_data->getName(); + + if (!mesh_name) + { + llwarns << "LPolyMesh::getSharedMeshName returned NULL" << llendl; + return; + } + + llinfos << "Save morph OBJ " << morph_name << " of mesh " << *mesh_name <getExpandedFilename(LL_PATH_CHARACTER, ""); + + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(file_name, FFSAVE_ALL, default_path, "mesh_obj"); + filepicker->run(boost::bind(&handle_morph_save_obj_continued, data, filepicker)); +} + +static void handle_morph_save_obj_continued(void* data, AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + { + llwarns << "No file" << llendl; + return; + } + std::string selected_filename = filepicker->getFilename(); + LLPolyMorphData* morph_data = (LLPolyMorphData*)data; + + llinfos << "Selected " << selected_filename << llendl; + + LLFILE* fp = LLFile::fopen(selected_filename, "wb"); /*Flawfinder: ignore*/ + if (!fp) + { + llerrs << "can't open: " << selected_filename << llendl; + return; + } + + morph_data->saveOBJ(fp); + fclose(fp); +} + +static void handle_morph_load_obj_continued(void* data, AIFilePicker* filepicker); +void handle_morph_load_obj(void* data) +{ + LLPolyMorphData* morph_data = (LLPolyMorphData*) data; + LLPolyMeshSharedData* mesh_shared = morph_data->mMesh; + std::string const* mesh_name = LLPolyMesh::getSharedMeshName(mesh_shared); + std::string const& morph_name = morph_data->getName(); + std::string default_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER, ""); + + if (!mesh_name) + { + llwarns << "LPolyMesh::getSharedMeshName returned NULL" << llendl; + return; + } + + llinfos << "Load morph OBJ " << morph_name << " of mesh " << *mesh_name <open(FFLOAD_ALL, default_path, "mesh_obj"); + filepicker->run(boost::bind(&handle_morph_load_obj_continued, data, filepicker)); +} + +static void handle_morph_load_obj_continued(void* data, AIFilePicker* filepicker) +{ + if(!filepicker->hasFilename()) + { + llwarns << "No file" << llendl; + return; + } + std::string selected_filename = filepicker->getFilename(); + LLPolyMorphData* morph_data = (LLPolyMorphData*) data; + LLPolyMeshSharedData* mesh_shared = morph_data->mMesh; + + llinfos << "Selected " << selected_filename <setMorphFromMesh(&mesh); +} + void handle_debug_avatar_textures(void*) { LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 22c4ab4f6..385782247 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1182,7 +1182,6 @@ void LLVOAvatar::getMeshInfo (mesh_info_t* mesh_info) return; } - // static void LLVOAvatar::dumpBakedStatus() { @@ -6852,6 +6851,22 @@ void LLVOAvatar::hideSkirt() mMeshLOD[MESH_ID_SKIRT]->setVisible(FALSE, TRUE); } +//----------------------------------------------------------------------------- +// getMesh( LLPolyMeshSharedData *shared_data ) +//----------------------------------------------------------------------------- +LLPolyMesh* LLVOAvatar::getMesh( LLPolyMeshSharedData *shared_data ) +{ + for (polymesh_map_t::iterator i = mMeshes.begin(); i != mMeshes.end(); ++i) + { + LLPolyMesh* mesh = i->second; + if (mesh->getSharedData() == shared_data) + { + return mesh; + } + } + return NULL; +} + //----------------------------------------------------------------------------- // requestLayerSetUpdate() //----------------------------------------------------------------------------- diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 1adb1fef8..7da445414 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -600,11 +600,6 @@ public: void setLocTexTE( U8 te, LLViewerTexture* image, BOOL set_by_user ); void setupComposites(); - typedef std::map lod_mesh_map_t; - typedef std::map mesh_info_t; - - static void getMeshInfo (mesh_info_t* mesh_info); - /** Textures ** ** *******************************************************************************/ @@ -651,6 +646,7 @@ public: void processAvatarAppearance(LLMessageSystem* mesgsys); void hideSkirt(); void startAppearanceAnimation(BOOL set_by_user, BOOL play_sound); + LLPolyMesh* getMesh(LLPolyMeshSharedData* shared_data); //-------------------------------------------------------------------- // Appearance morphing @@ -663,6 +659,12 @@ private: F32 mLastAppearanceBlendTime; BOOL mAppearanceAnimSetByUser; //1.23 +public: + typedef std::map lod_mesh_map_t; + typedef std::map mesh_info_t; + + static void getMeshInfo(mesh_info_t* mesh_info); + //-------------------------------------------------------------------- // Clothing colors (convenience functions to access visual parameters) //--------------------------------------------------------------------