diff options
Diffstat (limited to 'indra/llappearance/llwearable.cpp')
-rw-r--r-- | indra/llappearance/llwearable.cpp | 474 |
1 files changed, 474 insertions, 0 deletions
diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp new file mode 100644 index 0000000000..ea14c6320f --- /dev/null +++ b/indra/llappearance/llwearable.cpp @@ -0,0 +1,474 @@ +/** + * @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" + +using namespace LLAvatarAppearanceDefines; + +// static +S32 LLWearable::sCurrentDefinitionVersion = 1; + +// Private local functions +static std::string terse_F32_to_string(F32 f); + +// virtual +LLWearable::~LLWearable() +{ +} + +const std::string& LLWearable::getTypeLabel() const +{ + return LLWearableType::getTypeLabel(mType); +} + +const std::string& LLWearable::getTypeName() const +{ + return LLWearableType::getTypeName(mType); +} + +LLAssetType::EType LLWearable::getAssetType() const +{ + return LLWearableType::getAssetType(mType); +} + +// virtual +BOOL LLWearable::exportFile(LLFILE* file) const +{ + // header and version + if( fprintf( file, "LLWearable version %d\n", mDefinitionVersion ) < 0 ) + { + return FALSE; + } + + // name + if( fprintf( file, "%s\n", mName.c_str() ) < 0 ) + { + return FALSE; + } + + // description + if( fprintf( file, "%s\n", mDescription.c_str() ) < 0 ) + { + return FALSE; + } + + // permissions + if( !mPermissions.exportFile( file ) ) + { + return FALSE; + } + + // sale info + if( !mSaleInfo.exportFile( file ) ) + { + return FALSE; + } + + // wearable type + S32 type = (S32)mType; + if( fprintf( file, "type %d\n", type ) < 0 ) + { + return FALSE; + } + + // parameters + S32 num_parameters = mVisualParamIndexMap.size(); + if( fprintf( file, "parameters %d\n", num_parameters ) < 0 ) + { + return FALSE; + } + + for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); + iter != mVisualParamIndexMap.end(); + ++iter) + { + S32 param_id = iter->first; + const LLVisualParam* param = iter->second; + F32 param_weight = param->getWeight(); + if( fprintf( file, "%d %s\n", param_id, terse_F32_to_string( param_weight ).c_str() ) < 0 ) + { + return FALSE; + } + } + + // texture entries + S32 num_textures = mTextureIDMap.size(); + if( fprintf( file, "textures %d\n", num_textures ) < 0 ) + { + return FALSE; + } + + for (texture_id_map_t::const_iterator iter = mTextureIDMap.begin(); iter != mTextureIDMap.end(); ++iter) + { + S32 te = iter->first; + const LLUUID& image_id = iter->second; + if( fprintf( file, "%d %s\n", te, image_id.asString().c_str()) < 0 ) + { + return FALSE; + } + } + return TRUE; +} + + +// virtual +LLWearable::EImportResult LLWearable::importFile( LLFILE* file ) +{ + // *NOTE: changing the type or size of this buffer will require + // changes in the fscanf() code below. You would be better off + // rewriting this to use streams and not require an open FILE. + char text_buffer[2048]; /* Flawfinder: ignore */ + S32 fields_read = 0; + + // read header and version + fields_read = fscanf( file, "LLWearable version %d\n", &mDefinitionVersion ); + if( fields_read != 1 ) + { + return LLWearable::BAD_HEADER; + } + + + // Temporary 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 ) + { + llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl; + return LLWearable::FAILURE; + } + + // name + int next_char = fgetc( file ); /* Flawfinder: ignore */ + if( '\n' == next_char ) + { + // no name + mName = ""; + } + else + { + ungetc( next_char, file ); + fields_read = fscanf( /* Flawfinder: ignore */ + file, + "%2047[^\n]", + text_buffer); + if( (1 != fields_read) || (fgetc( file ) != '\n') ) /* Flawfinder: ignore */ + { + llwarns << "Bad Wearable asset: early end of file" << llendl; + return LLWearable::FAILURE; + } + mName = text_buffer; + } + + // description + next_char = fgetc( file ); /* Flawfinder: ignore */ + if( '\n' == next_char ) + { + // no description + mDescription = ""; + } + else + { + ungetc( next_char, file ); + fields_read = fscanf( /* Flawfinder: ignore */ + file, + "%2047[^\n]", + text_buffer ); + if( (1 != fields_read) || (fgetc( file ) != '\n') ) /* Flawfinder: ignore */ + { + llwarns << "Bad Wearable asset: early end of file" << llendl; + return LLWearable::FAILURE; + } + mDescription = text_buffer; + } + + // permissions + S32 perm_version; + fields_read = fscanf( file, " permissions %d\n", &perm_version ); + if( (fields_read != 1) || (perm_version != 0) ) + { + llwarns << "Bad Wearable asset: missing permissions" << llendl; + return LLWearable::FAILURE; + } + if( !mPermissions.importFile( file ) ) + { + return LLWearable::FAILURE; + } + + // sale info + S32 sale_info_version; + fields_read = fscanf( file, " sale_info %d\n", &sale_info_version ); + if( (fields_read != 1) || (sale_info_version != 0) ) + { + llwarns << "Bad Wearable asset: missing sale_info" << llendl; + 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.importFile(file, 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 + S32 type = -1; + fields_read = fscanf( file, "type %d\n", &type ); + if( fields_read != 1 ) + { + llwarns << "Bad Wearable asset: bad type" << llendl; + return LLWearable::FAILURE; + } + if( 0 <= type && type < LLWearableType::WT_COUNT ) + { + setType((LLWearableType::EType)type); + } + else + { + mType = LLWearableType::WT_COUNT; + llwarns << "Bad Wearable asset: bad type #" << type << llendl; + return LLWearable::FAILURE; + } + + // parameters header + S32 num_parameters = 0; + fields_read = fscanf( file, "parameters %d\n", &num_parameters ); + if( fields_read != 1 ) + { + llwarns << "Bad Wearable asset: missing parameters block" << llendl; + return LLWearable::FAILURE; + } + + if( num_parameters != mVisualParamIndexMap.size() ) + { + llwarns << "Wearable parameter mismatch. Reading in " << num_parameters << " from file, but created " << mVisualParamIndexMap.size() << " from avatar parameters. type: " << mType << llendl; + } + + // parameters + S32 i; + for( i = 0; i < num_parameters; i++ ) + { + S32 param_id = 0; + F32 param_weight = 0.f; + fields_read = fscanf( file, "%d %f\n", ¶m_id, ¶m_weight ); + if( fields_read != 2 ) + { + llwarns << "Bad Wearable asset: bad parameter, #" << i << llendl; + return LLWearable::FAILURE; + } + mSavedVisualParamMap[param_id] = param_weight; + } + + // textures header + S32 num_textures = 0; + fields_read = fscanf( file, "textures %d\n", &num_textures); + if( fields_read != 1 ) + { + llwarns << "Bad Wearable asset: missing textures block" << llendl; + return LLWearable::FAILURE; + } + + // textures + mTextureIDMap.clear(); + for( i = 0; i < num_textures; i++ ) + { + S32 te = 0; + fields_read = fscanf( /* Flawfinder: ignore */ + file, + "%d %2047s\n", + &te, text_buffer); + if( fields_read != 2 ) + { + llwarns << "Bad Wearable asset: bad texture, #" << i << llendl; + return LLWearable::FAILURE; + } + + if( !LLUUID::validate( text_buffer ) ) + { + llwarns << "Bad Wearable asset: bad texture uuid: " << text_buffer << llendl; + return LLWearable::FAILURE; + } + LLUUID id = LLUUID(text_buffer); + mTextureIDMap[te] = id; + } + + return LLWearable::SUCCESS; +} + + +void LLWearable::setType(LLWearableType::EType type) +{ + mType = type; + createVisualParams(); +} + + +void LLWearable::addVisualParam(LLVisualParam *param) +{ + if( mVisualParamIndexMap[param->getID()] ) + { + delete mVisualParamIndexMap[param->getID()]; + } + param->setIsDummy(FALSE); + mVisualParamIndexMap[param->getID()] = param; + mSavedVisualParamMap[param->getID()] = param->getDefaultWeight(); +} + + +void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_bake) +{ + if( is_in_map(mVisualParamIndexMap, param_index ) ) + { + LLVisualParam *wearable_param = mVisualParamIndexMap[param_index]; + wearable_param->setWeight(value, upload_bake); + } + else + { + llerrs << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << llendl; + } +} + +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 + { + llwarns << "LLWerable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << llendl; + } + 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) +{ + visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin(); + visual_param_index_map_t::iterator end = mVisualParamIndexMap.end(); + + // add all visual params to the passed-in vector + for( ; iter != end; ++iter ) + { + list.push_back(iter->second); + } +} + +void LLWearable::animateParams(F32 delta, BOOL upload_bake) +{ + for(visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin(); + iter != mVisualParamIndexMap.end(); + ++iter) + { + LLVisualParam *param = (LLVisualParam*) iter->second; + param->animate(delta, upload_bake); + } +} + +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, BOOL upload_bake ) +{ + 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], upload_bake); + } + } +} + +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; +} + |