SH-3264 Moved over a few more items to llappearance

moved over:
isWearingWearableType
wearable::writeToAvatar
wearable::mTEMap (stores LocalTextureObject*)
more from wearable::import/export
wearable::createVisualParams, etc
master
Nyx (Neal Orman) 2012-09-11 11:59:45 -04:00
parent d3cdc92039
commit f1d6052e36
19 changed files with 255 additions and 1142 deletions

View File

@ -1332,43 +1332,16 @@ LLColor4 LLAvatarAppearance::getGlobalColor( const std::string& color_name ) con
// virtual
BOOL LLAvatarAppearance::isWearingWearableType(LLWearableType::EType type) const
{
if (mIsDummy) return TRUE;
return mWearableData->getWearableCount(type) > 0;
}
switch(type)
{
case LLWearableType::WT_SHAPE:
case LLWearableType::WT_SKIN:
case LLWearableType::WT_HAIR:
case LLWearableType::WT_EYES:
return TRUE; // everyone has all bodyparts
default:
break; // Do nothing
}
/* switch(type)
case LLWearableType::WT_SHIRT:
indicator_te = TEX_UPPER_SHIRT; */
for (LLAvatarAppearanceDictionary::Textures::const_iterator tex_iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin();
tex_iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end();
++tex_iter)
{
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = tex_iter->second;
if (texture_dict->mWearableType == type)
{
// If you're checking another avatar's clothing, you don't have component textures.
// Thus, you must check to see if the corresponding baked texture is defined.
// NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing
// this works for detecting a skirt (most important), but is ineffective at any piece of clothing that
// gets baked into a texture that always exists (upper or lower).
if (texture_dict->mIsUsedByBakedTexture)
{
const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
return isTextureDefined(LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex);
}
return FALSE;
}
}
return FALSE;
LLTexLayerSet* LLAvatarAppearance::getAvatarLayerSet(EBakedTextureIndex baked_index) const
{
/* switch(index)
case TEX_HEAD_BAKED:
case TEX_HEAD_BODYPAINT:
return mHeadLayerSet; */
return mBakedTextureDatas[baked_index].mTexLayerSet;
}
//-----------------------------------------------------------------------------

View File

@ -269,8 +269,12 @@ private:
** **
** BAKED TEXTURES
**/
public:
LLTexLayerSet* getAvatarLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;
protected:
virtual LLTexLayerSet* createTexLayerSet() = 0;
protected:
class LLMaskedMorph;
typedef std::deque<LLMaskedMorph *> morph_list_t;

View File

@ -1620,7 +1620,7 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const
}
if (layer)
{
wearable->writeToAvatar();
wearable->writeToAvatar(mAvatarAppearance);
layer->setLTO(lto);
success &= layer->render(x,y,width,height);
}

View File

@ -123,27 +123,80 @@ BOOL LLWearable::exportFile(LLFILE* file) const
}
// texture entries
S32 num_textures = mTextureIDMap.size();
S32 num_textures = mTEMap.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;
}
}
for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter)
{
S32 te = iter->first;
const LLUUID& image_id = iter->second->getID();
if( fprintf( file, "%d %s\n", te, image_id.asString().c_str()) < 0 )
{
return FALSE;
}
}
return TRUE;
}
void LLWearable::createVisualParams(LLAvatarAppearance *avatarp)
{
for (LLViewerVisualParam* param = (LLViewerVisualParam*) avatarp->getFirstVisualParam();
param;
param = (LLViewerVisualParam*) avatarp->getNextVisualParam())
{
if (param->getWearableType() == mType)
{
addVisualParam(param->cloneParam(this));
}
}
// resync driver parameters to point to the newly cloned driven parameters
for (visual_param_index_map_t::iterator param_iter = mVisualParamIndexMap.begin();
param_iter != mVisualParamIndexMap.end();
++param_iter)
{
LLVisualParam* param = param_iter->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))
{
llwarns << "could not link driven params for wearable " << getName() << " id: " << param->getID() << llendl;
continue;
}
}
}
}
void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp)
{
LLTexLayerSet *layer_set = NULL;
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te);
if (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
{
llerrs << "could not find layerset for LTO in wearable!" << llendl;
}
}
// virtual
LLWearable::EImportResult LLWearable::importFile( LLFILE* file )
LLWearable::EImportResult LLWearable::importFile( LLFILE* file, LLAvatarAppearance* avatarp )
{
// *NOTE: changing the type or size of this buffer will require
// changes in the fscanf() code below. You would be better off
@ -158,6 +211,11 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file )
return LLWearable::BAD_HEADER;
}
if(!avatarp)
{
return LLWearable::FAILURE;
}
// 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
@ -265,7 +323,7 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file )
}
if( 0 <= type && type < LLWearableType::WT_COUNT )
{
setType((LLWearableType::EType)type);
setType((LLWearableType::EType)type, avatarp);
}
else
{
@ -313,37 +371,49 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file )
}
// 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);
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;
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;
llwarns << "Bad Wearable asset: bad texture uuid: " << text_buffer << llendl;
return LLWearable::FAILURE;
}
LLUUID id = LLUUID(text_buffer);
mTextureIDMap[te] = id;
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(text_buffer);
mTEMap[te] = new LLLocalTextureObject(image, textureid);
mSavedTEMap[te] = new LLLocalTextureObject(image, textureid);
createLayers(te, avatarp);
}
return LLWearable::SUCCESS;
}
void LLWearable::setType(LLWearableType::EType type)
void LLWearable::setType(LLWearableType::EType type, LLAvatarAppearance *avatarp)
{
mType = type;
createVisualParams();
createVisualParams(avatarp);
}
@ -442,6 +512,26 @@ void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload
}
}
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, FALSE );
}
}
}
std::string terse_F32_to_string(F32 f)
{
std::string r = llformat("%.2f", f);

View File

@ -37,6 +37,7 @@ class LLMD5;
class LLVisualParam;
class LLTexGlobalColorInfo;
class LLTexGlobalColor;
class LLAvatarAppearance;
// Abstract class.
class LLWearable
@ -52,7 +53,7 @@ public:
//--------------------------------------------------------------------
public:
LLWearableType::EType getType() const { return mType; }
void setType(LLWearableType::EType type);
void setType(LLWearableType::EType type, LLAvatarAppearance *avatarp);
const std::string& getName() const { return mName; }
void setName(const std::string& name) { mName = name; }
const std::string& getDescription() const { return mDescription; }
@ -70,7 +71,7 @@ public:
public:
typedef std::vector<LLVisualParam*> visual_param_vec_t;
virtual void writeToAvatar() = 0;
virtual void writeToAvatar(LLAvatarAppearance* avatarp);
enum EImportResult
{
@ -79,7 +80,7 @@ public:
BAD_HEADER
};
virtual BOOL exportFile(LLFILE* file) const;
virtual EImportResult importFile(LLFILE* file);
virtual EImportResult importFile(LLFILE* file, LLAvatarAppearance* avatarp);
@ -96,9 +97,6 @@ public:
LLColor4 getClothesColor(S32 te) const;
void setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake );
typedef std::map<S32, LLUUID> texture_id_map_t;
const texture_id_map_t& getTextureIDMap() const { return mTextureIDMap; }
// Something happened that requires the wearable to be updated (e.g. worn/unworn).
virtual void setUpdated() const = 0;
@ -106,7 +104,8 @@ public:
virtual void addToBakedTextureHash(LLMD5& hash) const = 0;
protected:
virtual void createVisualParams() = 0;
void createVisualParams(LLAvatarAppearance *avatarp);
void createLayers(S32 te, LLAvatarAppearance *avatarp);
static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml.
S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created.
@ -122,8 +121,9 @@ protected:
typedef std::map<S32, LLVisualParam *> visual_param_index_map_t;
visual_param_index_map_t mVisualParamIndexMap;
// *TODO: Lazy mutable. Find a better way?
mutable texture_id_map_t mTextureIDMap;
typedef std::map<S32, LLLocalTextureObject*> te_map_t;
te_map_t mTEMap; // maps TE to LocalTextureObject
te_map_t mSavedTEMap; // last saved version of TEMap
};
#endif // LL_LLWEARABLE_H

