summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--autobuild.xml14
-rwxr-xr-xdoc/contributions.txt3
-rw-r--r--indra/llappearance/llviewervisualparam.cpp2
-rw-r--r--indra/llappearance/llwearable.cpp6
-rw-r--r--indra/llappearance/llwearabledata.cpp5
-rw-r--r--indra/llappearance/llwearabletype.cpp119
-rw-r--r--indra/llappearance/llwearabletype.h56
-rw-r--r--indra/llcommon/llerror.cpp265
-rw-r--r--indra/llmessage/lldatapacker.cpp164
-rw-r--r--indra/llmessage/lldatapacker.h17
-rw-r--r--indra/llprimitive/llprimitive.cpp342
-rw-r--r--indra/llprimitive/llprimitive.h5
-rw-r--r--indra/llui/lltextbase.cpp6
-rw-r--r--indra/llui/lltextbase.h2
-rw-r--r--indra/llui/lltextbox.cpp4
-rw-r--r--indra/newview/app_settings/settings.xml11
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl6
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl4
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl4
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl4
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl4
-rw-r--r--indra/newview/llagentwearables.cpp9
-rw-r--r--indra/newview/llappearancemgr.cpp2
-rw-r--r--indra/newview/llappviewer.cpp9
-rw-r--r--indra/newview/llcofwearables.cpp2
-rw-r--r--indra/newview/llfavoritesbar.cpp58
-rw-r--r--indra/newview/llfavoritesbar.h2
-rw-r--r--indra/newview/llfloaterlinkreplace.cpp2
-rw-r--r--indra/newview/llfloaterpreference.cpp2
-rw-r--r--indra/newview/llinventorybridge.cpp38
-rw-r--r--indra/newview/llinventoryfunctions.cpp31
-rw-r--r--indra/newview/llinventoryfunctions.h2
-rw-r--r--indra/newview/llinventoryicon.cpp2
-rw-r--r--indra/newview/lloutfitgallery.cpp2
-rw-r--r--indra/newview/lloutfitslist.cpp2
-rw-r--r--indra/newview/llpaneleditwearable.cpp2
-rw-r--r--indra/newview/llpanelgroupcreate.cpp2
-rw-r--r--indra/newview/llpaneloutfitedit.cpp11
-rw-r--r--indra/newview/llpreviewnotecard.cpp38
-rw-r--r--indra/newview/llpreviewnotecard.h8
-rw-r--r--indra/newview/llpreviewtexture.cpp39
-rw-r--r--indra/newview/llpreviewtexture.h1
-rw-r--r--indra/newview/llsidepanelappearance.cpp2
-rw-r--r--indra/newview/llviewercontrol.cpp14
-rw-r--r--indra/newview/llviewerinventory.cpp2
-rw-r--r--indra/newview/llviewermenu.cpp4
-rw-r--r--indra/newview/llviewershadermgr.cpp2
-rw-r--r--indra/newview/llviewerwearable.cpp4
-rw-r--r--indra/newview/llvoavatar.cpp5
-rw-r--r--indra/newview/llvoavatarself.cpp9
-rw-r--r--indra/newview/llwearableitemslist.cpp2
-rw-r--r--indra/newview/llwearablelist.cpp3
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory.xml8
53 files changed, 883 insertions, 479 deletions
diff --git a/autobuild.xml b/autobuild.xml
index a8203bb643..3e1bd522de 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -580,9 +580,9 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>cc26af2ebfa241891caca829a6e46b88</string>
+ <string>b50d355c1c7088cafe5e12d31f1fb07f</string>
<key>url</key>
- <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/65005/607316/dullahan-1.7.0.202008031101_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-546064.tar.bz2</string>
+ <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/72181/697551/dullahan-1.7.0.202011111255_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-552103.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -592,9 +592,9 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>4e5b9e2fe65d94e30a4f3d831c767199</string>
+ <string>0a52a79ad9a182529f7856f78bf4a96f</string>
<key>url</key>
- <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/65004/607304/dullahan-1.7.0.202008031759_81.3.10_gb223419_chromium-81.0.4044.138-windows-546064.tar.bz2</string>
+ <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/72199/697588/dullahan-1.7.0.202011112115_81.3.10_gb223419_chromium-81.0.4044.138-windows-552103.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@@ -604,16 +604,16 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>6f7bf7f915f3d75dbdad08a2d41ca74e</string>
+ <string>715fe1bad3ba216508648b5763ea0404</string>
<key>url</key>
- <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/65003/607308/dullahan-1.7.0.202008031800_81.3.10_gb223419_chromium-81.0.4044.138-windows64-546064.tar.bz2</string>
+ <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/72196/697581/dullahan-1.7.0.202011112112_81.3.10_gb223419_chromium-81.0.4044.138-windows64-552103.tar.bz2</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map>
<key>version</key>
- <string>1.7.0.202008031800_81.3.10_gb223419_chromium-81.0.4044.138</string>
+ <string>1.7.0.202011112112_81.3.10_gb223419_chromium-81.0.4044.138</string>
</map>
<key>elfio</key>
<map>
diff --git a/doc/contributions.txt b/doc/contributions.txt
index bbdfaf655d..ed470c7ae8 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -1352,7 +1352,8 @@ Sovereign Engineer
MAINT-7343
SL-11079
OPEN-343
- SL-11625
+ SL-11625
+ BUG-229030
SpacedOut Frye
VWR-34
VWR-45
diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp
index af8394b60c..fb0d12f0af 100644
--- a/indra/llappearance/llviewervisualparam.cpp
+++ b/indra/llappearance/llviewervisualparam.cpp
@@ -70,7 +70,7 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node)
static LLStdStringHandle wearable_string = LLXmlTree::addAttributeString("wearable");
if( node->getFastAttributeString( wearable_string, wearable) )
{
- mWearableType = LLWearableType::typeNameToType( wearable );
+ mWearableType = LLWearableType::getInstance()->typeNameToType( wearable );
}
static LLStdStringHandle edit_group_string = LLXmlTree::addAttributeString("edit_group");
diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp
index 6079913a8e..e8df3d19f6 100644
--- a/indra/llappearance/llwearable.cpp
+++ b/indra/llappearance/llwearable.cpp
@@ -73,17 +73,17 @@ LLWearable::~LLWearable()
const std::string& LLWearable::getTypeLabel() const
{
- return LLWearableType::getTypeLabel(mType);
+ return LLWearableType::getInstance()->getTypeLabel(mType);
}
const std::string& LLWearable::getTypeName() const
{
- return LLWearableType::getTypeName(mType);
+ return LLWearableType::getInstance()->getTypeName(mType);
}
LLAssetType::EType LLWearable::getAssetType() const
{
- return LLWearableType::getAssetType(mType);
+ return LLWearableType::getInstance()->getAssetType(mType);
}
BOOL LLWearable::exportFile(const std::string& filename) const
diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp
index 2bf3b9085b..9cc65dc2ce 100644
--- a/indra/llappearance/llwearabledata.cpp
+++ b/indra/llappearance/llwearabledata.cpp
@@ -231,10 +231,11 @@ BOOL LLWearableData::getWearableIndex(const LLWearable *wearable, U32& index_fou
U32 LLWearableData::getClothingLayerCount() const
{
U32 count = 0;
+ LLWearableType *wr_inst = LLWearableType::getInstance();
for (S32 i = 0; i < LLWearableType::WT_COUNT; i++)
{
LLWearableType::EType type = (LLWearableType::EType)i;
- if (LLWearableType::getAssetType(type)==LLAssetType::AT_CLOTHING)
+ if (wr_inst->getAssetType(type)==LLAssetType::AT_CLOTHING)
{
count += getWearableCount(type);
}
@@ -244,7 +245,7 @@ U32 LLWearableData::getClothingLayerCount() const
BOOL LLWearableData::canAddWearable(const LLWearableType::EType type) const
{
- LLAssetType::EType a_type = LLWearableType::getAssetType(type);
+ LLAssetType::EType a_type = LLWearableType::getInstance()->getAssetType(type);
if (a_type==LLAssetType::AT_CLOTHING)
{
return (getClothingLayerCount() < MAX_CLOTHING_LAYERS);
diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp
index 281060d01d..4ac611b1de 100644
--- a/indra/llappearance/llwearabletype.cpp
+++ b/indra/llappearance/llwearabletype.cpp
@@ -30,153 +30,98 @@
#include "llinventorydefines.h"
-struct WearableEntry : public LLDictionaryEntry
+LLWearableType::LLWearableDictionary::LLWearableDictionary(LLTranslationBridge::ptr_t& trans)
{
- WearableEntry(LLWearableType& wtype,
- const std::string &name,
- const std::string& default_new_name,
- LLAssetType::EType assetType,
- LLInventoryType::EIconName iconName,
- BOOL disable_camera_switch = FALSE,
- BOOL allow_multiwear = TRUE) :
- LLDictionaryEntry(name),
- mAssetType(assetType),
- mDefaultNewName(default_new_name),
- mLabel(wtype.mTrans->getString(name)),
- mIconName(iconName),
- mDisableCameraSwitch(disable_camera_switch),
- mAllowMultiwear(allow_multiwear)
- {
-
- }
- const LLAssetType::EType mAssetType;
- const std::string mLabel;
- const std::string mDefaultNewName; //keep mLabel for backward compatibility
- LLInventoryType::EIconName mIconName;
- BOOL mDisableCameraSwitch;
- BOOL mAllowMultiwear;
-};
-
-class LLWearableDictionary : public LLParamSingleton<LLWearableDictionary>,
- public LLDictionary<LLWearableType::EType, WearableEntry>
-{
- LLSINGLETON(LLWearableDictionary, LLWearableType&);
-};
-
-LLWearableDictionary::LLWearableDictionary(LLWearableType& wtype)
-{
- addEntry(LLWearableType::WT_SHAPE, new WearableEntry(wtype, "shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE));
- addEntry(LLWearableType::WT_SKIN, new WearableEntry(wtype, "skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE));
- addEntry(LLWearableType::WT_HAIR, new WearableEntry(wtype, "hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE));
- addEntry(LLWearableType::WT_EYES, new WearableEntry(wtype, "eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, FALSE, FALSE));
- addEntry(LLWearableType::WT_SHIRT, new WearableEntry(wtype, "shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE));
- addEntry(LLWearableType::WT_PANTS, new WearableEntry(wtype, "pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, FALSE, TRUE));
- addEntry(LLWearableType::WT_SHOES, new WearableEntry(wtype, "shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, FALSE, TRUE));
- addEntry(LLWearableType::WT_SOCKS, new WearableEntry(wtype, "socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE));
- addEntry(LLWearableType::WT_JACKET, new WearableEntry(wtype, "jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, FALSE, TRUE));
- addEntry(LLWearableType::WT_GLOVES, new WearableEntry(wtype, "gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE));
- addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(wtype, "undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE));
- addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(wtype, "underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE));
- addEntry(LLWearableType::WT_SKIRT, new WearableEntry(wtype, "skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE));
- addEntry(LLWearableType::WT_ALPHA, new WearableEntry(wtype, "alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE));
- addEntry(LLWearableType::WT_TATTOO, new WearableEntry(wtype, "tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE));
- addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(wtype, "universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, FALSE, TRUE));
-
- addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(wtype, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
-
- addEntry(LLWearableType::WT_INVALID, new WearableEntry(wtype, "invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE));
- addEntry(LLWearableType::WT_NONE, new WearableEntry(wtype, "none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
+ addEntry(LLWearableType::WT_SHAPE, new WearableEntry(trans, "shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE));
+ addEntry(LLWearableType::WT_SKIN, new WearableEntry(trans, "skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE));
+ addEntry(LLWearableType::WT_HAIR, new WearableEntry(trans, "hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE));
+ addEntry(LLWearableType::WT_EYES, new WearableEntry(trans, "eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, FALSE, FALSE));
+ addEntry(LLWearableType::WT_SHIRT, new WearableEntry(trans, "shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE));
+ addEntry(LLWearableType::WT_PANTS, new WearableEntry(trans, "pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, FALSE, TRUE));
+ addEntry(LLWearableType::WT_SHOES, new WearableEntry(trans, "shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, FALSE, TRUE));
+ addEntry(LLWearableType::WT_SOCKS, new WearableEntry(trans, "socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE));
+ addEntry(LLWearableType::WT_JACKET, new WearableEntry(trans, "jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, FALSE, TRUE));
+ addEntry(LLWearableType::WT_GLOVES, new WearableEntry(trans, "gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE));
+ addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(trans, "undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE));
+ addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(trans, "underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE));
+ addEntry(LLWearableType::WT_SKIRT, new WearableEntry(trans, "skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE));
+ addEntry(LLWearableType::WT_ALPHA, new WearableEntry(trans, "alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE));
+ addEntry(LLWearableType::WT_TATTOO, new WearableEntry(trans, "tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE));
+ addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(trans, "universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, FALSE, TRUE));
+
+ addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(trans, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
+
+ addEntry(LLWearableType::WT_INVALID, new WearableEntry(trans, "invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE));
+ addEntry(LLWearableType::WT_NONE, new WearableEntry(trans, "none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
}
// class LLWearableType
-LLWearableType::LLWearableType(LLTranslationBridge* trans)
+LLWearableType::LLWearableType(LLTranslationBridge::ptr_t &trans)
+: mDictionary(trans)
{
- // LLTranslationBridge exists, but is not ready at this point in time since strings.xml is not yet loaded
- mTrans = trans;
}
LLWearableType::~LLWearableType()
{
- delete mTrans;
}
void LLWearableType::initSingleton()
{
- // To make sure all wrapping functions will crash without initing LLWearableType;
- LLWearableDictionary::initParamSingleton(*this);
-
- // Todo: consider merging LLWearableType and LLWearableDictionary
}
-// static
LLWearableType::EType LLWearableType::typeNameToType(const std::string& type_name)
{
- const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
- const LLWearableType::EType wearable = dict->lookup(type_name);
+ const LLWearableType::EType wearable = mDictionary.lookup(type_name);
return wearable;
}
-// static
const std::string& LLWearableType::getTypeName(LLWearableType::EType type)
{
- const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
- const WearableEntry *entry = dict->lookup(type);
+ const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getTypeName(WT_INVALID);
return entry->mName;
}
-//static
const std::string& LLWearableType::getTypeDefaultNewName(LLWearableType::EType type)
{
- const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
- const WearableEntry *entry = dict->lookup(type);
+ const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getTypeDefaultNewName(WT_INVALID);
return entry->mDefaultNewName;
}
-// static
const std::string& LLWearableType::getTypeLabel(LLWearableType::EType type)
{
- const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
- const WearableEntry *entry = dict->lookup(type);
+ const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getTypeLabel(WT_INVALID);
return entry->mLabel;
}
-// static
LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type)
{
- const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
- const WearableEntry *entry = dict->lookup(type);
+ const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getAssetType(WT_INVALID);
return entry->mAssetType;
}
-// static
LLInventoryType::EIconName LLWearableType::getIconName(LLWearableType::EType type)
{
- const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
- const WearableEntry *entry = dict->lookup(type);
+ const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getIconName(WT_INVALID);
return entry->mIconName;
}
-// static
BOOL LLWearableType::getDisableCameraSwitch(LLWearableType::EType type)
{
- const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
- const WearableEntry *entry = dict->lookup(type);
+ const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return FALSE;
return entry->mDisableCameraSwitch;
}
-// static
BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type)
{
- const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
- const WearableEntry *entry = dict->lookup(type);
+ const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return FALSE;
return entry->mAllowMultiwear;
}
diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h
index 57f3ef160d..c83f03e621 100644
--- a/indra/llappearance/llwearabletype.h
+++ b/indra/llappearance/llwearabletype.h
@@ -35,10 +35,9 @@
class LLWearableType : public LLParamSingleton<LLWearableType>
{
- LLSINGLETON(LLWearableType, LLTranslationBridge* trans);
+ LLSINGLETON(LLWearableType, LLTranslationBridge::ptr_t &trans);
~LLWearableType();
void initSingleton();
- friend struct WearableEntry;
public:
enum EType
{
@@ -67,20 +66,53 @@ public:
// Most methods are wrappers for dictionary, but if LLWearableType is not initialized,
// they will crash. Whole LLWearableType is just wrapper for convinient calls.
- static const std::string& getTypeName(EType type);
- static const std::string& getTypeDefaultNewName(EType type);
- static const std::string& getTypeLabel(EType type);
- static LLAssetType::EType getAssetType(EType type);
- static EType typeNameToType(const std::string& type_name);
- static LLInventoryType::EIconName getIconName(EType type);
- static BOOL getDisableCameraSwitch(EType type);
- static BOOL getAllowMultiwear(EType type);
+ const std::string& getTypeName(EType type);
+ const std::string& getTypeDefaultNewName(EType type);
+ const std::string& getTypeLabel(EType type);
+ LLAssetType::EType getAssetType(EType type);
+ EType typeNameToType(const std::string& type_name);
+ LLInventoryType::EIconName getIconName(EType type);
+ BOOL getDisableCameraSwitch(EType type);
+ BOOL getAllowMultiwear(EType type);
static EType inventoryFlagsToWearableType(U32 flags);
-protected:
+private:
+ struct WearableEntry : public LLDictionaryEntry
+ {
+ WearableEntry(LLTranslationBridge::ptr_t& trans,
+ const std::string &name,
+ const std::string& default_new_name,
+ LLAssetType::EType assetType,
+ LLInventoryType::EIconName iconName,
+ BOOL disable_camera_switch = FALSE,
+ BOOL allow_multiwear = TRUE) :
+ LLDictionaryEntry(name),
+ mAssetType(assetType),
+ mDefaultNewName(default_new_name),
+ mLabel(trans->getString(name)),
+ mIconName(iconName),
+ mDisableCameraSwitch(disable_camera_switch),
+ mAllowMultiwear(allow_multiwear)
+ {
- LLTranslationBridge* mTrans;
+ }
+ const LLAssetType::EType mAssetType;
+ const std::string mLabel;
+ const std::string mDefaultNewName; //keep mLabel for backward compatibility
+ LLInventoryType::EIconName mIconName;
+ BOOL mDisableCameraSwitch;
+ BOOL mAllowMultiwear;
+ };
+
+ class LLWearableDictionary : public LLDictionary<LLWearableType::EType, WearableEntry>
+ {
+ public:
+ LLWearableDictionary(LLTranslationBridge::ptr_t& trans);
+ ~LLWearableDictionary() {}
+ };
+
+ LLWearableDictionary mDictionary;
};
#endif // LL_LLWEARABLETYPE_H
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index f876b8ee4a..781c41f3de 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -435,6 +435,60 @@ namespace
typedef std::vector<LLError::RecorderPtr> Recorders;
typedef std::vector<LLError::CallSite*> CallSiteVector;
+ class SettingsConfig : public LLRefCount
+ {
+ friend class Globals;
+
+ public:
+ virtual ~SettingsConfig();
+
+ LLError::ELevel mDefaultLevel;
+
+ bool mLogAlwaysFlush;
+
+ U32 mEnabledLogTypesMask;
+
+ LevelMap mFunctionLevelMap;
+ LevelMap mClassLevelMap;
+ LevelMap mFileLevelMap;
+ LevelMap mTagLevelMap;
+ std::map<std::string, unsigned int> mUniqueLogMessages;
+
+ LLError::FatalFunction mCrashFunction;
+ LLError::TimeFunction mTimeFunction;
+
+ Recorders mRecorders;
+
+ int mShouldLogCallCounter;
+
+ private:
+ SettingsConfig();
+ };
+
+ typedef LLPointer<SettingsConfig> SettingsConfigPtr;
+
+ SettingsConfig::SettingsConfig()
+ : LLRefCount(),
+ mDefaultLevel(LLError::LEVEL_DEBUG),
+ mLogAlwaysFlush(true),
+ mEnabledLogTypesMask(255),
+ mFunctionLevelMap(),
+ mClassLevelMap(),
+ mFileLevelMap(),
+ mTagLevelMap(),
+ mUniqueLogMessages(),
+ mCrashFunction(NULL),
+ mTimeFunction(NULL),
+ mRecorders(),
+ mShouldLogCallCounter(0)
+ {
+ }
+
+ SettingsConfig::~SettingsConfig()
+ {
+ mRecorders.clear();
+ }
+
class Globals
{
public:
@@ -449,14 +503,21 @@ namespace
void addCallSite(LLError::CallSite&);
void invalidateCallSites();
+ SettingsConfigPtr getSettingsConfig();
+
+ void resetSettingsConfig();
+ LLError::SettingsStoragePtr saveAndResetSettingsConfig();
+ void restore(LLError::SettingsStoragePtr pSettingsStorage);
private:
CallSiteVector callSites;
+ SettingsConfigPtr mSettingsConfig;
};
Globals::Globals()
: messageStream(),
messageStreamInUse(false),
- callSites()
+ callSites(),
+ mSettingsConfig(new SettingsConfig())
{
}
@@ -486,120 +547,31 @@ namespace
callSites.clear();
}
-}
-
-namespace LLError
-{
- class SettingsConfig : public LLRefCount
- {
- friend class Settings;
-
- public:
- virtual ~SettingsConfig();
-
- LLError::ELevel mDefaultLevel;
-
- bool mLogAlwaysFlush;
-
- U32 mEnabledLogTypesMask;
-
- LevelMap mFunctionLevelMap;
- LevelMap mClassLevelMap;
- LevelMap mFileLevelMap;
- LevelMap mTagLevelMap;
- std::map<std::string, unsigned int> mUniqueLogMessages;
-
- LLError::FatalFunction mCrashFunction;
- LLError::TimeFunction mTimeFunction;
-
- Recorders mRecorders;
-
- int mShouldLogCallCounter;
-
- private:
- SettingsConfig();
- };
-
- typedef LLPointer<SettingsConfig> SettingsConfigPtr;
-
- class Settings
- {
- public:
- static Settings* getInstance();
- protected:
- Settings();
- public:
- SettingsConfigPtr getSettingsConfig();
-
- void reset();
- SettingsStoragePtr saveAndReset();
- void restore(SettingsStoragePtr pSettingsStorage);
-
- private:
- SettingsConfigPtr mSettingsConfig;
- };
-
- SettingsConfig::SettingsConfig()
- : LLRefCount(),
- mDefaultLevel(LLError::LEVEL_DEBUG),
- mLogAlwaysFlush(true),
- mEnabledLogTypesMask(255),
- mFunctionLevelMap(),
- mClassLevelMap(),
- mFileLevelMap(),
- mTagLevelMap(),
- mUniqueLogMessages(),
- mCrashFunction(NULL),
- mTimeFunction(NULL),
- mRecorders(),
- mShouldLogCallCounter(0)
- {
- }
- SettingsConfig::~SettingsConfig()
- {
- mRecorders.clear();
- }
-
- Settings::Settings():
- mSettingsConfig(new SettingsConfig())
- {
- }
-
- Settings* Settings::getInstance()
+ SettingsConfigPtr Globals::getSettingsConfig()
{
- // According to C++11 Function-Local Initialization
- // of static variables is supposed to be thread safe
- // without risk of deadlocks.
- static Settings inst;
-
- return &inst;
+ return mSettingsConfig;
}
- SettingsConfigPtr Settings::getSettingsConfig()
- {
- return mSettingsConfig;
- }
-
- void Settings::reset()
- {
- Globals::getInstance()->invalidateCallSites();
- mSettingsConfig = new SettingsConfig();
- }
+ void Globals::resetSettingsConfig()
+ {
+ invalidateCallSites();
+ mSettingsConfig = new SettingsConfig();
+ }
- SettingsStoragePtr Settings::saveAndReset()
- {
- SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get());
- reset();
- return oldSettingsConfig;
- }
+ LLError::SettingsStoragePtr Globals::saveAndResetSettingsConfig()
+ {
+ LLError::SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get());
+ resetSettingsConfig();
+ return oldSettingsConfig;
+ }
- void Settings::restore(SettingsStoragePtr pSettingsStorage)
- {
- Globals::getInstance()->invalidateCallSites();
- SettingsConfigPtr newSettingsConfig(dynamic_cast<SettingsConfig *>(pSettingsStorage.get()));
- mSettingsConfig = newSettingsConfig;
- }
+ void Globals::restore(LLError::SettingsStoragePtr pSettingsStorage)
+ {
+ invalidateCallSites();
+ SettingsConfigPtr newSettingsConfig(dynamic_cast<SettingsConfig *>(pSettingsStorage.get()));
+ mSettingsConfig = newSettingsConfig;
+ }
}
namespace LLError
@@ -723,7 +695,7 @@ namespace
void commonInit(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true)
{
- LLError::Settings::getInstance()->reset();
+ Globals::getInstance()->resetSettingsConfig();
LLError::setDefaultLevel(LLError::LEVEL_INFO);
LLError::setAlwaysFlush(true);
@@ -765,13 +737,13 @@ namespace LLError
void setFatalFunction(const FatalFunction& f)
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mCrashFunction = f;
}
FatalFunction getFatalFunction()
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mCrashFunction;
}
@@ -782,72 +754,77 @@ namespace LLError
void setTimeFunction(TimeFunction f)
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mTimeFunction = f;
}
void setDefaultLevel(ELevel level)
{
- Globals::getInstance()->invalidateCallSites();
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ Globals *g = Globals::getInstance();
+ g->invalidateCallSites();
+ SettingsConfigPtr s = g->getSettingsConfig();
s->mDefaultLevel = level;
}
ELevel getDefaultLevel()
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mDefaultLevel;
}
void setAlwaysFlush(bool flush)
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mLogAlwaysFlush = flush;
}
bool getAlwaysFlush()
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mLogAlwaysFlush;
}
void setEnabledLogTypesMask(U32 mask)
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mEnabledLogTypesMask = mask;
}
U32 getEnabledLogTypesMask()
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mEnabledLogTypesMask;
}
void setFunctionLevel(const std::string& function_name, ELevel level)
{
- Globals::getInstance()->invalidateCallSites();
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ Globals *g = Globals::getInstance();
+ g->invalidateCallSites();
+ SettingsConfigPtr s = g->getSettingsConfig();
s->mFunctionLevelMap[function_name] = level;
}
void setClassLevel(const std::string& class_name, ELevel level)
{
- Globals::getInstance()->invalidateCallSites();
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ Globals *g = Globals::getInstance();
+ g->invalidateCallSites();
+ SettingsConfigPtr s = g->getSettingsConfig();
s->mClassLevelMap[class_name] = level;
}
void setFileLevel(const std::string& file_name, ELevel level)
{
- Globals::getInstance()->invalidateCallSites();
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ Globals *g = Globals::getInstance();
+ g->invalidateCallSites();
+ SettingsConfigPtr s = g->getSettingsConfig();
s->mFileLevelMap[file_name] = level;
}
void setTagLevel(const std::string& tag_name, ELevel level)
{
- Globals::getInstance()->invalidateCallSites();
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ Globals *g = Globals::getInstance();
+ g->invalidateCallSites();
+ SettingsConfigPtr s = g->getSettingsConfig();
s->mTagLevelMap[tag_name] = level;
}
@@ -892,8 +869,9 @@ namespace LLError
{
void configure(const LLSD& config)
{
- Globals::getInstance()->invalidateCallSites();
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ Globals *g = Globals::getInstance();
+ g->invalidateCallSites();
+ SettingsConfigPtr s = g->getSettingsConfig();
s->mFunctionLevelMap.clear();
s->mClassLevelMap.clear();
@@ -1020,7 +998,7 @@ namespace LLError
{
return;
}
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mRecorders.push_back(recorder);
}
@@ -1030,7 +1008,7 @@ namespace LLError
{
return;
}
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder),
s->mRecorders.end());
}
@@ -1046,7 +1024,7 @@ namespace LLError
std::pair<boost::shared_ptr<RECORDER>, Recorders::iterator>
findRecorderPos()
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
// Since we promise to return an iterator, use a classic iterator
// loop.
auto end{s->mRecorders.end()};
@@ -1089,7 +1067,7 @@ namespace LLError
auto found = findRecorderPos<RECORDER>();
if (found.first)
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mRecorders.erase(found.second);
}
return bool(found.first);
@@ -1187,7 +1165,7 @@ namespace
void writeToRecorders(const LLError::CallSite& site, const std::string& message)
{
LLError::ELevel level = site.mLevel;
- LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
std::string escaped_message;
@@ -1325,7 +1303,8 @@ namespace LLError
return false;
}
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ Globals *g = Globals::getInstance();
+ SettingsConfigPtr s = g->getSettingsConfig();
s->mShouldLogCallCounter++;
@@ -1355,7 +1334,7 @@ namespace LLError
: false);
site.mCached = true;
- Globals::getInstance()->addCallSite(site);
+ g->addCallSite(site);
return site.mShouldLog = site.mLevel >= compareLevel;
}
@@ -1419,7 +1398,7 @@ namespace LLError
}
Globals* g = Globals::getInstance();
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = g->getSettingsConfig();
std::string message = out->str();
if (out == &g->messageStream)
@@ -1478,12 +1457,12 @@ namespace LLError
{
SettingsStoragePtr saveAndResetSettings()
{
- return Settings::getInstance()->saveAndReset();
+ return Globals::getInstance()->saveAndResetSettingsConfig();
}
void restoreSettings(SettingsStoragePtr pSettingsStorage)
{
- return Settings::getInstance()->restore(pSettingsStorage);
+ return Globals::getInstance()->restore(pSettingsStorage);
}
std::string removePrefix(std::string& s, const std::string& p)
@@ -1529,7 +1508,7 @@ namespace LLError
int shouldLogCallCount()
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mShouldLogCallCounter;
}
@@ -1707,8 +1686,8 @@ bool debugLoggingEnabled(const std::string& tag)
{
return false;
}
-
- LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
+
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
LLError::ELevel level = LLError::LEVEL_DEBUG;
bool res = checkLevelMap(s->mTagLevelMap, tag, level);
return res;
diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp
index 6cf6af6437..96c1297e0d 100644
--- a/indra/llmessage/lldatapacker.cpp
+++ b/indra/llmessage/lldatapacker.cpp
@@ -173,6 +173,71 @@ BOOL LLDataPacker::unpackFixed(F32 &value, const char *name,
return ok;
}
+BOOL LLDataPacker::unpackU16s(U16 *values, S32 count, const char *name)
+{
+ for (S32 idx = 0; idx < count; ++idx)
+ {
+ if (!unpackU16(values[idx], name))
+ {
+ LL_WARNS("DATAPACKER") << "Buffer overflow reading Unsigned 16s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLDataPacker::unpackS16s(S16 *values, S32 count, const char *name)
+{
+ for (S32 idx = 0; idx < count; ++idx)
+ {
+ if (!unpackS16(values[idx], name))
+ {
+ LL_WARNS("DATAPACKER") << "Buffer overflow reading Signed 16s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLDataPacker::unpackF32s(F32 *values, S32 count, const char *name)
+{
+ for (S32 idx = 0; idx < count; ++idx)
+ {
+ if (!unpackF32(values[idx], name))
+ {
+ LL_WARNS("DATAPACKER") << "Buffer overflow reading Float 32s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLDataPacker::unpackColor4Us(LLColor4U *values, S32 count, const char *name)
+{
+ for (S32 idx = 0; idx < count; ++idx)
+ {
+ if (!unpackColor4U(values[idx], name))
+ {
+ LL_WARNS("DATAPACKER") << "Buffer overflow reading Float 32s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLDataPacker::unpackUUIDs(LLUUID *values, S32 count, const char *name)
+{
+ for (S32 idx = 0; idx < count; ++idx)
+ {
+ if (!unpackUUID(values[idx], name))
+ {
+ LL_WARNS("DATAPACKER") << "Buffer overflow reading UUIDs \"" << name << "\" at index " << idx << "!" << LL_ENDL;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
//---------------------------------------------------------------------------
// LLDataPackerBinaryBuffer implementation
//---------------------------------------------------------------------------
@@ -319,6 +384,29 @@ BOOL LLDataPackerBinaryBuffer::unpackU16(U16 &value, const char *name)
return success;
}
+BOOL LLDataPackerBinaryBuffer::packS16(const S16 value, const char *name)
+{
+ BOOL success = verifyLength(sizeof(S16), name);
+
+ if (mWriteEnabled && success)
+ {
+ htolememcpy(mCurBufferp, &value, MVT_S16, 2);
+ }
+ mCurBufferp += 2;
+ return success;
+}
+
+BOOL LLDataPackerBinaryBuffer::unpackS16(S16 &value, const char *name)
+{
+ BOOL success = verifyLength(sizeof(S16), name);
+
+ if (success)
+ {
+ htolememcpy(&value, mCurBufferp, MVT_S16, 2);
+ }
+ mCurBufferp += 2;
+ return success;
+}
BOOL LLDataPackerBinaryBuffer::packU32(const U32 value, const char *name)
{
@@ -884,6 +972,52 @@ BOOL LLDataPackerAsciiBuffer::unpackU16(U16 &value, const char *name)
return success;
}
+BOOL LLDataPackerAsciiBuffer::packS16(const S16 value, const char *name)
+{
+ BOOL success = TRUE;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp, getBufferSize() - getCurrentSize(), "%d\n", value); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%d\n", value); /* Flawfinder: ignore */
+ }
+
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if(numCopied < 0 || numCopied > getBufferSize() - getCurrentSize())
+ {
+ numCopied = getBufferSize() - getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packS16: val truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+
+ return success;
+}
+
+
+BOOL LLDataPackerAsciiBuffer::unpackS16(S16 &value, const char *name)
+{
+ BOOL success = TRUE;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return FALSE;
+ }
+
+ S32 in_val;
+ sscanf(valuestr, "%d", &in_val);
+ value = in_val;
+ return success;
+}
BOOL LLDataPackerAsciiBuffer::packU32(const U32 value, const char *name)
{
@@ -1587,6 +1721,36 @@ BOOL LLDataPackerAsciiFile::unpackU16(U16 &value, const char *name)
return success;
}
+BOOL LLDataPackerAsciiFile::packS16(const S16 value, const char *name)
+{
+ BOOL success = TRUE;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP, "%d\n", value);
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream << "" << value << "\n";
+ }
+ return success;
+}
+
+
+BOOL LLDataPackerAsciiFile::unpackS16(S16 &value, const char *name)
+{
+ BOOL success = TRUE;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return FALSE;
+ }
+
+ S32 in_val;
+ sscanf(valuestr, "%d", &in_val);
+ value = in_val;
+ return success;
+}
BOOL LLDataPackerAsciiFile::packU32(const U32 value, const char *name)
{
diff --git a/indra/llmessage/lldatapacker.h b/indra/llmessage/lldatapacker.h
index 5140f56c01..ac28cadbce 100644
--- a/indra/llmessage/lldatapacker.h
+++ b/indra/llmessage/lldatapacker.h
@@ -60,6 +60,11 @@ public:
virtual BOOL packU16(const U16 value, const char *name) = 0;
virtual BOOL unpackU16(U16 &value, const char *name) = 0;
+ BOOL unpackU16s(U16 *value, S32 count, const char *name);
+
+ virtual BOOL packS16(const S16 value, const char *name) = 0;
+ virtual BOOL unpackS16(S16 &value, const char *name) = 0;
+ BOOL unpackS16s(S16 *value, S32 count, const char *name);
virtual BOOL packU32(const U32 value, const char *name) = 0;
virtual BOOL unpackU32(U32 &value, const char *name) = 0;
@@ -69,6 +74,7 @@ public:
virtual BOOL packF32(const F32 value, const char *name) = 0;
virtual BOOL unpackF32(F32 &value, const char *name) = 0;
+ BOOL unpackF32s(F32 *values, S32 count, const char *name);
// Packs a float into an integer, using the given size
// and picks the right U* data type to pack into.
@@ -82,6 +88,7 @@ public:
virtual BOOL packColor4U(const LLColor4U &value, const char *name) = 0;
virtual BOOL unpackColor4U(LLColor4U &value, const char *name) = 0;
+ BOOL unpackColor4Us(LLColor4U *values, S32 count, const char *name);
virtual BOOL packVector2(const LLVector2 &value, const char *name) = 0;
virtual BOOL unpackVector2(LLVector2 &value, const char *name) = 0;
@@ -94,6 +101,7 @@ public:
virtual BOOL packUUID(const LLUUID &value, const char *name) = 0;
virtual BOOL unpackUUID(LLUUID &value, const char *name) = 0;
+ BOOL unpackUUIDs(LLUUID *values, S32 count, const char *name);
U32 getPassFlags() const { return mPassFlags; }
void setPassFlags(U32 flags) { mPassFlags = flags; }
protected:
@@ -139,6 +147,9 @@ public:
/*virtual*/ BOOL packU16(const U16 value, const char *name);
/*virtual*/ BOOL unpackU16(U16 &value, const char *name);
+ /*virtual*/ BOOL packS16(const S16 value, const char *name);
+ /*virtual*/ BOOL unpackS16(S16 &value, const char *name);
+
/*virtual*/ BOOL packU32(const U32 value, const char *name);
/*virtual*/ BOOL unpackU32(U32 &value, const char *name);
@@ -247,6 +258,9 @@ public:
/*virtual*/ BOOL packU16(const U16 value, const char *name);
/*virtual*/ BOOL unpackU16(U16 &value, const char *name);
+ /*virtual*/ BOOL packS16(const S16 value, const char *name);
+ /*virtual*/ BOOL unpackS16(S16 &value, const char *name);
+
/*virtual*/ BOOL packU32(const U32 value, const char *name);
/*virtual*/ BOOL unpackU32(U32 &value, const char *name);
@@ -375,6 +389,9 @@ public:
/*virtual*/ BOOL packU16(const U16 value, const char *name);
/*virtual*/ BOOL unpackU16(U16 &value, const char *name);
+ /*virtual*/ BOOL packS16(const S16 value, const char *name);
+ /*virtual*/ BOOL unpackS16(S16 &value, const char *name);
+
/*virtual*/ BOOL packU32(const U32 value, const char *name);
/*virtual*/ BOOL unpackU32(U32 &value, const char *name);
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index 53b83a40d7..e08b1914e8 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -114,6 +114,35 @@ const char *SCULPT_DEFAULT_TEXTURE = "be293869-d0d9-0a69-5989-ad27f1946fd4"; //
// can't be divided by 2. See DEV-19108
const F32 TEXTURE_ROTATION_PACK_FACTOR = ((F32) 0x08000);
+struct material_id_type // originally from llrendermaterialtable
+{
+ material_id_type()
+ {
+ memset(m_value, 0, sizeof(m_value));
+ }
+
+ bool operator==(const material_id_type& other) const
+ {
+ return (memcmp(m_value, other.m_value, sizeof(m_value)) == 0);
+ }
+
+ bool operator!=(const material_id_type& other) const
+ {
+ return !operator==(other);
+ }
+
+ bool isNull() const
+ {
+ return (memcmp(m_value, s_null_id, sizeof(m_value)) == 0);
+ }
+
+ U8 m_value[MATERIAL_ID_SIZE]; // server side this is MD5RAW_BYTES
+
+ static const U8 s_null_id[MATERIAL_ID_SIZE];
+};
+
+const U8 material_id_type::s_null_id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
//static
// LEGACY: by default we use the LLVolumeMgr::gVolumeMgr global
// TODO -- eliminate this global from the codebase!
@@ -1079,50 +1108,85 @@ S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_fa
return (S32)(cur_ptr - start_loc);
}
-S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type)
-{
- U8 *start_loc = cur_ptr;
- U64 i;
- htolememcpy(data_ptr,cur_ptr, type,data_size);
- cur_ptr += data_size;
-
- for (i = 1; i < face_count; i++)
- {
- // Already unswizzled, don't need to unswizzle it again!
- memcpy(data_ptr+(i*data_size),data_ptr,data_size); /* Flawfinder: ignore */
- }
-
- while ((cur_ptr < buffer_end) && (*cur_ptr != 0))
- {
- LL_DEBUGS("TEFieldDecode") << "TE exception" << LL_ENDL;
- i = 0;
- while (*cur_ptr & 0x80)
- {
- i |= ((*cur_ptr++) & 0x7F);
- i = i << 7;
- }
-
- i |= *cur_ptr++;
-
- for (S32 j = 0; j < face_count; j++)
- {
- if (i & 0x01)
- {
- htolememcpy(data_ptr+(j*data_size),cur_ptr,type,data_size);
- LL_DEBUGS("TEFieldDecode") << "Assigning " ;
- char foo[64];
- sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1));
- LL_CONT << foo << " to face " << j << LL_ENDL;
- }
- i = i >> 1;
- }
- cur_ptr += data_size;
- }
- llassert(cur_ptr <= buffer_end); // buffer underrun
- return (S32)(cur_ptr - start_loc);
+namespace
+{
+ template< typename T >
+ bool unpack_TEField(T dest[], U8 dest_count, U8 * &source, U8 *source_end, EMsgVariableType type)
+ {
+ const size_t size(sizeof(T));
+
+ LL_DEBUGS("TEXTUREENTRY") << "Request to read items of size " << size << " with swizzle " << type << " froum buffer sized " << (source_end - source) << LL_ENDL;
+
+ if ((source + size + 1) > source_end)
+ {
+ // we add 1 above to take into account the byte that we know must follow the value.
+ LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Requires " << size << " + 1 bytes for default, " << (source_end - source) << " bytes remaning." << LL_ENDL;
+ source = source_end;
+ return false;
+ }
+
+ // Extract the default value and fill the array.
+ htolememcpy(dest, source, type, size);
+ source += size;
+ for (S32 idx = 1; idx < dest_count; ++idx)
+ {
+ dest[idx] = dest[0];
+ }
+
+ while (source < source_end)
+ {
+ U64 index_flags(0);
+ U8 sbit(0);
+
+ // Unpack the variable length bitfield. Each bit represents whether the following
+ // value will be placed at the corresponding array index.
+ do
+ {
+ if (source >= source_end)
+ {
+ LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Reading index flags." << LL_ENDL;
+ source = source_end;
+ return false;
+ }
+
+ sbit = *source++;
+ index_flags <<= 7; // original code had this after?
+ index_flags |= (sbit & 0x7F);
+ } while (sbit & 0x80);
+
+ if (!index_flags)
+ { // We've hit the terminating 0 byte.
+ break;
+ }
+
+ if ((source + size + 1) > source_end)
+ {
+ // we add 1 above to take into account the byte that we know must follow the value.
+ LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Requires " << size << " + 1 bytes for default, " << (source_end - source) << " bytes remaning." << LL_ENDL;
+ source = source_end;
+ return false;
+ }
+
+ // get the value for the indexs.
+ T value;
+ htolememcpy(&value, source, type, size);
+ source += size;
+
+ for (S32 idx = 0; idx < dest_count; idx++)
+ {
+ if (index_flags & 1ULL << idx)
+ {
+ dest[idx] = value;
+ }
+ }
+
+ }
+ return true;
+ }
}
+
// Pack information about all texture entries into container:
// { TextureEntry Variable 2 }
// Includes information about image ID, color, scale S,T, offset S,T and rotation
@@ -1298,9 +1362,9 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num, LLTEContents& tec)
{
S32 retval = 0;
- // temp buffer for material ID processing
- // data will end up in tec.material_id[]
- U8 material_data[LLTEContents::MAX_TES*16];
+ // temp buffer for material ID processing
+ // data will end up in tec.material_id[]
+ material_id_type material_data[LLTEContents::MAX_TES];
if (block_num < 0)
{
@@ -1316,54 +1380,49 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name
tec.face_count = 0;
return retval;
}
+ else if (tec.size >= LLTEContents::MAX_TE_BUFFER)
+ {
+ LL_WARNS("TEXTUREENTRY") << "Excessive buffer size detected in Texture Entry! Truncating." << LL_ENDL;
+ tec.size = LLTEContents::MAX_TE_BUFFER - 1;
+ }
- if (block_num < 0)
- {
- mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, 0, LLTEContents::MAX_TE_BUFFER);
- }
- else
- {
- mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, block_num, LLTEContents::MAX_TE_BUFFER);
- }
+ // if block_num < 0 ask for block 0
+ mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, std::max(block_num, 0), LLTEContents::MAX_TE_BUFFER - 1);
-
+ // The last field is not zero terminated.
+ // Rather than special case the upack functions. Just make it 0x00 terminated.
+ tec.packed_buffer[tec.size] = 0x00;
+ ++tec.size;
tec.face_count = llmin((U32)getNumTEs(),(U32)LLTEContents::MAX_TES);
U8 *cur_ptr = tec.packed_buffer;
- cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.image_data, 16, tec.face_count, MVT_LLUUID);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.colors, 4, tec.face_count, MVT_U8);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.scale_s, 4, tec.face_count, MVT_F32);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.scale_t, 4, tec.face_count, MVT_F32);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.offset_s, 2, tec.face_count, MVT_S16Array);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.offset_t, 2, tec.face_count, MVT_S16Array);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.image_rot, 2, tec.face_count, MVT_S16Array);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.bump, 1, tec.face_count, MVT_U8);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.media_flags, 1, tec.face_count, MVT_U8);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.glow, 1, tec.face_count, MVT_U8);
-
- if (cur_ptr < tec.packed_buffer + tec.size)
- {
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)material_data, 16, tec.face_count, MVT_LLUUID);
- }
- else
+ LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffere sized: " << tec.size << LL_ENDL;
+ U8 *buffer_end = tec.packed_buffer + tec.size;
+
+ if (!( unpack_TEField<LLUUID>(tec.image_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID) &&
+ unpack_TEField<LLColor4U>(tec.colors, tec.face_count, cur_ptr, buffer_end, MVT_U8) &&
+ unpack_TEField<F32>(tec.scale_s, tec.face_count, cur_ptr, buffer_end, MVT_F32) &&
+ unpack_TEField<F32>(tec.scale_t, tec.face_count, cur_ptr, buffer_end, MVT_F32) &&
+ unpack_TEField<S16>(tec.offset_s, tec.face_count, cur_ptr, buffer_end, MVT_S16) &&
+ unpack_TEField<S16>(tec.offset_t, tec.face_count, cur_ptr, buffer_end, MVT_S16) &&
+ unpack_TEField<S16>(tec.image_rot, tec.face_count, cur_ptr, buffer_end, MVT_S16) &&
+ unpack_TEField<U8>(tec.bump, tec.face_count, cur_ptr, buffer_end, MVT_U8) &&
+ unpack_TEField<U8>(tec.media_flags, tec.face_count, cur_ptr, buffer_end, MVT_U8) &&
+ unpack_TEField<U8>(tec.glow, tec.face_count, cur_ptr, buffer_end, MVT_U8)))
+ {
+ LL_WARNS("TEXTUREENTRY") << "Failure parsing Texture Entry Message due to malformed TE Field! Dropping changes on the floor. " << LL_ENDL;
+ return 0;
+ }
+
+ if (cur_ptr >= buffer_end || !unpack_TEField<material_id_type>(material_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID))
{
memset(material_data, 0, sizeof(material_data));
}
for (U32 i = 0; i < tec.face_count; i++)
{
- tec.material_ids[i].set(&material_data[i * 16]);
+ tec.material_ids[i].set(&(material_data[i]));
}
retval = 1;
@@ -1375,7 +1434,6 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec)
S32 retval = 0;
LLColor4 color;
- LLColor4U coloru;
for (U32 i = 0; i < tec.face_count; i++)
{
LLUUID& req_id = ((LLUUID*)tec.image_data)[i];
@@ -1388,20 +1446,15 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec)
retval |= setTEGlow(i, (F32)tec.glow[i] / (F32)0xFF);
retval |= setTEMaterialID(i, tec.material_ids[i]);
- coloru = LLColor4U(tec.colors + 4*i);
-
// Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
// as all zeros. However, the subtraction and addition must be done in unsigned
// byte space, not in float space, otherwise off-by-one errors occur. JC
- color.mV[VRED] = F32(255 - coloru.mV[VRED]) / 255.f;
- color.mV[VGREEN] = F32(255 - coloru.mV[VGREEN]) / 255.f;
- color.mV[VBLUE] = F32(255 - coloru.mV[VBLUE]) / 255.f;
- color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f;
+ color.mV[VRED] = F32(255 - tec.colors[i].mV[VRED]) / 255.f;
+ color.mV[VGREEN] = F32(255 - tec.colors[i].mV[VGREEN]) / 255.f;
+ color.mV[VBLUE] = F32(255 - tec.colors[i].mV[VBLUE]) / 255.f;
+ color.mV[VALPHA] = F32(255 - tec.colors[i].mV[VALPHA]) / 255.f;
retval |= setTEColor(i, color);
-
-
-
}
return retval;
@@ -1423,24 +1476,32 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
const U32 MAX_TES = 45;
// Avoid construction of 32 UUIDs per call
- static LLUUID image_ids[MAX_TES];
static LLMaterialID material_ids[MAX_TES];
- U8 image_data[MAX_TES*16];
- U8 colors[MAX_TES*4];
- F32 scale_s[MAX_TES];
- F32 scale_t[MAX_TES];
- S16 offset_s[MAX_TES];
- S16 offset_t[MAX_TES];
- S16 image_rot[MAX_TES];
- U8 bump[MAX_TES];
- U8 media_flags[MAX_TES];
- U8 glow[MAX_TES];
- U8 material_data[MAX_TES*16];
-
- const U32 MAX_TE_BUFFER = 4096;
- U8 packed_buffer[MAX_TE_BUFFER];
- U8 *cur_ptr = packed_buffer;
+ const U32 MAX_TE_BUFFER = 4096;
+ U8 packed_buffer[MAX_TE_BUFFER];
+ memset(packed_buffer, 0, MAX_TE_BUFFER);
+
+ LLUUID image_data[MAX_TES];
+ LLColor4U colors[MAX_TES];
+ F32 scale_s[MAX_TES];
+ F32 scale_t[MAX_TES];
+ S16 offset_s[MAX_TES];
+ S16 offset_t[MAX_TES];
+ S16 image_rot[MAX_TES];
+ U8 bump[MAX_TES];
+ U8 media_flags[MAX_TES];
+ U8 glow[MAX_TES];
+ material_id_type material_data[MAX_TES];
+
+ memset(scale_s, 0, sizeof(scale_s));
+ memset(scale_t, 0, sizeof(scale_t));
+ memset(offset_s, 0, sizeof(offset_s));
+ memset(offset_t, 0, sizeof(offset_t));
+ memset(image_rot, 0, sizeof(image_rot));
+ memset(bump, 0, sizeof(bump));
+ memset(media_flags, 0, sizeof(media_flags));
+ memset(glow, 0, sizeof(glow));
S32 size;
U32 face_count = 0;
@@ -1456,50 +1517,52 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
{
return retval;
}
+ else if (size >= MAX_TE_BUFFER)
+ {
+ LL_WARNS("TEXTUREENTRY") << "Excessive buffer size detected in Texture Entry! Truncating." << LL_ENDL;
+ size = MAX_TE_BUFFER - 1;
+ }
+ // The last field is not zero terminated.
+ // Rather than special case the upack functions. Just make it 0x00 terminated.
+ packed_buffer[size] = 0x00;
+ ++size;
face_count = llmin((U32) getNumTEs(), MAX_TES);
U32 i;
- cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)colors, 4, face_count, MVT_U8);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_s, 4, face_count, MVT_F32);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_t, 4, face_count, MVT_F32);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_s, 2, face_count, MVT_S16Array);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_t, 2, face_count, MVT_S16Array);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_rot, 2, face_count, MVT_S16Array);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)bump, 1, face_count, MVT_U8);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)media_flags, 1, face_count, MVT_U8);
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)glow, 1, face_count, MVT_U8);
- if (cur_ptr < packed_buffer + size)
- {
- cur_ptr++;
- cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)material_data, 16, face_count, MVT_LLUUID);
- }
- else
+ U8 *cur_ptr = packed_buffer;
+ LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffer sized: " << size << LL_ENDL;
+ U8 *buffer_end = packed_buffer + size;
+
+ if (!( unpack_TEField<LLUUID>(image_data, face_count, cur_ptr, buffer_end, MVT_LLUUID) &&
+ unpack_TEField<LLColor4U>(colors, face_count, cur_ptr, buffer_end, MVT_U8) &&
+ unpack_TEField<F32>(scale_s, face_count, cur_ptr, buffer_end, MVT_F32) &&
+ unpack_TEField<F32>(scale_t, face_count, cur_ptr, buffer_end, MVT_F32) &&
+ unpack_TEField<S16>(offset_s, face_count, cur_ptr, buffer_end, MVT_S16) &&
+ unpack_TEField<S16>(offset_t, face_count, cur_ptr, buffer_end, MVT_S16) &&
+ unpack_TEField<S16>(image_rot, face_count, cur_ptr, buffer_end, MVT_S16) &&
+ unpack_TEField<U8>(bump, face_count, cur_ptr, buffer_end, MVT_U8) &&
+ unpack_TEField<U8>(media_flags, face_count, cur_ptr, buffer_end, MVT_U8) &&
+ unpack_TEField<U8>(glow, face_count, cur_ptr, buffer_end, MVT_U8)))
+ {
+ LL_WARNS("TEXTUREENTRY") << "Failure parsing Texture Entry Message due to malformed TE Field! Dropping changes on the floor. " << LL_ENDL;
+ return 0;
+ }
+
+ if (cur_ptr >= buffer_end || !unpack_TEField<material_id_type>(material_data, face_count, cur_ptr, buffer_end, MVT_LLUUID))
{
memset(material_data, 0, sizeof(material_data));
}
for (i = 0; i < face_count; i++)
{
- memcpy(image_ids[i].mData,&image_data[i*16],16); /* Flawfinder: ignore */
- material_ids[i].set(&material_data[i * 16]);
+ material_ids[i].set(&(material_data[i]));
}
LLColor4 color;
- LLColor4U coloru;
for (i = 0; i < face_count; i++)
{
- retval |= setTETexture(i, image_ids[i]);
+ retval |= setTETexture(i, ((LLUUID*)image_data)[i]);
retval |= setTEScale(i, scale_s[i], scale_t[i]);
retval |= setTEOffset(i, (F32)offset_s[i] / (F32)0x7FFF, (F32) offset_t[i] / (F32) 0x7FFF);
retval |= setTERotation(i, ((F32)image_rot[i] / TEXTURE_ROTATION_PACK_FACTOR) * F_TWO_PI);
@@ -1507,15 +1570,14 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
retval |= setTEMediaTexGen(i, media_flags[i]);
retval |= setTEGlow(i, (F32)glow[i] / (F32)0xFF);
retval |= setTEMaterialID(i, material_ids[i]);
- coloru = LLColor4U(colors + 4*i);
// Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
// as all zeros. However, the subtraction and addition must be done in unsigned
// byte space, not in float space, otherwise off-by-one errors occur. JC
- color.mV[VRED] = F32(255 - coloru.mV[VRED]) / 255.f;
- color.mV[VGREEN] = F32(255 - coloru.mV[VGREEN]) / 255.f;
- color.mV[VBLUE] = F32(255 - coloru.mV[VBLUE]) / 255.f;
- color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f;
+ color.mV[VRED] = F32(255 - colors[i].mV[VRED]) / 255.f;
+ color.mV[VGREEN] = F32(255 - colors[i].mV[VGREEN]) / 255.f;
+ color.mV[VBLUE] = F32(255 - colors[i].mV[VBLUE]) / 255.f;
+ color.mV[VALPHA] = F32(255 - colors[i].mV[VALPHA]) / 255.f;
retval |= setTEColor(i, color);
}
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index b1f8112223..309b18faa9 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -330,8 +330,8 @@ struct LLTEContents
{
static const U32 MAX_TES = 45;
- U8 image_data[MAX_TES*16];
- U8 colors[MAX_TES*4];
+ LLUUID image_data[MAX_TES];
+ LLColor4U colors[MAX_TES];
F32 scale_s[MAX_TES];
F32 scale_t[MAX_TES];
S16 offset_s[MAX_TES];
@@ -423,7 +423,6 @@ public:
void copyTEs(const LLPrimitive *primitive);
S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const;
- S32 unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type);
BOOL packTEMessage(LLMessageSystem *mesgsys) const;
BOOL packTEMessage(LLDataPacker &dp) const;
S32 unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num); // Variable num of blocks
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index ff72417867..d92f10bdbb 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -184,6 +184,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
mFontShadow(p.font_shadow),
mPopupMenuHandle(),
mReadOnly(p.read_only),
+ mSkipTripleClick(false),
mSkipLinkUnderline(p.skip_link_underline),
mSpellCheck(p.spellcheck),
mSpellCheckStart(-1),
@@ -1017,6 +1018,11 @@ BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask)
// handle triple click
if (!mTripleClickTimer.hasExpired())
{
+ if (mSkipTripleClick)
+ {
+ return TRUE;
+ }
+
S32 real_line = getLineNumFromDocIndex(mCursorPos, false);
S32 line_start = -1;
S32 line_end = -1;
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 4e966b7cef..2e2e1b9833 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -699,7 +699,7 @@ protected:
bool mPlainText; // didn't use Image or Icon segments
bool mAutoIndent;
S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes
-
+ bool mSkipTripleClick;
bool mSkipLinkUnderline;
// support widgets
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 0afd32f332..4dc2a6a597 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -45,7 +45,9 @@ LLTextBox::LLTextBox(const LLTextBox::Params& p)
: LLTextBase(p),
mClickedCallback(NULL),
mShowCursorHand(true)
-{}
+{
+ mSkipTripleClick = true;
+}
LLTextBox::~LLTextBox()
{}
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 52dc4744f2..96da0743a4 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -12641,6 +12641,17 @@
<key>Value</key>
<integer>50</integer>
</map>
+ <key>TextureSaveLocation</key>
+ <map>
+ <key>Comment</key>
+ <string>Current location for bulk saving textures to disk</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
<key>ThrottleBandwidthKBPS</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl
index b768d609f4..d87403c78f 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl
@@ -43,13 +43,13 @@ void default_lighting()
{
vec4 color = texture2D(diffuseMap,vary_texcoord0.xy);
- color *= vertex_color;
-
if (color.a < minimum_alpha)
{
discard;
}
-
+
+ color *= vertex_color;
+
color.rgb = atmosLighting(color.rgb);
color.rgb = scaleSoftClip(color.rgb);
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl
index d04cd79f4b..37cac5f437 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl
@@ -43,13 +43,13 @@ void fullbright_lighting_water()
{
vec4 color = diffuseLookup(vary_texcoord0.xy);
- color.rgb *= vertex_color.rgb;
-
if (color.a < minimum_alpha)
{
discard;
}
+ color.rgb *= vertex_color.rgb;
+
color.rgb = fullbrightAtmosTransport(color.rgb);
frag_color = applyWaterFog(color);
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl
index 3b9c04b22b..c98db4795c 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl
@@ -41,13 +41,15 @@ VARYING vec2 vary_texcoord0;
void fullbright_lighting_water()
{
- vec4 color = texture2D(diffuseMap, vary_texcoord0.xy) * vertex_color;
+ vec4 color = texture2D(diffuseMap, vary_texcoord0.xy);
if (color.a < minimum_alpha)
{
discard;
}
+ color.rgb *= vertex_color.rgb;
+
color.rgb = fullbrightAtmosTransport(color.rgb);
frag_color = applyWaterFog(color);
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl
index 0916797259..9c89c09573 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl
@@ -41,13 +41,13 @@ void default_lighting_water()
{
vec4 color = diffuseLookup(vary_texcoord0.xy);
- color.rgb *= vertex_color.rgb;
-
if (color.a < minimum_alpha)
{
discard;
}
+ color.rgb *= vertex_color.rgb;
+
color.rgb = atmosLighting(color.rgb);
frag_color = applyWaterFog(color);
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl
index f2a84f1d42..9de7a03180 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl
@@ -43,13 +43,13 @@ void default_lighting_water()
{
vec4 color = texture2D(diffuseMap,vary_texcoord0.xy);
- color.rgb *= vertex_color.rgb;
-
if (color.a < minimum_alpha)
{
discard;
}
+ color.rgb *= vertex_color.rgb;
+
color.rgb = atmosLighting(color.rgb);
color = applyWaterFog(color);
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 7f18ea6fe2..be168ff5dd 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -1049,13 +1049,14 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
}
// updating inventory
+ LLWearableType* wearable_type_inst = LLWearableType::getInstance();
// TODO: Removed check for ensuring that teens don't remove undershirt and underwear. Handle later
// note: shirt is the first non-body part wearable item. Update if wearable order changes.
// This loop should remove all clothing, but not any body parts
for (S32 j = 0; j < (S32)LLWearableType::WT_COUNT; j++)
{
- if (LLWearableType::getAssetType((LLWearableType::EType)j) == LLAssetType::AT_CLOTHING)
+ if (wearable_type_inst->getAssetType((LLWearableType::EType)j) == LLAssetType::AT_CLOTHING)
{
removeWearable((LLWearableType::EType)j, true, 0);
}
@@ -1075,7 +1076,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
new_wearable->setName(new_item->getName());
new_wearable->setItemID(new_item->getUUID());
- if (LLWearableType::getAssetType(type) == LLAssetType::AT_BODYPART)
+ if (wearable_type_inst->getAssetType(type) == LLAssetType::AT_BODYPART)
{
// exactly one wearable per body part
setWearable(type,0,new_wearable);
@@ -1162,7 +1163,7 @@ void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearab
if ((old_wearable->getAssetID() == new_wearable->getAssetID()) &&
(old_item_id == new_item->getUUID()))
{
- LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << LL_ENDL;
+ LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getInstance()->getTypeName(type) << LL_ENDL;
return;
}
@@ -1594,7 +1595,7 @@ void LLAgentWearables::editWearable(const LLUUID& item_id)
return;
}
- const BOOL disable_camera_switch = LLWearableType::getDisableCameraSwitch(wearable->getType());
+ const BOOL disable_camera_switch = LLWearableType::getInstance()->getDisableCameraSwitch(wearable->getType());
LLPanel* panel = LLFloaterSidePanelContainer::getPanel("appearance");
LLSidepanelAppearance::editWearable(wearable, panel, disable_camera_switch);
}
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index e5c505501e..5ceeb65d0e 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -1021,7 +1021,7 @@ void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type
// Try to recover by replacing missing wearable with a new one.
LLNotificationsUtil::add("ReplacedMissingWearable");
- LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type)
+ LL_DEBUGS() << "Wearable " << LLWearableType::getInstance()->getTypeLabel(type)
<< " could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL;
LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 515d6ffc14..e8466610d2 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -777,10 +777,6 @@ bool LLAppViewer::init()
// Start of the application
//
- // initialize LLWearableType translation bridge.
- // Memory will be cleaned up in ::cleanupClass()
- LLWearableType::initParamSingleton(new LLUITranslationBridge());
-
// initialize the LLSettingsType translation bridge.
LLTranslationBridge::ptr_t trans = std::make_shared<LLUITranslationBridge>();
LLSettingsType::initParamSingleton(trans);
@@ -802,9 +798,14 @@ bool LLAppViewer::init()
//
init_default_trans_args();
+ // inits from settings.xml and from strings.xml
if (!initConfiguration())
return false;
+ // initialize LLWearableType translation bridge.
+ // Will immediately use LLTranslationBridge to init LLWearableDictionary
+ LLWearableType::initParamSingleton(trans);
+
LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ;
//set the max heap size.
diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp
index b31981b235..aa2ba752b7 100644
--- a/indra/newview/llcofwearables.cpp
+++ b/indra/newview/llcofwearables.cpp
@@ -74,7 +74,7 @@ protected:
}
// Set proper label for the "Create new <WEARABLE_TYPE>" menu item.
- std::string new_label = LLTrans::getString("create_new_" + LLWearableType::getTypeName(w_type));
+ std::string new_label = LLTrans::getString("create_new_" + LLWearableType::getInstance()->getTypeName(w_type));
menu_item->setLabel(new_label);
}
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index 347997a69a..c76920c9ce 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -677,8 +677,12 @@ void LLFavoritesBarCtrl::changed(U32 mask)
//virtual
void LLFavoritesBarCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
{
+ S32 delta_width = width - getRect().getWidth();
+ S32 delta_height = height - getRect().getHeight();
+
+ bool force_update = delta_width || delta_height || sForceReshape;
LLUICtrl::reshape(width, height, called_from_parent);
- updateButtons();
+ updateButtons(force_update);
}
void LLFavoritesBarCtrl::draw()
@@ -741,8 +745,13 @@ const LLButton::Params& LLFavoritesBarCtrl::getButtonParams()
return button_params;
}
-void LLFavoritesBarCtrl::updateButtons()
+void LLFavoritesBarCtrl::updateButtons(bool force_update)
{
+ if (LLApp::isExiting())
+ {
+ return;
+ }
+
mItems.clear();
if (!collectFavoriteItems(mItems))
@@ -773,28 +782,29 @@ void LLFavoritesBarCtrl::updateButtons()
const child_list_t* childs = getChildList();
child_list_const_iter_t child_it = childs->begin();
int first_changed_item_index = 0;
- int rightest_point = getRect().mRight - mMoreTextBox->getRect().getWidth();
- //lets find first changed button
- while (child_it != childs->end() && first_changed_item_index < mItems.size())
- {
- LLFavoriteLandmarkButton* button = dynamic_cast<LLFavoriteLandmarkButton*> (*child_it);
- if (button)
- {
- const LLViewerInventoryItem *item = mItems[first_changed_item_index].get();
- if (item)
- {
- // an child's order and mItems should be same
- if (button->getLandmarkId() != item->getUUID() // sort order has been changed
- || button->getLabelSelected() != item->getName() // favorite's name has been changed
- || button->getRect().mRight < rightest_point) // favbar's width has been changed
- {
- break;
- }
- }
- first_changed_item_index++;
- }
- child_it++;
- }
+ if (!force_update)
+ {
+ //lets find first changed button
+ while (child_it != childs->end() && first_changed_item_index < mItems.size())
+ {
+ LLFavoriteLandmarkButton* button = dynamic_cast<LLFavoriteLandmarkButton*> (*child_it);
+ if (button)
+ {
+ const LLViewerInventoryItem *item = mItems[first_changed_item_index].get();
+ if (item)
+ {
+ // an child's order and mItems should be same
+ if (button->getLandmarkId() != item->getUUID() // sort order has been changed
+ || button->getLabelSelected() != item->getName()) // favorite's name has been changed
+ {
+ break;
+ }
+ }
+ first_changed_item_index++;
+ }
+ child_it++;
+ }
+ }
// now first_changed_item_index should contains a number of button that need to change
if (first_changed_item_index <= mItems.size())
diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h
index 571208aa31..d4a6f7b06b 100644
--- a/indra/newview/llfavoritesbar.h
+++ b/indra/newview/llfavoritesbar.h
@@ -75,7 +75,7 @@ public:
void setLandingTab(LLUICtrl* tab) { mLandingTab = tab; }
protected:
- void updateButtons();
+ void updateButtons(bool force_update = false);
LLButton* createButton(const LLPointer<LLViewerInventoryItem> item, const LLButton::Params& button_params, S32 x_offset );
const LLButton::Params& getButtonParams();
BOOL collectFavoriteItems(LLInventoryModel::item_array_t &items);
diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp
index 595d584799..8ee7a72055 100644
--- a/indra/newview/llfloaterlinkreplace.cpp
+++ b/indra/newview/llfloaterlinkreplace.cpp
@@ -162,7 +162,7 @@ void LLFloaterLinkReplace::onStartClicked()
else
{
LLSD args;
- args["TYPE"] = LLWearableType::getTypeName(source_item->getWearableType());
+ args["TYPE"] = LLWearableType::getInstance()->getTypeName(source_item->getWearableType());
params.substitutions(args);
LLNotifications::instance().add(params);
}
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 1cd8841bb4..c7d3ccbb69 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2492,7 +2492,7 @@ BOOL LLPanelPreference::postBuild()
}
//////////////////////PanelSetup ///////////////////
- if (hasChild("max_bandwidth"), TRUE)
+ if (hasChild("max_bandwidth", TRUE))
{
mBandWidthUpdater = new LLPanelPreference::Updater(boost::bind(&handleBandwidthChanged, _1), BANDWIDTH_UPDATER_TIMEOUT);
gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&LLPanelPreference::Updater::update, mBandWidthUpdater, _2));
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index e9aaca13eb..5be58e43ea 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -5469,11 +5469,20 @@ void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
getClipboardEntries(true, items, disabled_items, flags);
items.push_back(std::string("Texture Separator"));
- items.push_back(std::string("Save As"));
- if (!canSaveTexture())
- {
- disabled_items.push_back(std::string("Save As"));
- }
+
+ if ((flags & ITEM_IN_MULTI_SELECTION) != 0)
+ {
+ items.push_back(std::string("Save Selected As"));
+ }
+ else
+ {
+ items.push_back(std::string("Save As"));
+ if (!canSaveTexture())
+ {
+ disabled_items.push_back(std::string("Save As"));
+ }
+ }
+
}
addLinkReplaceMenuOption(items, disabled_items);
hide_context_entries(menu, items, disabled_items);
@@ -5491,6 +5500,23 @@ void LLTextureBridge::performAction(LLInventoryModel* model, std::string action)
preview_texture->saveAs();
}
}
+ else if ("save_selected_as" == action)
+ {
+ openItem();
+ if (canSaveTexture())
+ {
+ LLPreviewTexture* preview_texture = LLFloaterReg::getTypedInstance<LLPreviewTexture>("preview_texture", mUUID);
+ if (preview_texture)
+ {
+ preview_texture->saveMultipleToFile();
+ }
+ }
+ else
+ {
+ LL_WARNS() << "You don't have permission to save " << getName() << " to disk." << LL_ENDL;
+ }
+
+ }
else LLItemBridge::performAction(model, action);
}
@@ -6820,7 +6846,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
disabled_items.push_back(std::string("Wearable Edit"));
}
- if (LLWearableType::getAllowMultiwear(mWearableType))
+ if (LLWearableType::getInstance()->getAllowMultiwear(mWearableType))
{
items.push_back(std::string("Wearable Add"));
if (!gAgentWearables.canAddWearable(mWearableType))
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index d069aa3223..937e38aaf0 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -47,6 +47,7 @@
#include "llappviewer.h"
#include "llavataractions.h"
#include "llclipboard.h"
+#include "lldirpicker.h"
#include "lldonotdisturbnotificationstorage.h"
#include "llfloatersidepanelcontainer.h"
#include "llfocusmgr.h"
@@ -2489,6 +2490,10 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
{
LLAppearanceMgr::instance().removeItemsFromAvatar(ids);
}
+ else if ("save_selected_as" == action)
+ {
+ (new LLDirPickerThread(boost::bind(&LLInventoryAction::saveMultipleTextures, _1, selected_items, model), std::string()))->getFile();
+ }
else
{
std::set<LLFolderViewItem*>::iterator set_iter;
@@ -2516,6 +2521,32 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
}
}
+void LLInventoryAction::saveMultipleTextures(const std::vector<std::string>& filenames, std::set<LLFolderViewItem*> selected_items, LLInventoryModel* model)
+{
+ gSavedSettings.setString("TextureSaveLocation", filenames[0]);
+
+ LLMultiPreview* multi_previewp = new LLMultiPreview();
+ gFloaterView->addChild(multi_previewp);
+
+ LLFloater::setFloaterHost(multi_previewp);
+
+ std::set<LLFolderViewItem*>::iterator set_iter;
+ for (set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter)
+ {
+ LLFolderViewItem* folder_item = *set_iter;
+ if(!folder_item) continue;
+ LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
+ if(!bridge) continue;
+ bridge->performAction(model, "save_selected_as");
+ }
+
+ LLFloater::setFloaterHost(NULL);
+ if (multi_previewp)
+ {
+ multi_previewp->openFloater(LLSD());
+ }
+}
+
void LLInventoryAction::removeItemFromDND(LLFolderView* root)
{
if(gAgent.isDoNotDisturb())
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 04eb962372..c1c4b8fe6c 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -466,6 +466,8 @@ struct LLInventoryAction
static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root);
static void removeItemFromDND(LLFolderView* root);
+ static void saveMultipleTextures(const std::vector<std::string>& filenames, std::set<LLFolderViewItem*> selected_items, LLInventoryModel* model);
+
static const int sConfirmOnDeleteItemsNumber;
private:
diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp
index 81c001b8bd..44e493fdf4 100644
--- a/indra/newview/llinventoryicon.cpp
+++ b/indra/newview/llinventoryicon.cpp
@@ -196,7 +196,7 @@ const std::string& LLInventoryIcon::getIconName(LLInventoryType::EIconName idx)
LLInventoryType::EIconName LLInventoryIcon::assignWearableIcon(U32 misc_flag)
{
const LLWearableType::EType wearable_type = LLWearableType::inventoryFlagsToWearableType(misc_flag);
- return LLWearableType::getIconName(wearable_type);
+ return LLWearableType::getInstance()->getIconName(wearable_type);
}
LLInventoryType::EIconName LLInventoryIcon::assignSettingsIcon(U32 misc_flag)
diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index 272e7ae351..ca7bd8cb2c 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -893,7 +893,7 @@ void LLOutfitGalleryContextMenu::onOutfitsRemovalConfirmation(const LLSD& notifi
void LLOutfitGalleryContextMenu::onCreate(const LLSD& data)
{
- LLWearableType::EType type = LLWearableType::typeNameToType(data.asString());
+ LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(data.asString());
if (type == LLWearableType::WT_NONE)
{
LL_WARNS() << "Invalid wearable type" << LL_ENDL;
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 71ab826e1c..a71432e314 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -1210,7 +1210,7 @@ void LLOutfitListGearMenuBase::onRename()
void LLOutfitListGearMenuBase::onCreate(const LLSD& data)
{
- LLWearableType::EType type = LLWearableType::typeNameToType(data.asString());
+ LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(data.asString());
if (type == LLWearableType::WT_NONE)
{
LL_WARNS() << "Invalid wearable type" << LL_ENDL;
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index c601a6c210..be11a4a9f3 100644
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -1276,7 +1276,7 @@ void LLPanelEditWearable::changeCamera(U8 subpart)
{
// Don't change the camera if this type doesn't have a camera switch.
// Useful for wearables like physics that don't have an associated physical body part.
- if (LLWearableType::getDisableCameraSwitch(mWearablePtr->getType()))
+ if (LLWearableType::getInstance()->getDisableCameraSwitch(mWearablePtr->getType()))
{
return;
}
diff --git a/indra/newview/llpanelgroupcreate.cpp b/indra/newview/llpanelgroupcreate.cpp
index 052212dc27..52be75072c 100644
--- a/indra/newview/llpanelgroupcreate.cpp
+++ b/indra/newview/llpanelgroupcreate.cpp
@@ -45,6 +45,7 @@
#include "llfloaterreg.h"
#include "llfloater.h"
#include "llgroupmgr.h"
+#include "llstatusbar.h" // to re-request balance
#include "lltrans.h"
#include "llnotificationsutil.h"
#include "lluicolortable.h"
@@ -117,6 +118,7 @@ void LLPanelGroupCreate::refreshCreatedGroup(const LLUUID& group_id)
params["group_id"] = group_id;
params["open_tab_name"] = "panel_group_info_sidetray";
LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
+ LLStatusBar::sendMoneyBalanceRequest();
}
void LLPanelGroupCreate::addMembershipRow(const std::string &name)
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index 1d87aa6f5d..9828e14262 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -97,7 +97,7 @@ std::string LLShopURLDispatcher::resolveURL(LLWearableType::EType wearable_type,
{
const std::string prefix = "MarketplaceURL";
const std::string sex_str = (sex == SEX_MALE) ? "Male" : "Female";
- const std::string type_str = LLWearableType::getTypeName(wearable_type);
+ const std::string type_str = LLWearableType::getInstance()->getTypeName(wearable_type);
std::string setting_name = prefix;
@@ -173,7 +173,7 @@ public:
private:
static void onCreate(const LLSD& param)
{
- LLWearableType::EType type = LLWearableType::typeNameToType(param.asString());
+ LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(param.asString());
if (type == LLWearableType::WT_NONE)
{
LL_WARNS() << "Invalid wearable type" << LL_ENDL;
@@ -188,19 +188,20 @@ private:
{
LLView* menu_clothes = gMenuHolder->getChildView("COF.Gear.New_Clothes", FALSE);
LLView* menu_bp = gMenuHolder->getChildView("COF.Gear.New_Body_Parts", FALSE);
+ LLWearableType * wearable_type_inst = LLWearableType::getInstance();
for (U8 i = LLWearableType::WT_SHAPE; i != (U8) LLWearableType::WT_COUNT; ++i)
{
LLWearableType::EType type = (LLWearableType::EType) i;
- const std::string& type_name = LLWearableType::getTypeName(type);
+ const std::string& type_name = wearable_type_inst->getTypeName(type);
LLMenuItemCallGL::Params p;
p.name = type_name;
- p.label = LLTrans::getString(LLWearableType::getTypeDefaultNewName(type));
+ p.label = LLTrans::getString(wearable_type_inst->getTypeDefaultNewName(type));
p.on_click.function_name = "Wearable.Create";
p.on_click.parameter = LLSD(type_name);
- LLView* parent = LLWearableType::getAssetType(type) == LLAssetType::AT_CLOTHING ? menu_clothes : menu_bp;
+ LLView* parent = wearable_type_inst->getAssetType(type) == LLAssetType::AT_CLOTHING ? menu_clothes : menu_bp;
LLUICtrlFactory::create<LLMenuItemCallGL>(p, parent);
}
}
diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp
index 1b60610668..59be35fe92 100644
--- a/indra/newview/llpreviewnotecard.cpp
+++ b/indra/newview/llpreviewnotecard.cpp
@@ -232,6 +232,7 @@ void LLPreviewNotecard::loadAsset()
if (!editor)
return;
+ bool fail = false;
if(item)
{
@@ -315,7 +316,31 @@ void LLPreviewNotecard::loadAsset()
getChildView("Delete")->setEnabled(TRUE);
}
}
- else
+ else if (mObjectUUID.notNull() && mItemUUID.notNull())
+ {
+ LLViewerObject* objectp = gObjectList.findObject(mObjectUUID);
+ if (objectp && (objectp->isInventoryPending() || objectp->isInventoryDirty()))
+ {
+ // It's a notecard in object's inventory and we failed to get it because inventory is not up to date.
+ // Subscribe for callback and retry at inventoryChanged()
+ registerVOInventoryListener(objectp, NULL); //removes previous listener
+
+ if (objectp->isInventoryDirty())
+ {
+ objectp->requestInventory();
+ }
+ }
+ else
+ {
+ fail = true;
+ }
+ }
+ else
+ {
+ fail = true;
+ }
+
+ if (fail)
{
editor->setText(LLStringUtil::null);
editor->makePristine();
@@ -600,6 +625,17 @@ void LLPreviewNotecard::syncExternal()
}
}
+/*virtual*/
+void LLPreviewNotecard::inventoryChanged(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void* user_data)
+{
+ removeVOInventoryListener();
+ loadAsset();
+}
+
+
void LLPreviewNotecard::deleteNotecard()
{
LLNotificationsUtil::add("DeleteNotecard", LLSD(), LLSD(), boost::bind(&LLPreviewNotecard::handleConfirmDeleteDialog,this, _1, _2));
diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h
index d9c14815c1..3a706b8645 100644
--- a/indra/newview/llpreviewnotecard.h
+++ b/indra/newview/llpreviewnotecard.h
@@ -31,6 +31,7 @@
#include "llassetstorage.h"
#include "llpreviewscript.h"
#include "lliconctrl.h"
+#include "llvoinventorylistener.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLPreviewNotecard
@@ -41,7 +42,7 @@
class LLViewerTextEditor;
class LLButton;
-class LLPreviewNotecard : public LLPreview
+class LLPreviewNotecard : public LLPreview, public LLVOInventoryListener
{
public:
LLPreviewNotecard(const LLSD& key);
@@ -75,6 +76,11 @@ public:
void syncExternal();
+ void inventoryChanged(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void* user_data) override;
+
protected:
void updateTitleButtons() override;
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index 9d8be4b2fe..303034ca3d 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -50,6 +50,7 @@
#include "llviewertexture.h"
#include "llviewertexturelist.h"
#include "lluictrlfactory.h"
+#include "llviewercontrol.h"
#include "llviewerwindow.h"
#include "lllineeditor.h"
@@ -317,6 +318,44 @@ void LLPreviewTexture::saveTextureToFile(const std::vector<std::string>& filenam
0, TRUE, FALSE, new LLUUID(mItemUUID), &mCallbackTextureList);
}
+
+void LLPreviewTexture::saveMultipleToFile()
+{
+ std::string texture_location(gSavedSettings.getString("TextureSaveLocation"));
+ std::string texture_name = getItem()->getName();
+
+ std::string filepath;
+ S32 i = 0;
+ S32 err = 0;
+ std::string extension(".png");
+ do
+ {
+ filepath = texture_location;
+ filepath += gDirUtilp->getDirDelimiter();
+ filepath += texture_name;
+
+ if (i != 0)
+ {
+ filepath += llformat("_%.3d", i);
+ }
+
+ filepath += extension;
+
+ llstat stat_info;
+ err = LLFile::stat( filepath, &stat_info );
+ i++;
+ } while (-1 != err); // Search until the file is not found (i.e., stat() gives an error).
+
+
+ mSaveFileName = filepath;
+ mLoadingFullImage = TRUE;
+ getWindow()->incBusyCount();
+
+ mImage->forceToSaveRawImage(0);//re-fetch the raw image if the old one is removed.
+ mImage->setLoadedCallback(LLPreviewTexture::onFileLoadedForSave,
+ 0, TRUE, FALSE, new LLUUID(mItemUUID), &mCallbackTextureList);
+}
+
// virtual
void LLPreviewTexture::reshape(S32 width, S32 height, BOOL called_from_parent)
{
diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h
index ad77d9e118..cc6c7854b6 100644
--- a/indra/newview/llpreviewtexture.h
+++ b/indra/newview/llpreviewtexture.h
@@ -63,6 +63,7 @@ public:
void openToSave();
void saveTextureToFile(const std::vector<std::string>& filenames);
+ void saveMultipleToFile();
static void onSaveAsBtn(void* data);
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index 6e2b4a00fc..81b67134d2 100644
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -204,7 +204,7 @@ void LLSidepanelAppearance::updateToVisibility(const LLSD &new_visibility)
// when editing its physics.
if (!gAgentCamera.cameraCustomizeAvatar())
{
- LLVOAvatarSelf::onCustomizeStart(LLWearableType::getDisableCameraSwitch(wearable_ptr->getType()));
+ LLVOAvatarSelf::onCustomizeStart(LLWearableType::getInstance()->getDisableCameraSwitch(wearable_ptr->getType()));
}
if (is_wearable_edit_visible)
{
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 8aa5b07561..6363edfb36 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -143,6 +143,20 @@ static bool handleSetShaderChanged(const LLSD& newvalue)
gBumpImageList.destroyGL();
gBumpImageList.restoreGL();
+ if (gPipeline.isInit())
+ {
+ // ALM depends onto atmospheric shaders, state might have changed
+ bool old_state = LLPipeline::sRenderDeferred;
+ LLPipeline::refreshCachedSettings();
+ gPipeline.updateRenderDeferred();
+ if (old_state != LLPipeline::sRenderDeferred)
+ {
+ gPipeline.releaseGLBuffers();
+ gPipeline.createGLBuffers();
+ gPipeline.resetVertexBuffers();
+ }
+ }
+
// else, leave terrain detail as is
LLViewerShaderMgr::instance()->setShaders();
return true;
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index bbed741a33..55ac817479 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -1756,7 +1756,7 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge,
else
{
// Use for all clothing and body parts. Adding new wearable types requires updating LLWearableDictionary.
- LLWearableType::EType wearable_type = LLWearableType::typeNameToType(type_name);
+ LLWearableType::EType wearable_type = LLWearableType::getInstance()->typeNameToType(type_name);
if (wearable_type >= LLWearableType::WT_SHAPE && wearable_type < LLWearableType::WT_COUNT)
{
const LLUUID parent_id = bridge ? bridge->getUUID() : LLUUID::null;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 4890867f29..c0e5a7abce 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -8477,7 +8477,7 @@ class LLEditEnableTakeOff : public view_listener_t
bool handleEvent(const LLSD& userdata)
{
std::string clothing = userdata.asString();
- LLWearableType::EType type = LLWearableType::typeNameToType(clothing);
+ LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing);
if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT)
return LLAgentWearables::selfHasWearable(type);
return false;
@@ -8493,7 +8493,7 @@ class LLEditTakeOff : public view_listener_t
LLAppearanceMgr::instance().removeAllClothesFromAvatar();
else
{
- LLWearableType::EType type = LLWearableType::typeNameToType(clothing);
+ LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing);
if (type >= LLWearableType::WT_SHAPE
&& type < LLWearableType::WT_COUNT
&& (gAgentWearables.getWearableCount(type) > 0))
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index be5c22e7c3..945b51d819 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -466,8 +466,8 @@ void LLViewerShaderMgr::setShaders()
bool canRenderDeferred = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred");
bool hasWindLightShaders = LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders");
S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail");
- bool useRenderDeferred = canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred") && gSavedSettings.getBOOL("RenderAvatarVP");
bool doingWindLight = hasWindLightShaders && gSavedSettings.getBOOL("WindLightUseAtmosShaders");
+ bool useRenderDeferred = doingWindLight && canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred") && gSavedSettings.getBOOL("RenderAvatarVP");
//using shaders, disable fixed function
LLGLSLShader::sNoFixedFunction = true;
diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp
index 2d7a0f920f..ebb31f9453 100644
--- a/indra/newview/llviewerwearable.cpp
+++ b/indra/newview/llviewerwearable.cpp
@@ -563,7 +563,7 @@ void LLViewerWearable::saveNewAsset() const
void LLViewerWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* userdata, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
{
LLWearableSaveData* data = (LLWearableSaveData*)userdata;
- const std::string& type_name = LLWearableType::getTypeName(data->mType);
+ const std::string& type_name = LLWearableType::getInstance()->getTypeName(data->mType);
if(0 == status)
{
// Success
@@ -589,7 +589,7 @@ void LLViewerWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void*
std::ostream& operator<<(std::ostream &s, const LLViewerWearable &w)
{
- s << "wearable " << LLWearableType::getTypeName(w.mType) << "\n";
+ s << "wearable " << LLWearableType::getInstance()->getTypeName(w.mType) << "\n";
s << " Name: " << w.mName << "\n";
s << " Desc: " << w.mDescription << "\n";
//w.mPermissions
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 0aee4a3398..603af7e5cc 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -8734,7 +8734,7 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value)
S32 u8_value = F32_to_U8(value,viewer_param->getMinWeight(),viewer_param->getMaxWeight());
apr_file_printf(file, "\t\t<param id=\"%d\" name=\"%s\" display=\"%s\" value=\"%.3f\" u8=\"%d\" type=\"%s\" wearable=\"%s\" group=\"%d\"/>\n",
viewer_param->getID(), viewer_param->getName().c_str(), viewer_param->getDisplayName().c_str(), value, u8_value, type_string.c_str(),
- LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str(),
+ LLWearableType::getInstance()->getTypeName(LLWearableType::EType(wtype)).c_str(),
viewer_param->getGroup());
}
@@ -9508,6 +9508,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml");
LLAPRFile outfile;
+ LLWearableType *wr_inst = LLWearableType::getInstance();
std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename);
if (APR_SUCCESS == outfile.open(fullpath, LL_APR_WB ))
{
@@ -9524,7 +9525,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
{
for (S32 type = LLWearableType::WT_SHAPE; type < LLWearableType::WT_COUNT; type++)
{
- const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type);
+ const std::string& wearable_name = wr_inst->getTypeName((LLWearableType::EType)type);
apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() );
for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index aea12380e8..c0f063e54a 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -2030,6 +2030,7 @@ void LLVOAvatarSelf::debugBakedTextureUpload(EBakedTextureIndex index, BOOL fini
const std::string LLVOAvatarSelf::verboseDebugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const
{
std::ostringstream outbuf;
+ LLWearableType *wr_inst = LLWearableType::getInstance();
for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter =
LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin();
baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end();
@@ -2053,7 +2054,7 @@ const std::string LLVOAvatarSelf::verboseDebugDumpLocalTextureDataInfo(const LLV
{
for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
{
- outbuf << " " << LLWearableType::getTypeName(wearable_type) << " " << wearable_index << ":";
+ outbuf << " " << wr_inst->getTypeName(wearable_type) << " " << wearable_index << ":";
const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(tex_index, wearable_index);
if (local_tex_obj)
{
@@ -2108,6 +2109,7 @@ void LLVOAvatarSelf::dumpAllTextures() const
const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const
{
std::string text="";
+ LLWearableType *wr_inst = LLWearableType::getInstance();
text = llformat("[Final:%d Avail:%d] ",isLocalTextureDataFinal(layerset), isLocalTextureDataAvailable(layerset));
@@ -2131,7 +2133,7 @@ const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLViewerTe
const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
if (wearable_count > 0)
{
- text += LLWearableType::getTypeName(wearable_type) + ":";
+ text += wr_inst->getTypeName(wearable_type) + ":";
for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
{
const U32 discard_level = getLocalDiscardLevel(tex_index, wearable_index);
@@ -2838,9 +2840,10 @@ void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile)
apr_file_printf( file, "\n<wearable_info>\n" );
LLWearableData *wd = getWearableData();
+ LLWearableType *wr_inst = LLWearableType::getInstance();
for (S32 type = 0; type < LLWearableType::WT_COUNT; type++)
{
- const std::string& type_name = LLWearableType::getTypeName((LLWearableType::EType)type);
+ const std::string& type_name = wr_inst->getTypeName((LLWearableType::EType)type);
for (U32 j=0; j< wd->getWearableCount((LLWearableType::EType)type); j++)
{
LLViewerWearable *wearable = gAgentWearables.getViewerWearable((LLWearableType::EType)type,j);
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index e7f62e77b4..12a6fc02ac 100644
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -959,7 +959,7 @@ void LLWearableItemsList::ContextMenu::updateItemsLabels(LLContextMenu* menu)
if (!item || !item->isWearableType()) return;
LLWearableType::EType w_type = item->getWearableType();
- std::string new_label = LLTrans::getString("create_new_" + LLWearableType::getTypeName(w_type));
+ std::string new_label = LLTrans::getString("create_new_" + LLWearableType::getInstance()->getTypeName(w_type));
LLMenuItemGL* menu_item = menu->getChild<LLMenuItemGL>("create_new");
menu_item->setLabel(new_label);
diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp
index b61fbbd073..b07905629a 100644
--- a/indra/newview/llwearablelist.cpp
+++ b/indra/newview/llwearablelist.cpp
@@ -241,7 +241,8 @@ LLViewerWearable* LLWearableList::createNewWearable( LLWearableType::EType type,
LLViewerWearable *wearable = generateNewWearable();
wearable->setType( type, avatarp );
- std::string name = LLTrans::getString( LLWearableType::getTypeDefaultNewName(wearable->getType()) );
+ // LLWearableType has pre-translated getTypeLabel(), but it uses default translation
+ std::string name = LLTrans::getString( LLWearableType::getInstance()->getTypeDefaultNewName(wearable->getType()) );
wearable->setName( name );
LLPermissions perm;
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index eda9739976..0f790bf26a 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -807,6 +807,14 @@
function="Inventory.DoToSelected"
parameter="save_as" />
</menu_item_call>
+ <menu_item_call
+ label="Save Selected As"
+ layout="topleft"
+ name="Save Selected As">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="save_selected_as" />
+ </menu_item_call>
<menu_item_separator
layout="topleft"
name="Wearable And Object Separator"/>