Files
SingularityViewer/indra/newview/llwearable.cpp
2011-06-09 01:35:49 -05:00

1124 lines
27 KiB
C++

/**
* @file llwearable.cpp
* @brief LLWearable class implementation
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "imageids.h"
#include "llassetstorage.h"
#include "lldbstrings.h"
#include "lldir.h"
#include "llquantize.h"
#include "llagent.h"
#include "llagentcamera.h"
#include "llagentwearables.h"
#include "llassetuploadresponders.h"
#include "llviewerwindow.h"
#include "llfloatercustomize.h"
#include "llinventorymodel.h"
#include "llviewertexturelist.h"
#include "llviewerinventory.h"
#include "llviewerregion.h"
#include "llvoavatar.h"
#include "llwearable.h"
using namespace LLVOAvatarDefines;
// static
S32 LLWearable::sCurrentDefinitionVersion = 1;
// static
const std::string LLWearable::sTypeName[ WT_COUNT+1 ] =
{
"shape",
"skin",
"hair",
"eyes",
"shirt",
"pants",
"shoes",
"socks",
"jacket",
"gloves",
"undershirt",
"underpants",
"skirt",
"alpha",
"tattoo",
"physics",
"invalid"
};
// static
const std::string LLWearable::sTypeLabel[ WT_COUNT+1 ] =
{
"Shape",
"Skin",
"Hair",
"Eyes",
"Shirt",
"Pants",
"Shoes",
"Socks",
"Jacket",
"Gloves",
"Undershirt",
"Underpants",
"Skirt",
"Alpha",
"Tattoo",
"Physics",
"invalid"
};
// static
LLAssetType::EType LLWearable::typeToAssetType(EWearableType wearable_type)
{
switch( wearable_type )
{
case WT_SHAPE:
case WT_SKIN:
case WT_HAIR:
case WT_EYES:
return LLAssetType::AT_BODYPART;
case WT_SHIRT:
case WT_PANTS:
case WT_SHOES:
case WT_SOCKS:
case WT_JACKET:
case WT_GLOVES:
case WT_UNDERSHIRT:
case WT_UNDERPANTS:
case WT_SKIRT:
case WT_ALPHA:
case WT_TATTOO:
case WT_PHYSICS:
return LLAssetType::AT_CLOTHING;
default:
return LLAssetType::AT_NONE;
}
}
LLWearable::LLWearable(const LLTransactionID& transaction_id) :
mDefinitionVersion(LLWearable::sCurrentDefinitionVersion),
mType(WT_SHAPE)
{
mTransactionID = transaction_id;
mAssetID = mTransactionID.makeAssetID(gAgent.getSecureSessionID());
}
LLWearable::LLWearable(const LLAssetID& asset_id) :
mDefinitionVersion( LLWearable::sCurrentDefinitionVersion ),
mType(WT_SHAPE)
{
mAssetID = asset_id;
mTransactionID.setNull();
}
LLWearable::~LLWearable()
{
}
// static
EWearableType LLWearable::typeNameToType( const std::string& type_name )
{
for( S32 i = 0; i < WT_COUNT; i++ )
{
if( type_name == LLWearable::sTypeName[ i ] )
{
return (EWearableType)i;
}
}
return WT_INVALID;
}
std::string terse_F32_to_string( F32 f )
{
std::string r = llformat( "%.2f", f );
// "1.20" -> "1.2"
// "24.00" -> "24."
S32 len = r.length();
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;
}
// reX: new function
BOOL LLWearable::FileExportParams( FILE* file )
{
// wearable type
S32 type = (S32)mType;
fprintf( file, "type %d\n", type );
// parameters
S32 num_parameters = mVisualParamMap.size();
fprintf( file, "parameters %d\n", num_parameters );
for (param_map_t::iterator iter = mVisualParamMap.begin();
iter != mVisualParamMap.end(); ++iter)
{
S32 param_id = iter->first;
F32 param_weight = iter->second;
fprintf( file, "%d %s\n", param_id, terse_F32_to_string(param_weight).c_str() );
}
return TRUE;
}
// reX: new function
BOOL LLWearable::FileExportTextures( FILE* file )
{
// wearable type
S32 type = (S32)mType;
fprintf( file, "type %d\n", type );
// texture entries
S32 num_textures = mTEMap.size();
fprintf( file, "textures %d\n", num_textures );
for (te_map_t::iterator iter = mTEMap.begin();
iter != mTEMap.end(); ++iter)
{
S32 te = iter->first;
LLUUID& image_id = iter->second;
fprintf( file, "%d %s\n", te, image_id.asString().c_str() );
}
return TRUE;
}
BOOL LLWearable::exportFile( LLFILE* file )
{
// 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 = mVisualParamMap.size();
if( fprintf( file, "parameters %d\n", num_parameters ) < 0 )
{
return FALSE;
}
for (param_map_t::iterator iter = mVisualParamMap.begin();
iter != mVisualParamMap.end(); ++iter)
{
S32 param_id = iter->first;
F32 param_weight = iter->second;
if( fprintf( file, "%d %s\n", param_id, terse_F32_to_string( param_weight ).c_str() ) < 0 )
{
return FALSE;
}
}
// texture entries
S32 num_textures = mTEMap.size();
if( fprintf( file, "textures %d\n", num_textures ) < 0 )
{
return FALSE;
}
for (te_map_t::iterator iter = mTEMap.begin();
iter != mTEMap.end(); ++iter)
{
S32 te = iter->first;
LLUUID& image_id = iter->second;
if( fprintf( file, "%d %s\n", te, image_id.asString().c_str()) < 0 )
{
return FALSE;
}
}
return TRUE;
}
BOOL 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 )
{
// Shouldn't really log the asset id for security reasons, but
// we need it in this case.
llwarns << "Bad Wearable asset header: " << mAssetID << llendl;
//gVFS->dumpMap();
return FALSE;
}
if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion )
{
llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl;
return FALSE;
}
// name
char 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 FALSE;
}
mName = text_buffer;
LLStringUtil::truncate(mName, DB_INV_ITEM_NAME_STR_LEN );
}
// 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 FALSE;
}
mDescription = text_buffer;
LLStringUtil::truncate(mDescription, DB_INV_ITEM_DESC_STR_LEN );
}
// 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 FALSE;
}
if( !mPermissions.importFile( file ) )
{
return FALSE;
}
// 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 FALSE;
}
// 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 FALSE;
}
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 FALSE;
}
if( 0 <= type && type < WT_COUNT )
{
mType = (EWearableType)type;
}
else
{
mType = WT_COUNT;
llwarns << "Bad Wearable asset: bad type #" << type << llendl;
return FALSE;
}
// 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 FALSE;
}
// 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", &param_id, &param_weight );
if( fields_read != 2 )
{
llwarns << "Bad Wearable asset: bad parameter, #" << i << llendl;
return FALSE;
}
mVisualParamMap[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 FALSE;
}
// textures
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 FALSE;
}
if( !LLUUID::validate( text_buffer ) )
{
llwarns << "Bad Wearable asset: bad texture uuid: " << text_buffer << llendl;
return FALSE;
}
mTEMap[te] = LLUUID(text_buffer );
}
return TRUE;
}
// Avatar parameter and texture definitions can change over time.
// This function returns true if parameters or textures have been added or removed
// since this wearable was created.
BOOL LLWearable::isOldVersion()
{
LLVOAvatar* avatar = gAgent.getAvatarObject();
llassert( avatar );
if( !avatar )
{
return FALSE;
}
if( LLWearable::sCurrentDefinitionVersion < mDefinitionVersion )
{
llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl;
llassert(0);
}
if( LLWearable::sCurrentDefinitionVersion != mDefinitionVersion )
{
return TRUE;
}
S32 param_count = 0;
for( LLViewerVisualParam* param = (LLViewerVisualParam*) avatar->getFirstVisualParam();
param;
param = (LLViewerVisualParam*) avatar->getNextVisualParam() )
{
if( (param->getWearableType() == mType) && (param->isTweakable()) )
{
param_count++;
if( !is_in_map(mVisualParamMap, param->getID() ) )
{
return TRUE;
}
}
}
if( param_count != mVisualParamMap.size() )
{
return TRUE;
}
S32 te_count = 0;
for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
{
if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == mType )
{
te_count++;
if( !is_in_map(mTEMap, te ) )
{
return TRUE;
}
}
}
if( te_count != mTEMap.size() )
{
return TRUE;
}
return FALSE;
}
// Avatar parameter and texture definitions can change over time.
// * If parameters or textures have been REMOVED since the wearable was created,
// they're just ignored, so we consider the wearable clean even though isOldVersion()
// will return true.
// * If parameters or textures have been ADDED since the wearable was created,
// they are taken to have default values, so we consider the wearable clean
// only if those values are the same as the defaults.
BOOL LLWearable::isDirty()
{
LLVOAvatar* avatar = gAgent.getAvatarObject();
llassert( avatar );
if( !avatar )
{
return FALSE;
}
for( LLViewerVisualParam* param = (LLViewerVisualParam*) avatar->getFirstVisualParam();
param;
param = (LLViewerVisualParam*) avatar->getNextVisualParam() )
{
if( (param->getWearableType() == mType) && (param->isTweakable()) )
{
F32 weight = get_if_there(mVisualParamMap, param->getID(), param->getDefaultWeight());
weight = llclamp( weight, param->getMinWeight(), param->getMaxWeight() );
U8 a = F32_to_U8( param->getWeight(), param->getMinWeight(), param->getMaxWeight() );
if(avatar->getAppearanceFlag() == true)
{
//boob
if(param->getID() == 507)
{
weight = get_if_there(mVisualParamMap, param->getID(), avatar->getActualBoobGrav());
weight = llclamp( weight, param->getMinWeight(), param->getMaxWeight() );
}
/*//butt
if(param->getID() == 795)
{
weight = get_if_there(mVisualParamMap, param->getID(), avatar->getActualButtGrav());
weight = llclamp( weight, param->getMinWeight(), param->getMaxWeight() );
}
//fat
if(param->getID() == 157)
{
weight = get_if_there(mVisualParamMap, param->getID(), avatar->getActualFatGrav());
weight = llclamp( weight, param->getMinWeight(), param->getMaxWeight() );
}
*/
}
else
{
//boob
if(param->getID() == 507)
{
a = F32_to_U8( avatar->getActualBoobGrav(), param->getMinWeight(), param->getMaxWeight() );
}
/*//butt
if(param->getID() == 795)
{
a = F32_to_U8( avatar->getActualButtGrav(), param->getMinWeight(), param->getMaxWeight() );
}
//fat
if(param->getID() == 157)
{
a = F32_to_U8( avatar->getActualFatGrav(), param->getMinWeight(), param->getMaxWeight() );
}
*/
}
U8 b = F32_to_U8( weight, param->getMinWeight(), param->getMaxWeight() );
if( a != b )
{
llwarns << "param ID " << param->getID() << " was changed." << llendl;
return TRUE;
}
}
}
for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
{
if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == mType )
{
LLViewerTexture* avatar_image = avatar->getTEImage( te );
if( !avatar_image )
{
llassert( 0 );
continue;
}
const LLUUID& image_id = get_if_there(mTEMap, te, LLVOAvatar::getDefaultTEImageID((ETextureIndex) te ) );
if( avatar_image->getID() != image_id )
{
llwarns << "image ID " << avatar_image->getID() << " was changed." << llendl;
return TRUE;
}
}
}
//if( gFloaterCustomize )
//{
// if( mDescription != gFloaterCustomize->getWearableDescription( mType ) )
// {
// return TRUE;
// }
//}
return FALSE;
}
void LLWearable::setParamsToDefaults()
{
LLVOAvatar* avatar = gAgent.getAvatarObject();
llassert( avatar );
if( !avatar )
{
return;
}
mVisualParamMap.clear();
for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() )
{
if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->isTweakable()) )
{
mVisualParamMap[param->getID()] = param->getDefaultWeight();
}
}
}
void LLWearable::setTexturesToDefaults()
{
mTEMap.clear();
for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
{
if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == mType )
{
mTEMap[te] = LLVOAvatar::getDefaultTEImageID((ETextureIndex) te );
}
}
}
// Updates the user's avatar's appearance
void LLWearable::writeToAvatar( BOOL set_by_user )
{
LLVOAvatar* avatar = gAgent.getAvatarObject();
llassert( avatar );
if( !avatar )
{
return;
}
ESex old_sex = avatar->getSex();
// Pull params
for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() )
{
if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (param->isTweakable()) )
{
S32 param_id = param->getID();
F32 weight = get_if_there(mVisualParamMap, param_id, param->getDefaultWeight());
//ZOMG: When switching shapes from inventory
if(param_id == 507)
avatar->setActualBoobGrav(weight);
/*if(param_id == 795)
avatar->setActualButtGrav(weight);
if(param_id == 157)
avatar->setActualFatGrav(weight);
*/
// only animate with user-originated changes
if (set_by_user)
{
param->setAnimationTarget(weight, set_by_user);
}
else
{
avatar->setVisualParamWeight( param_id, weight, set_by_user );
}
}
}
// only interpolate with user-originated changes
if (set_by_user)
{
avatar->startAppearanceAnimation(TRUE, TRUE);
}
// Pull texture entries
for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
{
if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == mType )
{
const LLUUID& image_id = get_if_there(mTEMap, te, LLVOAvatar::getDefaultTEImageID((ETextureIndex) te ) );
LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture( image_id );
avatar->setLocTexTE( te, image, set_by_user );
}
}
avatar->updateVisualParams();
if( gFloaterCustomize )
{
LLViewerInventoryItem* item;
item = (LLViewerInventoryItem*)gInventory.getItem(gAgentWearables.getWearableItemID(mType));
U32 perm_mask = PERM_NONE;
BOOL is_complete = FALSE;
if(item)
{
perm_mask = item->getPermissions().getMaskOwner();
is_complete = item->isComplete();
if(!is_complete)
{
item->fetchFromServer();
}
}
gFloaterCustomize->setWearable(mType, this, perm_mask, is_complete);
LLFloaterCustomize::setCurrentWearableType( mType );
}
ESex new_sex = avatar->getSex();
if( old_sex != new_sex )
{
avatar->updateSexDependentLayerSets( set_by_user );
}
avatar->updateMeshTextures();
// if( set_by_user )
// {
// gAgent.sendAgentSetAppearance();
// }
}
// Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values.
// static
void LLWearable::removeFromAvatar( EWearableType type, BOOL set_by_user )
{
LLVOAvatar* avatar = gAgent.getAvatarObject();
llassert( avatar );
if( !avatar )
{
return;
}
// You can't just remove body parts.
if( (type == WT_SHAPE) ||
(type == WT_SKIN) ||
(type == WT_HAIR) ||
(type == WT_EYES) )
{
return;
}
// Pull params
for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() )
{
if( (((LLViewerVisualParam*)param)->getWearableType() == type) && (param->isTweakable()) )
{
S32 param_id = param->getID();
avatar->setVisualParamWeight( param_id, param->getDefaultWeight(), set_by_user );
}
}
// Pull textures
LLViewerTexture* image =LLViewerTextureManager::getFetchedTexture( IMG_DEFAULT_AVATAR );
for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
{
if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == type )
{
avatar->setLocTexTE( te, image, set_by_user );
}
}
if( gFloaterCustomize )
{
gFloaterCustomize->setWearable(type, NULL, PERM_ALL, TRUE);
}
avatar->updateVisualParams();
avatar->updateMeshTextures();
// if( set_by_user )
// {
// gAgent.sendAgentSetAppearance();
// }
}
// Updates asset from the user's avatar
void LLWearable::readFromAvatar()
{
LLVOAvatar* avatar = gAgent.getAvatarObject();
llassert( avatar );
if( !avatar )
{
return;
}
mDefinitionVersion = LLWearable::sCurrentDefinitionVersion;
mVisualParamMap.clear();
for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() )
{
if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (param->isTweakable()) )
{
//pretty sure is right
if(param->getID() == 507)
avatar->setActualBoobGrav(param->getWeight());
/*if(param->getID() == 151)
avatar->setActualButtGrav(param->getWeight());
if(param->getID() == 157)
avatar->setActualFatGrav(param->getWeight());
*/
//if(param->getID() == 507)
//{
// llwarns << "current = " << avatar->getActualBoobGrav() << llendl;
// llwarns << "param weight = " << param->getWeight() << llendl;
//}
mVisualParamMap[param->getID()] = param->getWeight();
}
}
mTEMap.clear();
for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
{
if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == mType )
{
LLViewerTexture* image = avatar->getTEImage( te );
if( image )
{
mTEMap[te] = image->getID();
}
}
}
//if( gFloaterCustomize )
//{
// mDescription = gFloaterCustomize->getWearableDescription( mType );
//}
}
// Does not copy mAssetID.
// Definition version is current: removes obsolete enties and creates default values for new ones.
void LLWearable::copyDataFrom( LLWearable* src )
{
LLVOAvatar* avatar = gAgent.getAvatarObject();
llassert( avatar );
if( !avatar )
{
return;
}
mDefinitionVersion = LLWearable::sCurrentDefinitionVersion;
mName = src->mName;
mDescription = src->mDescription;
mPermissions = src->mPermissions;
mSaleInfo = src->mSaleInfo;
mType = src->mType;
// Deep copy of mVisualParamMap (copies only those params that are current, filling in defaults where needed)
for( LLViewerVisualParam* param = (LLViewerVisualParam*) avatar->getFirstVisualParam();
param;
param = (LLViewerVisualParam*) avatar->getNextVisualParam() )
{
if( (param->getWearableType() == mType) && (param->isTweakable()) )
{
S32 id = param->getID();
F32 weight = get_if_there(src->mVisualParamMap, id, param->getDefaultWeight() );
//llwarns << "------------------------------" << llendl;
//llwarns << "copydatafrom" << llendl;
//llwarns << "------------------------------" << llendl;
//if(id == 507)
//{
// llwarns << "weight = " << weight << llendl;
// llwarns << "actual = " << avatar->getActualBoobGrav() << llendl;
// llwarns << "mVisualParamMap[id] = " << mVisualParamMap[id] << llendl;
//}
//pretty sure right
if(id == 507)
avatar->setActualBoobGrav(weight);
/*if(id == 795)
avatar->setActualButtGrav(weight);
if(id == 157)
avatar->setActualFatGrav(weight);
*/
mVisualParamMap[id] = weight;
}
}
// Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed)
for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
{
if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == mType )
{
const LLUUID& image_id = get_if_there(src->mTEMap, te, LLVOAvatar::getDefaultTEImageID((ETextureIndex) te ) );
mTEMap[te] = image_id;
}
}
}
struct LLWearableSaveData
{
EWearableType mType;
};
void LLWearable::saveNewAsset()
{
// llinfos << "LLWearable::saveNewAsset() type: " << getTypeName() << llendl;
//llinfos << *this << llendl;
std::string new_asset_id_string;
mAssetID.toString(new_asset_id_string);
std::string filename;
filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,new_asset_id_string) + ".wbl";
LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */
BOOL successful_save = FALSE;
if(fp && exportFile(fp))
{
successful_save = TRUE;
}
if(fp)
{
fclose(fp);
fp = NULL;
}
if(!successful_save)
{
std::string buffer = llformat("Unable to save '%s' to wearable file.", mName.c_str());
llwarns << buffer << llendl;
LLSD args;
args["NAME"] = mName;
LLNotifications::instance().add("CannotSaveWearableOutOfSpace", args);
return;
}
// save it out to database
if( gAssetStorage )
{
/*
std::string url = gAgent.getRegion()->getCapability("NewAgentInventory");
if (!url.empty())
{
llinfos << "Update Agent Inventory via capability" << llendl;
LLSD body;
body["folder_id"] = gInventory.findCategoryUUIDForType(getAssetType());
body["asset_type"] = LLAssetType::lookup(getAssetType());
body["inventory_type"] = LLInventoryType::lookup(LLInventoryType::IT_WEARABLE);
body["name"] = getName();
body["description"] = getDescription();
LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, filename));
}
else
{
}
*/
LLWearableSaveData* data = new LLWearableSaveData;
data->mType = mType;
gAssetStorage->storeAssetData(filename, mTransactionID, getAssetType(),
&LLWearable::onSaveNewAssetComplete,
(void*)data);
}
}
// static
void LLWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* userdata, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
{
LLWearableSaveData* data = (LLWearableSaveData*)userdata;
const std::string& type_name = LLWearable::typeToTypeName(data->mType);
if(0 == status)
{
// Success
llinfos << "Saved wearable " << type_name << llendl;
}
else
{
std::string buffer = llformat("Unable to save %s to central asset store.", type_name.c_str());
llwarns << buffer << " Status: " << status << llendl;
LLSD args;
args["NAME"] = type_name;
LLNotifications::instance().add("CannotSaveToAssetStore", args);
}
// Delete temp file
std::string new_asset_id_string;
new_asset_id.toString(new_asset_id_string);
std::string src_filename;
src_filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,new_asset_id_string) + ".wbl";
LLFile::remove(src_filename);
// delete the context data
delete data;
}
BOOL LLWearable::isMatchedToInventoryItem( LLViewerInventoryItem* item )
{
return
( mName == item->getName() ) &&
( mDescription == item->getDescription() ) &&
( mPermissions == item->getPermissions() ) &&
( mSaleInfo == item->getSaleInfo() );
}
std::ostream& operator<<(std::ostream &s, const LLWearable &w)
{
s << "wearable " << LLWearable::typeToTypeName( w.mType ) << "\n";
s << " Name: " << w.mName << "\n";
s << " Desc: " << w.mDescription << "\n";
//w.mPermissions
//w.mSaleInfo
s << " Params:" << "\n";
for (LLWearable::param_map_t::const_iterator iter = w.mVisualParamMap.begin();
iter != w.mVisualParamMap.end(); ++iter)
{
S32 param_id = iter->first;
F32 param_weight = iter->second;
s << " " << param_id << " " << param_weight << "\n";
}
s << " Textures:" << "\n";
for (LLWearable::te_map_t::const_iterator iter = w.mTEMap.begin();
iter != w.mTEMap.end(); ++iter)
{
S32 te = iter->first;
const LLUUID& image_id = iter->second;
s << " " << te << " " << image_id << "\n";
}
return s;
}