View File

@ -898,7 +898,7 @@ void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type,
// Try to recover by replacing missing wearable with a new one.
LLNotificationsUtil::add("ReplacedMissingWearable");
lldebugs << "Wearable " << LLWearableType::getTypeLabel(type) << " could not be downloaded. Replaced inventory item with default wearable." << llendl;
LLViewerWearable* new_wearable = LLWearableList::instance().createNewWearable(type);
LLViewerWearable* new_wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);
setWearable(type,index,new_wearable);
//new_wearable->writeToAvatar(TRUE);
@ -1048,7 +1048,7 @@ void LLAgentWearables::createStandardWearables()
if (create[i])
{
llassert(getWearableCount((LLWearableType::EType)i) == 0);
LLViewerWearable* wearable = LLWearableList::instance().createNewWearable((LLWearableType::EType)i);
LLViewerWearable* wearable = LLWearableList::instance().createNewWearable((LLWearableType::EType)i, gAgentAvatarp);
((OnWearableItemCreatedCB*)(&(*cb)))->addPendingWearable(wearable);
// no need to update here...
LLUUID category_id = LLUUID::null;
@ -1786,7 +1786,7 @@ void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, con
{
if (type == LLWearableType::WT_INVALID || type == LLWearableType::WT_NONE) return;
LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type);
LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);
LLAssetType::EType asset_type = wearable->getAssetType();
LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE;
LLPointer<LLInventoryCallback> cb = wear ? new LLWearAndEditCallback : NULL;

View File

@ -665,7 +665,7 @@ void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type
LLNotificationsUtil::add("ReplacedMissingWearable");
lldebugs << "Wearable " << LLWearableType::getTypeLabel(type)
<< " could not be downloaded. Replaced inventory item with default wearable." << llendl;
LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type);
LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);
// Add a new one in the lost and found folder.
const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
@ -1841,6 +1841,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
// Fetch the wearables about to be worn.
LLWearableList::instance().getAsset(found.mAssetID,
found.mName,
gAgentAvatarp,
found.mAssetType,
onWearableAssetFetch,
(void*)holder);

View File

