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, etcmaster
parent
d3cdc92039
commit
f1d6052e36
|
|
@ -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;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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 ) );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue