summaryrefslogtreecommitdiff
path: root/indra/llappearance
diff options
context:
space:
mode:
authorDon Kjer <don@lindenlab.com>2012-09-06 02:53:55 +0000
committerDon Kjer <don@lindenlab.com>2012-09-06 02:53:55 +0000
commit85d0bcc0630bfbf8b50be3a47a113c4f8d6ec9df (patch)
treeaa12b717648de8e4f689055907bcfa7640907bd6 /indra/llappearance
parent2cb3b8ef6bbfa328e35b9c066f0b5c3ceebba55f (diff)
Extracted mWearableDatas from LLAgentWearables into llappearance/LLWearableData. Moved LLDriverParam into llappearance
Diffstat (limited to 'indra/llappearance')
-rw-r--r--indra/llappearance/CMakeLists.txt4
-rw-r--r--indra/llappearance/llavatarappearance.cpp60
-rw-r--r--indra/llappearance/llavatarappearance.h21
-rw-r--r--indra/llappearance/lldriverparam.cpp614
-rw-r--r--indra/llappearance/lldriverparam.h133
-rw-r--r--indra/llappearance/lltexlayer.cpp5
-rw-r--r--indra/llappearance/llwearable.h7
-rw-r--r--indra/llappearance/llwearabledata.cpp353
-rw-r--r--indra/llappearance/llwearabledata.h108
9 files changed, 1292 insertions, 13 deletions
diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt
index 0206f76546..41da898457 100644
--- a/indra/llappearance/CMakeLists.txt
+++ b/indra/llappearance/CMakeLists.txt
@@ -42,6 +42,7 @@ include_directories(
set(llappearance_SOURCE_FILES
llavatarappearance.cpp
+ lldriverparam.cpp
llinventoryicon.cpp
lllocaltextureobject.cpp
lltexglobalcolor.cpp
@@ -49,6 +50,7 @@ set(llappearance_SOURCE_FILES
lltexlayerparams.cpp
lltexturemanagerbridge.cpp
llwearable.cpp
+ llwearabledata.cpp
llwearabletype.cpp
llviewervisualparam.cpp
llavatarappearancedefines.cpp
@@ -58,6 +60,7 @@ set(llappearance_HEADER_FILES
CMakeLists.txt
llavatarappearance.h
+ lldriverparam.h
llinventoryicon.h
lljointpickname.h
lllocaltextureobject.h
@@ -66,6 +69,7 @@ set(llappearance_HEADER_FILES
lltexlayerparams.h
lltexturemanagerbridge.h
llwearable.h
+ llwearabledata.h
llwearabletype.h
llviewervisualparam.h
llavatarappearancedefines.h
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index 75b9c1ffa5..0f0942d8dc 100644
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -29,16 +29,19 @@
#include "llavatarappearance.h"
#include "lldeleteutils.h"
#include "lltexglobalcolor.h"
+#include "llwearabledata.h"
const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0);
-LLAvatarAppearance::LLAvatarAppearance() :
+LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) :
LLCharacter(),
+ mIsDummy(FALSE),
mTexSkinColor( NULL ),
mTexHairColor( NULL ),
mTexEyeColor( NULL ),
- mIsDummy(FALSE)
+ mWearableData(wearable_data)
{
+ llassert(mWearableData);
}
// virtual
@@ -51,6 +54,17 @@ LLAvatarAppearance::~LLAvatarAppearance()
using namespace LLAvatarAppearanceDefines;
+// virtual
+BOOL LLAvatarAppearance::isValid() const
+{
+ // This should only be called on ourself.
+ if (!isSelf())
+ {
+ llerrs << "Called LLAvatarAppearance::isValid() on when isSelf() == false" << llendl;
+ }
+ return TRUE;
+}
+
//static
BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name )
{
@@ -178,5 +192,47 @@ LLColor4 LLAvatarAppearance::getGlobalColor( const std::string& color_name ) con
}
}
+// Unlike most wearable functions, this works for both self and other.
+// virtual
+BOOL LLAvatarAppearance::isWearingWearableType(LLWearableType::EType type) const
+{
+ if (mIsDummy) return TRUE;
+
+ 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;
+}
diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h
index 0e746b3b9d..2209ede927 100644
--- a/indra/llappearance/llavatarappearance.h
+++ b/indra/llappearance/llavatarappearance.h
@@ -33,6 +33,7 @@
class LLTexLayerSet;
class LLTexGlobalColor;
+class LLWearableData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLAvatarAppearance
@@ -47,9 +48,12 @@ class LLAvatarAppearance : public LLCharacter
** **
** INITIALIZATION
**/
+private:
+ // Hide default constructor.
+ LLAvatarAppearance() {}
public:
- LLAvatarAppearance();
+ LLAvatarAppearance(LLWearableData* wearable_data);
virtual ~LLAvatarAppearance();
/** Initialization
@@ -62,6 +66,7 @@ public:
**/
public:
virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent
+ virtual BOOL isValid() const;
virtual BOOL isUsingBakedTextures() const = 0;
/** State
@@ -145,15 +150,13 @@ public:
**/
public:
- virtual BOOL isWearingWearableType(LLWearableType::EType type ) const = 0;
-
- virtual U32 getWearableCount(const LLWearableType::EType type) const = 0;
- virtual U32 getWearableCount(const U32 tex_index) const = 0;
-
- virtual LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) = 0;
- virtual const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const = 0;
-
+ LLWearableData* getWearableData() { return mWearableData; }
+ const LLWearableData* getWearableData() const { return mWearableData; }
+ virtual BOOL isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex te, U32 index = 0 ) const = 0;
+ virtual BOOL isWearingWearableType(LLWearableType::EType type ) const;
+private:
+ LLWearableData* mWearableData;
};
#endif // LL_AVATAR_APPEARANCE_H
diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp
new file mode 100644
index 0000000000..1092b525d0
--- /dev/null
+++ b/indra/llappearance/lldriverparam.cpp
@@ -0,0 +1,614 @@
+/**
+ * @file lldriverparam.cpp
+ * @brief A visual parameter that drives (controls) other visual parameters.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "lldriverparam.h"
+
+#include "llavatarappearance.h"
+#include "llwearable.h"
+#include "llwearabledata.h"
+
+//-----------------------------------------------------------------------------
+// LLDriverParamInfo
+//-----------------------------------------------------------------------------
+
+LLDriverParamInfo::LLDriverParamInfo() :
+ mDriverParam(NULL)
+{
+}
+
+BOOL LLDriverParamInfo::parseXml(LLXmlTreeNode* node)
+{
+ llassert( node->hasName( "param" ) && node->getChildByName( "param_driver" ) );
+
+ if( !LLViewerVisualParamInfo::parseXml( node ))
+ return FALSE;
+
+ LLXmlTreeNode* param_driver_node = node->getChildByName( "param_driver" );
+ if( !param_driver_node )
+ return FALSE;
+
+ for (LLXmlTreeNode* child = param_driver_node->getChildByName( "driven" );
+ child;
+ child = param_driver_node->getNextNamedChild())
+ {
+ S32 driven_id;
+ static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
+ if( child->getFastAttributeS32( id_string, driven_id ) )
+ {
+ F32 min1 = mMinWeight;
+ F32 max1 = mMaxWeight;
+ F32 max2 = max1;
+ F32 min2 = max1;
+
+ // driven ________ //
+ // ^ /| |\ //
+ // | / | | \ //
+ // | / | | \ //
+ // | / | | \ //
+ // | / | | \ //
+ //-------|----|-------|----|-------> driver //
+ // | min1 max1 max2 min2
+
+ static LLStdStringHandle min1_string = LLXmlTree::addAttributeString("min1");
+ child->getFastAttributeF32( min1_string, min1 ); // optional
+ static LLStdStringHandle max1_string = LLXmlTree::addAttributeString("max1");
+ child->getFastAttributeF32( max1_string, max1 ); // optional
+ static LLStdStringHandle max2_string = LLXmlTree::addAttributeString("max2");
+ child->getFastAttributeF32( max2_string, max2 ); // optional
+ static LLStdStringHandle min2_string = LLXmlTree::addAttributeString("min2");
+ child->getFastAttributeF32( min2_string, min2 ); // optional
+
+ // Push these on the front of the deque, so that we can construct
+ // them in order later (faster)
+ mDrivenInfoList.push_front( LLDrivenEntryInfo( driven_id, min1, max1, max2, min2 ) );
+ }
+ else
+ {
+ llerrs << "<driven> Unable to resolve driven parameter: " << driven_id << llendl;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+//virtual
+void LLDriverParamInfo::toStream(std::ostream &out)
+{
+ LLViewerVisualParamInfo::toStream(out);
+ out << "driver" << "\t";
+ out << mDrivenInfoList.size() << "\t";
+ for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++)
+ {
+ LLDrivenEntryInfo driven = *iter;
+ out << driven.mDrivenID << "\t";
+ }
+
+ out << std::endl;
+
+ if(mDriverParam && mDriverParam->getAvatarAppearance()->isSelf() &&
+ mDriverParam->getAvatarAppearance()->isValid())
+ {
+ for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++)
+ {
+ LLDrivenEntryInfo driven = *iter;
+ LLViewerVisualParam *param =
+ (LLViewerVisualParam*)mDriverParam->getAvatarAppearance()->getVisualParam(driven.mDrivenID);
+ if (param)
+ {
+ param->getInfo()->toStream(out);
+ if (param->getWearableType() != mWearableType)
+ {
+ if(param->getCrossWearable())
+ {
+ out << "cross-wearable" << "\t";
+ }
+ else
+ {
+ out << "ERROR!" << "\t";
+ }
+ }
+ else
+ {
+ out << "valid" << "\t";
+ }
+ }
+ else
+ {
+ llwarns << "could not get parameter " << driven.mDrivenID << " from avatar "
+ << mDriverParam->getAvatarAppearance()
+ << " for driver parameter " << getID() << llendl;
+ }
+ out << std::endl;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// LLDriverParam
+//-----------------------------------------------------------------------------
+
+LLDriverParam::LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable /* = NULL */) :
+ mCurrentDistortionParam( NULL ),
+ mAvatarAppearance(appearance),
+ mWearablep(wearable)
+{
+ llassert(mAvatarAppearance);
+ if (mWearablep)
+ {
+ llassert(mAvatarAppearance->isSelf());
+ }
+ mDefaultVec.clear();
+}
+
+LLDriverParam::~LLDriverParam()
+{
+}
+
+BOOL LLDriverParam::setInfo(LLDriverParamInfo *info)
+{
+ llassert(mInfo == NULL);
+ if (info->mID < 0)
+ return FALSE;
+ mInfo = info;
+ mID = info->mID;
+ info->mDriverParam = this;
+
+ setWeight(getDefaultWeight(), FALSE );
+
+ return TRUE;
+}
+
+/*virtual*/ LLViewerVisualParam* LLDriverParam::cloneParam(LLWearable* wearable) const
+{
+ llassert(wearable);
+ LLDriverParam *new_param = new LLDriverParam(mAvatarAppearance, wearable);
+ *new_param = *this;
+ return new_param;
+}
+
+void LLDriverParam::setWeight(F32 weight, BOOL upload_bake)
+{
+ F32 min_weight = getMinWeight();
+ F32 max_weight = getMaxWeight();
+ if (mIsAnimating)
+ {
+ // allow overshoot when animating
+ mCurWeight = weight;
+ }
+ else
+ {
+ mCurWeight = llclamp(weight, min_weight, max_weight);
+ }
+
+ // driven ________
+ // ^ /| |\ ^
+ // | / | | \ |
+ // | / | | \ |
+ // | / | | \ |
+ // | / | | \ |
+ //-------|----|-------|----|-------> driver
+ // | min1 max1 max2 min2
+
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ {
+ LLDrivenEntry* driven = &(*iter);
+ LLDrivenEntryInfo* info = driven->mInfo;
+
+ F32 driven_weight = 0.f;
+ F32 driven_min = driven->mParam->getMinWeight();
+ F32 driven_max = driven->mParam->getMaxWeight();
+
+ if (mIsAnimating)
+ {
+ // driven param doesn't interpolate (textures, for example)
+ if (!driven->mParam->getAnimating())
+ {
+ continue;
+ }
+ if( mCurWeight < info->mMin1 )
+ {
+ if (info->mMin1 == min_weight)
+ {
+ if (info->mMin1 == info->mMax1)
+ {
+ driven_weight = driven_max;
+ }
+ else
+ {
+ //up slope extrapolation
+ F32 t = (mCurWeight - info->mMin1) / (info->mMax1 - info->mMin1 );
+ driven_weight = driven_min + t * (driven_max - driven_min);
+ }
+ }
+ else
+ {
+ driven_weight = driven_min;
+ }
+
+ setDrivenWeight(driven,driven_weight,upload_bake);
+ continue;
+ }
+ else
+ if ( mCurWeight > info->mMin2 )
+ {
+ if (info->mMin2 == max_weight)
+ {
+ if (info->mMin2 == info->mMax2)
+ {
+ driven_weight = driven_max;
+ }
+ else
+ {
+ //down slope extrapolation
+ F32 t = (mCurWeight - info->mMax2) / (info->mMin2 - info->mMax2 );
+ driven_weight = driven_max + t * (driven_min - driven_max);
+ }
+ }
+ else
+ {
+ driven_weight = driven_min;
+ }
+
+ setDrivenWeight(driven,driven_weight,upload_bake);
+ continue;
+ }
+ }
+
+ driven_weight = getDrivenWeight(driven, mCurWeight);
+ setDrivenWeight(driven,driven_weight,upload_bake);
+ }
+}
+
+F32 LLDriverParam::getTotalDistortion()
+{
+ F32 sum = 0.f;
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ {
+ LLDrivenEntry* driven = &(*iter);
+ sum += driven->mParam->getTotalDistortion();
+ }
+
+ return sum;
+}
+
+const LLVector4a &LLDriverParam::getAvgDistortion()
+{
+ // It's not actually correct to take the average of averages, but it good enough here.
+ LLVector4a sum;
+ sum.clear();
+ S32 count = 0;
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ {
+ LLDrivenEntry* driven = &(*iter);
+ sum.add(driven->mParam->getAvgDistortion());
+ count++;
+ }
+ sum.mul( 1.f/(F32)count);
+
+ mDefaultVec = sum;
+ return mDefaultVec;
+}
+
+F32 LLDriverParam::getMaxDistortion()
+{
+ F32 max = 0.f;
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ {
+ LLDrivenEntry* driven = &(*iter);
+ F32 param_max = driven->mParam->getMaxDistortion();
+ if( param_max > max )
+ {
+ max = param_max;
+ }
+ }
+
+ return max;
+}
+
+
+LLVector4a LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)
+{
+ LLVector4a sum;
+ sum.clear();
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ {
+ LLDrivenEntry* driven = &(*iter);
+ sum.add(driven->mParam->getVertexDistortion( index, poly_mesh ));
+ }
+ return sum;
+}
+
+const LLVector4a* LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
+{
+ mCurrentDistortionParam = NULL;
+ const LLVector4a* v = NULL;
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ {
+ LLDrivenEntry* driven = &(*iter);
+ v = driven->mParam->getFirstDistortion( index, poly_mesh );
+ if( v )
+ {
+ mCurrentDistortionParam = driven->mParam;
+ break;
+ }
+ }
+
+ return v;
+};
+
+const LLVector4a* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
+{
+ llassert( mCurrentDistortionParam );
+ if( !mCurrentDistortionParam )
+ {
+ return NULL;
+ }
+
+ LLDrivenEntry* driven = NULL;
+ entry_list_t::iterator iter;
+
+ // Set mDriven iteration to the right point
+ for( iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ {
+ driven = &(*iter);
+ if( driven->mParam == mCurrentDistortionParam )
+ {
+ break;
+ }
+ }
+
+ llassert(driven);
+ if (!driven)
+ {
+ return NULL; // shouldn't happen, but...
+ }
+
+ // We're already in the middle of a param's distortions, so get the next one.
+ const LLVector4a* v = driven->mParam->getNextDistortion( index, poly_mesh );
+ if( (!v) && (iter != mDriven.end()) )
+ {
+ // This param is finished, so start the next param. It might not have any
+ // distortions, though, so we have to loop to find the next param that does.
+ for( iter++; iter != mDriven.end(); iter++ )
+ {
+ driven = &(*iter);
+ v = driven->mParam->getFirstDistortion( index, poly_mesh );
+ if( v )
+ {
+ mCurrentDistortionParam = driven->mParam;
+ break;
+ }
+ }
+ }
+
+ return v;
+};
+
+S32 LLDriverParam::getDrivenParamsCount() const
+{
+ return mDriven.size();
+}
+
+const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const
+{
+ if (0 > index || index >= mDriven.size())
+ {
+ return NULL;
+ }
+ return mDriven[index].mParam;
+}
+
+//-----------------------------------------------------------------------------
+// setAnimationTarget()
+//-----------------------------------------------------------------------------
+void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake )
+{
+ LLVisualParam::setAnimationTarget(target_value, upload_bake);
+
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ {
+ LLDrivenEntry* driven = &(*iter);
+ F32 driven_weight = getDrivenWeight(driven, mTargetWeight);
+
+ // this isn't normally necessary, as driver params handle interpolation of their driven params
+ // but texture params need to know to assume their final value at beginning of interpolation
+ driven->mParam->setAnimationTarget(driven_weight, upload_bake);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// stopAnimating()
+//-----------------------------------------------------------------------------
+void LLDriverParam::stopAnimating(BOOL upload_bake)
+{
+ LLVisualParam::stopAnimating(upload_bake);
+
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ {
+ LLDrivenEntry* driven = &(*iter);
+ driven->mParam->setAnimating(FALSE);
+ }
+}
+
+/*virtual*/
+BOOL LLDriverParam::linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params)
+{
+ BOOL success = TRUE;
+ LLDriverParamInfo::entry_info_list_t::iterator iter;
+ for (iter = getInfo()->mDrivenInfoList.begin(); iter != getInfo()->mDrivenInfoList.end(); ++iter)
+ {
+ LLDrivenEntryInfo *driven_info = &(*iter);
+ S32 driven_id = driven_info->mDrivenID;
+
+ // check for already existing links. Do not overwrite.
+ BOOL found = FALSE;
+ for (entry_list_t::iterator driven_iter = mDriven.begin(); driven_iter != mDriven.end() && !found; ++driven_iter)
+ {
+ if (driven_iter->mInfo->mDrivenID == driven_id)
+ {
+ found = TRUE;
+ }
+ }
+
+ if (!found)
+ {
+ LLViewerVisualParam* param = (LLViewerVisualParam*)mapper(driven_id);
+ bool push = param && (!only_cross_params || param->getCrossWearable());
+ if (push)
+ {
+ mDriven.push_back(LLDrivenEntry( param, driven_info ));
+ }
+ else
+ {
+ success = FALSE;
+ }
+ }
+ }
+
+ return success;
+}
+
+void LLDriverParam::resetDrivenParams()
+{
+ mDriven.clear();
+ mDriven.reserve(getInfo()->mDrivenInfoList.size());
+}
+
+void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type)
+{
+ bool needs_update = (getWearableType()==driven_type);
+
+ // if the driver has a driven entry for the passed-in wearable type, we need to refresh the value
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ {
+ LLDrivenEntry* driven = &(*iter);
+ if (driven && driven->mParam && driven->mParam->getCrossWearable() && driven->mParam->getWearableType() == driven_type)
+ {
+ needs_update = true;
+ }
+ }
+
+
+ if (needs_update)
+ {
+ LLWearableType::EType driver_type = (LLWearableType::EType)getWearableType();
+
+ // If we've gotten here, we've added a new wearable of type "type"
+ // Thus this wearable needs to get updates from the driver wearable.
+ // The call to setVisualParamWeight seems redundant, but is necessary
+ // as the number of driven wearables has changed since the last update. -Nyx
+ LLWearable *wearable = mAvatarAppearance->getWearableData()->getTopWearable(driver_type);
+ if (wearable)
+ {
+ wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false);
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// getDrivenWeight()
+//-----------------------------------------------------------------------------
+F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight)
+{
+ F32 min_weight = getMinWeight();
+ F32 max_weight = getMaxWeight();
+ const LLDrivenEntryInfo* info = driven->mInfo;
+
+ F32 driven_weight = 0.f;
+ F32 driven_min = driven->mParam->getMinWeight();
+ F32 driven_max = driven->mParam->getMaxWeight();
+
+ if( input_weight <= info->mMin1 )
+ {
+ if( info->mMin1 == info->mMax1 &&
+ info->mMin1 <= min_weight)
+ {
+ driven_weight = driven_max;
+ }
+ else
+ {
+ driven_weight = driven_min;
+ }
+ }
+ else
+ if( input_weight <= info->mMax1 )
+ {
+ F32 t = (input_weight - info->mMin1) / (info->mMax1 - info->mMin1 );
+ driven_weight = driven_min + t * (driven_max - driven_min);
+ }
+ else
+ if( input_weight <= info->mMax2 )
+ {
+ driven_weight = driven_max;
+ }
+ else
+ if( input_weight <= info->mMin2 )
+ {
+ F32 t = (input_weight - info->mMax2) / (info->mMin2 - info->mMax2 );
+ driven_weight = driven_max + t * (driven_min - driven_max);
+ }
+ else
+ {
+ if (info->mMax2 >= max_weight)
+ {
+ driven_weight = driven_max;
+ }
+ else
+ {
+ driven_weight = driven_min;
+ }
+ }
+
+ return driven_weight;
+}
+
+void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake)
+{
+ bool use_self = false;
+ if(mWearablep &&
+ mAvatarAppearance->isValid() &&
+ driven->mParam->getCrossWearable())
+ {
+ LLWearable* wearable = dynamic_cast<LLWearable*> (mWearablep);
+ if (mAvatarAppearance->getWearableData()->isOnTop(wearable))
+ {
+ use_self = true;
+ }
+ }
+
+ if (use_self)
+ {
+ // call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values
+ mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake );
+ }
+ else
+ {
+ driven->mParam->setWeight( driven_weight, upload_bake );
+ }
+}
diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h
new file mode 100644
index 0000000000..30e71daad9
--- /dev/null
+++ b/indra/llappearance/lldriverparam.h
@@ -0,0 +1,133 @@
+/**
+ * @file lldriverparam.h
+ * @brief A visual parameter that drives (controls) other visual parameters.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLDRIVERPARAM_H
+#define LL_LLDRIVERPARAM_H
+
+#include "llviewervisualparam.h"
+#include "llwearabletype.h"
+
+class LLAvatarAppearance;
+class LLDriverParam;
+class LLWearable;
+
+//-----------------------------------------------------------------------------
+
+struct LLDrivenEntryInfo
+{
+ LLDrivenEntryInfo( S32 id, F32 min1, F32 max1, F32 max2, F32 min2 )
+ : mDrivenID( id ), mMin1( min1 ), mMax1( max1 ), mMax2( max2 ), mMin2( min2 ) {}
+ S32 mDrivenID;
+ F32 mMin1;
+ F32 mMax1;
+ F32 mMax2;
+ F32 mMin2;
+};
+
+struct LLDrivenEntry
+{
+ LLDrivenEntry( LLViewerVisualParam* param, LLDrivenEntryInfo *info )
+ : mParam( param ), mInfo( info ) {}
+ LLViewerVisualParam* mParam;
+ LLDrivenEntryInfo* mInfo;
+};
+
+//-----------------------------------------------------------------------------
+
+class LLDriverParamInfo : public LLViewerVisualParamInfo
+{
+ friend class LLDriverParam;
+public:
+ LLDriverParamInfo();
+ /*virtual*/ ~LLDriverParamInfo() {};
+
+ /*virtual*/ BOOL parseXml(LLXmlTreeNode* node);
+
+ /*virtual*/ void toStream(std::ostream &out);
+
+protected:
+ typedef std::deque<LLDrivenEntryInfo> entry_info_list_t;
+ entry_info_list_t mDrivenInfoList;
+ LLDriverParam* mDriverParam; // backpointer
+};
+
+//-----------------------------------------------------------------------------
+
+class LLDriverParam : public LLViewerVisualParam
+{
+private:
+ // Hide the default constructor. Force construction with LLAvatarAppearance.
+ LLDriverParam() {}
+public:
+ LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable = NULL);
+ ~LLDriverParam();
+
+ // Special: These functions are overridden by child classes
+ LLDriverParamInfo* getInfo() const { return (LLDriverParamInfo*)mInfo; }
+ // This sets mInfo and calls initialization functions
+ BOOL setInfo(LLDriverParamInfo *info);
+
+ LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; }
+ const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
+
+ void updateCrossDrivenParams(LLWearableType::EType driven_type);
+
+ /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
+
+ // LLVisualParam Virtual functions
+ /*virtual*/ void apply( ESex sex ) {} // apply is called separately for each driven param.
+ /*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
+ /*virtual*/ void setAnimationTarget( F32 target_value, BOOL upload_bake );
+ /*virtual*/ void stopAnimating(BOOL upload_bake);
+ /*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
+ /*virtual*/ void resetDrivenParams();
+
+ // 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);
+
+ S32 getDrivenParamsCount() const;
+ const LLViewerVisualParam* getDrivenParam(S32 index) const;
+
+protected:
+ F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
+ void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake);
+
+
+ LLVector4a mDefaultVec; // temp holder
+ typedef std::vector<LLDrivenEntry> entry_list_t;
+ entry_list_t mDriven;
+ LLViewerVisualParam* mCurrentDistortionParam;
+ // Backlink only; don't make this an LLPointer.
+ LLAvatarAppearance* mAvatarAppearance;
+ LLWearable* mWearablep;
+};
+
+#endif // LL_LLDRIVERPARAM_H
diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp
index a741a83af7..9b70f737a0 100644
--- a/indra/llappearance/lltexlayer.cpp
+++ b/indra/llappearance/lltexlayer.cpp
@@ -40,6 +40,7 @@
#include "lltexturemanagerbridge.h"
#include "llui.h"
#include "llwearable.h"
+#include "llwearabledata.h"
#include "llvertexbuffer.h"
#include "llviewervisualparam.h"
@@ -1560,11 +1561,11 @@ U32 LLTexLayerTemplate::updateWearableCache() const
return 0;
}
LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te);
- U32 num_wearables = getAvatarAppearance()->getWearableCount(wearable_type);
+ U32 num_wearables = getAvatarAppearance()->getWearableData()->getWearableCount(wearable_type);
U32 added = 0;
for (U32 i = 0; i < num_wearables; i++)
{
- LLWearable* wearable = getAvatarAppearance()->getWearable(wearable_type, i);
+ LLWearable* wearable = getAvatarAppearance()->getWearableData()->getWearable(wearable_type, i);
if (!wearable)
{
continue;
diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h
index 8a99debac8..e1cd26bdef 100644
--- a/indra/llappearance/llwearable.h
+++ b/indra/llappearance/llwearable.h
@@ -33,6 +33,7 @@
#include "llwearabletype.h"
#include "lllocaltextureobject.h"
+class LLMD5;
class LLVisualParam;
class LLTexGlobalColorInfo;
class LLTexGlobalColor;
@@ -98,6 +99,12 @@ public:
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;
+
+ // Update the baked texture hash.
+ virtual void addToBakedTextureHash(LLMD5& hash) const = 0;
+
protected:
virtual void createVisualParams() = 0;
diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp
new file mode 100644
index 0000000000..d70bbf286a
--- /dev/null
+++ b/indra/llappearance/llwearabledata.cpp
@@ -0,0 +1,353 @@
+/**
+ * @file llwearabledata.cpp
+ * @brief LLWearableData class implementation
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llwearabledata.h"
+
+#include "llavatarappearance.h"
+#include "llavatarappearancedefines.h"
+#include "lldriverparam.h"
+#include "llmd5.h"
+
+LLWearableData::LLWearableData() :
+ mAvatarAppearance(NULL)
+{
+}
+
+// virtual
+LLWearableData::~LLWearableData()
+{
+}
+
+using namespace LLAvatarAppearanceDefines;
+
+LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index)
+{
+ wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ return NULL;
+ }
+ wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ if (index>=wearable_vec.size())
+ {
+ return NULL;
+ }
+ else
+ {
+ return wearable_vec[index];
+ }
+}
+
+void LLWearableData::setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable)
+{
+ LLWearable *old_wearable = getWearable(type,index);
+ if (!old_wearable)
+ {
+ pushWearable(type,wearable);
+ return;
+ }
+
+ wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ llwarns << "invalid type, type " << type << " index " << index << llendl;
+ return;
+ }
+ wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ if (index>=wearable_vec.size())
+ {
+ llwarns << "invalid index, type " << type << " index " << index << llendl;
+ }
+ else
+ {
+ wearable_vec[index] = wearable;
+ old_wearable->setUpdated();
+ const BOOL removed = FALSE;
+ wearableUpdated(wearable, removed);
+ }
+}
+
+U32 LLWearableData::pushWearable(const LLWearableType::EType type,
+ LLWearable *wearable,
+ bool trigger_updated /* = true */)
+{
+ if (wearable == NULL)
+ {
+ // no null wearables please!
+ llwarns << "Null wearable sent for type " << type << llendl;
+ return MAX_CLOTHING_PER_TYPE;
+ }
+ if (type < LLWearableType::WT_COUNT || mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE)
+ {
+ mWearableDatas[type].push_back(wearable);
+ if (trigger_updated)
+ {
+ const BOOL removed = FALSE;
+ wearableUpdated(wearable, removed);
+ }
+ return mWearableDatas[type].size()-1;
+ }
+ return MAX_CLOTHING_PER_TYPE;
+}
+
+// virtual
+void LLWearableData::wearableUpdated(LLWearable *wearable, BOOL removed)
+{
+ wearable->setUpdated();
+ if (!removed)
+ {
+ pullCrossWearableValues(wearable->getType());
+ }
+}
+
+void LLWearableData::popWearable(LLWearable *wearable)
+{
+ if (wearable == NULL)
+ {
+ // nothing to do here. move along.
+ return;
+ }
+
+ U32 index = getWearableIndex(wearable);
+ const LLWearableType::EType type = wearable->getType();
+
+ if (index < MAX_CLOTHING_PER_TYPE && index < getWearableCount(type))
+ {
+ popWearable(type, index);
+ }
+}
+
+void LLWearableData::popWearable(const LLWearableType::EType type, U32 index)
+{
+ LLWearable *wearable = getWearable(type, index);
+ if (wearable)
+ {
+ mWearableDatas[type].erase(mWearableDatas[type].begin() + index);
+ const BOOL removed = TRUE;
+ wearableUpdated(wearable, removed);
+ }
+}
+
+void LLWearableData::clearWearableType(const LLWearableType::EType type)
+{
+ wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ return;
+ }
+ wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ wearable_vec.clear();
+}
+
+bool LLWearableData::swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b)
+{
+ wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ return false;
+ }
+
+ wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ if (0 > index_a || index_a >= wearable_vec.size()) return false;
+ if (0 > index_b || index_b >= wearable_vec.size()) return false;
+
+ LLWearable* wearable = wearable_vec[index_a];
+ wearable_vec[index_a] = wearable_vec[index_b];
+ wearable_vec[index_b] = wearable;
+ return true;
+}
+
+void LLWearableData::pullCrossWearableValues(const LLWearableType::EType type)
+{
+ llassert(mAvatarAppearance);
+ // scan through all of the avatar's visual parameters
+ for (LLViewerVisualParam* param = (LLViewerVisualParam*) mAvatarAppearance->getFirstVisualParam();
+ param;
+ param = (LLViewerVisualParam*) mAvatarAppearance->getNextVisualParam())
+ {
+ if( param )
+ {
+ LLDriverParam *driver_param = dynamic_cast<LLDriverParam*>(param);
+ if(driver_param)
+ {
+ // parameter is a driver parameter, have it update its cross-driven params
+ driver_param->updateCrossDrivenParams(type);
+ }
+ }
+ }
+}
+
+
+U32 LLWearableData::getWearableIndex(const LLWearable *wearable) const
+{
+ if (wearable == NULL)
+ {
+ return MAX_CLOTHING_PER_TYPE;
+ }
+
+ const LLWearableType::EType type = wearable->getType();
+ wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ llwarns << "tried to get wearable index with an invalid type!" << llendl;
+ return MAX_CLOTHING_PER_TYPE;
+ }
+ const wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ for(U32 index = 0; index < wearable_vec.size(); index++)
+ {
+ if (wearable_vec[index] == wearable)
+ {
+ return index;
+ }
+ }
+
+ return MAX_CLOTHING_PER_TYPE;
+}
+
+BOOL LLWearableData::isOnTop(LLWearable* wearable) const
+{
+ if (!wearable) return FALSE;
+ const LLWearableType::EType type = wearable->getType();
+ return ( getTopWearable(type) == wearable );
+}
+
+const LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index) const
+{
+ wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ return NULL;
+ }
+ const wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ if (index>=wearable_vec.size())
+ {
+ return NULL;
+ }
+ else
+ {
+ return wearable_vec[index];
+ }
+}
+
+LLWearable* LLWearableData::getTopWearable(const LLWearableType::EType type)
+{
+ U32 count = getWearableCount(type);
+ if ( count == 0)
+ {
+ return NULL;
+ }
+
+ return getWearable(type, count-1);
+}
+
+const LLWearable* LLWearableData::getTopWearable(const LLWearableType::EType type) const
+{
+ U32 count = getWearableCount(type);
+ if ( count == 0)
+ {
+ return NULL;
+ }
+
+ return getWearable(type, count-1);
+}
+
+LLWearable* LLWearableData::getBottomWearable(const LLWearableType::EType type)
+{
+ if (getWearableCount(type) == 0)
+ {
+ return NULL;
+ }
+
+ return getWearable(type, 0);
+}
+
+const LLWearable* LLWearableData::getBottomWearable(const LLWearableType::EType type) const
+{
+ if (getWearableCount(type) == 0)
+ {
+ return NULL;
+ }
+
+ return getWearable(type, 0);
+}
+
+U32 LLWearableData::getWearableCount(const LLWearableType::EType type) const
+{
+ wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ return 0;
+ }
+ const wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ return wearable_vec.size();
+}
+
+U32 LLWearableData::getWearableCount(const U32 tex_index) const
+{
+ const LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType((LLAvatarAppearanceDefines::ETextureIndex)tex_index);
+ return getWearableCount(wearable_type);
+}
+
+LLUUID LLWearableData::computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index,
+ BOOL generate_valid_hash) // Set to false if you want to upload the baked texture w/o putting it in the cache
+{
+ LLUUID hash_id;
+ bool hash_computed = false;
+ LLMD5 hash;
+ const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index);
+
+ for (U8 i=0; i < baked_dict->mWearables.size(); i++)
+ {
+ const LLWearableType::EType baked_type = baked_dict->mWearables[i];
+ const U32 num_wearables = getWearableCount(baked_type);
+ for (U32 index = 0; index < num_wearables; ++index)
+ {
+ const LLWearable* wearable = getWearable(baked_type,index);
+ if (wearable)
+ {
+ wearable->addToBakedTextureHash(hash);
+ hash_computed = true;
+ }
+ }
+ }
+ if (hash_computed)
+ {
+ hash.update((const unsigned char*)baked_dict->mWearablesHashID.mData, UUID_BYTES);
+
+ if (!generate_valid_hash)
+ {
+ invalidateBakedTextureHash(hash);
+ }
+ hash.finalize();
+ hash.raw_digest(hash_id.mData);
+ }
+
+ return hash_id;
+}
+
+
diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h
new file mode 100644
index 0000000000..2931424131
--- /dev/null
+++ b/indra/llappearance/llwearabledata.h
@@ -0,0 +1,108 @@
+/**
+ * @file llwearabledata.h
+ * @brief LLWearableData class header file
+ *
+ * $LicenseInfo:firstyear=20012license=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_WEARABLEDATA_H
+#define LL_WEARABLEDATA_H
+
+#include "llavatarappearancedefines.h"
+#include "llerror.h"
+
+class LLAvatarAppearance;
+
+class LLWearableData
+{
+ // *TODO: Figure out why this is causing compile error.
+ //LOG_CLASS(LLWearableData);
+
+ //--------------------------------------------------------------------
+ // Constructors / destructors / Initializers
+ //--------------------------------------------------------------------
+public:
+ LLWearableData();
+ virtual ~LLWearableData();
+
+ void setAvatarAppearance(LLAvatarAppearance* appearance) { mAvatarAppearance = appearance; }
+
+protected:
+ //--------------------------------------------------------------------
+ // Accessors
+ //--------------------------------------------------------------------
+public:
+ LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/);
+ const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const;
+ LLWearable* getTopWearable(const LLWearableType::EType type);
+ const LLWearable* getTopWearable(const LLWearableType::EType type) const;
+ LLWearable* getBottomWearable(const LLWearableType::EType type);
+ const LLWearable* getBottomWearable(const LLWearableType::EType type) const;
+ U32 getWearableCount(const LLWearableType::EType type) const;
+ U32 getWearableCount(const U32 tex_index) const;
+ U32 getWearableIndex(const LLWearable *wearable) const;
+
+ BOOL isOnTop(LLWearable* wearable) const;
+
+ static const U32 MAX_CLOTHING_PER_TYPE = 5;
+
+ //--------------------------------------------------------------------
+ // Setters
+ //--------------------------------------------------------------------
+protected:
+ // Low-level data structure setter - public access is via setWearableItem, etc.
+ void setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable);
+ U32 pushWearable(const LLWearableType::EType type, LLWearable *wearable,
+ bool trigger_updated = true);
+ virtual void wearableUpdated(LLWearable *wearable, BOOL removed);
+ void popWearable(LLWearable *wearable);
+ void popWearable(const LLWearableType::EType type, U32 index);
+ void clearWearableType(const LLWearableType::EType type);
+ bool swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b);
+
+private:
+ void pullCrossWearableValues(const LLWearableType::EType type);
+
+ //--------------------------------------------------------------------
+ // Server Communication
+ //--------------------------------------------------------------------
+public:
+ LLUUID computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index,
+ BOOL generate_valid_hash = TRUE);
+protected:
+ virtual void invalidateBakedTextureHash(LLMD5& hash) const {}
+
+ //--------------------------------------------------------------------
+ // Member variables
+ //--------------------------------------------------------------------
+private:
+ LLAvatarAppearance* mAvatarAppearance;
+ typedef std::vector<LLWearable*> wearableentry_vec_t; // all wearables of a certain type (EG all shirts)
+ typedef std::map<LLWearableType::EType, wearableentry_vec_t> wearableentry_map_t; // wearable "categories" arranged by wearable type
+ wearableentry_map_t mWearableDatas;
+
+};
+
+
+
+#endif // LL_WEARABLEDATA_H
+