@ -1,747 +0,0 @@
/**
* @file llpolymorph.cpp
* @brief Implementation of LLPolyMesh class
*
* $LicenseInfo:firstyear=2001&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$
*/
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "llviewerprecompiledheaders.h"
#include "llpolymorph.h"
#include "llvoavatar.h"
#include "llwearable.h"
#include "llxmltree.h"
#include "llendianswizzle.h"
//#include "../tools/imdebug/imdebug.h"
const F32 NORMAL_SOFTEN_FACTOR = 0.65f;
//-----------------------------------------------------------------------------
// LLPolyMorphData()
//-----------------------------------------------------------------------------
LLPolyMorphData::LLPolyMorphData(const std::string& morph_name)
: mName(morph_name)
{
mNumIndices = 0;
mCurrentIndex = 0;
mTotalDistortion = 0.f;
mAvgDistortion.clear();
mMaxDistortion = 0.f;
mVertexIndices = NULL;
mCoords = NULL;
mNormals = NULL;
mBinormals = NULL;
mTexCoords = NULL;
mMesh = NULL;
}
LLPolyMorphData::LLPolyMorphData(const LLPolyMorphData &rhs) :
mName(rhs.mName),
mNumIndices(rhs.mNumIndices),
mTotalDistortion(rhs.mTotalDistortion),
mAvgDistortion(rhs.mAvgDistortion),
mMaxDistortion(rhs.mMaxDistortion),
mVertexIndices(NULL),
mCoords(NULL),
mNormals(NULL),
mBinormals(NULL),
mTexCoords(NULL)
{
const S32 numVertices = mNumIndices;
mCoords = new LLVector4a[numVertices];
mNormals = new LLVector4a[numVertices];
mBinormals = new LLVector4a[numVertices];
mTexCoords = new LLVector2[numVertices];
mVertexIndices = new U32[numVertices];
for (S32 v=0; v < numVertices; v++)
{
mCoords[v] = rhs.mCoords[v];
mNormals[v] = rhs.mNormals[v];
mBinormals[v] = rhs.mBinormals[v];
mTexCoords[v] = rhs.mTexCoords[v];
mVertexIndices[v] = rhs.mVertexIndices[v];
}
}
//-----------------------------------------------------------------------------
// ~LLPolyMorphData()
//-----------------------------------------------------------------------------
LLPolyMorphData::~LLPolyMorphData()
{
delete [] mVertexIndices;
delete [] mCoords;
delete [] mNormals;
delete [] mBinormals;
delete [] mTexCoords;
}
//-----------------------------------------------------------------------------
// loadBinary()
//-----------------------------------------------------------------------------
BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh)
{
S32 numVertices;
S32 numRead;
numRead = fread(&numVertices, sizeof(S32), 1, fp);
llendianswizzle(&numVertices, sizeof(S32), 1);
if (numRead != 1)
{
llwarns << "Can't read number of morph target vertices" << llendl;
return FALSE;
}
//-------------------------------------------------------------------------
// allocate vertices
//-------------------------------------------------------------------------
mCoords = new LLVector4a[numVertices];
mNormals = new LLVector4a[numVertices];
mBinormals = new LLVector4a[numVertices];
mTexCoords = new LLVector2[numVertices];
// Actually, we are allocating more space than we need for the skiplist
mVertexIndices = new U32[numVertices];
mNumIndices = 0;
mTotalDistortion = 0.f;
mMaxDistortion = 0.f;
mAvgDistortion.clear();
mMesh = mesh;
//-------------------------------------------------------------------------
// read vertices
//-------------------------------------------------------------------------
for(S32 v = 0; v < numVertices; v++)
{
numRead = fread(&mVertexIndices[v], sizeof(U32), 1, fp);
llendianswizzle(&mVertexIndices[v], sizeof(U32), 1);
if (numRead != 1)
{
llwarns << "Can't read morph target vertex number" << llendl;
return FALSE;
}
if (mVertexIndices[v] > 10000)
{
llerrs << "Bad morph index: " << mVertexIndices[v] << llendl;
}
numRead = fread(&mCoords[v], sizeof(F32), 3, fp);
llendianswizzle(&mCoords[v], sizeof(F32), 3);
if (numRead != 3)
{
llwarns << "Can't read morph target vertex coordinates" << llendl;
return FALSE;
}
F32 magnitude = mCoords[v].getLength3().getF32();
mTotalDistortion += magnitude;
LLVector4a t;
t.setAbs(mCoords[v]);
mAvgDistortion.add(t);
if (magnitude > mMaxDistortion)
{
mMaxDistortion = magnitude;
}
numRead = fread(&mNormals[v], sizeof(F32), 3, fp);
llendianswizzle(&mNormals[v], sizeof(F32), 3);
if (numRead != 3)
{
llwarns << "Can't read morph target normal" << llendl;
return FALSE;
}
numRead = fread(&mBinormals[v], sizeof(F32), 3, fp);
llendianswizzle(&mBinormals[v], sizeof(F32), 3);
if (numRead != 3)
{
llwarns << "Can't read morph target binormal" << llendl;
return FALSE;
}
numRead = fread(&mTexCoords[v].mV, sizeof(F32), 2, fp);
llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2);
if (numRead != 2)
{
llwarns << "Can't read morph target uv" << llendl;
return FALSE;
}
mNumIndices++;
}
mAvgDistortion.mul(1.f/(F32)mNumIndices);
mAvgDistortion.normalize3fast();
return TRUE;
}
//-----------------------------------------------------------------------------
// LLPolyMorphTargetInfo()
//-----------------------------------------------------------------------------
LLPolyMorphTargetInfo::LLPolyMorphTargetInfo()
: mIsClothingMorph(FALSE)
{
}
BOOL LLPolyMorphTargetInfo::parseXml(LLXmlTreeNode* node)
{
llassert( node->hasName( "param" ) && node->getChildByName( "param_morph" ) );
if (!LLViewerVisualParamInfo::parseXml(node))
return FALSE;
// Get mixed-case name
static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
if( !node->getFastAttributeString( name_string, mMorphName ) )
{
llwarns << "Avatar file: <param> is missing name attribute" << llendl;
return FALSE; // Continue, ignoring this tag
}
static LLStdStringHandle clothing_morph_string = LLXmlTree::addAttributeString("clothing_morph");
node->getFastAttributeBOOL(clothing_morph_string, mIsClothingMorph);
LLXmlTreeNode *paramNode = node->getChildByName("param_morph");
if (NULL == paramNode)
{
llwarns << "Failed to getChildByName(\"param_morph\")"
<< llendl;
return FALSE;
}
for (LLXmlTreeNode* child_node = paramNode->getFirstChild();
child_node;
child_node = paramNode->getNextChild())
{
static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
if (child_node->hasName("volume_morph"))
{
std::string volume_name;
if (child_node->getFastAttributeString(name_string, volume_name))
{
LLVector3 scale;
static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
child_node->getFastAttributeVector3(scale_string, scale);
LLVector3 pos;
static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
child_node->getFastAttributeVector3(pos_string, pos);
mVolumeInfoList.push_back(LLPolyVolumeMorphInfo(volume_name,scale,pos));
}
}
}
return TRUE;
}
//-----------------------------------------------------------------------------
// LLPolyMorphTarget()
//-----------------------------------------------------------------------------
LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh)
: mMorphData(NULL), mMesh(poly_mesh),
mVertMask(NULL),
mLastSex(SEX_FEMALE),
mNumMorphMasksPending(0)
{
}
//-----------------------------------------------------------------------------
// ~LLPolyMorphTarget()
//-----------------------------------------------------------------------------
LLPolyMorphTarget::~LLPolyMorphTarget()
{
if (mVertMask)
{
delete mVertMask;
}
}
//-----------------------------------------------------------------------------
// setInfo()
//-----------------------------------------------------------------------------
BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
{
llassert(mInfo == NULL);
if (info->mID < 0)
return FALSE;
mInfo = info;
mID = info->mID;
setWeight(getDefaultWeight(), FALSE );
LLVOAvatar* avatarp = mMesh->getAvatar();
LLPolyMorphTargetInfo::volume_info_list_t::iterator iter;
for (iter = getInfo()->mVolumeInfoList.begin(); iter != getInfo()->mVolumeInfoList.end(); iter++)
{
LLPolyVolumeMorphInfo *volume_info = &(*iter);
for (S32 i = 0; i < avatarp->mNumCollisionVolumes; i++)
{
if (avatarp->mCollisionVolumes[i].getName() == volume_info->mName)
{
mVolumeMorphs.push_back(LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i],
volume_info->mScale,
volume_info->mPos));
break;
}
}
}
std::string morph_param_name = getInfo()->mMorphName;
mMorphData = mMesh->getMorphData(morph_param_name);
if (!mMorphData)
{
const std::string driven_tag = "_Driven";
U32 pos = morph_param_name.find(driven_tag);
if (pos > 0)
{
morph_param_name = morph_param_name.substr(0,pos);
mMorphData = mMesh->getMorphData(morph_param_name);
}
}
if (!mMorphData)
{
llwarns << "No morph target named " << morph_param_name << " found in mesh." << llendl;
return FALSE; // Continue, ignoring this tag
}
return TRUE;
}
/*virtual*/ LLViewerVisualParam* LLPolyMorphTarget::cloneParam(LLWearable* wearable) const
{
LLPolyMorphTarget *new_param = new LLPolyMorphTarget(mMesh);
*new_param = *this;
return new_param;
}
#if 0 // obsolete
//-----------------------------------------------------------------------------
// parseData()
//-----------------------------------------------------------------------------
BOOL LLPolyMorphTarget::parseData(LLXmlTreeNode* node)
{
LLPolyMorphTargetInfo* info = new LLPolyMorphTargetInfo;
info->parseXml(node);
if (!setInfo(info))
{
delete info;
return FALSE;
}
return TRUE;
}
#endif
//-----------------------------------------------------------------------------
// getVertexDistortion()
//-----------------------------------------------------------------------------
LLVector4a LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh *mesh)
{
if (!mMorphData || mMesh != mesh) return LLVector4a::getZero();
for(U32 index = 0; index < mMorphData->mNumIndices; index++)
{
if (mMorphData->mVertexIndices[index] == (U32)requested_index)
{
return mMorphData->mCoords[index];
}
}
return LLVector4a::getZero();
}
//-----------------------------------------------------------------------------
// getFirstDistortion()
//-----------------------------------------------------------------------------
const LLVector4a *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
{
if (!mMorphData) return &LLVector4a::getZero();
LLVector4a* resultVec;
mMorphData->mCurrentIndex = 0;
if (mMorphData->mNumIndices)
{
resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex];
if (index != NULL)
{
*index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex];
}
if (poly_mesh != NULL)
{
*poly_mesh = mMesh;
}
return resultVec;
}
return NULL;
}
//-----------------------------------------------------------------------------
// getNextDistortion()
//-----------------------------------------------------------------------------
const LLVector4a *LLPolyMorphTarget::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
{
if (!mMorphData) return &LLVector4a::getZero();
LLVector4a* resultVec;
mMorphData->mCurrentIndex++;
if (mMorphData->mCurrentIndex < mMorphData->mNumIndices)
{
resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex];
if (index != NULL)
{
*index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex];
}
if (poly_mesh != NULL)
{
*poly_mesh = mMesh;
}
return resultVec;
}
return NULL;
}
//-----------------------------------------------------------------------------
// getTotalDistortion()
//-----------------------------------------------------------------------------
F32 LLPolyMorphTarget::getTotalDistortion()
{
if (mMorphData)
{
return mMorphData->mTotalDistortion;
}
else
{
return 0.f;
}
}
//-----------------------------------------------------------------------------
// getAvgDistortion()
//-----------------------------------------------------------------------------
const LLVector4a& LLPolyMorphTarget::getAvgDistortion()
{
if (mMorphData)
{
return mMorphData->mAvgDistortion;
}
else
{
return LLVector4a::getZero();
}
}
//-----------------------------------------------------------------------------
// getMaxDistortion()
//-----------------------------------------------------------------------------
F32 LLPolyMorphTarget::getMaxDistortion()
{
if (mMorphData)
{
return mMorphData->mMaxDistortion;
}
else
{
return 0.f;
}
}
//-----------------------------------------------------------------------------
// apply()
//-----------------------------------------------------------------------------
static LLFastTimer::DeclareTimer FTM_APPLY_MORPH_TARGET("Apply Morph");
void LLPolyMorphTarget::apply( ESex avatar_sex )
{
if (!mMorphData || mNumMorphMasksPending > 0)
{
return;
}
LLFastTimer t(FTM_APPLY_MORPH_TARGET);
mLastSex = avatar_sex;
// Check for NaN condition (NaN is detected if a variable doesn't equal itself.
if (mCurWeight != mCurWeight)
{
mCurWeight = 0.0;
}
if (mLastWeight != mLastWeight)
{
mLastWeight = mCurWeight+.001;
}
// perform differential update of morph
F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight);
// store last weight
mLastWeight += delta_weight;
if (delta_weight != 0.f)
{
llassert(!mMesh->isLOD());
LLVector4a *coords = mMesh->getWritableCoords();
LLVector4a *scaled_normals = mMesh->getScaledNormals();
LLVector4a *normals = mMesh->getWritableNormals();
LLVector4a *scaled_binormals = mMesh->getScaledBinormals();
LLVector4a *binormals = mMesh->getWritableBinormals();
LLVector4a *clothing_weights = mMesh->getWritableClothingWeights();
LLVector2 *tex_coords = mMesh->getWritableTexCoords();
F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
for(U32 vert_index_morph = 0; vert_index_morph < mMorphData->mNumIndices; vert_index_morph++)
{
S32 vert_index_mesh = mMorphData->mVertexIndices[vert_index_morph];
F32 maskWeight = 1.f;
if (maskWeightArray)
{
maskWeight = maskWeightArray[vert_index_morph];
}
LLVector4a pos = mMorphData->mCoords[vert_index_morph];
pos.mul(delta_weight*maskWeight);
coords[vert_index_mesh].add(pos);
if (getInfo()->mIsClothingMorph && clothing_weights)
{
LLVector4a clothing_offset = mMorphData->mCoords[vert_index_morph];
clothing_offset.mul(delta_weight * maskWeight);
LLVector4a* clothing_weight = &clothing_weights[vert_index_mesh];
clothing_weight->add(clothing_offset);
clothing_weight->getF32ptr()[VW] = maskWeight;
}
// calculate new normals based on half angles
LLVector4a norm = mMorphData->mNormals[vert_index_morph];
norm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
scaled_normals[vert_index_mesh].add(norm);
norm = scaled_normals[vert_index_mesh];
norm.normalize3fast();
normals[vert_index_mesh] = norm;
// calculate new binormals
LLVector4a binorm = mMorphData->mBinormals[vert_index_morph];
binorm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
scaled_binormals[vert_index_mesh].add(binorm);
LLVector4a tangent;
tangent.setCross3(scaled_binormals[vert_index_mesh], norm);
LLVector4a& normalized_binormal = binormals[vert_index_mesh];
normalized_binormal.setCross3(norm, tangent);
normalized_binormal.normalize3fast();
tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight;
}
// now apply volume changes
for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ )
{
LLPolyVolumeMorph* volume_morph = &(*iter);
LLVector3 scale_delta = volume_morph->mScale * delta_weight;
LLVector3 pos_delta = volume_morph->mPos * delta_weight;
volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta);
volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta);
}
}
if (mNext)
{
mNext->apply(avatar_sex);
}
}
//-----------------------------------------------------------------------------
// applyMask()
//-----------------------------------------------------------------------------
void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert)
{
LLVector4a *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL;
if (!mVertMask)
{
mVertMask = new LLPolyVertexMask(mMorphData);
mNumMorphMasksPending--;
}
else
{
// remove effect of previous mask
F32 *maskWeights = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
if (maskWeights)
{
LLVector4a *coords = mMesh->getWritableCoords();
LLVector4a *scaled_normals = mMesh->getScaledNormals();
LLVector4a *scaled_binormals = mMesh->getScaledBinormals();
LLVector2 *tex_coords = mMesh->getWritableTexCoords();
LLVector4Logical clothing_mask;
clothing_mask.clear();
clothing_mask.setElement<0>();
clothing_mask.setElement<1>();
clothing_mask.setElement<2>();
for(U32 vert = 0; vert < mMorphData->mNumIndices; vert++)
{
F32 lastMaskWeight = mLastWeight * maskWeights[vert];
S32 out_vert = mMorphData->mVertexIndices[vert];
// remove effect of existing masked morph
LLVector4a t;
t = mMorphData->mCoords[vert];
t.mul(lastMaskWeight);
coords[out_vert].sub(t);
t = mMorphData->mNormals[vert];
t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR);
scaled_normals[out_vert].sub(t);
t = mMorphData->mBinormals[vert];
t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR);
scaled_binormals[out_vert].sub(t);
tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight;
if (clothing_weights)
{
LLVector4a clothing_offset = mMorphData->mCoords[vert];
clothing_offset.mul(lastMaskWeight);
LLVector4a* clothing_weight = &clothing_weights[out_vert];
LLVector4a t;
t.setSub(*clothing_weight, clothing_offset);
clothing_weight->setSelectWithMask(clothing_mask, t, *clothing_weight);
}
}
}
}
// set last weight to 0, since we've removed the effect of this morph
mLastWeight = 0.f;
mVertMask->generateMask(maskTextureData, width, height, num_components, invert, clothing_weights);
apply(mLastSex);
}
//-----------------------------------------------------------------------------
// LLPolyVertexMask()
//-----------------------------------------------------------------------------
LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data)
{
mWeights = new F32[morph_data->mNumIndices];
mMorphData = morph_data;
mWeightsGenerated = FALSE;
}
//-----------------------------------------------------------------------------
// ~LLPolyVertexMask()
//-----------------------------------------------------------------------------
LLPolyVertexMask::~LLPolyVertexMask()
{
delete[] mWeights;
}
//-----------------------------------------------------------------------------
// generateMask()
//-----------------------------------------------------------------------------
void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights)
{
// RN debug output that uses Image Debugger (http://www.cs.unc.edu/~baxter/projects/imdebug/)
// BOOL debugImg = FALSE;
// if (debugImg)
// {
// if (invert)
// {
// imdebug("lum rbga=rgba b=8 w=%d h=%d *-1 %p", width, height, maskTextureData);
// }
// else
// {
// imdebug("lum rbga=rgba b=8 w=%d h=%d %p", width, height, maskTextureData);
// }
// }
for (U32 index = 0; index < mMorphData->mNumIndices; index++)
{
S32 vertIndex = mMorphData->mVertexIndices[index];
const S32 *sharedVertIndex = mMorphData->mMesh->getSharedVert(vertIndex);
LLVector2 uvCoords;
if (sharedVertIndex)
{
uvCoords = mMorphData->mMesh->getUVs(*sharedVertIndex);
}
else
{
uvCoords = mMorphData->mMesh->getUVs(vertIndex);
}
U32 s = llclamp((U32)(uvCoords.mV[VX] * (F32)(width - 1)), (U32)0, (U32)width - 1);
U32 t = llclamp((U32)(uvCoords.mV[VY] * (F32)(height - 1)), (U32)0, (U32)height - 1);
mWeights[index] = ((F32) maskTextureData[((t * width + s) * num_components) + (num_components - 1)]) / 255.f;
if (invert)
{
mWeights[index] = 1.f - mWeights[index];
}
// now apply step function
// mWeights[index] = mWeights[index] > 0.95f ? 1.f : 0.f;
if (clothing_weights)
{
clothing_weights[vertIndex].getF32ptr()[VW] = mWeights[index];
}
}
mWeightsGenerated = TRUE;
}
//-----------------------------------------------------------------------------
// getMaskForMorphIndex()
//-----------------------------------------------------------------------------
F32* LLPolyVertexMask::getMorphMaskWeights()
{
if (!mWeightsGenerated)
{
return NULL;
}
return mWeights;
}

