// Creates new parameters for the given wearable and applies them to the avatar. void LLGenePool::spawn( EWearableType type ) { LLVOAvatar* avatar = gAgent.getAvatarObject(); if( !avatar ) { return; } if( !mLoaded ) { if( !load() ) { return; } } if( mArchetypes.count() < 1 ) { return; } // Only consider archetypes that have the same sex as you have already. LLVisualParam* male_param = avatar->getVisualParam( "male" ); if (!male_param) { llwarns << "The hard coded \'male\' parameter passed to avatar->getVisualParam() in LLGenePool::spawn() is no longer valid." << llendl; return; } S32 male_param_id = male_param->getID(); F32 sex_weight = male_param->getWeight(); S32 i = 0; S32 j = 0; S32 k = 0; const S32 MAX_CYCLES = 1000; S32 cycles = 0; F32 cur_sex_weight = 0.f; do { i = rand() % mArchetypes.count(); cur_sex_weight = mArchetypes[i]->getParam(male_param_id, 0.f); cycles++; if (cur_sex_weight != sex_weight) { break; } } while((cycles < MAX_CYCLES)); if( cycles >= MAX_CYCLES ) { return; } LLAppearance* arch1 = mArchetypes[i]; LLAppearance* arch2 = NULL; LLAppearance* arch3 = NULL; if( mArchetypes.count() > 1 ) { cycles = 0; do { j = rand() % mArchetypes.count(); cur_sex_weight = mArchetypes[j]->getParam(male_param_id, 0.f); cycles++; } while( (cycles < MAX_CYCLES) && ( (i == j) || (cur_sex_weight != sex_weight) ) ); if( cycles >= MAX_CYCLES ) { return; } arch2 = mArchetypes[j]; } if( mArchetypes.count() > 2 ) { cycles = 0; do { k = rand() % mArchetypes.count(); cur_sex_weight = mArchetypes[k]->getParam(male_param_id, 0.f); cycles++; } while( (cycles < MAX_CYCLES) && ( (i == k) || (j == k) || (cur_sex_weight != sex_weight) ) ); if( cycles >= MAX_CYCLES ) { return; } arch3 = mArchetypes[k]; } // Lame generation of barycentric coordinates F32 b1 = F32( rand() ) / RAND_MAX; F32 b2 = (F32( rand() ) / RAND_MAX) * (1.f - b1); F32 b3 = 1.f - b1 - b2; // ESex old_sex = avatar->getSex(); // Pull params for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() ) { if( (((LLViewerVisualParam*)param)->getWearableType() == type) && (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) ) { S32 param_id = param->getID(); // don't try to blend male/female param...as fp innaccuracy will break the [0 | 1] semantics if (param_id != male_param_id) { F32 weight1 = arch1->getParam( param_id, param->getDefaultWeight() ); F32 net_weight = weight1; if( arch2 && arch3 ) { F32 weight2 = arch2->getParam( param_id, param->getDefaultWeight() ); F32 weight3 = arch3->getParam( param_id, param->getDefaultWeight() ); net_weight = b1 * weight1 + b2 * weight2 + b3 * weight3; } param->setAnimationTarget(net_weight, TRUE); } } } // Find the archetype with the greatest influence LLAppearance* dominant_arch = arch1; if( (b2 > b1) && (b2 > b3) ) { dominant_arch = arch2; } else if( (b3 > b1) && (b3 > b2) ) { dominant_arch = arch3; } // Pull Textures from the dominant archetype for( S32 te = 0; te < LLVOAvatar::TEX_NUM_ENTRIES; te++ ) { if( LLVOAvatar::isTextureIndexBaked( te ) ) { continue; } if( LLVOAvatar::getTEWearableType( te ) == type ) { LLUUID image_id = dominant_arch->getTexture( te ); if( image_id.isNull() ) { image_id = LLVOAvatar::getDefaultTEImageID( te ); } LLViewerImage* image = gImageList.getImage( image_id ); if( image ) { avatar->setLocTexTE( te, image, TRUE ); } } } // avatar->setVisualParamWeight( "male", sex_weight ); avatar->startAppearanceAnimation(TRUE, TRUE); avatar->updateVisualParams(); // ESex new_sex = avatar->getSex(); // if( old_sex != new_sex ) // { // avatar->updateSexDependentLayerSets( TRUE ); // } avatar->updateMeshTextures(); gAgent.sendAgentSetAppearance(); }
//----------------------------------------------------------------------------- // setMorphFromMesh() //----------------------------------------------------------------------------- BOOL LLPolyMorphData::setMorphFromMesh(LLPolyMesh *morph) { if (!morph) return FALSE; LLVector4a *morph_coords = morph->getWritableCoords(); LLVector4a *morph_normals = morph->getWritableNormals(); LLVector4a *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(); LLVector4a *delta_coords = delta.getWritableCoords(); LLVector4a *delta_normals = delta.getWritableNormals(); LLVector4a *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].setSub( morph_coords[vert_index], delta_coords[vert_index]); delta_normals[vert_index].setSub( morph_normals[vert_index], delta_normals[vert_index]); delta_binormals[vert_index].setSub( 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].getLength3().getF32() > SIGNIFICANT_DELTA || delta_normals[vert_index].getLength3().getF32() > SIGNIFICANT_DELTA || delta_binormals[vert_index].getLength3().getF32() > 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; LLVector4a* new_coords = new LLVector4a[nindices]; LLVector4a* new_normals = new LLVector4a[nindices]; LLVector4a* new_binormals = new LLVector4a[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.clear(); U32 morph_index = 0; for( vert_index = 0; vert_index < nverts; vert_index++) { if (delta_coords[vert_index].getLength3().getF32() > SIGNIFICANT_DELTA || delta_normals[vert_index].getLength3().getF32() > SIGNIFICANT_DELTA || delta_binormals[vert_index].getLength3().getF32() > 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].getLength3().getF32(); mTotalDistortion += magnitude; LLVector4a t; t.setAbs(new_coords[morph_index]); mAvgDistortion.add(t); if (magnitude > mMaxDistortion) { mMaxDistortion = magnitude; } morph_index++; num_significant = 1; } } mAvgDistortion.mul(1.f/(F32)nindices); mAvgDistortion.normalize3(); //------------------------------------------------------------------------- // 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].sub( mCoords[morph_index]); delta_normals[vert_index].sub( mNormals[morph_index]); delta_binormals[vert_index].sub(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; }*/ LLVector4a *mesh_coords = mesh->getWritableCoords(); LLVector4a *mesh_normals = mesh->getWritableNormals(); LLVector4a *mesh_binormals = mesh->getWritableBinormals(); LLVector2 *mesh_tex_coords = mesh->getWritableTexCoords(); LLVector4a *mesh_scaled_normals = mesh->getScaledNormals(); LLVector4a *mesh_scaled_binormals = mesh->getScaledBinormals(); for( vert_index = 0; vert_index < nverts; vert_index++) { delta_coords[vert_index].mul(weight); mesh_coords[vert_index].add(delta_coords[vert_index]); mesh_tex_coords[vert_index] += delta_tex_coords[vert_index] * weight; delta_normals[vert_index].mul(weight * NORMAL_SOFTEN_FACTOR); mesh_scaled_normals[vert_index].add(delta_normals[vert_index]); LLVector4a normalized_normal = mesh_scaled_normals[vert_index]; normalized_normal.normalize3(); mesh_normals[vert_index] = normalized_normal; delta_binormals[vert_index].mul(weight * NORMAL_SOFTEN_FACTOR); mesh_scaled_binormals[vert_index].add(delta_binormals[vert_index]); LLVector4a tangent; tangent.setCross3(mesh_scaled_binormals[vert_index], normalized_normal); LLVector4a normalized_binormal; normalized_binormal.setCross3(normalized_normal, tangent); normalized_binormal.normalize3(); mesh_binormals[vert_index] = normalized_binormal; } avatarp->dirtyMesh(); } //------------------------------------------------------------------------- // 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; }
//----------------------------------------------------------------------------- // loadNodeArchetype(): loads <archetype> node from XML tree //----------------------------------------------------------------------------- BOOL LLGenePool::loadNodeArchetype( LLXmlTreeNode* node ) { llassert( node->hasName( "archetype" ) ); LLAppearance* archetype = new LLAppearance(); BOOL success = TRUE; LLVOAvatar* avatar = gAgent.getAvatarObject(); if( !avatar ) { delete archetype; return FALSE; } LLXmlTreeNode* child; for (child = node->getChildByName( "param" ); child; child = node->getNextNamedChild()) { F32 value; static LLStdStringHandle value_string = LLXmlTree::addAttributeString("value"); if( !child->getFastAttributeF32( value_string, value ) ) { llwarns << "avatar genepool file: <param> missing value attribute" << llendl; success = FALSE; break; } S32 id; static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id"); if( !child->getFastAttributeS32( id_string, id ) ) { llwarns << "avatar genepool file: <param> missing id attribute" << llendl; success = FALSE; break; } LLVisualParam* param = avatar->getVisualParam( id ); if( param ) { archetype->addParam( id, value ); } else { llwarns << "avatar genepool file: ignoring invalid <param> with id: " << id << llendl; } } for (child = node->getChildByName( "texture" ); child; child = node->getNextNamedChild()) { LLUUID uuid; static LLStdStringHandle uuid_string = LLXmlTree::addAttributeString("uuid"); if( !child->getFastAttributeUUID( uuid_string, uuid ) ) { llwarns << "avatar genepool file: <texture> missing uuid attribute" << llendl; success = FALSE; break; } S32 te; static LLStdStringHandle te_string = LLXmlTree::addAttributeString("te"); if( !child->getFastAttributeS32( te_string, te ) ) { llwarns << "avatar genepool file: <texture> missing te attribute" << llendl; success = FALSE; break; } archetype->addTexture( te, uuid ); } if( success ) { mArchetypes.put( archetype ); } else { delete archetype; } return success; }