diff options
Diffstat (limited to 'indra/llappearance/llwearable.cpp')
-rw-r--r-- | indra/llappearance/llwearable.cpp | 1546 |
1 files changed, 773 insertions, 773 deletions
diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 7f57d1c9c5..9c41e3c256 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -1,773 +1,773 @@ -/**
- * @file llwearable.cpp
- * @brief LLWearable class implementation
- *
- * $LicenseInfo:firstyear=2002&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$
- */
-
-#include "linden_common.h"
-
-#include "llavatarappearance.h"
-#include "lllocaltextureobject.h"
-#include "lltexlayer.h"
-#include "lltexturemanagerbridge.h"
-#include "llvisualparam.h"
-#include "llavatarappearancedefines.h"
-#include "llwearable.h"
-#include "boost/bind.hpp"
-
-using namespace LLAvatarAppearanceDefines;
-
-// static
-S32 LLWearable::sCurrentDefinitionVersion = 1;
-
-// Private local functions
-static std::string terse_F32_to_string(F32 f);
-
-LLWearable::LLWearable()
- : mDefinitionVersion(-1),
- mName(),
- mDescription(),
- mPermissions(),
- mSaleInfo(),
- mType(LLWearableType::WT_NONE),
- mSavedVisualParamMap(),
- mVisualParamIndexMap(),
- mTEMap(),
- mSavedTEMap()
-{
-}
-
-// virtual
-LLWearable::~LLWearable()
-{
- for (visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
- {
- LLVisualParam* vp = vp_pair.second;
- vp->clearNextParam();
- delete vp;
- vp_pair.second = NULL;
- }
-
- destroyTextures();
-}
-
-const std::string& LLWearable::getTypeLabel() const
-{
- return LLWearableType::getInstance()->getTypeLabel(mType);
-}
-
-const std::string& LLWearable::getTypeName() const
-{
- return LLWearableType::getInstance()->getTypeName(mType);
-}
-
-LLAssetType::EType LLWearable::getAssetType() const
-{
- return LLWearableType::getInstance()->getAssetType(mType);
-}
-
-bool LLWearable::exportFile(const std::string& filename) const
-{
- llofstream ofs(filename.c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
- return ofs.is_open() && exportStream(ofs);
-}
-
-// virtual
-bool LLWearable::exportStream( std::ostream& output_stream ) const
-{
- if (!output_stream.good()) return false;
-
- // header and version
- output_stream << "LLWearable version " << mDefinitionVersion << "\n";
- // name
- output_stream << mName << "\n";
- // description
- output_stream << mDescription << "\n";
-
- // permissions
- if( !mPermissions.exportLegacyStream( output_stream ) )
- {
- return false;
- }
-
- // sale info
- if( !mSaleInfo.exportLegacyStream( output_stream ) )
- {
- return false;
- }
-
- // wearable type
- output_stream << "type " << (S32) getType() << "\n";
-
- // parameters
- output_stream << "parameters " << mVisualParamIndexMap.size() << "\n";
-
- for (const visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
- {
- S32 param_id = vp_pair.first;
- const LLVisualParam* param = vp_pair.second;
- F32 param_weight = param->getWeight();
- output_stream << param_id << " " << terse_F32_to_string( param_weight ) << "\n";
- }
-
- // texture entries
- output_stream << "textures " << mTEMap.size() << "\n";
-
- for (const te_map_t::value_type& te_pair : mTEMap)
- {
- S32 te = te_pair.first;
- const LLUUID& image_id = te_pair.second->getID();
- output_stream << te << " " << image_id << "\n";
- }
- return true;
-}
-
-void LLWearable::createVisualParams(LLAvatarAppearance *avatarp)
-{
- for (LLViewerVisualParam* param = (LLViewerVisualParam*) avatarp->getFirstVisualParam();
- param;
- param = (LLViewerVisualParam*) avatarp->getNextVisualParam())
- {
- if (param->getWearableType() == mType)
- {
- LLVisualParam *clone_param = param->cloneParam(this);
- clone_param->setParamLocation(LOC_UNKNOWN);
- clone_param->setParamLocation(LOC_WEARABLE);
- addVisualParam(clone_param);
- }
- }
-
- // resync driver parameters to point to the newly cloned driven parameters
- for (visual_param_index_map_t::value_type& param_pair : mVisualParamIndexMap)
- {
- LLVisualParam* param = param_pair.second;
- LLVisualParam*(LLWearable::*wearable_function)(S32)const = &LLWearable::getVisualParam;
- // need this line to disambiguate between versions of LLCharacter::getVisualParam()
- LLVisualParam*(LLAvatarAppearance::*param_function)(S32)const = &LLAvatarAppearance::getVisualParam;
- param->resetDrivenParams();
- if(!param->linkDrivenParams(boost::bind(wearable_function,(LLWearable*)this, _1), false))
- {
- if( !param->linkDrivenParams(boost::bind(param_function,avatarp,_1 ), true))
- {
- LL_DEBUGS("Avatar") << "could not link driven params for wearable " << getName() << " id: " << param->getID() << LL_ENDL;
- continue;
- }
- }
- }
-}
-
-void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp)
-{
- LLTexLayerSet *layer_set = NULL;
- const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearance::getDictionary()->getTexture((ETextureIndex)te);
- if (texture_dict && texture_dict->mIsUsedByBakedTexture)
- {
- const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
-
- layer_set = avatarp->getAvatarLayerSet(baked_index);
- }
-
- if (layer_set)
- {
- layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this);
- }
- else
- {
- LL_WARNS() << "could not find layerset for LTO in wearable!" << LL_ENDL;
- }
-}
-
-LLWearable::EImportResult LLWearable::importFile(const std::string& filename,
- LLAvatarAppearance* avatarp )
-{
- llifstream ifs(filename.c_str(), std::ios_base::in | std::ios_base::binary);
- return (! ifs.is_open())? FAILURE : importStream(ifs, avatarp);
-}
-
-// virtual
-LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, LLAvatarAppearance* avatarp )
-{
- // *NOTE: changing the type or size of this buffer will require
- // changes in the fscanf() code below.
- // We are using a local max buffer size here to avoid issues
- // if MAX_STRING size changes.
- const U32 PARSE_BUFFER_SIZE = 2048;
- char buffer[PARSE_BUFFER_SIZE]; /* Flawfinder: ignore */
- char uuid_buffer[37]; /* Flawfinder: ignore */
-
- // This data is being generated on the viewer.
- // Impose some sane limits on parameter and texture counts.
- const S32 MAX_WEARABLE_ASSET_TEXTURES = 100;
- const S32 MAX_WEARABLE_ASSET_PARAMETERS = 1000;
-
- if(!avatarp)
- {
- return LLWearable::FAILURE;
- }
-
- // read header and version
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Failed to read wearable asset input stream." << LL_ENDL;
- return LLWearable::FAILURE;
- }
- if ( 1 != sscanf( /* Flawfinder: ignore */
- buffer,
- "LLWearable version %d\n",
- &mDefinitionVersion ) )
- {
- return LLWearable::BAD_HEADER;
- }
-
- // Hack to allow wearables with definition version 24 to still load.
- // This should only affect lindens and NDA'd testers who have saved wearables in 2.0
- // the extra check for version == 24 can be removed before release, once internal testers
- // have loaded these wearables again. See hack pt 2 at bottom of function to ensure that
- // these wearables get re-saved with version definition 22.
- if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion && mDefinitionVersion != 24 )
- {
- LL_WARNS() << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << LL_ENDL;
- return LLWearable::FAILURE;
- }
-
- // name may be empty
- if (!input_stream.good())
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading name" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- input_stream.getline(buffer, PARSE_BUFFER_SIZE);
- mName = buffer;
-
- // description may be empty
- if (!input_stream.good())
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading description" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- input_stream.getline(buffer, PARSE_BUFFER_SIZE);
- mDescription = buffer;
-
- // permissions may have extra empty lines before the correct line
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading permissions" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 perm_version = -1;
- if ( 1 != sscanf( buffer, " permissions %d\n", &perm_version ) ||
- perm_version != 0 )
- {
- LL_WARNS() << "Bad Wearable asset: missing valid permissions" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- if( !mPermissions.importLegacyStream( input_stream ) )
- {
- return LLWearable::FAILURE;
- }
-
- // sale info
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading sale info" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 sale_info_version = -1;
- if ( 1 != sscanf( buffer, " sale_info %d\n", &sale_info_version ) ||
- sale_info_version != 0 )
- {
- LL_WARNS() << "Bad Wearable asset: missing valid sale_info" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- // Sale info used to contain next owner perm. It is now in the
- // permissions. Thus, we read that out, and fix legacy
- // objects. It's possible this op would fail, but it should pick
- // up the vast majority of the tasks.
- bool has_perm_mask = false;
- U32 perm_mask = 0;
- if( !mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask) )
- {
- return LLWearable::FAILURE;
- }
- if(has_perm_mask)
- {
- // fair use fix.
- if(!(perm_mask & PERM_COPY))
- {
- perm_mask |= PERM_TRANSFER;
- }
- mPermissions.setMaskNext(perm_mask);
- }
-
- // wearable type
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading type" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 type = -1;
- if ( 1 != sscanf( buffer, "type %d\n", &type ) )
- {
- LL_WARNS() << "Bad Wearable asset: bad type" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- if( 0 <= type && type < LLWearableType::WT_COUNT )
- {
- setType((LLWearableType::EType)type, avatarp);
- }
- else
- {
- mType = LLWearableType::WT_COUNT;
- LL_WARNS() << "Bad Wearable asset: bad type #" << type << LL_ENDL;
- return LLWearable::FAILURE;
- }
-
- // parameters header
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading parameters header" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 num_parameters = -1;
- if ( 1 != sscanf( buffer, "parameters %d\n", &num_parameters ) )
- {
- LL_WARNS() << "Bad Wearable asset: missing parameters block" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- if ( num_parameters > MAX_WEARABLE_ASSET_PARAMETERS )
- {
- LL_WARNS() << "Bad Wearable asset: too many parameters, "
- << num_parameters << LL_ENDL;
- return LLWearable::FAILURE;
- }
- if( num_parameters != mVisualParamIndexMap.size() )
- {
- LL_WARNS() << "Wearable parameter mismatch. Reading in "
- << num_parameters << " from file, but created "
- << mVisualParamIndexMap.size()
- << " from avatar parameters. type: "
- << getType() << LL_ENDL;
- }
-
- // parameters
- S32 i;
- for( i = 0; i < num_parameters; i++ )
- {
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading parameter #" << i << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 param_id = 0;
- F32 param_weight = 0.f;
- if ( 2 != sscanf( buffer, "%d %f\n", ¶m_id, ¶m_weight ) )
- {
- LL_WARNS() << "Bad Wearable asset: bad parameter, #" << i << LL_ENDL;
- return LLWearable::FAILURE;
- }
- mSavedVisualParamMap[param_id] = param_weight;
- }
-
- // textures header
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading textures header" << i << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 num_textures = -1;
- if ( 1 != sscanf( buffer, "textures %d\n", &num_textures) )
- {
- LL_WARNS() << "Bad Wearable asset: missing textures block" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- if ( num_textures > MAX_WEARABLE_ASSET_TEXTURES )
- {
- LL_WARNS() << "Bad Wearable asset: too many textures, "
- << num_textures << LL_ENDL;
- return LLWearable::FAILURE;
- }
-
- // textures
- for( i = 0; i < num_textures; i++ )
- {
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading textures #" << i << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 te = 0;
- if ( 2 != sscanf( /* Flawfinder: ignore */
- buffer,
- "%d %36s\n",
- &te, uuid_buffer) )
- {
- LL_WARNS() << "Bad Wearable asset: bad texture, #" << i << LL_ENDL;
- return LLWearable::FAILURE;
- }
-
- if (te >= ETextureIndex::TEX_NUM_INDICES) //createLayers() converts to ETextureIndex
- {
- LL_WARNS() << "Bad Wearable asset: bad texture index: " << te << LL_ENDL;
- return LLWearable::FAILURE;
- }
-
- if( !LLUUID::validate( uuid_buffer ) )
- {
- LL_WARNS() << "Bad Wearable asset: bad texture uuid: "
- << uuid_buffer << LL_ENDL;
- return LLWearable::FAILURE;
- }
- LLUUID id = LLUUID(uuid_buffer);
- LLGLTexture* image = gTextureManagerBridgep->getFetchedTexture( id );
- if( mTEMap.find(te) != mTEMap.end() )
- {
- delete mTEMap[te];
- }
- if( mSavedTEMap.find(te) != mSavedTEMap.end() )
- {
- delete mSavedTEMap[te];
- }
-
- LLUUID textureid(uuid_buffer);
- mTEMap[te] = new LLLocalTextureObject(image, textureid);
- mSavedTEMap[te] = new LLLocalTextureObject(image, textureid);
- createLayers(te, avatarp);
- }
-
- // copy all saved param values to working params
- revertValues();
-
- return LLWearable::SUCCESS;
-}
-
-bool LLWearable::getNextPopulatedLine(std::istream& input_stream, char* buffer, U32 buffer_size)
-{
- if (!input_stream.good())
- {
- return false;
- }
-
- do
- {
- input_stream.getline(buffer, buffer_size);
- }
- while (input_stream.good() && buffer[0]=='\0');
-
- return (buffer[0] != '\0');
-}
-
-
-void LLWearable::setType(LLWearableType::EType type, LLAvatarAppearance *avatarp)
-{
- mType = type;
- createVisualParams(avatarp);
-}
-
-
-LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index)
-{
- te_map_t::iterator iter = mTEMap.find(index);
- if( iter != mTEMap.end() )
- {
- LLLocalTextureObject* lto = iter->second;
- return lto;
- }
- return NULL;
-}
-
-const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const
-{
- te_map_t::const_iterator iter = mTEMap.find(index);
- if( iter != mTEMap.end() )
- {
- const LLLocalTextureObject* lto = iter->second;
- return lto;
- }
- return NULL;
-}
-
-std::vector<LLLocalTextureObject*> LLWearable::getLocalTextureListSeq()
-{
- std::vector<LLLocalTextureObject*> result;
-
- for(te_map_t::value_type& te_pair : mTEMap)
- {
- LLLocalTextureObject* lto = te_pair.second;
- result.push_back(lto);
- }
-
- return result;
-}
-
-void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject <o)
-{
- if( mTEMap.find(index) != mTEMap.end() )
- {
- mTEMap.erase(index);
- }
- mTEMap[index] = new LLLocalTextureObject(lto);
-}
-
-void LLWearable::revertValues()
-{
- // FIXME DRANO - this triggers changes to driven params on avatar, potentially clobbering baked appearance.
-
- //update saved settings so wearable is no longer dirty
- // One loop should be necessary here
- for (param_map_t::value_type& vp_pair : mSavedVisualParamMap)
- {
- S32 id = vp_pair.first;
- LLVisualParam *param = getVisualParam(id);
- if(param)
- {
- F32 value = vp_pair.second;
- param->setWeight(value);
- mSavedVisualParamMap[id] = param->getWeight();
- }
- }
-
- syncImages(mSavedTEMap, mTEMap);
-}
-
-void LLWearable::saveValues()
-{
- //update saved settings so wearable is no longer dirty
- mSavedVisualParamMap.clear();
- for (const visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
- {
- S32 id = vp_pair.first;
- LLVisualParam *wearable_param = vp_pair.second;
- F32 value = wearable_param->getWeight();
- mSavedVisualParamMap[id] = value;
- }
-
- // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed)
- syncImages(mTEMap, mSavedTEMap);
-}
-
-void LLWearable::syncImages(te_map_t &src, te_map_t &dst)
-{
- // Deep copy of src (copies only those tes that are current, filling in defaults where needed)
- for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
- {
- if (LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex) te) == mType)
- {
- te_map_t::const_iterator iter = src.find(te);
- LLUUID image_id;
- LLGLTexture *image = NULL;
- LLLocalTextureObject *lto = NULL;
- if(iter != src.end())
- {
- // there's a Local Texture Object in the source image map. Use this to populate the values to store in the destination image map.
- lto = iter->second;
- image = lto->getImage();
- image_id = lto->getID();
- }
- else
- {
- // there is no Local Texture Object in the source image map. Get defaults values for populating the destination image map.
- image_id = getDefaultTextureImageID((ETextureIndex) te);
- image = gTextureManagerBridgep->getFetchedTexture( image_id );
- }
-
- if( dst.find(te) != dst.end() )
- {
- // there's already an entry in the destination map for the texture. Just update its values.
- dst[te]->setImage(image);
- dst[te]->setID(image_id);
- }
- else
- {
- // no entry found in the destination map, we need to create a new Local Texture Object
- dst[te] = new LLLocalTextureObject(image, image_id);
- }
-
- if( lto )
- {
- // If we pulled values from a Local Texture Object in the source map, make sure the proper flags are set in the new (or updated) entry in the destination map.
- dst[te]->setBakedReady(lto->getBakedReady());
- dst[te]->setDiscard(lto->getDiscard());
- }
- }
- }
-}
-
-void LLWearable::destroyTextures()
-{
- std::for_each(mTEMap.begin(), mTEMap.end(), DeletePairedPointer());
- mTEMap.clear();
-
- std::for_each(mSavedTEMap.begin(), mSavedTEMap.end(), DeletePairedPointer());
- mSavedTEMap.clear();
-}
-
-void LLWearable::addVisualParam(LLVisualParam *param)
-{
- if( mVisualParamIndexMap[param->getID()] )
- {
- delete mVisualParamIndexMap[param->getID()];
- }
- param->setIsDummy(false);
- param->setParamLocation(LOC_WEARABLE);
- mVisualParamIndexMap[param->getID()] = param;
- mSavedVisualParamMap[param->getID()] = param->getDefaultWeight();
-}
-
-
-void LLWearable::setVisualParamWeight(S32 param_index, F32 value)
-{
- if( is_in_map(mVisualParamIndexMap, param_index ) )
- {
- LLVisualParam *wearable_param = mVisualParamIndexMap[param_index];
- wearable_param->setWeight(value);
- }
- else
- {
- LL_ERRS() << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
- }
-}
-
-F32 LLWearable::getVisualParamWeight(S32 param_index) const
-{
- if( is_in_map(mVisualParamIndexMap, param_index ) )
- {
- const LLVisualParam *wearable_param = mVisualParamIndexMap.find(param_index)->second;
- return wearable_param->getWeight();
- }
- else
- {
- LL_WARNS() << "LLWerable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
- }
- return (F32)-1.0;
-}
-
-LLVisualParam* LLWearable::getVisualParam(S32 index) const
-{
- visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.find(index);
- return (iter == mVisualParamIndexMap.end()) ? NULL : iter->second;
-}
-
-
-void LLWearable::getVisualParams(visual_param_vec_t &list)
-{
- // add all visual params to the passed-in vector
- for(visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
- {
- list.push_back(vp_pair.second);
- }
-}
-
-void LLWearable::animateParams(F32 delta)
-{
- for(visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
- {
- LLVisualParam *param = (LLVisualParam*)vp_pair.second;
- param->animate(delta);
- }
-}
-
-LLColor4 LLWearable::getClothesColor(S32 te) const
-{
- LLColor4 color;
- U32 param_name[3];
- if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
- {
- for( U8 index = 0; index < 3; index++ )
- {
- color.mV[index] = getVisualParamWeight(param_name[index]);
- }
- }
- return color;
-}
-
-void LLWearable::setClothesColor( S32 te, const LLColor4& new_color)
-{
- U32 param_name[3];
- if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
- {
- for( U8 index = 0; index < 3; index++ )
- {
- setVisualParamWeight(param_name[index], new_color.mV[index]);
- }
- }
-}
-
-void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)
-{
- if (!avatarp) return;
-
- // Pull params
- for( LLVisualParam* param = avatarp->getFirstVisualParam(); param; param = avatarp->getNextVisualParam() )
- {
- // cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the
- // avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way.
- if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (!((LLViewerVisualParam*)param)->getCrossWearable()) )
- {
- S32 param_id = param->getID();
- F32 weight = getVisualParamWeight(param_id);
-
- avatarp->setVisualParamWeight( param_id, weight);
- }
- }
-}
-
-
-std::string terse_F32_to_string(F32 f)
-{
- std::string r = llformat("%.2f", f);
- S32 len = r.length();
-
- // "1.20" -> "1.2"
- // "24.00" -> "24."
- while (len > 0 && ('0' == r[len - 1]))
- {
- r.erase(len-1, 1);
- len--;
- }
- if ('.' == r[len - 1])
- {
- // "24." -> "24"
- r.erase(len-1, 1);
- }
- else if (('-' == r[0]) && ('0' == r[1]))
- {
- // "-0.59" -> "-.59"
- r.erase(1, 1);
- }
- else if ('0' == r[0])
- {
- // "0.59" -> ".59"
- r.erase(0, 1);
- }
- return r;
-}
-
+/** + * @file llwearable.cpp + * @brief LLWearable class implementation + * + * $LicenseInfo:firstyear=2002&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$ + */ + +#include "linden_common.h" + +#include "llavatarappearance.h" +#include "lllocaltextureobject.h" +#include "lltexlayer.h" +#include "lltexturemanagerbridge.h" +#include "llvisualparam.h" +#include "llavatarappearancedefines.h" +#include "llwearable.h" +#include "boost/bind.hpp" + +using namespace LLAvatarAppearanceDefines; + +// static +S32 LLWearable::sCurrentDefinitionVersion = 1; + +// Private local functions +static std::string terse_F32_to_string(F32 f); + +LLWearable::LLWearable() + : mDefinitionVersion(-1), + mName(), + mDescription(), + mPermissions(), + mSaleInfo(), + mType(LLWearableType::WT_NONE), + mSavedVisualParamMap(), + mVisualParamIndexMap(), + mTEMap(), + mSavedTEMap() +{ +} + +// virtual +LLWearable::~LLWearable() +{ + for (visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap) + { + LLVisualParam* vp = vp_pair.second; + vp->clearNextParam(); + delete vp; + vp_pair.second = NULL; + } + + destroyTextures(); +} + +const std::string& LLWearable::getTypeLabel() const +{ + return LLWearableType::getInstance()->getTypeLabel(mType); +} + +const std::string& LLWearable::getTypeName() const +{ + return LLWearableType::getInstance()->getTypeName(mType); +} + +LLAssetType::EType LLWearable::getAssetType() const +{ + return LLWearableType::getInstance()->getAssetType(mType); +} + +bool LLWearable::exportFile(const std::string& filename) const +{ + llofstream ofs(filename.c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary); + return ofs.is_open() && exportStream(ofs); +} + +// virtual +bool LLWearable::exportStream( std::ostream& output_stream ) const +{ + if (!output_stream.good()) return false; + + // header and version + output_stream << "LLWearable version " << mDefinitionVersion << "\n"; + // name + output_stream << mName << "\n"; + // description + output_stream << mDescription << "\n"; + + // permissions + if( !mPermissions.exportLegacyStream( output_stream ) ) + { + return false; + } + + // sale info + if( !mSaleInfo.exportLegacyStream( output_stream ) ) + { + return false; + } + + // wearable type + output_stream << "type " << (S32) getType() << "\n"; + + // parameters + output_stream << "parameters " << mVisualParamIndexMap.size() << "\n"; + + for (const visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap) + { + S32 param_id = vp_pair.first; + const LLVisualParam* param = vp_pair.second; + F32 param_weight = param->getWeight(); + output_stream << param_id << " " << terse_F32_to_string( param_weight ) << "\n"; + } + + // texture entries + output_stream << "textures " << mTEMap.size() << "\n"; + + for (const te_map_t::value_type& te_pair : mTEMap) + { + S32 te = te_pair.first; + const LLUUID& image_id = te_pair.second->getID(); + output_stream << te << " " << image_id << "\n"; + } + return true; +} + +void LLWearable::createVisualParams(LLAvatarAppearance *avatarp) +{ + for (LLViewerVisualParam* param = (LLViewerVisualParam*) avatarp->getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) avatarp->getNextVisualParam()) + { + if (param->getWearableType() == mType) + { + LLVisualParam *clone_param = param->cloneParam(this); + clone_param->setParamLocation(LOC_UNKNOWN); + clone_param->setParamLocation(LOC_WEARABLE); + addVisualParam(clone_param); + } + } + + // resync driver parameters to point to the newly cloned driven parameters + for (visual_param_index_map_t::value_type& param_pair : mVisualParamIndexMap) + { + LLVisualParam* param = param_pair.second; + LLVisualParam*(LLWearable::*wearable_function)(S32)const = &LLWearable::getVisualParam; + // need this line to disambiguate between versions of LLCharacter::getVisualParam() + LLVisualParam*(LLAvatarAppearance::*param_function)(S32)const = &LLAvatarAppearance::getVisualParam; + param->resetDrivenParams(); + if(!param->linkDrivenParams(boost::bind(wearable_function,(LLWearable*)this, _1), false)) + { + if( !param->linkDrivenParams(boost::bind(param_function,avatarp,_1 ), true)) + { + LL_DEBUGS("Avatar") << "could not link driven params for wearable " << getName() << " id: " << param->getID() << LL_ENDL; + continue; + } + } + } +} + +void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp) +{ + LLTexLayerSet *layer_set = NULL; + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearance::getDictionary()->getTexture((ETextureIndex)te); + if (texture_dict && texture_dict->mIsUsedByBakedTexture) + { + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + + layer_set = avatarp->getAvatarLayerSet(baked_index); + } + + if (layer_set) + { + layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this); + } + else + { + LL_WARNS() << "could not find layerset for LTO in wearable!" << LL_ENDL; + } +} + +LLWearable::EImportResult LLWearable::importFile(const std::string& filename, + LLAvatarAppearance* avatarp ) +{ + llifstream ifs(filename.c_str(), std::ios_base::in | std::ios_base::binary); + return (! ifs.is_open())? FAILURE : importStream(ifs, avatarp); +} + +// virtual +LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, LLAvatarAppearance* avatarp ) +{ + // *NOTE: changing the type or size of this buffer will require + // changes in the fscanf() code below. + // We are using a local max buffer size here to avoid issues + // if MAX_STRING size changes. + const U32 PARSE_BUFFER_SIZE = 2048; + char buffer[PARSE_BUFFER_SIZE]; /* Flawfinder: ignore */ + char uuid_buffer[37]; /* Flawfinder: ignore */ + + // This data is being generated on the viewer. + // Impose some sane limits on parameter and texture counts. + const S32 MAX_WEARABLE_ASSET_TEXTURES = 100; + const S32 MAX_WEARABLE_ASSET_PARAMETERS = 1000; + + if(!avatarp) + { + return LLWearable::FAILURE; + } + + // read header and version + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) + { + LL_WARNS() << "Failed to read wearable asset input stream." << LL_ENDL; + return LLWearable::FAILURE; + } + if ( 1 != sscanf( /* Flawfinder: ignore */ + buffer, + "LLWearable version %d\n", + &mDefinitionVersion ) ) + { + return LLWearable::BAD_HEADER; + } + + // Hack to allow wearables with definition version 24 to still load. + // This should only affect lindens and NDA'd testers who have saved wearables in 2.0 + // the extra check for version == 24 can be removed before release, once internal testers + // have loaded these wearables again. See hack pt 2 at bottom of function to ensure that + // these wearables get re-saved with version definition 22. + if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion && mDefinitionVersion != 24 ) + { + LL_WARNS() << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << LL_ENDL; + return LLWearable::FAILURE; + } + + // name may be empty + if (!input_stream.good()) + { + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading name" << LL_ENDL; + return LLWearable::FAILURE; + } + input_stream.getline(buffer, PARSE_BUFFER_SIZE); + mName = buffer; + + // description may be empty + if (!input_stream.good()) + { + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading description" << LL_ENDL; + return LLWearable::FAILURE; + } + input_stream.getline(buffer, PARSE_BUFFER_SIZE); + mDescription = buffer; + + // permissions may have extra empty lines before the correct line + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) + { + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading permissions" << LL_ENDL; + return LLWearable::FAILURE; + } + S32 perm_version = -1; + if ( 1 != sscanf( buffer, " permissions %d\n", &perm_version ) || + perm_version != 0 ) + { + LL_WARNS() << "Bad Wearable asset: missing valid permissions" << LL_ENDL; + return LLWearable::FAILURE; + } + if( !mPermissions.importLegacyStream( input_stream ) ) + { + return LLWearable::FAILURE; + } + + // sale info + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) + { + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading sale info" << LL_ENDL; + return LLWearable::FAILURE; + } + S32 sale_info_version = -1; + if ( 1 != sscanf( buffer, " sale_info %d\n", &sale_info_version ) || + sale_info_version != 0 ) + { + LL_WARNS() << "Bad Wearable asset: missing valid sale_info" << LL_ENDL; + return LLWearable::FAILURE; + } + // Sale info used to contain next owner perm. It is now in the + // permissions. Thus, we read that out, and fix legacy + // objects. It's possible this op would fail, but it should pick + // up the vast majority of the tasks. + bool has_perm_mask = false; + U32 perm_mask = 0; + if( !mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask) ) + { + return LLWearable::FAILURE; + } + if(has_perm_mask) + { + // fair use fix. + if(!(perm_mask & PERM_COPY)) + { + perm_mask |= PERM_TRANSFER; + } + mPermissions.setMaskNext(perm_mask); + } + + // wearable type + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) + { + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading type" << LL_ENDL; + return LLWearable::FAILURE; + } + S32 type = -1; + if ( 1 != sscanf( buffer, "type %d\n", &type ) ) + { + LL_WARNS() << "Bad Wearable asset: bad type" << LL_ENDL; + return LLWearable::FAILURE; + } + if( 0 <= type && type < LLWearableType::WT_COUNT ) + { + setType((LLWearableType::EType)type, avatarp); + } + else + { + mType = LLWearableType::WT_COUNT; + LL_WARNS() << "Bad Wearable asset: bad type #" << type << LL_ENDL; + return LLWearable::FAILURE; + } + + // parameters header + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) + { + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading parameters header" << LL_ENDL; + return LLWearable::FAILURE; + } + S32 num_parameters = -1; + if ( 1 != sscanf( buffer, "parameters %d\n", &num_parameters ) ) + { + LL_WARNS() << "Bad Wearable asset: missing parameters block" << LL_ENDL; + return LLWearable::FAILURE; + } + if ( num_parameters > MAX_WEARABLE_ASSET_PARAMETERS ) + { + LL_WARNS() << "Bad Wearable asset: too many parameters, " + << num_parameters << LL_ENDL; + return LLWearable::FAILURE; + } + if( num_parameters != mVisualParamIndexMap.size() ) + { + LL_WARNS() << "Wearable parameter mismatch. Reading in " + << num_parameters << " from file, but created " + << mVisualParamIndexMap.size() + << " from avatar parameters. type: " + << getType() << LL_ENDL; + } + + // parameters + S32 i; + for( i = 0; i < num_parameters; i++ ) + { + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) + { + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading parameter #" << i << LL_ENDL; + return LLWearable::FAILURE; + } + S32 param_id = 0; + F32 param_weight = 0.f; + if ( 2 != sscanf( buffer, "%d %f\n", ¶m_id, ¶m_weight ) ) + { + LL_WARNS() << "Bad Wearable asset: bad parameter, #" << i << LL_ENDL; + return LLWearable::FAILURE; + } + mSavedVisualParamMap[param_id] = param_weight; + } + + // textures header + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) + { + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading textures header" << i << LL_ENDL; + return LLWearable::FAILURE; + } + S32 num_textures = -1; + if ( 1 != sscanf( buffer, "textures %d\n", &num_textures) ) + { + LL_WARNS() << "Bad Wearable asset: missing textures block" << LL_ENDL; + return LLWearable::FAILURE; + } + if ( num_textures > MAX_WEARABLE_ASSET_TEXTURES ) + { + LL_WARNS() << "Bad Wearable asset: too many textures, " + << num_textures << LL_ENDL; + return LLWearable::FAILURE; + } + + // textures + for( i = 0; i < num_textures; i++ ) + { + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) + { + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading textures #" << i << LL_ENDL; + return LLWearable::FAILURE; + } + S32 te = 0; + if ( 2 != sscanf( /* Flawfinder: ignore */ + buffer, + "%d %36s\n", + &te, uuid_buffer) ) + { + LL_WARNS() << "Bad Wearable asset: bad texture, #" << i << LL_ENDL; + return LLWearable::FAILURE; + } + + if (te >= ETextureIndex::TEX_NUM_INDICES) //createLayers() converts to ETextureIndex + { + LL_WARNS() << "Bad Wearable asset: bad texture index: " << te << LL_ENDL; + return LLWearable::FAILURE; + } + + if( !LLUUID::validate( uuid_buffer ) ) + { + LL_WARNS() << "Bad Wearable asset: bad texture uuid: " + << uuid_buffer << LL_ENDL; + return LLWearable::FAILURE; + } + LLUUID id = LLUUID(uuid_buffer); + LLGLTexture* image = gTextureManagerBridgep->getFetchedTexture( id ); + if( mTEMap.find(te) != mTEMap.end() ) + { + delete mTEMap[te]; + } + if( mSavedTEMap.find(te) != mSavedTEMap.end() ) + { + delete mSavedTEMap[te]; + } + + LLUUID textureid(uuid_buffer); + mTEMap[te] = new LLLocalTextureObject(image, textureid); + mSavedTEMap[te] = new LLLocalTextureObject(image, textureid); + createLayers(te, avatarp); + } + + // copy all saved param values to working params + revertValues(); + + return LLWearable::SUCCESS; +} + +bool LLWearable::getNextPopulatedLine(std::istream& input_stream, char* buffer, U32 buffer_size) +{ + if (!input_stream.good()) + { + return false; + } + + do + { + input_stream.getline(buffer, buffer_size); + } + while (input_stream.good() && buffer[0]=='\0'); + + return (buffer[0] != '\0'); +} + + +void LLWearable::setType(LLWearableType::EType type, LLAvatarAppearance *avatarp) +{ + mType = type; + createVisualParams(avatarp); +} + + +LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) +{ + te_map_t::iterator iter = mTEMap.find(index); + if( iter != mTEMap.end() ) + { + LLLocalTextureObject* lto = iter->second; + return lto; + } + return NULL; +} + +const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const +{ + te_map_t::const_iterator iter = mTEMap.find(index); + if( iter != mTEMap.end() ) + { + const LLLocalTextureObject* lto = iter->second; + return lto; + } + return NULL; +} + +std::vector<LLLocalTextureObject*> LLWearable::getLocalTextureListSeq() +{ + std::vector<LLLocalTextureObject*> result; + + for(te_map_t::value_type& te_pair : mTEMap) + { + LLLocalTextureObject* lto = te_pair.second; + result.push_back(lto); + } + + return result; +} + +void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject <o) +{ + if( mTEMap.find(index) != mTEMap.end() ) + { + mTEMap.erase(index); + } + mTEMap[index] = new LLLocalTextureObject(lto); +} + +void LLWearable::revertValues() +{ + // FIXME DRANO - this triggers changes to driven params on avatar, potentially clobbering baked appearance. + + //update saved settings so wearable is no longer dirty + // One loop should be necessary here + for (param_map_t::value_type& vp_pair : mSavedVisualParamMap) + { + S32 id = vp_pair.first; + LLVisualParam *param = getVisualParam(id); + if(param) + { + F32 value = vp_pair.second; + param->setWeight(value); + mSavedVisualParamMap[id] = param->getWeight(); + } + } + + syncImages(mSavedTEMap, mTEMap); +} + +void LLWearable::saveValues() +{ + //update saved settings so wearable is no longer dirty + mSavedVisualParamMap.clear(); + for (const visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap) + { + S32 id = vp_pair.first; + LLVisualParam *wearable_param = vp_pair.second; + F32 value = wearable_param->getWeight(); + mSavedVisualParamMap[id] = value; + } + + // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed) + syncImages(mTEMap, mSavedTEMap); +} + +void LLWearable::syncImages(te_map_t &src, te_map_t &dst) +{ + // Deep copy of src (copies only those tes that are current, filling in defaults where needed) + for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) + { + if (LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex) te) == mType) + { + te_map_t::const_iterator iter = src.find(te); + LLUUID image_id; + LLGLTexture *image = NULL; + LLLocalTextureObject *lto = NULL; + if(iter != src.end()) + { + // there's a Local Texture Object in the source image map. Use this to populate the values to store in the destination image map. + lto = iter->second; + image = lto->getImage(); + image_id = lto->getID(); + } + else + { + // there is no Local Texture Object in the source image map. Get defaults values for populating the destination image map. + image_id = getDefaultTextureImageID((ETextureIndex) te); + image = gTextureManagerBridgep->getFetchedTexture( image_id ); + } + + if( dst.find(te) != dst.end() ) + { + // there's already an entry in the destination map for the texture. Just update its values. + dst[te]->setImage(image); + dst[te]->setID(image_id); + } + else + { + // no entry found in the destination map, we need to create a new Local Texture Object + dst[te] = new LLLocalTextureObject(image, image_id); + } + + if( lto ) + { + // If we pulled values from a Local Texture Object in the source map, make sure the proper flags are set in the new (or updated) entry in the destination map. + dst[te]->setBakedReady(lto->getBakedReady()); + dst[te]->setDiscard(lto->getDiscard()); + } + } + } +} + +void LLWearable::destroyTextures() +{ + std::for_each(mTEMap.begin(), mTEMap.end(), DeletePairedPointer()); + mTEMap.clear(); + + std::for_each(mSavedTEMap.begin(), mSavedTEMap.end(), DeletePairedPointer()); + mSavedTEMap.clear(); +} + +void LLWearable::addVisualParam(LLVisualParam *param) +{ + if( mVisualParamIndexMap[param->getID()] ) + { + delete mVisualParamIndexMap[param->getID()]; + } + param->setIsDummy(false); + param->setParamLocation(LOC_WEARABLE); + mVisualParamIndexMap[param->getID()] = param; + mSavedVisualParamMap[param->getID()] = param->getDefaultWeight(); +} + + +void LLWearable::setVisualParamWeight(S32 param_index, F32 value) +{ + if( is_in_map(mVisualParamIndexMap, param_index ) ) + { + LLVisualParam *wearable_param = mVisualParamIndexMap[param_index]; + wearable_param->setWeight(value); + } + else + { + LL_ERRS() << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL; + } +} + +F32 LLWearable::getVisualParamWeight(S32 param_index) const +{ + if( is_in_map(mVisualParamIndexMap, param_index ) ) + { + const LLVisualParam *wearable_param = mVisualParamIndexMap.find(param_index)->second; + return wearable_param->getWeight(); + } + else + { + LL_WARNS() << "LLWerable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL; + } + return (F32)-1.0; +} + +LLVisualParam* LLWearable::getVisualParam(S32 index) const +{ + visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.find(index); + return (iter == mVisualParamIndexMap.end()) ? NULL : iter->second; +} + + +void LLWearable::getVisualParams(visual_param_vec_t &list) +{ + // add all visual params to the passed-in vector + for(visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap) + { + list.push_back(vp_pair.second); + } +} + +void LLWearable::animateParams(F32 delta) +{ + for(visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap) + { + LLVisualParam *param = (LLVisualParam*)vp_pair.second; + param->animate(delta); + } +} + +LLColor4 LLWearable::getClothesColor(S32 te) const +{ + LLColor4 color; + U32 param_name[3]; + if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) ) + { + for( U8 index = 0; index < 3; index++ ) + { + color.mV[index] = getVisualParamWeight(param_name[index]); + } + } + return color; +} + +void LLWearable::setClothesColor( S32 te, const LLColor4& new_color) +{ + U32 param_name[3]; + if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) ) + { + for( U8 index = 0; index < 3; index++ ) + { + setVisualParamWeight(param_name[index], new_color.mV[index]); + } + } +} + +void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp) +{ + if (!avatarp) return; + + // Pull params + for( LLVisualParam* param = avatarp->getFirstVisualParam(); param; param = avatarp->getNextVisualParam() ) + { + // cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the + // avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way. + if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (!((LLViewerVisualParam*)param)->getCrossWearable()) ) + { + S32 param_id = param->getID(); + F32 weight = getVisualParamWeight(param_id); + + avatarp->setVisualParamWeight( param_id, weight); + } + } +} + + +std::string terse_F32_to_string(F32 f) +{ + std::string r = llformat("%.2f", f); + S32 len = r.length(); + + // "1.20" -> "1.2" + // "24.00" -> "24." + while (len > 0 && ('0' == r[len - 1])) + { + r.erase(len-1, 1); + len--; + } + if ('.' == r[len - 1]) + { + // "24." -> "24" + r.erase(len-1, 1); + } + else if (('-' == r[0]) && ('0' == r[1])) + { + // "-0.59" -> "-.59" + r.erase(1, 1); + } + else if ('0' == r[0]) + { + // "0.59" -> ".59" + r.erase(0, 1); + } + return r; +} + |