View File

@ -1,182 +0,0 @@
/**
* @file llpolymorph.h
* @brief Implementation of LLPolyMesh class
*
* $LicenseInfo:firstyear=2001&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$
*/
#ifndef LL_LLPOLYMORPH_H
#define LL_LLPOLYMORPH_H
#include <string>
#include <vector>
#include "llviewervisualparam.h"
class LLPolyMeshSharedData;
class LLVOAvatar;
class LLVector2;
class LLAvatarJointCollisionVolume;
class LLWearable;
//-----------------------------------------------------------------------------
// LLPolyMorphData()
//-----------------------------------------------------------------------------
class LLPolyMorphData
{
public:
LLPolyMorphData(const std::string& morph_name);
~LLPolyMorphData();
LLPolyMorphData(const LLPolyMorphData &rhs);
BOOL loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh);
const std::string& getName() { return mName; }
public:
std::string mName;
// morphology
U32 mNumIndices;
U32* mVertexIndices;
U32 mCurrentIndex;
LLVector4a* mCoords;
LLVector4a* mNormals;
LLVector4a* mBinormals;
LLVector2* mTexCoords;
F32 mTotalDistortion; // vertex distortion summed over entire morph
F32 mMaxDistortion; // maximum single vertex distortion in a given morph
LLVector4a mAvgDistortion; // average vertex distortion, to infer directionality of the morph
LLPolyMeshSharedData* mMesh;
};
//-----------------------------------------------------------------------------
// LLPolyVertexMask()
//-----------------------------------------------------------------------------
class LLPolyVertexMask
{
public:
LLPolyVertexMask(LLPolyMorphData* morph_data);
~LLPolyVertexMask();
void generateMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights);
F32* getMorphMaskWeights();
protected:
F32* mWeights;
LLPolyMorphData *mMorphData;
BOOL mWeightsGenerated;
};
//-----------------------------------------------------------------------------
// LLPolyMorphTarget Data structs
//-----------------------------------------------------------------------------
struct LLPolyVolumeMorphInfo
{
LLPolyVolumeMorphInfo(std::string &name, LLVector3 &scale, LLVector3 &pos)
: mName(name), mScale(scale), mPos(pos) {};
std::string mName;
LLVector3 mScale;
LLVector3 mPos;
};
struct LLPolyVolumeMorph
{
LLPolyVolumeMorph(LLAvatarJointCollisionVolume* volume, LLVector3 scale, LLVector3 pos)
: mVolume(volume), mScale(scale), mPos(pos) {};
LLAvatarJointCollisionVolume* mVolume;
LLVector3 mScale;
LLVector3 mPos;
};
//-----------------------------------------------------------------------------
// LLPolyMorphTargetInfo
// Shared information for LLPolyMorphTargets
//-----------------------------------------------------------------------------
class LLPolyMorphTargetInfo : public LLViewerVisualParamInfo
{
friend class LLPolyMorphTarget;
public:
LLPolyMorphTargetInfo();
/*virtual*/ ~LLPolyMorphTargetInfo() {};
/*virtual*/ BOOL parseXml(LLXmlTreeNode* node);
protected:
std::string mMorphName;
BOOL mIsClothingMorph;
typedef std::vector<LLPolyVolumeMorphInfo> volume_info_list_t;
volume_info_list_t mVolumeInfoList;
};
//-----------------------------------------------------------------------------
// LLPolyMorphTarget
// A set of vertex data associated with morph target.
// These morph targets must be topologically consistent with a given Polymesh
// (share face sets)
//-----------------------------------------------------------------------------
class LLPolyMorphTarget : public LLViewerVisualParam
{
public:
LLPolyMorphTarget(LLPolyMesh *poly_mesh);
~LLPolyMorphTarget();
// Special: These functions are overridden by child classes
LLPolyMorphTargetInfo* getInfo() const { return (LLPolyMorphTargetInfo*)mInfo; }
// This sets mInfo and calls initialization functions
BOOL setInfo(LLPolyMorphTargetInfo *info);
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
// LLVisualParam Virtual functions
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
/*virtual*/ void apply( ESex sex );
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion();
/*virtual*/ const LLVector4a& getAvgDistortion();
/*virtual*/ F32 getMaxDistortion();
/*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh);
/*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
/*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
void applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert);
void addPendingMorphMask() { mNumMorphMasksPending++; }
protected:
LLPolyMorphData* mMorphData;
LLPolyMesh* mMesh;
LLPolyVertexMask * mVertMask;
ESex mLastSex;
// number of morph masks that haven't been generated, must be 0 before this morph is applied
BOOL mNumMorphMasksPending;
typedef std::vector<LLPolyVolumeMorph> volume_list_t;
volume_list_t mVolumeMorphs;
};
#endif // LL_LLPOLYMORPH_H

View File

@ -267,7 +267,7 @@ void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint )
&& new_percent < slider->getMaxValue())
{
mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight, FALSE);
mWearable->writeToAvatar();
mWearable->writeToAvatar(gAgentAvatarp);
gAgentAvatarp->updateVisualParams();
slider->setValue( weightToPercent( new_weight ) );
@ -300,7 +300,7 @@ void LLScrollingPanelParam::onHintMinMouseUp( void* userdata )
&& new_percent < slider->getMaxValue())
{
self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE);
self->mWearable->writeToAvatar();
self->mWearable->writeToAvatar(gAgentAvatarp);
slider->setValue( self->weightToPercent( new_weight ) );
}
}
@ -334,7 +334,7 @@ void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata )
&& new_percent < slider->getMaxValue())
{
self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE);
self->mWearable->writeToAvatar();
self->mWearable->writeToAvatar(gAgentAvatarp);
slider->setValue( self->weightToPercent( new_weight ) );
}
}

View File

@ -94,7 +94,7 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata)
if (current_weight != new_weight )
{
self->mWearable->setVisualParamWeight( param->getID(), new_weight, FALSE );
self->mWearable->writeToAvatar();
self->mWearable->writeToAvatar(gAgentAvatarp);
gAgentAvatarp->updateVisualParams();
}
}

View File

@ -90,60 +90,13 @@ LLViewerWearable::~LLViewerWearable()
}
// virtual
BOOL LLViewerWearable::exportFile(LLFILE* file) const
{
mTextureIDMap.clear();
for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter)
{
S32 te = iter->first;
const LLUUID& image_id = iter->second->getID();
mTextureIDMap[te] = image_id;
}
return LLWearable::exportFile(file);
}
void LLViewerWearable::createVisualParams()
{
for (LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam();
param;
param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam())
{
if (param->getWearableType() == mType)
{
addVisualParam(param->cloneParam(this));
}
}
// resync driver parameters to point to the newly cloned driven parameters
for (visual_param_index_map_t::iterator param_iter = mVisualParamIndexMap.begin();
param_iter != mVisualParamIndexMap.end();
++param_iter)
{
LLVisualParam* param = param_iter->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,gAgentAvatarp.get(),_1 ), true))
{
llwarns << "could not link driven params for wearable " << getName() << " id: " << param->getID() << llendl;
continue;
}
}
}
}
// virtual
LLWearable::EImportResult LLViewerWearable::importFile( LLFILE* file )
LLWearable::EImportResult LLViewerWearable::importFile( LLFILE* file, LLAvatarAppearance* avatarp )
{
// suppress texlayerset updates while wearables are being imported. Layersets will be updated
// when the wearables are "worn", not loaded. Note state will be restored when this object is destroyed.
LLOverrideBakedTextureUpdate stop_bakes(false);
LLWearable::EImportResult result = LLWearable::importFile(file);
LLWearable::EImportResult result = LLWearable::importFile(file, avatarp);
if (LLWearable::FAILURE == result) return result;
if (LLWearable::BAD_HEADER == result)
{
@ -157,19 +110,16 @@ LLWearable::EImportResult LLViewerWearable::importFile( LLFILE* file )
LLStringUtil::truncate(mName, DB_INV_ITEM_NAME_STR_LEN );
LLStringUtil::truncate(mDescription, DB_INV_ITEM_DESC_STR_LEN );
texture_id_map_t::const_iterator iter = mTextureIDMap.begin();
texture_id_map_t::const_iterator end = mTextureIDMap.end();
te_map_t::const_iterator iter = mTEMap.begin();
te_map_t::const_iterator end = mTEMap.end();
for (; iter != end; ++iter)
{
S32 te = iter->first;
const LLUUID& textureid = iter->second;
if( mTEMap.find(te) != mTEMap.end() )
LLLocalTextureObject* lto = iter->second;
LLUUID textureid = LLUUID::null;
if (lto)
{
delete mTEMap[te];
}
if( mSavedTEMap.find(te) != mSavedTEMap.end() )
{
delete mSavedTEMap[te];
textureid = lto->getID();
}
LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( textureid );
@ -177,9 +127,6 @@ LLWearable::EImportResult LLViewerWearable::importFile( LLFILE* file )
{
image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(textureid, (LLAvatarAppearanceDefines::ETextureIndex)te), NULL);
}
mTEMap[te] = new LLLocalTextureObject(image, textureid);
mSavedTEMap[te] = new LLLocalTextureObject(image, textureid);
createLayers(te);
}
// copy all saved param values to working params
@ -335,7 +282,7 @@ void LLViewerWearable::setTexturesToDefaults()
if( mTEMap.find(te) == mTEMap.end() )
{
mTEMap[te] = new LLLocalTextureObject(image, id);
createLayers(te);
createLayers(te, gAgentAvatarp);
}
else
{
@ -366,25 +313,17 @@ const LLUUID LLViewerWearable::getDefaultTextureImageID(ETextureIndex index)
// Updates the user's avatar's appearance
void LLViewerWearable::writeToAvatar()
//virtual
void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp)
{
if (!isAgentAvatarValid()) return;
LLVOAvatarSelf* viewer_avatar = dynamic_cast<LLVOAvatarSelf*>(avatarp);
ESex old_sex = gAgentAvatarp->getSex();
if (!avatarp || !viewer_avatar) return;
// Pull params
for( LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->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);
ESex old_sex = avatarp->getSex();
LLWearable::writeToAvatar(avatarp);
gAgentAvatarp->setVisualParamWeight( param_id, weight, FALSE );
}
}
// Pull texture entries
for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
@ -403,14 +342,14 @@ void LLViewerWearable::writeToAvatar()
}
LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture( image_id, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE );
// MULTI-WEARABLE: assume index 0 will be used when writing to avatar. TODO: eliminate the need for this.
gAgentAvatarp->setLocalTextureTE(te, image, 0);
viewer_avatar->setLocalTextureTE(te, image, 0);
}
}
ESex new_sex = gAgentAvatarp->getSex();
ESex new_sex = avatarp->getSex();
if( old_sex != new_sex )
{
gAgentAvatarp->updateSexDependentLayerSets( FALSE );
viewer_avatar->updateSexDependentLayerSets( FALSE );
}
// if( upload_bake )
@ -472,7 +411,7 @@ void LLViewerWearable::copyDataFrom(const LLViewerWearable* src)
mPermissions = src->mPermissions;
mSaleInfo = src->mSaleInfo;
setType(src->mType);
setType(src->mType, gAgentAvatarp);
mSavedVisualParamMap.clear();
// Deep copy of mVisualParamMap (copies only those params that are current, filling in defaults where needed)
@ -513,7 +452,7 @@ void LLViewerWearable::copyDataFrom(const LLViewerWearable* src)
mTEMap[te] = new LLLocalTextureObject(image, image_id);
mSavedTEMap[te] = new LLLocalTextureObject(image, image_id);
}
createLayers(te);
createLayers(te, gAgentAvatarp);
}
}
@ -632,19 +571,6 @@ void LLViewerWearable::revertValues()
}
}
void LLViewerWearable::createLayers(S32 te)
{
LLViewerTexLayerSet *layer_set = gAgentAvatarp->getLayerSet((ETextureIndex)te);
if (layer_set)
{
layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this);
}
else
{
llerrs << "could not find layerset for LTO in wearable!" << llendl;
}
}
void LLViewerWearable::saveValues()
{
//update saved settings so wearable is no longer dirty

View File

@ -30,6 +30,8 @@
#include "llwearable.h"
#include "llavatarappearancedefines.h"
class LLVOAvatar;
class LLViewerWearable : public LLWearable
{
friend class LLWearableList;
@ -58,12 +60,11 @@ public:
BOOL isDirty() const;
BOOL isOldVersion() const;
/*virtual*/ void writeToAvatar();
/*virtual*/ void writeToAvatar(LLAvatarAppearance *avatarp);
void removeFromAvatar( BOOL upload_bake ) { LLViewerWearable::removeFromAvatar( mType, upload_bake ); }
static void removeFromAvatar( LLWearableType::EType type, BOOL upload_bake );
/*virtual*/ BOOL exportFile(LLFILE* file) const;
/*virtual*/ EImportResult importFile(LLFILE* file);
/*virtual*/ EImportResult importFile(LLFILE* file, LLAvatarAppearance* avatarp);
void setParamsToDefaults();
void setTexturesToDefaults();
@ -98,18 +99,11 @@ public:
/*virtual*/void addToBakedTextureHash(LLMD5& hash) const;
protected:
typedef std::map<S32, LLLocalTextureObject*> te_map_t;
void createLayers(S32 te);
/*virtual*/void createVisualParams();
void syncImages(te_map_t &src, te_map_t &dst);
void destroyTextures();
LLAssetID mAssetID;
LLTransactionID mTransactionID;
te_map_t mTEMap; // maps TE to LocalTextureObject
te_map_t mSavedTEMap; // last saved version of TEMap
LLUUID mItemID; // ID of the inventory item in the agent's inventory
};

View File

@ -5560,6 +5560,53 @@ S32 LLVOAvatar::getAttachmentCount()
return count;
}
BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const
{
if (mIsDummy) return TRUE;
if (isSelf())
{
return LLAvatarAppearance::isWearingWearableType(type);
}
switch(type)
{
case LLWearableType::WT_SHAPE:
case LLWearableType::WT_SKIN:
case LLWearableType::WT_HAIR:
case LLWearableType::WT_EYES:
return TRUE; // everyone has all bodyparts
default:
break; // Do nothing
}
/* switch(type)
case LLWearableType::WT_SHIRT:
indicator_te = TEX_UPPER_SHIRT; */
for (LLAvatarAppearanceDictionary::Textures::const_iterator tex_iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin();
tex_iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end();
++tex_iter)
{
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = tex_iter->second;
if (texture_dict->mWearableType == type)
{
// If you're checking another avatar's clothing, you don't have component textures.
// Thus, you must check to see if the corresponding baked texture is defined.
// NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing
// this works for detecting a skirt (most important), but is ineffective at any piece of clothing that
// gets baked into a texture that always exists (upper or lower).
if (texture_dict->mIsUsedByBakedTexture)
{
const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
return isTextureDefined(LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex);
}
return FALSE;
}
}
return FALSE;
}
// virtual
void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result )

View File

@ -677,6 +677,7 @@ public:
virtual BOOL detachObject(LLViewerObject *viewer_object);
void cleanupAttachedMesh( LLViewerObject* pVO );
static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj);
/*virtual*/ BOOL isWearingWearableType(LLWearableType::EType type ) const;
protected:
LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object);
void lazyAttach();

View File

@ -703,7 +703,7 @@ void LLVOAvatarSelf::idleUpdateAppearanceAnimation()
LLWearable *wearable = gAgentWearables.getTopWearable((LLWearableType::EType)type);
if (wearable)
{
wearable->writeToAvatar();
wearable->writeToAvatar(this);
}
}
@ -1001,11 +1001,6 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode)
}
}
/*virtual*/ BOOL LLVOAvatarSelf::isWearingWearableType(LLWearableType::EType type ) const
{
return gAgentWearables.getWearableCount(type) > 0;
}
//-----------------------------------------------------------------------------
// updatedWearable( LLWearableType::EType type )
// forces an update to any baked textures relevant to type.
@ -2616,17 +2611,17 @@ void LLVOAvatarSelf::requestLayerSetUpdate(ETextureIndex index )
LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(ETextureIndex index) const
{
/* switch(index)
case TEX_HEAD_BAKED:
case TEX_HEAD_BODYPAINT:
return mHeadLayerSet; */
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(index);
if (texture_dict->mIsUsedByBakedTexture)
{
const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
return getLayerSet(baked_index);
}
return NULL;
/* switch(index)
case TEX_HEAD_BAKED:
case TEX_HEAD_BODYPAINT:
return mHeadLayerSet; */
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(index);
if (texture_dict->mIsUsedByBakedTexture)
{
const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
return getLayerSet(baked_index);
}
return NULL;
}
LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(EBakedTextureIndex baked_index) const
@ -2637,12 +2632,14 @@ LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(EBakedTextureIndex baked_index)
return mHeadLayerSet; */
if (baked_index >= 0 && baked_index < BAKED_NUM_INDICES)
{
return getTexLayerSet(baked_index);
return getTexLayerSet(baked_index);
}
return NULL;
}
// static
void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch)
{

View File

@ -249,8 +249,9 @@ public:
void requestLayerSetUploads();
void requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i);
void requestLayerSetUpdate(LLAvatarAppearanceDefines::ETextureIndex i);
LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::ETextureIndex index) const;
LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;
LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;
LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::ETextureIndex index) const;
//--------------------------------------------------------------------
// Composites
@ -299,7 +300,6 @@ protected:
**/
public:
/*virtual*/ BOOL isWearingWearableType(LLWearableType::EType type) const;
void wearableUpdated(LLWearableType::EType type, BOOL upload_result);
protected:
U32 getNumWearables(LLAvatarAppearanceDefines::ETextureIndex i) const;

View File

@ -42,13 +42,15 @@ struct LLWearableArrivedData
{
LLWearableArrivedData(LLAssetType::EType asset_type,
const std::string& wearable_name,
LLAvatarAppearance* avatarp,
void(*asset_arrived_callback)(LLViewerWearable*, void* userdata),
void* userdata) :
mAssetType( asset_type ),
mCallback( asset_arrived_callback ),
mUserdata( userdata ),
mName( wearable_name ),
mRetries(0)
mRetries(0),
mAvatarp(avatarp)
{}
LLAssetType::EType mAssetType;
@ -56,6 +58,7 @@ struct LLWearableArrivedData
void* mUserdata;
std::string mName;
S32 mRetries;
LLAvatarAppearance *mAvatarp;
};
////////////////////////////////////////////////////////////////////////////
@ -72,7 +75,7 @@ void LLWearableList::cleanup()
mList.clear();
}
void LLWearableList::getAsset(const LLAssetID& assetID, const std::string& wearable_name, LLAssetType::EType asset_type, void(*asset_arrived_callback)(LLViewerWearable*, void* userdata), void* userdata)
void LLWearableList::getAsset(const LLAssetID& assetID, const std::string& wearable_name, LLAvatarAppearance* avatarp, LLAssetType::EType asset_type, void(*asset_arrived_callback)(LLViewerWearable*, void* userdata), void* userdata)
{
llassert( (asset_type == LLAssetType::AT_CLOTHING) || (asset_type == LLAssetType::AT_BODYPART) );
LLViewerWearable* instance = get_if_there(mList, assetID, (LLViewerWearable*)NULL );
@ -85,7 +88,7 @@ void LLWearableList::getAsset(const LLAssetID& assetID, const std::string& weara
gAssetStorage->getAssetData(assetID,
asset_type,
LLWearableList::processGetAssetReply,
(void*)new LLWearableArrivedData( asset_type, wearable_name, asset_arrived_callback, userdata ),
(void*)new LLWearableArrivedData( asset_type, wearable_name, avatarp, asset_arrived_callback, userdata ),
TRUE);
}
}
@ -96,11 +99,16 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID
BOOL isNewWearable = FALSE;
LLWearableArrivedData* data = (LLWearableArrivedData*) userdata;
LLViewerWearable* wearable = NULL; // NULL indicates failure
LLAvatarAppearance *avatarp = data->mAvatarp;
if( !filename )
{
LL_WARNS("Wearable") << "Bad Wearable Asset: missing file." << LL_ENDL;
}
else if(!avatarp)
{
LL_WARNS("Wearable") << "Bad asset request: missing avatar pointer." << LL_ENDL;
}
else if (status >= 0)
{
// read the file
@ -112,7 +120,7 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID
else
{
wearable = new LLViewerWearable(uuid);
LLWearable::EImportResult result = wearable->importFile( fp );
LLWearable::EImportResult result = wearable->importFile( fp, avatarp );
if (LLWearable::SUCCESS != result)
{
if (wearable->getType() == LLWearableType::WT_COUNT)
@ -222,12 +230,12 @@ LLViewerWearable* LLWearableList::createCopy(const LLViewerWearable* old_wearabl
return wearable;
}
LLViewerWearable* LLWearableList::createNewWearable( LLWearableType::EType type )
LLViewerWearable* LLWearableList::createNewWearable( LLWearableType::EType type, LLAvatarAppearance *avatarp )
{
lldebugs << "LLWearableList::createNewWearable()" << llendl;
LLViewerWearable *wearable = generateNewWearable();
wearable->setType( type );
wearable->setType( type, avatarp );
std::string name = LLTrans::getString( LLWearableType::getTypeDefaultNewName(wearable->getType()) );
wearable->setName( name );

View File

@ -50,12 +50,13 @@ public:
void getAsset(const LLAssetID& assetID,
const std::string& wearable_name,
LLAvatarAppearance *avatarp,
LLAssetType::EType asset_type,
void(*asset_arrived_callback)(LLViewerWearable*, void* userdata),
void* userdata);
LLViewerWearable* createCopy(const LLViewerWearable* old_wearable, const std::string& new_name = std::string());
LLViewerWearable* createNewWearable(LLWearableType::EType type);
LLViewerWearable* createNewWearable(LLWearableType::EType type, LLAvatarAppearance *avatarp);
// Callback
static void processGetAssetReply(const char* filename, const LLAssetID& assetID, void* user_data, S32 status, LLExtStat ext_status);