diff --git a/doc/contributions.txt b/doc/contributions.txt
index d02c88ba47..af8b259c74 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -238,6 +238,7 @@ Ansariel Hiller
SL-15227
SL-15398
SL-18432
+ SL-19140
SL-4126
Aralara Rajal
Arare Chantilly
@@ -895,6 +896,7 @@ Kitty Barnett
STORM-2149
MAINT-7581
MAINT-7081
+ SL-18988
Kolor Fall
Komiko Okamoto
Korvel Noh
diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt
index 75c0e276eb..c3be8bc78e 100644
--- a/indra/llappearance/CMakeLists.txt
+++ b/indra/llappearance/CMakeLists.txt
@@ -21,7 +21,6 @@ set(llappearance_SOURCE_FILES
lltexglobalcolor.cpp
lltexlayer.cpp
lltexlayerparams.cpp
- lltexturemanagerbridge.cpp
llwearable.cpp
llwearabledata.cpp
llwearabletype.cpp
@@ -44,7 +43,6 @@ set(llappearance_HEADER_FILES
lltexglobalcolor.h
lltexlayer.h
lltexlayerparams.h
- lltexturemanagerbridge.h
llwearable.h
llwearabledata.h
llwearabletype.h
diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp
index 93d0a035da..9f23ce5317 100644
--- a/indra/llcommon/llcallbacklist.cpp
+++ b/indra/llcommon/llcallbacklist.cpp
@@ -55,7 +55,7 @@ void LLCallbackList::addFunction( callback_t func, void *data)
// only add one callback per func/data pair
//
- if (containsFunction(func))
+ if (containsFunction(func, data))
{
return;
}
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index 81261f0767..5adf1fa0e6 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -40,9 +40,12 @@
///----------------------------------------------------------------------------
/// Exported functions
///----------------------------------------------------------------------------
+// FIXME D567 - what's the point of these, especially if we don't even use them consistently?
static const std::string INV_ITEM_ID_LABEL("item_id");
static const std::string INV_FOLDER_ID_LABEL("cat_id");
static const std::string INV_PARENT_ID_LABEL("parent_id");
+static const std::string INV_THUMBNAIL_LABEL("thumbnail");
+static const std::string INV_THUMBNAIL_ID_LABEL("thumbnail_id");
static const std::string INV_ASSET_TYPE_LABEL("type");
static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type");
static const std::string INV_INVENTORY_TYPE_LABEL("inv_type");
@@ -99,6 +102,7 @@ void LLInventoryObject::copyObject(const LLInventoryObject* other)
mParentUUID = other->mParentUUID;
mType = other->mType;
mName = other->mName;
+ mThumbnailUUID = other->mThumbnailUUID;
}
const LLUUID& LLInventoryObject::getUUID() const
@@ -111,6 +115,11 @@ const LLUUID& LLInventoryObject::getParentUUID() const
return mParentUUID;
}
+const LLUUID& LLInventoryObject::getThumbnailUUID() const
+{
+ return mThumbnailUUID;
+}
+
const std::string& LLInventoryObject::getName() const
{
return mName;
@@ -160,6 +169,11 @@ void LLInventoryObject::setParent(const LLUUID& new_parent)
mParentUUID = new_parent;
}
+void LLInventoryObject::setThumbnailUUID(const LLUUID& thumbnail_uuid)
+{
+ mThumbnailUUID = thumbnail_uuid;
+}
+
void LLInventoryObject::setType(LLAssetType::EType type)
{
mType = type;
@@ -201,6 +215,26 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream)
{
mType = LLAssetType::lookup(valuestr);
}
+ else if (0 == strcmp("metadata", keyword))
+ {
+ LLSD metadata(valuestr);
+ if (metadata.has("thumbnail"))
+ {
+ const LLSD& thumbnail = metadata["thumbnail"];
+ if (thumbnail.has("asset_id"))
+ {
+ setThumbnailUUID(thumbnail["asset_id"].asUUID());
+ }
+ else
+ {
+ setThumbnailUUID(LLUUID::null);
+ }
+ }
+ else
+ {
+ setThumbnailUUID(LLUUID::null);
+ }
+ }
else if(0 == strcmp("name", keyword))
{
//strcpy(valuestr, buffer + strlen(keyword) + 3);
@@ -336,6 +370,7 @@ void LLInventoryItem::copyItem(const LLInventoryItem* other)
copyObject(other);
mPermissions = other->mPermissions;
mAssetUUID = other->mAssetUUID;
+ mThumbnailUUID = other->mThumbnailUUID;
mDescription = other->mDescription;
mSaleInfo = other->mSaleInfo;
mInventoryType = other->mInventoryType;
@@ -400,6 +435,7 @@ U32 LLInventoryItem::getCRC32() const
//LL_DEBUGS() << "8 crc: " << std::hex << crc << std::dec << LL_ENDL;
crc += (U32)mCreationDate;
//LL_DEBUGS() << "9 crc: " << std::hex << crc << std::dec << LL_ENDL;
+ crc += mThumbnailUUID.getCRC32();
return crc;
}
@@ -655,6 +691,26 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream)
{
mType = LLAssetType::lookup(valuestr);
}
+ else if (0 == strcmp("metadata", keyword))
+ {
+ LLSD metadata(valuestr);
+ if (metadata.has("thumbnail"))
+ {
+ const LLSD& thumbnail = metadata["thumbnail"];
+ if (thumbnail.has("asset_id"))
+ {
+ setThumbnailUUID(thumbnail["asset_id"].asUUID());
+ }
+ else
+ {
+ setThumbnailUUID(LLUUID::null);
+ }
+ }
+ else
+ {
+ setThumbnailUUID(LLUUID::null);
+ }
+ }
else if(0 == strcmp("inv_type", keyword))
{
mInventoryType = LLInventoryType::lookup(std::string(valuestr));
@@ -744,6 +800,13 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu
output_stream << "\t\tparent_id\t" << uuid_str << "\n";
mPermissions.exportLegacyStream(output_stream);
+ if (mThumbnailUUID.notNull())
+ {
+ LLSD metadata;
+ metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
+ output_stream << "\t\tmetadata\t" << metadata << "|\n";
+ }
+
// Check for permissions to see the asset id, and if so write it
// out as an asset id. Otherwise, apply our cheesy encryption.
if(include_asset_key)
@@ -797,6 +860,11 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
sd[INV_PARENT_ID_LABEL] = mParentUUID;
sd[INV_PERMISSIONS_LABEL] = ll_create_sd_from_permissions(mPermissions);
+ if (mThumbnailUUID.notNull())
+ {
+ sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
+ }
+
U32 mask = mPermissions.getMaskBase();
if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
|| (mAssetUUID.isNull()))
@@ -848,6 +916,35 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
{
mParentUUID = sd[w];
}
+ mThumbnailUUID.setNull();
+ w = INV_THUMBNAIL_LABEL;
+ if (sd.has(w))
+ {
+ const LLSD &thumbnail_map = sd[w];
+ w = INV_ASSET_ID_LABEL;
+ if (thumbnail_map.has(w))
+ {
+ mThumbnailUUID = thumbnail_map[w];
+ }
+ /* Example:
+ asset_id
+ acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7
+ perms
+ 8
+ service
+ 3
+ version
+ 1
+ */
+ }
+ else
+ {
+ w = INV_THUMBNAIL_ID_LABEL;
+ if (sd.has(w))
+ {
+ mThumbnailUUID = sd[w].asUUID();
+ }
+ }
w = INV_PERMISSIONS_LABEL;
if (sd.has(w))
{
@@ -972,135 +1069,6 @@ fail:
}
-// Deleted LLInventoryItem::exportFileXML() and LLInventoryItem::importXML()
-// because I can't find any non-test code references to it. 2009-05-04 JC
-
-S32 LLInventoryItem::packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override) const
-{
- // Figure out which permissions to use.
- LLPermissions perm;
- if (perm_override)
- {
- // Use the permissions override.
- perm = *perm_override;
- }
- else
- {
- // Use the current permissions.
- perm = getPermissions();
- }
-
- // describe the inventory item
- char* buffer = (char*) bin_bucket;
- std::string creator_id_str;
-
- perm.getCreator().toString(creator_id_str);
- std::string owner_id_str;
- perm.getOwner().toString(owner_id_str);
- std::string last_owner_id_str;
- perm.getLastOwner().toString(last_owner_id_str);
- std::string group_id_str;
- perm.getGroup().toString(group_id_str);
- std::string asset_id_str;
- getAssetUUID().toString(asset_id_str);
- S32 size = sprintf(buffer, /* Flawfinder: ignore */
- "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x",
- getType(),
- getInventoryType(),
- getName().c_str(),
- creator_id_str.c_str(),
- owner_id_str.c_str(),
- last_owner_id_str.c_str(),
- group_id_str.c_str(),
- perm.getMaskBase(),
- perm.getMaskOwner(),
- perm.getMaskGroup(),
- perm.getMaskEveryone(),
- perm.getMaskNextOwner(),
- asset_id_str.c_str(),
- getDescription().c_str(),
- getSaleInfo().getSaleType(),
- getSaleInfo().getSalePrice(),
- getFlags()) + 1;
-
- return size;
-}
-
-void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size)
-{
- // Early exit on an empty binary bucket.
- if (bin_bucket_size <= 1) return;
-
- if (NULL == bin_bucket)
- {
- LL_ERRS() << "unpackBinaryBucket failed. bin_bucket is NULL." << LL_ENDL;
- return;
- }
-
- // Convert the bin_bucket into a string.
- std::vector item_buffer(bin_bucket_size+1);
- memcpy(&item_buffer[0], bin_bucket, bin_bucket_size); /* Flawfinder: ignore */
- item_buffer[bin_bucket_size] = '\0';
- std::string str(&item_buffer[0]);
-
- LL_DEBUGS() << "item buffer: " << str << LL_ENDL;
-
- // Tokenize the string.
- typedef boost::tokenizer > tokenizer;
- boost::char_separator sep("|", "", boost::keep_empty_tokens);
- tokenizer tokens(str, sep);
- tokenizer::iterator iter = tokens.begin();
-
- // Extract all values.
- LLUUID item_id;
- item_id.generate();
- setUUID(item_id);
-
- LLAssetType::EType type;
- type = (LLAssetType::EType)(atoi((*(iter++)).c_str()));
- setType( type );
-
- LLInventoryType::EType inv_type;
- inv_type = (LLInventoryType::EType)(atoi((*(iter++)).c_str()));
- setInventoryType( inv_type );
-
- std::string name((*(iter++)).c_str());
- rename( name );
-
- LLUUID creator_id((*(iter++)).c_str());
- LLUUID owner_id((*(iter++)).c_str());
- LLUUID last_owner_id((*(iter++)).c_str());
- LLUUID group_id((*(iter++)).c_str());
- PermissionMask mask_base = strtoul((*(iter++)).c_str(), NULL, 16);
- PermissionMask mask_owner = strtoul((*(iter++)).c_str(), NULL, 16);
- PermissionMask mask_group = strtoul((*(iter++)).c_str(), NULL, 16);
- PermissionMask mask_every = strtoul((*(iter++)).c_str(), NULL, 16);
- PermissionMask mask_next = strtoul((*(iter++)).c_str(), NULL, 16);
- LLPermissions perm;
- perm.init(creator_id, owner_id, last_owner_id, group_id);
- perm.initMasks(mask_base, mask_owner, mask_group, mask_every, mask_next);
- setPermissions(perm);
- //LL_DEBUGS() << "perm: " << perm << LL_ENDL;
-
- LLUUID asset_id((*(iter++)).c_str());
- setAssetUUID(asset_id);
-
- std::string desc((*(iter++)).c_str());
- setDescription(desc);
-
- LLSaleInfo::EForSale sale_type;
- sale_type = (LLSaleInfo::EForSale)(atoi((*(iter++)).c_str()));
- S32 price = atoi((*(iter++)).c_str());
- LLSaleInfo sale_info(sale_type, price);
- setSaleInfo(sale_info);
-
- U32 flags = strtoul((*(iter++)).c_str(), NULL, 16);
- setFlags(flags);
-
- time_t now = time(NULL);
- setCreationDate(now);
-}
-
///----------------------------------------------------------------------------
/// Class LLInventoryCategory
///----------------------------------------------------------------------------
@@ -1150,11 +1118,32 @@ void LLInventoryCategory::setPreferredType(LLFolderType::EType type)
LLSD LLInventoryCategory::asLLSD() const
{
LLSD sd = LLSD();
- sd["item_id"] = mUUID;
- sd["parent_id"] = mParentUUID;
+ sd[INV_ITEM_ID_LABEL] = mUUID;
+ sd[INV_PARENT_ID_LABEL] = mParentUUID;
S8 type = static_cast(mPreferredType);
- sd["type"] = type;
- sd["name"] = mName;
+ sd[INV_ASSET_TYPE_LABEL] = type;
+ sd[INV_NAME_LABEL] = mName;
+
+ if (mThumbnailUUID.notNull())
+ {
+ sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
+ }
+
+ return sd;
+}
+
+LLSD LLInventoryCategory::asAISCreateCatLLSD() const
+{
+ LLSD sd = LLSD();
+ sd[INV_FOLDER_ID_LABEL_WS] = mUUID;
+ sd[INV_PARENT_ID_LABEL] = mParentUUID;
+ S8 type = static_cast(mPreferredType);
+ sd[INV_ASSET_TYPE_LABEL_WS] = type;
+ sd[INV_NAME_LABEL] = mName;
+ if (mThumbnailUUID.notNull())
+ {
+ sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
+ }
return sd;
}
@@ -1184,6 +1173,25 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd)
{
mParentUUID = sd[w];
}
+ mThumbnailUUID.setNull();
+ w = INV_THUMBNAIL_LABEL;
+ if (sd.has(w))
+ {
+ const LLSD &thumbnail_map = sd[w];
+ w = INV_ASSET_ID_LABEL;
+ if (thumbnail_map.has(w))
+ {
+ mThumbnailUUID = thumbnail_map[w];
+ }
+ }
+ else
+ {
+ w = INV_THUMBNAIL_ID_LABEL;
+ if (sd.has(w))
+ {
+ mThumbnailUUID = sd[w];
+ }
+ }
w = INV_ASSET_TYPE_LABEL;
if (sd.has(w))
{
@@ -1275,6 +1283,26 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream)
LLStringUtil::replaceNonstandardASCII(mName, ' ');
LLStringUtil::replaceChar(mName, '|', ' ');
}
+ else if (0 == strcmp("metadata", keyword))
+ {
+ LLSD metadata(valuestr);
+ if (metadata.has("thumbnail"))
+ {
+ const LLSD& thumbnail = metadata["thumbnail"];
+ if (thumbnail.has("asset_id"))
+ {
+ setThumbnailUUID(thumbnail["asset_id"].asUUID());
+ }
+ else
+ {
+ setThumbnailUUID(LLUUID::null);
+ }
+ }
+ else
+ {
+ setThumbnailUUID(LLUUID::null);
+ }
+ }
else
{
LL_WARNS() << "unknown keyword '" << keyword
@@ -1295,6 +1323,12 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL)
output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType) << "\n";
output_stream << "\t\tname\t" << mName.c_str() << "|\n";
+ if (mThumbnailUUID.notNull())
+ {
+ LLSD metadata;
+ metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
+ output_stream << "\t\tmetadata\t" << metadata << "|\n";
+ }
output_stream << "\t}\n";
return TRUE;
}
@@ -1308,6 +1342,11 @@ LLSD LLInventoryCategory::exportLLSD() const
cat_data[INV_PREFERRED_TYPE_LABEL] = LLFolderType::lookup(mPreferredType);
cat_data[INV_NAME_LABEL] = mName;
+ if (mThumbnailUUID.notNull())
+ {
+ cat_data[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
+ }
+
return cat_data;
}
@@ -1329,6 +1368,16 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data)
{
setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE_LABEL].asString()));
}
+ if (cat_data.has(INV_THUMBNAIL_LABEL))
+ {
+ LLUUID thumbnail_uuid;
+ const LLSD &thumbnail_data = cat_data[INV_THUMBNAIL_LABEL];
+ if (thumbnail_data.has(INV_ASSET_ID_LABEL))
+ {
+ thumbnail_uuid = thumbnail_data[INV_ASSET_ID_LABEL].asUUID();
+ }
+ setThumbnailUUID(thumbnail_uuid);
+ }
if (cat_data.has(INV_NAME_LABEL))
{
mName = cat_data[INV_NAME_LABEL].asString();
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index 7d9f9704f1..6d4535af27 100644
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -70,6 +70,7 @@ public:
virtual const LLUUID& getUUID() const; // inventoryID that this item points to
virtual const LLUUID& getLinkedUUID() const; // inventoryID that this item points to, else this item's inventoryID
const LLUUID& getParentUUID() const;
+ virtual const LLUUID& getThumbnailUUID() const;
virtual const std::string& getName() const;
virtual LLAssetType::EType getType() const;
LLAssetType::EType getActualType() const; // bypasses indirection for linked items
@@ -84,6 +85,7 @@ public:
void setUUID(const LLUUID& new_uuid);
virtual void rename(const std::string& new_name);
void setParent(const LLUUID& new_parent);
+ virtual void setThumbnailUUID(const LLUUID& thumbnail_uuid);
void setType(LLAssetType::EType type);
virtual void setCreationDate(time_t creation_date_utc); // only stored for items
@@ -108,6 +110,7 @@ public:
protected:
LLUUID mUUID;
LLUUID mParentUUID; // Parent category. Root categories have LLUUID::NULL.
+ LLUUID mThumbnailUUID;
LLAssetType::EType mType;
std::string mName;
time_t mCreationDate; // seconds from 1/1/1970, UTC
@@ -203,9 +206,6 @@ public:
// Helper Functions
//--------------------------------------------------------------------
public:
- // Pack all information needed to reconstruct this item into the given binary bucket.
- S32 packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override = NULL) const;
- void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size);
LLSD asLLSD() const;
void asLLSD( LLSD& sd ) const;
bool fromLLSD(const LLSD& sd, bool is_new = true);
@@ -253,6 +253,7 @@ public:
LLFolderType::EType getPreferredType() const;
void setPreferredType(LLFolderType::EType type);
LLSD asLLSD() const;
+ LLSD asAISCreateCatLLSD() const;
bool fromLLSD(const LLSD& sd);
//--------------------------------------------------------------------
diff --git a/indra/llinventory/tests/inventorymisc_test.cpp b/indra/llinventory/tests/inventorymisc_test.cpp
index e8b063bffe..039fa938dd 100644
--- a/indra/llinventory/tests/inventorymisc_test.cpp
+++ b/indra/llinventory/tests/inventorymisc_test.cpp
@@ -400,27 +400,7 @@ namespace tut
// Deleted LLInventoryItem::exportFileXML() and LLInventoryItem::importXML()
// because I can't find any non-test code references to it. 2009-05-04 JC
}
-
- template<> template<>
- void inventory_object::test<10>()
- {
- LLPointer src1 = create_random_inventory_item();
- U8* bin_bucket = new U8[300];
- S32 bin_bucket_size = src1->packBinaryBucket(bin_bucket, NULL);
- LLPointer src2 = new LLInventoryItem();
- src2->unpackBinaryBucket(bin_bucket, bin_bucket_size);
-
- ensure_equals("1.sale price::getSalePrice() failed price", src1->getSaleInfo().getSalePrice(), src2->getSaleInfo().getSalePrice());
- ensure_equals("2.sale type::getSaleType() failed type", src1->getSaleInfo().getSaleType(), src2->getSaleInfo().getSaleType());
- ensure_equals("3.type::getType() failed", src1->getType(), src2->getType());
- ensure_equals("4.inventory type::getInventoryType() failed type", src1->getInventoryType(), src2->getInventoryType());
- ensure_equals("5.name::getName() failed", src1->getName(), src2->getName());
- ensure_equals("6.description::getDescription() failed", src1->getDescription(), src2->getDescription());
- ensure_equals("7.flags::getFlags() failed", src1->getFlags(), src2->getFlags());
-
- }
-
template<> template<>
void inventory_object::test<11>()
{
diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h
index 27eaa614c9..c4d04f5d02 100644
--- a/indra/llmath/llcamera.h
+++ b/indra/llmath/llcamera.h
@@ -39,7 +39,7 @@ const F32 DEFAULT_NEAR_PLANE = 0.25f;
const F32 DEFAULT_FAR_PLANE = 64.f; // far reaches across two horizontal, not diagonal, regions
const F32 MAX_ASPECT_RATIO = 50.0f;
-const F32 MAX_NEAR_PLANE = 10.f;
+const F32 MAX_NEAR_PLANE = 1023.9f; // Clamp the near plane just before the skybox ends
const F32 MAX_FAR_PLANE = 100000.0f; //1000000.0f; // Max allowed. Not good Z precision though.
const F32 MAX_FAR_CLIP = 512.0f;
diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp
index d310cefd1e..ebbaea9b12 100644
--- a/indra/llmessage/llcoproceduremanager.cpp
+++ b/indra/llmessage/llcoproceduremanager.cpp
@@ -364,7 +364,26 @@ LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoproced
{
LLUUID id(LLUUID::generateNewID());
- LL_INFOS("CoProcMgr") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName << "\" at " << mPending << LL_ENDL;
+ if (mPoolName == "AIS")
+ {
+ // Fetch is going to be spammy.
+ LL_DEBUGS("CoProcMgr", "Inventory") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName
+ << "\" at "
+ << mPending << LL_ENDL;
+
+ if (mPending >= (LLCoprocedureManager::DEFAULT_QUEUE_SIZE - 1))
+ {
+ // If it's all used up (not supposed to happen,
+ // fetched should cap it), we are going to crash
+ LL_WARNS("CoProcMgr", "Inventory") << "About to run out of queue space for Coprocedure(" << name
+ << ") enqueuing with id=" << id.asString() << " Already pending:" << mPending << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_INFOS("CoProcMgr") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName << "\" at "
+ << mPending << LL_ENDL;
+ }
auto pushed = mPendingCoprocs->try_push(boost::make_shared(name, id, proc));
if (pushed == boost::fibers::channel_op_status::success)
{
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index 19146c64f4..31acc65642 100644
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -3402,6 +3402,7 @@ typedef std::map BuilderMap;
void LLMessageSystem::newMessageFast(const char *name)
{
+ //LL_DEBUGS("Messaging") << "creating new message: " << name << LL_ENDL;
LLMessageConfig::Flavor message_flavor =
LLMessageConfig::getMessageFlavor(name);
LLMessageConfig::Flavor server_flavor =
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt
index 76d261ab3e..2bd1edaacc 100644
--- a/indra/llprimitive/CMakeLists.txt
+++ b/indra/llprimitive/CMakeLists.txt
@@ -34,6 +34,7 @@ set(llprimitive_HEADER_FILES
lldaeloader.h
llgltfloader.h
llgltfmaterial.h
+ llgltfmaterial_templates.h
legacy_object_types.h
llmaterial.h
llmaterialid.h
diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp
index 19b7413934..f42c11ee21 100644
--- a/indra/llprimitive/llgltfmaterial.cpp
+++ b/indra/llprimitive/llgltfmaterial.cpp
@@ -24,25 +24,28 @@
* $/LicenseInfo$
*/
+
#include "linden_common.h"
#include "llgltfmaterial.h"
+
#include "llsdserialize.h"
// NOTE -- this should be the one and only place tiny_gltf.h is included
#include "tinygltf/tiny_gltf.h"
+#include "llgltfmaterial_templates.h"
const char* const LLGLTFMaterial::ASSET_VERSION = "1.1";
const char* const LLGLTFMaterial::ASSET_TYPE = "GLTF 2.0";
const std::array LLGLTFMaterial::ACCEPTED_ASSET_VERSIONS = { "1.0", "1.1" };
-const char* const GLTF_FILE_EXTENSION_TRANSFORM = "KHR_texture_transform";
-const char* const GLTF_FILE_EXTENSION_TRANSFORM_SCALE = "scale";
-const char* const GLTF_FILE_EXTENSION_TRANSFORM_OFFSET = "offset";
-const char* const GLTF_FILE_EXTENSION_TRANSFORM_ROTATION = "rotation";
+const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM = "KHR_texture_transform";
+const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM_SCALE = "scale";
+const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM_OFFSET = "offset";
+const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM_ROTATION = "rotation";
// special UUID that indicates a null UUID in override data
-static const LLUUID GLTF_OVERRIDE_NULL_UUID = LLUUID("ffffffff-ffff-ffff-ffff-ffffffffffff");
+const LLUUID LLGLTFMaterial::GLTF_OVERRIDE_NULL_UUID = LLUUID("ffffffff-ffff-ffff-ffff-ffffffffffff");
void LLGLTFMaterial::TextureTransform::getPacked(F32 (&packed)[8]) const
{
@@ -68,14 +71,14 @@ LLGLTFMaterial::LLGLTFMaterial(const LLGLTFMaterial& rhs)
LLGLTFMaterial& LLGLTFMaterial::operator=(const LLGLTFMaterial& rhs)
{
- //have to do a manual operator= because of LLRefCount
+ //have to do a manual operator= because of LLRefCount
mTextureId = rhs.mTextureId;
mTextureTransform = rhs.mTextureTransform;
mBaseColor = rhs.mBaseColor;
mEmissiveColor = rhs.mEmissiveColor;
-
+
mMetallicFactor = rhs.mMetallicFactor;
mRoughnessFactor = rhs.mRoughnessFactor;
mAlphaCutoff = rhs.mAlphaCutoff;
@@ -97,7 +100,7 @@ bool LLGLTFMaterial::operator==(const LLGLTFMaterial& rhs) const
mBaseColor == rhs.mBaseColor &&
mEmissiveColor == rhs.mEmissiveColor &&
-
+
mMetallicFactor == rhs.mMetallicFactor &&
mRoughnessFactor == rhs.mRoughnessFactor &&
mAlphaCutoff == rhs.mAlphaCutoff &&
@@ -122,6 +125,7 @@ bool LLGLTFMaterial::fromJSON(const std::string& json, std::string& warn_msg, st
return true;
}
+
return false;
}
@@ -190,7 +194,8 @@ void LLGLTFMaterial::setFromModel(const tinygltf::Model& model, S32 mat_index)
}
}
-LLVector2 vec2_from_json(const tinygltf::Value::Object& object, const char* key, const LLVector2& default_value)
+// static
+LLVector2 LLGLTFMaterial::vec2FromJson(const tinygltf::Value::Object& object, const char* key, const LLVector2& default_value)
{
const auto it = object.find(key);
if (it == object.end())
@@ -215,7 +220,8 @@ LLVector2 vec2_from_json(const tinygltf::Value::Object& object, const char* key,
return value;
}
-F32 float_from_json(const tinygltf::Value::Object& object, const char* key, const F32 default_value)
+// static
+F32 LLGLTFMaterial::floatFromJson(const tinygltf::Value::Object& object, const char* key, const F32 default_value)
{
const auto it = object.find(key);
if (it == object.end())
@@ -230,52 +236,6 @@ F32 float_from_json(const tinygltf::Value::Object& object, const char* key, cons
return (F32)real_json.GetNumberAsDouble();
}
-template
-std::string gltf_get_texture_image(const tinygltf::Model& model, const T& texture_info)
-{
- const S32 texture_idx = texture_info.index;
- if (texture_idx < 0 || texture_idx >= model.textures.size())
- {
- return "";
- }
- const tinygltf::Texture& texture = model.textures[texture_idx];
-
- // Ignore texture.sampler for now
-
- const S32 image_idx = texture.source;
- if (image_idx < 0 || image_idx >= model.images.size())
- {
- return "";
- }
- const tinygltf::Image& image = model.images[image_idx];
-
- return image.uri;
-}
-
-// *NOTE: Use template here as workaround for the different similar texture info classes
-template
-void LLGLTFMaterial::setFromTexture(const tinygltf::Model& model, const T& texture_info, TextureInfo texture_info_id)
-{
- LL_PROFILE_ZONE_SCOPED;
- const std::string uri = gltf_get_texture_image(model, texture_info);
- mTextureId[texture_info_id].set(uri);
-
- const tinygltf::Value::Object& extensions_object = texture_info.extensions;
- const auto transform_it = extensions_object.find(GLTF_FILE_EXTENSION_TRANSFORM);
- if (transform_it != extensions_object.end())
- {
- const tinygltf::Value& transform_json = std::get<1>(*transform_it);
- if (transform_json.IsObject())
- {
- const tinygltf::Value::Object& transform_object = transform_json.Get();
- TextureTransform& transform = mTextureTransform[texture_info_id];
- transform.mOffset = vec2_from_json(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_OFFSET, getDefaultTextureOffset());
- transform.mScale = vec2_from_json(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_SCALE, getDefaultTextureScale());
- transform.mRotation = float_from_json(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_ROTATION, getDefaultTextureRotation());
- }
- }
-}
-
void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const
{
LL_PROFILE_ZONE_SCOPED;
@@ -302,7 +262,7 @@ void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const
material_out.alphaMode = getAlphaMode();
material_out.alphaCutoff = mAlphaCutoff;
-
+
mBaseColor.write(material_out.pbrMetallicRoughness.baseColorFactor);
if (mEmissiveColor != LLGLTFMaterial::getDefaultEmissiveColor())
@@ -320,7 +280,7 @@ void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const
tinygltf::Value::Object extras;
bool write_extras = false;
if (mOverrideAlphaMode && mAlphaMode == getDefaultAlphaMode())
- {
+ {
extras["override_alpha_mode"] = tinygltf::Value(mOverrideAlphaMode);
write_extras = true;
}
@@ -339,57 +299,6 @@ void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const
model.asset.version = "2.0";
}
-template
-void gltf_allocate_texture_image(tinygltf::Model& model, T& texture_info, const std::string& uri)
-{
- const S32 image_idx = model.images.size();
- model.images.emplace_back();
- model.images[image_idx].uri = uri;
-
- // The texture, not to be confused with the texture info
- const S32 texture_idx = model.textures.size();
- model.textures.emplace_back();
- tinygltf::Texture& texture = model.textures[texture_idx];
- texture.source = image_idx;
-
- texture_info.index = texture_idx;
-}
-
-template
-void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, bool force_write) const
-{
- LL_PROFILE_ZONE_SCOPED;
- const LLUUID& texture_id = mTextureId[texture_info_id];
- const TextureTransform& transform = mTextureTransform[texture_info_id];
- const bool is_blank_transform = transform == sDefault.mTextureTransform[0];
- // Check if this material matches all the fallback values, and if so, then
- // skip including it to reduce material size
- if (!force_write && texture_id.isNull() && is_blank_transform)
- {
- return;
- }
-
- // tinygltf will discard this texture info if there is no valid texture,
- // causing potential loss of information for overrides, so ensure one is
- // defined. -Cosmic,2023-01-30
- gltf_allocate_texture_image(model, texture_info, texture_id.asString());
-
- if (!is_blank_transform)
- {
- tinygltf::Value::Object transform_map;
- transform_map[GLTF_FILE_EXTENSION_TRANSFORM_OFFSET] = tinygltf::Value(tinygltf::Value::Array({
- tinygltf::Value(transform.mOffset.mV[VX]),
- tinygltf::Value(transform.mOffset.mV[VY])
- }));
- transform_map[GLTF_FILE_EXTENSION_TRANSFORM_SCALE] = tinygltf::Value(tinygltf::Value::Array({
- tinygltf::Value(transform.mScale.mV[VX]),
- tinygltf::Value(transform.mScale.mV[VY])
- }));
- transform_map[GLTF_FILE_EXTENSION_TRANSFORM_ROTATION] = tinygltf::Value(transform.mRotation);
- texture_info.extensions[GLTF_FILE_EXTENSION_TRANSFORM] = tinygltf::Value(transform_map);
- }
-}
-
void LLGLTFMaterial::sanitizeAssetMaterial()
{
mTextureTransform = sDefault.mTextureTransform;
@@ -403,19 +312,19 @@ bool LLGLTFMaterial::setBaseMaterial()
return *this != old_override;
}
-bool LLGLTFMaterial::isClearedForBaseMaterial()
-{
- LLGLTFMaterial cleared_override = sDefault;
- cleared_override.setBaseMaterial(*this);
- return *this == cleared_override;
-}
-
// For material overrides only. Copies transforms from the old override.
void LLGLTFMaterial::setBaseMaterial(const LLGLTFMaterial& old_override_mat)
{
mTextureTransform = old_override_mat.mTextureTransform;
}
+bool LLGLTFMaterial::isClearedForBaseMaterial() const
+{
+ LLGLTFMaterial cleared_override = sDefault;
+ cleared_override.setBaseMaterial(*this);
+ return *this == cleared_override;
+}
+
// static
void LLGLTFMaterial::hackOverrideUUID(LLUUID& id)
@@ -516,7 +425,7 @@ void LLGLTFMaterial::setAlphaMode(const std::string& mode, bool for_override)
{
m = ALPHA_MODE_BLEND;
}
-
+
setAlphaMode(m, for_override);
}
@@ -709,7 +618,6 @@ void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& d
{
data["tex"][i] = LLSD::UUID(override_texture_id);
}
-
}
if (override_mat.mBaseColor != getDefaultBaseColor())
@@ -764,23 +672,6 @@ void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& d
data["ti"][i]["r"] = override_mat.mTextureTransform[i].mRotation;
}
}
-
-#if 0
- {
- std::ostringstream ostr;
- LLSDSerialize::serialize(data, ostr, LLSDSerialize::LLSD_NOTATION);
- std::string param_str(ostr.str());
- LL_INFOS() << param_str << LL_ENDL;
- LL_INFOS() << "Notation size: " << param_str.size() << LL_ENDL;
- }
-
- {
- std::ostringstream ostr;
- LLSDSerialize::serialize(data, ostr, LLSDSerialize::LLSD_BINARY);
- std::string param_str(ostr.str());
- LL_INFOS() << "Binary size: " << param_str.size() << LL_ENDL;
- }
-#endif
}
diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h
index ca27507707..a078a530a4 100644
--- a/indra/llprimitive/llgltfmaterial.h
+++ b/indra/llprimitive/llgltfmaterial.h
@@ -35,10 +35,13 @@
#include "hbxxh.h"
#include
+#include
+ INVENTORY_MATERIAL
+
JSON_APPEND
- InventoryInboxToggleState
-
InventoryLinking
- RenderLocalLights
+ RenderLocalLightCount
RenderShadowSplitExponent
- AmbientDisable
-
- SunlightDisable
-
- LocalLightDisable
-
TextureDiscardLevel
+ BatchSizeAIS3
+
PoolSizeAIS
PoolSizeUpload
+ FindOriginalOpenWindow
+
StatsReportMaxDuration
+MultiModeDoubleClickFolder
+
+SingleModeDoubleClickOpenWindow
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
index c8eaba6418..f9ebf33b4a 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
@@ -382,8 +382,7 @@ vec3 pbrIbl(vec3 diffuseColor,
vec3 irradiance, // irradiance map sample
float ao, // ambient occlusion factor
float nv, // normal dot view vector
- float perceptualRough,
- out vec3 specContrib)
+ float perceptualRough)
{
// retrieve a scale and bias to F0. See [1], Figure 3
vec2 brdf = BRDF(clamp(nv, 0, 1), 1.0-perceptualRough);
@@ -393,23 +392,9 @@ vec3 pbrIbl(vec3 diffuseColor,
vec3 diffuse = diffuseLight * diffuseColor;
vec3 specular = specularLight * (specularColor * brdf.x + brdf.y);
- specContrib = specular * ao;
-
return (diffuse + specular) * ao;
}
-vec3 pbrIbl(vec3 diffuseColor,
- vec3 specularColor,
- vec3 radiance, // radiance map sample
- vec3 irradiance, // irradiance map sample
- float ao, // ambient occlusion factor
- float nv, // normal dot view vector
- float perceptualRough)
-{
- vec3 specContrib;
- return pbrIbl(diffuseColor, specularColor, radiance, irradiance, ao, nv, perceptualRough, specContrib);
-}
-
// Encapsulate the various inputs used by the various functions in the shading equation
// We store values in this struct to simplify the integration of alternative implementations
@@ -475,8 +460,7 @@ vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
float metallic,
vec3 n, // normal
vec3 v, // surface point to camera
- vec3 l, //surface point to light
- out vec3 specContrib) //specular contribution (exposed to alpha shaders to calculate "glare")
+ vec3 l) //surface point to light
{
// make sure specular highlights from punctual lights don't fall off of polished surfaces
perceptualRoughness = max(perceptualRoughness, 8.0/255.0);
@@ -524,28 +508,13 @@ vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
// Calculation of analytical lighting contribution
vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs);
- specContrib = F * G * D / (4.0 * NdotL * NdotV);
+ vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV);
// Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)
vec3 color = NdotL * (diffuseContrib + specContrib);
- specContrib *= NdotL;
- specContrib = max(specContrib, vec3(0));
-
return clamp(color, vec3(0), vec3(10));
}
-vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
- float perceptualRoughness,
- float metallic,
- vec3 n, // normal
- vec3 v, // surface point to camera
- vec3 l) //surface point to light
-{
- vec3 specContrib;
-
- return pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n, v, l, specContrib);
-}
-
void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor)
{
vec3 f0 = vec3(0.04);
@@ -554,30 +523,21 @@ void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor
specularColor = mix(f0, baseColor, metallic);
}
-vec3 pbrBaseLight(vec3 diffuseColor, vec3 specularColor, float metallic, vec3 v, vec3 norm, float perceptualRoughness, vec3 light_dir, vec3 sunlit, float scol, vec3 radiance, vec3 irradiance, vec3 colorEmissive, float ao, vec3 additive, vec3 atten, out vec3 specContrib)
+vec3 pbrBaseLight(vec3 diffuseColor, vec3 specularColor, float metallic, vec3 v, vec3 norm, float perceptualRoughness, vec3 light_dir, vec3 sunlit, float scol, vec3 radiance, vec3 irradiance, vec3 colorEmissive, float ao, vec3 additive, vec3 atten)
{
vec3 color = vec3(0);
float NdotV = clamp(abs(dot(norm, v)), 0.001, 1.0);
- vec3 ibl_spec;
- color += pbrIbl(diffuseColor, specularColor, radiance, irradiance, ao, NdotV, perceptualRoughness, ibl_spec);
+ color += pbrIbl(diffuseColor, specularColor, radiance, irradiance, ao, NdotV, perceptualRoughness);
- color += pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, norm, v, normalize(light_dir), specContrib) * sunlit * 3.0 * scol; //magic number to balance with legacy materials
- specContrib *= sunlit * 2.75 * scol;
- specContrib += ibl_spec;
+ color += pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, norm, v, normalize(light_dir)) * sunlit * 3.0 * scol; //magic number to balance with legacy materials
color += colorEmissive;
return color;
}
-vec3 pbrBaseLight(vec3 diffuseColor, vec3 specularColor, float metallic, vec3 v, vec3 norm, float perceptualRoughness, vec3 light_dir, vec3 sunlit, float scol, vec3 radiance, vec3 irradiance, vec3 colorEmissive, float ao, vec3 additive, vec3 atten)
-{
- vec3 specContrib;
- return pbrBaseLight(diffuseColor, specularColor, metallic, v, norm, perceptualRoughness, light_dir, sunlit, scol, radiance, irradiance, colorEmissive, ao, additive, atten, specContrib);
-}
-
uniform vec4 waterPlane;
uniform float waterSign;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
index b752307d13..5d58cc91cd 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
@@ -40,8 +40,6 @@ vec4 applyWaterFogView(vec3 pos, vec4 color);
#endif
vec3 srgb_to_linear(vec3 cs);
-vec3 legacy_adjust_fullbright(vec3 c);
-vec3 legacy_adjust(vec3 c);
vec3 linear_to_srgb(vec3 cl);
vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten);
void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten);
@@ -98,9 +96,7 @@ void main()
#endif
#ifndef IS_HUD
- color.rgb = legacy_adjust(color.rgb);
color.rgb = srgb_to_linear(color.rgb);
- color.rgb = legacy_adjust_fullbright(color.rgb);
color.rgb = atmosFragLighting(color.rgb, additive, atten);
#endif
diff --git a/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl b/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl
index 31b02377da..e3fd10447e 100644
--- a/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl
@@ -113,31 +113,3 @@ vec3 inv_toneMapACES_Hill(vec3 color)
return color;
}
-// adjust legacy colors to back out tonemapping and exposure
-// NOTE: obsolete now that setting probe ambiance to zero removes tonemapping and exposure, but keeping for a minute
-// while that change goes through testing - davep 6/1/2023
-#define LEGACY_ADJUST 0
-
-vec3 legacy_adjust(vec3 c)
-{
-#if LEGACY_ADJUST
- vec3 desat = rgb2hsv(c.rgb);
- desat.g *= 1.0-(1.0-desat.b)*0.5;
- desat.b += (1.0-desat.b)*0.1f;
- desat.rgb = hsv2rgb(desat);
- return desat;
-#else
- return c;
-#endif
-}
-
-vec3 legacy_adjust_fullbright(vec3 c)
-{
-#if LEGACY_ADJUST
- float exp_scale = clamp(texture(exposureMap, vec2(0.5, 0.5)).r, 0.01, 10.0);
- return c / exp_scale * 1.34; //magic 1.34 arrived at by binary search for a value that reproduces midpoint grey consistenty
-#else
- return c;
-#endif
-}
-
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl
index a8aa5a36a3..a1da4b1f9a 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl
@@ -45,7 +45,6 @@ uniform float sky_ambient_scale;
float getAmbientClamp() { return 1.0f; }
vec3 srgb_to_linear(vec3 col);
-vec3 legacy_adjust(vec3 col);
// return colors in sRGB space
void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive,
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
index 3a251af240..b63f3b60f9 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
@@ -71,7 +71,6 @@ vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit);
vec3 srgb_to_linear(vec3 c);
vec3 linear_to_srgb(vec3 c);
-vec3 legacy_adjust(vec3 c);
vec2 encode_normal (vec3 n);
vec3 atmosFragLightingLinear(vec3 light, vec3 additive, vec3 atten);
@@ -234,7 +233,6 @@ void main()
}
diffuse_srgb.rgb *= vertex_color.rgb;
- diffuse_srgb.rgb = legacy_adjust(diffuse_srgb.rgb);
diffuse_linear.rgb = srgb_to_linear(diffuse_srgb.rgb);
#endif // USE_VERTEX_COLOR
@@ -291,9 +289,7 @@ void main()
LIGHT_LOOP(7)
// sum local light contrib in linear colorspace
-#if !defined(LOCAL_LIGHT_KILL)
color.rgb += light.rgb;
-#endif // !defined(LOCAL_LIGHT_KILL)
#endif // #else // FOR_IMPOSTOR
diff --git a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
index be66b6feb2..35d752be02 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
@@ -112,16 +112,14 @@ vec3 pbrBaseLight(vec3 diffuseColor,
vec3 colorEmissive,
float ao,
vec3 additive,
- vec3 atten,
- out vec3 specContrib);
+ vec3 atten);
vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
float perceptualRoughness,
float metallic,
vec3 n, // normal
vec3 v, // surface point to camera
- vec3 l, //surface point to light
- out vec3 specContrib);
+ vec3 l); //surface point to light
vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
float perceptualRoughness,
@@ -132,7 +130,7 @@ vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
vec3 lp, // light position
vec3 ld, // light direction (for spotlights)
vec3 lightColor,
- float lightSize, float falloff, float is_pointlight, inout float glare, float ambiance)
+ float lightSize, float falloff, float is_pointlight, float ambiance)
{
vec3 color = vec3(0,0,0);
@@ -154,10 +152,7 @@ vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
vec3 intensity = spot_atten * dist_atten * lightColor * 3.0; //magic number to balance with legacy materials
- vec3 speccol;
- color = intensity*pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, lv, speccol);
- speccol *= intensity;
- glare += max(max(speccol.r, speccol.g), speccol.b);
+ color = intensity*pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, lv);
}
return color;
@@ -166,7 +161,6 @@ vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
void main()
{
vec3 color = vec3(0,0,0);
- float glare = 0.0;
vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir;
vec3 pos = vary_position;
@@ -232,9 +226,7 @@ void main()
vec3 v = -normalize(pos.xyz);
- vec3 spec;
- color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, ao, additive, atten, spec);
- glare += max(max(spec.r, spec.g), spec.b);
+ color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, ao, additive, atten);
color.rgb = atmosFragLightingLinear(color.rgb, additive, atten);
@@ -246,7 +238,7 @@ void main()
vec3 light = vec3(0);
// Punctual lights
-#define LIGHT_LOOP(i) light += calcPointLightOrSpotLight(diffuseColor, specularColor, perceptualRoughness, metallic, norm.xyz, pos.xyz, v, light_position[i].xyz, light_direction[i].xyz, light_diffuse[i].rgb, light_deferred_attenuation[i].x, light_deferred_attenuation[i].y, light_attenuation[i].z, glare, light_attenuation[i].w);
+#define LIGHT_LOOP(i) light += calcPointLightOrSpotLight(diffuseColor, specularColor, perceptualRoughness, metallic, norm.xyz, pos.xyz, v, light_position[i].xyz, light_direction[i].xyz, light_diffuse[i].rgb, light_deferred_attenuation[i].x, light_deferred_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w);
LIGHT_LOOP(1)
LIGHT_LOOP(2)
@@ -261,9 +253,6 @@ void main()
float a = basecolor.a*vertex_color.a;
- glare = min(glare, 1.0);
- a = max(a, glare);
-
frag_color = max(vec4(color.rgb,a), vec4(0));
}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl
index 54a887262b..5483a4e29c 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl
@@ -40,8 +40,6 @@ in vec3 vary_position;
uniform samplerCube environmentMap;
vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten);
-vec3 legacy_adjust_fullbright(vec3 c);
-vec3 legacy_adjust(vec3 c);
void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten);
vec3 linear_to_srgb(vec3 c);
@@ -82,10 +80,8 @@ void main()
vec4 spec = vec4(0,0,0,0);
sampleReflectionProbesLegacy(ambenv, glossenv, legacyenv, vec2(0), pos.xyz, norm.xyz, spec.a, env_intensity, false, amblit);
- color.rgb = legacy_adjust(color.rgb);
color.rgb = srgb_to_linear(color.rgb);
- color.rgb = legacy_adjust_fullbright(color.rgb);
-
+
applyLegacyEnv(color.rgb, legacyenv, spec, pos, norm, env_intensity);
color.rgb = atmosFragLighting(color.rgb, additive, atten);
#endif
diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
index af49e76984..db0daa9b7e 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
@@ -48,8 +48,6 @@ void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float
vec3 srgb_to_linear(vec3 cs);
vec3 linear_to_srgb(vec3 cs);
-vec3 legacy_adjust(vec3 c);
-vec3 legacy_adjust_fullbright(vec3 c);
uniform vec4 clipPlane;
uniform float clipSign;
@@ -329,7 +327,6 @@ void main()
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
//forward rendering, output lit linear color
- diffcol.rgb = legacy_adjust(diffcol.rgb);
diffcol.rgb = srgb_to_linear(diffcol.rgb);
spec.rgb = srgb_to_linear(spec.rgb);
spec.a = glossiness; // pack glossiness into spec alpha for lighting functions
@@ -395,7 +392,7 @@ void main()
applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz);
}
- color = mix(color.rgb, legacy_adjust_fullbright(diffcol.rgb), emissive);
+ color = mix(color.rgb, diffcol.rgb, emissive);
if (env > 0.0)
{ // add environmentmap
diff --git a/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl
index 2a096a98ec..ec8168465e 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl
@@ -52,7 +52,6 @@ vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensi
vec2 getScreenXY(vec4 clip);
vec2 getScreenCoord(vec4 clip);
vec3 srgb_to_linear(vec3 c);
-vec3 legacy_adjust(vec3 c);
// Util
vec3 hue_to_rgb(float hue);
@@ -67,9 +66,6 @@ vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
void main()
{
-#if defined(LOCAL_LIGHT_KILL)
- discard; // Bail immediately
-#else
vec3 final_color = vec3(0, 0, 0);
vec2 tc = getScreenCoord(vary_fragcoord);
vec3 pos = getPosition(tc).xyz;
@@ -118,7 +114,7 @@ void main()
float dist_atten = calcLegacyDistanceAttenuation(dist, falloff);
- vec3 intensity = dist_atten * lightColor * 3.9;
+ vec3 intensity = dist_atten * lightColor * 3.25;
final_color += intensity*pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, lv);
}
@@ -126,7 +122,6 @@ void main()
}
else
{
- diffuse.rgb = legacy_adjust(diffuse.rgb);
diffuse = srgb_to_linear(diffuse);
spec.rgb = srgb_to_linear(spec.rgb);
@@ -174,7 +169,6 @@ void main()
frag_color.rgb = max(final_color, vec3(0));
frag_color.a = 0.0;
-#endif // LOCAL_LIGHT_KILL
#ifdef IS_AMD_CARD
// If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage
diff --git a/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl
deleted file mode 100644
index 23120bbbbe..0000000000
--- a/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl
+++ /dev/null
@@ -1,263 +0,0 @@
-/**
- * @file class3\deferred\multiSpotLightF.glsl
- *
- * $LicenseInfo:firstyear=2022&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2022, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-/*[EXTRA_CODE_HERE]*/
-
-out vec4 frag_color;
-
-uniform sampler2D diffuseRect;
-uniform sampler2D specularRect;
-uniform sampler2D depthMap;
-uniform sampler2D normalMap;
-uniform sampler2D emissiveRect; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl
-uniform samplerCube environmentMap;
-uniform sampler2D lightMap;
-uniform sampler2D projectionMap; // rgba
-uniform sampler2D lightFunc;
-
-uniform mat4 proj_mat; //screen space to light space
-uniform float proj_near; //near clip for projection
-uniform vec3 proj_p; //plane projection is emitting from (in screen space)
-uniform vec3 proj_n;
-uniform float proj_focus; //distance from plane to begin blurring
-uniform float proj_lod; //(number of mips in proj map)
-uniform float proj_range; //range between near clip and far clip plane of projection
-uniform float proj_ambient_lod;
-uniform float proj_ambiance;
-uniform float near_clip;
-uniform float far_clip;
-
-uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
-uniform float sun_wash;
-uniform int proj_shadow_idx;
-uniform float shadow_fade;
-
-// Light params
-uniform vec3 center;
-uniform float size;
-uniform vec3 color;
-uniform float falloff;
-
-in vec4 vary_fragcoord;
-uniform vec2 screen_res;
-
-uniform mat4 inv_proj;
-
-void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
-float calcLegacyDistanceAttenuation(float distance, float falloff);
-vec3 colorized_dot(float x);
-bool clipProjectedLightVars(vec3 center, vec3 pos, out float dist, out float l_dist, out vec3 lv, out vec4 proj_tc );
-vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity);
-vec3 getProjectedLightAmbiance(float amb_da, float attenuation, float lit, float nl, float noise, vec2 projected_uv);
-vec3 getProjectedLightDiffuseColor(float light_distance, vec2 projected_uv );
-vec3 getProjectedLightSpecularColor(vec3 pos, vec3 n);
-vec2 getScreenXY(vec4 clip);
-vec2 getScreenCoord(vec4 clip);
-vec3 srgb_to_linear(vec3 cs);
-vec3 legacy_adjust(vec3 c);
-vec4 texture2DLodSpecular(vec2 tc, float lod);
-
-vec4 getPosition(vec2 pos_screen);
-
-const float M_PI = 3.14159265;
-
-vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
- float perceptualRoughness,
- float metallic,
- vec3 n, // normal
- vec3 v, // surface point to camera
- vec3 l); //surface point to light
-
-void main()
-{
-#if defined(LOCAL_LIGHT_KILL)
- discard;
-#else
- vec3 final_color = vec3(0,0,0);
- vec2 tc = getScreenCoord(vary_fragcoord);
- vec3 pos = getPosition(tc).xyz;
-
- vec3 lv;
- vec4 proj_tc;
- float dist, l_dist;
- if (clipProjectedLightVars(center, pos, dist, l_dist, lv, proj_tc))
- {
- discard;
- }
-
- float shadow = 1.0;
-
- if (proj_shadow_idx >= 0)
- {
- vec4 shd = texture(lightMap, tc);
- shadow = (proj_shadow_idx==0)?shd.b:shd.a;
- shadow += shadow_fade;
- shadow = clamp(shadow, 0.0, 1.0);
- }
-
- float envIntensity;
- vec3 n;
- vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity);
-
- float dist_atten = calcLegacyDistanceAttenuation(dist, falloff);
- if (dist_atten <= 0.0)
- {
- discard;
- }
-
- lv = proj_origin-pos.xyz;
- vec3 h, l, v = -normalize(pos);
- float nh, nl, nv, vh, lightDist;
- calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist);
-
- vec3 diffuse = texture(diffuseRect, tc).rgb;
- vec4 spec = texture(specularRect, tc);
- vec3 dlit = vec3(0, 0, 0);
- vec3 slit = vec3(0, 0, 0);
-
- vec3 amb_rgb = vec3(0);
-
- if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR))
- {
- vec3 colorEmissive = texture(emissiveRect, tc).rgb;
- vec3 orm = spec.rgb;
- float perceptualRoughness = orm.g;
- float metallic = orm.b;
- vec3 f0 = vec3(0.04);
- vec3 baseColor = diffuse.rgb;
-
- vec3 diffuseColor = baseColor.rgb*(vec3(1.0)-f0);
- diffuseColor *= 1.0 - metallic;
-
- vec3 specularColor = mix(f0, baseColor.rgb, metallic);
-
- // We need this additional test inside a light's frustum since a spotlight's ambiance can be applied
- if (proj_tc.x > 0.0 && proj_tc.x < 1.0
- && proj_tc.y > 0.0 && proj_tc.y < 1.0)
- {
- float lit = 0.0;
- float amb_da = 0.0;
-
- if (nl > 0.0)
- {
- amb_da += (nl*0.5 + 0.5) * proj_ambiance;
-
- dlit = getProjectedLightDiffuseColor( l_dist, proj_tc.xy );
-
- vec3 intensity = dist_atten * dlit * 3.9 * shadow; // Legacy attenuation, magic number to balance with legacy materials
- final_color += intensity*pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, normalize(lv));
- }
-
- amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, 1.0, proj_tc.xy );
- final_color += diffuse.rgb * amb_rgb;
- }
- }
- else
- {
- diffuse = legacy_adjust(diffuse);
- diffuse = srgb_to_linear(diffuse);
- spec.rgb = srgb_to_linear(spec.rgb);
-
- if (proj_tc.z > 0.0 &&
- proj_tc.x < 1.0 &&
- proj_tc.y < 1.0 &&
- proj_tc.x > 0.0 &&
- proj_tc.y > 0.0)
- {
- float amb_da = 0;
- float lit = 0.0;
-
- if (nl > 0.0)
- {
- lit = nl * dist_atten;
-
- dlit = getProjectedLightDiffuseColor( l_dist, proj_tc.xy );
-
- final_color = dlit*lit*diffuse*shadow;
-
- // unshadowed for consistency between forward and deferred?
- amb_da += (nl*0.5+0.5) /* * (1.0-shadow) */ * proj_ambiance;
- }
-
- amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, 1.0, proj_tc.xy );
- final_color += diffuse.rgb * amb_rgb;
- }
-
- if (spec.a > 0.0)
- {
- dlit *= min(nl*6.0, 1.0) * dist_atten;
-
- float fres = pow(1 - vh, 5)*0.4+0.5;
-
- float gtdenom = 2 * nh;
- float gt = max(0, min(gtdenom * nv / vh, gtdenom * nl / vh));
-
- if (nh > 0.0)
- {
- float scol = fres*texture(lightFunc, vec2(nh, spec.a)).r*gt/(nh*nl);
- vec3 speccol = dlit*scol*spec.rgb*shadow;
- speccol = clamp(speccol, vec3(0), vec3(1));
- final_color += speccol;
- }
- }
-
- if (envIntensity > 0.0)
- {
- vec3 ref = reflect(normalize(pos), n);
-
- //project from point pos in direction ref to plane proj_p, proj_n
- vec3 pdelta = proj_p-pos;
- float ds = dot(ref, proj_n);
-
- if (ds < 0.0)
- {
- vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
-
- vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
-
- if (stc.z > 0.0)
- {
- stc /= stc.w;
-
- if (stc.x < 1.0 &&
- stc.y < 1.0 &&
- stc.x > 0.0 &&
- stc.y > 0.0)
- {
- final_color += color.rgb * texture2DLodSpecular(stc.xy, (1 - spec.a) * (proj_lod * 0.6)).rgb * shadow * envIntensity;
- }
- }
- }
- }
- }
-
- //not sure why, but this line prevents MATBUG-194
- final_color = max(final_color, vec3(0.0));
-
- //output linear
- frag_color.rgb = final_color;
- frag_color.a = 0.0;
-#endif // LOCAL_LIGHT_KILL
-}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl
index 42ba96148c..31af1208bd 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl
@@ -57,7 +57,6 @@ vec4 getPosition(vec2 pos_screen);
vec2 getScreenXY(vec4 clip);
vec2 getScreenCoord(vec4 clip);
vec3 srgb_to_linear(vec3 c);
-vec3 legacy_adjust(vec3 c);
float getDepth(vec2 tc);
vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
@@ -107,7 +106,7 @@ void main()
vec3 specularColor = mix(f0, baseColor.rgb, metallic);
- vec3 intensity = dist_atten * color * 3.9; // Legacy attenuation, magic number to balance with legacy materials
+ vec3 intensity = dist_atten * color * 3.25; // Legacy attenuation, magic number to balance with legacy materials
final_color += intensity*pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, normalize(lv));
}
else
@@ -116,7 +115,6 @@ void main()
{
discard;
}
- diffuse = legacy_adjust(diffuse);
diffuse = srgb_to_linear(diffuse);
spec.rgb = srgb_to_linear(spec.rgb);
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index d42388ae78..8b7aea24ed 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -86,7 +86,6 @@ float getDepth(vec2 pos_screen);
vec3 linear_to_srgb(vec3 c);
vec3 srgb_to_linear(vec3 c);
-vec3 legacy_adjust(vec3 c);
uniform vec4 waterPlane;
@@ -234,8 +233,6 @@ void main()
else
{
// legacy shaders are still writng sRGB to gbuffer
- baseColor.rgb = legacy_adjust(baseColor.rgb);
-
baseColor.rgb = srgb_to_linear(baseColor.rgb);
spec.rgb = srgb_to_linear(spec.rgb);
diff --git a/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl
index 1ea801d7d7..d31b37fb60 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl
@@ -25,16 +25,6 @@
/*[EXTRA_CODE_HERE]*/
-#define DEBUG_ANY_LIGHT_TYPE 0 // Output green light cone
-#define DEBUG_LEG_LIGHT_TYPE 0 // Show Legacy objects in green
-#define DEBUG_PBR_LIGHT_TYPE 0 // Show PBR objects in green
-#define DEBUG_PBR_SPOT 0
-#define DEBUG_PBR_SPOT_DIFFUSE 0
-#define DEBUG_PBR_SPOT_SPECULAR 0
-
-#define DEBUG_SPOT_NL 0 // monochome area effected by light
-#define DEBUG_SPOT_ZERO 0 // Output zero for spotlight
-
out vec4 frag_color;
uniform sampler2D diffuseRect;
@@ -64,11 +54,16 @@ uniform float sun_wash;
uniform int proj_shadow_idx;
uniform float shadow_fade;
+// Light params
+#if defined(MULTI_SPOTLIGHT)
+uniform vec3 center;
+#else
+in vec3 trans_center;
+#endif
uniform float size;
uniform vec3 color;
uniform float falloff;
-in vec3 trans_center;
in vec4 vary_fragcoord;
uniform vec2 screen_res;
@@ -80,11 +75,8 @@ bool clipProjectedLightVars(vec3 center, vec3 pos, out float dist, out float l_d
vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity);
vec3 getProjectedLightAmbiance(float amb_da, float attenuation, float lit, float nl, float noise, vec2 projected_uv);
vec3 getProjectedLightDiffuseColor(float light_distance, vec2 projected_uv );
-vec3 getProjectedLightSpecularColor(vec3 pos, vec3 n);
-vec2 getScreenXY(vec4 clip_point);
-vec2 getScreenCoord(vec4 clip_point);
-vec3 srgb_to_linear(vec3 c);
-vec3 legacy_adjust(vec3 c);
+vec2 getScreenCoord(vec4 clip);
+vec3 srgb_to_linear(vec3 cs);
vec4 texture2DLodSpecular(vec2 tc, float lod);
vec4 getPosition(vec2 pos_screen);
@@ -100,9 +92,6 @@ vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
void main()
{
-#if defined(LOCAL_LIGHT_KILL)
- discard;
-#else
vec3 final_color = vec3(0,0,0);
vec2 tc = getScreenCoord(vary_fragcoord);
vec3 pos = getPosition(tc).xyz;
@@ -110,24 +99,31 @@ void main()
vec3 lv;
vec4 proj_tc;
float dist, l_dist;
- if (clipProjectedLightVars(trans_center, pos, dist, l_dist, lv, proj_tc))
+ vec3 c;
+#if defined(MULTI_SPOTLIGHT)
+ c = center;
+#else
+ c = trans_center;
+#endif
+
+ if (clipProjectedLightVars(c, pos, dist, l_dist, lv, proj_tc))
{
discard;
}
float shadow = 1.0;
-
+
if (proj_shadow_idx >= 0)
{
vec4 shd = texture(lightMap, tc);
- shadow = (proj_shadow_idx == 0) ? shd.b : shd.a;
+ shadow = (proj_shadow_idx==0)?shd.b:shd.a;
shadow += shadow_fade;
- shadow = clamp(shadow, 0.0, 1.0);
+ shadow = clamp(shadow, 0.0, 1.0);
}
float envIntensity;
vec3 n;
- vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG()
+ vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity);
float dist_atten = calcLegacyDistanceAttenuation(dist, falloff);
if (dist_atten <= 0.0)
@@ -135,7 +131,7 @@ void main()
discard;
}
- lv = proj_origin-pos.xyz; // NOTE: Re-using lv
+ lv = proj_origin-pos.xyz;
vec3 h, l, v = -normalize(pos);
float nh, nl, nv, vh, lightDist;
calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist);
@@ -146,10 +142,11 @@ void main()
vec3 slit = vec3(0, 0, 0);
vec3 amb_rgb = vec3(0);
+
if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR))
{
- vec3 colorEmissive = texture(emissiveRect, tc).rgb;
- vec3 orm = spec.rgb;
+ vec3 colorEmissive = texture(emissiveRect, tc).rgb;
+ vec3 orm = spec.rgb;
float perceptualRoughness = orm.g;
float metallic = orm.b;
vec3 f0 = vec3(0.04);
@@ -167,33 +164,34 @@ void main()
float lit = 0.0;
float amb_da = 0.0;
+ lv = normalize(lv);
+
if (nl > 0.0)
{
amb_da += (nl*0.5 + 0.5) * proj_ambiance;
dlit = getProjectedLightDiffuseColor( l_dist, proj_tc.xy );
- vec3 intensity = dist_atten * dlit * 3.9 * shadow; // Legacy attenuation
- final_color += intensity*pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, normalize(lv));
+ vec3 intensity = dist_atten * dlit * 3.25 * shadow; // Legacy attenuation, magic number to balance with legacy materials
+ final_color += intensity*pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, lv);
}
- amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, 1.0, proj_tc.xy );
- final_color += diffuse.rgb * amb_rgb;
+ amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, 1.0, proj_tc.xy ) * 3.25; //magic number to balance with legacy ambiance
+ final_color += amb_rgb * pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, -lv);
}
}
else
{
- diffuse = legacy_adjust(diffuse);
diffuse = srgb_to_linear(diffuse);
spec.rgb = srgb_to_linear(spec.rgb);
-
+
if (proj_tc.z > 0.0 &&
proj_tc.x < 1.0 &&
proj_tc.y < 1.0 &&
proj_tc.x > 0.0 &&
proj_tc.y > 0.0)
{
- float amb_da = proj_ambiance;
+ float amb_da = 0;
float lit = 0.0;
if (nl > 0.0)
@@ -204,24 +202,23 @@ void main()
final_color = dlit*lit*diffuse*shadow;
+ // unshadowed for consistency between forward and deferred?
amb_da += (nl*0.5+0.5) /* * (1.0-shadow) */ * proj_ambiance;
}
-
- vec3 amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, 1.0, proj_tc.xy );
- final_color += diffuse.rgb*amb_rgb;
- #if DEBUG_LEG_LIGHT_TYPE
- final_color = vec3(0,0.5,0);
- #endif
+
+ amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, 1.0, proj_tc.xy );
+ final_color += diffuse.rgb * amb_rgb * max(dot(-normalize(lv), n), 0.0);
}
-
+
if (spec.a > 0.0)
{
dlit *= min(nl*6.0, 1.0) * dist_atten;
- float fres = pow(1 - dot(h, v), 5)*0.4+0.5;
+
+ float fres = pow(1 - vh, 5)*0.4+0.5;
float gtdenom = 2 * nh;
float gt = max(0, min(gtdenom * nv / vh, gtdenom * nl / vh));
-
+
if (nh > 0.0)
{
float scol = fres*texture(lightFunc, vec2(nh, spec.a)).r*gt/(nh*nl);
@@ -229,26 +226,26 @@ void main()
speccol = clamp(speccol, vec3(0), vec3(1));
final_color += speccol;
}
- }
+ }
if (envIntensity > 0.0)
{
vec3 ref = reflect(normalize(pos), n);
-
+
//project from point pos in direction ref to plane proj_p, proj_n
vec3 pdelta = proj_p-pos;
float ds = dot(ref, proj_n);
-
+
if (ds < 0.0)
{
vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
-
+
vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
if (stc.z > 0.0)
{
stc /= stc.w;
-
+
if (stc.x < 1.0 &&
stc.y < 1.0 &&
stc.x > 0.0 &&
@@ -261,24 +258,10 @@ void main()
}
}
-#if DEBUG_PBR_SPOT_DIFFUSE
- final_color = vec3(nl * dist_atten);
-#endif
-#if DEBUG_SPOT_NL
- final_color = vec3(nl);
-#endif
-#if DEBUG_SPOT_ZERO
- final_color = vec3(0,0,0);
-#endif
-#if DEBUG_ANY_LIGHT_TYPE
- final_color = vec3(0,0.3333,0);
-#endif
-
//not sure why, but this line prevents MATBUG-194
final_color = max(final_color, vec3(0.0));
- //output linear colors as gamma correction happens down stream
+ //output linear
frag_color.rgb = final_color;
frag_color.a = 0.0;
-#endif // LOCAL_LIGHT_KILL
}
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index 39f7996c7c..f92d9a2a0e 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 58
+version 59
// The version number above should be incremented IF AND ONLY IF some
// change has been made that is sufficiently important to justify
// resetting the graphics preferences of all users to the recommended
@@ -42,7 +42,7 @@ RenderGamma 1 0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 8192
RenderObjectBump 1 1
-RenderLocalLights 1 1
+RenderLocalLightCount 1 4096
RenderTransparentWater 1 1
RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 2
@@ -87,10 +87,10 @@ RenderAvatarMaxComplexity 1 35000
RenderFarClip 1 64
RenderFlexTimeFactor 1 0
RenderGlowResolutionPow 1 8
-RenderLocalLights 1 0
+RenderLocalLightCount 1 8
RenderMaxPartCount 1 0
RenderTransparentWater 1 0
-RenderReflectionsEnabled 1 0
+RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 0
RenderTerrainDetail 1 0
RenderTerrainLODFactor 1 1
@@ -117,7 +117,7 @@ RenderFarClip 1 96
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 8
RenderMaxPartCount 1 2048
-RenderLocalLights 1 1
+RenderLocalLightCount 1 256
RenderTransparentWater 1 0
RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 0
@@ -146,7 +146,7 @@ RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
-RenderLocalLights 1 1
+RenderLocalLightCount 1 512
RenderTransparentWater 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
@@ -175,7 +175,7 @@ RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
-RenderLocalLights 1 1
+RenderLocalLightCount 1 1024
RenderTransparentWater 1 1
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
@@ -204,7 +204,7 @@ RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
-RenderLocalLights 1 1
+RenderLocalLightCount 1 2048
RenderTransparentWater 1 1
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
@@ -233,7 +233,7 @@ RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
-RenderLocalLights 1 1
+RenderLocalLightCount 1 4096
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTransparentWater 1 1
@@ -260,7 +260,7 @@ RenderAvatarPhysicsLODFactor 1 1.0
RenderFarClip 1 256
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
-RenderLocalLights 1 1
+RenderLocalLightCount 1 8192
RenderMaxPartCount 1 8192
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
@@ -299,7 +299,7 @@ list safe
RenderAnisotropic 1 0
RenderAvatarMaxNonImpostors 1 16
RenderAvatarMaxComplexity 1 80000
-RenderLocalLights 1 0
+RenderLocalLightCount 1 0
RenderMaxPartCount 1 1024
RenderTerrainDetail 1 0
RenderTransparentWater 1 0
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index cce403c7aa..d86412a237 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,4 +1,4 @@
-version 53
+version 54
// The version number above should be incremented IF AND ONLY IF some
// change has been made that is sufficiently important to justify
// resetting the graphics preferences of all users to the recommended
@@ -42,7 +42,7 @@ RenderGamma 1 0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 8192
RenderObjectBump 1 1
-RenderLocalLights 1 1
+RenderLocalLightCount 1 4096
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTransparentWater 1 1
@@ -85,7 +85,7 @@ RenderAvatarMaxComplexity 1 35000
RenderFarClip 1 64
RenderFlexTimeFactor 1 0
RenderGlowResolutionPow 1 8
-RenderLocalLights 1 0
+RenderLocalLightCount 1 8
RenderMaxPartCount 1 0
RenderTerrainDetail 1 0
RenderTerrainLODFactor 1 1
@@ -97,7 +97,7 @@ RenderUseAdvancedAtmospherics 1 0
RenderShadowDetail 1 0
WLSkyDetail 1 96
RenderFSAASamples 1 0
-RenderReflectionsEnabled 1 0
+RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 0
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 0
@@ -115,7 +115,7 @@ RenderFarClip 1 96
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 8
RenderMaxPartCount 1 2048
-RenderLocalLights 1 1
+RenderLocalLightCount 1 256
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 1.0
RenderTransparentWater 1 1
@@ -144,7 +144,7 @@ RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
-RenderLocalLights 1 1
+RenderLocalLightCount 1 512
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTransparentWater 1 1
@@ -173,7 +173,7 @@ RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
-RenderLocalLights 1 1
+RenderLocalLightCount 1 1024
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTransparentWater 1 1
@@ -202,7 +202,7 @@ RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
-RenderLocalLights 1 1
+RenderLocalLightCount 1 2048
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTransparentWater 1 1
@@ -231,7 +231,7 @@ RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
-RenderLocalLights 1 1
+RenderLocalLightCount 1 4096
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTransparentWater 1 1
@@ -258,7 +258,7 @@ RenderAvatarMaxNonImpostors 1 16
RenderFarClip 1 256
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
-RenderLocalLights 1 1
+RenderLocalLightCount 1 8192
RenderMaxPartCount 1 8192
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
@@ -298,7 +298,7 @@ list safe
RenderAnisotropic 1 0
RenderAvatarMaxNonImpostors 1 16
RenderAvatarMaxComplexity 1 80000
-RenderLocalLights 1 0
+RenderLocalLightCount 1 0
RenderMaxPartCount 1 1024
RenderTerrainDetail 1 0
RenderDeferredSSAO 0 0
@@ -313,7 +313,6 @@ RenderDeferredSSAO 1 0
list Intel
RenderAnisotropic 1 0
-RenderLocalLights 1 0
RenderFSAASamples 1 0
list GL3
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 193db88977..a273afab52 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -122,8 +122,7 @@ const F32 MAX_FIDGET_TIME = 20.f; // seconds
const S32 UI_FEATURE_VERSION = 1;
// For version 1: 1 - inventory, 2 - gltf
-// Will need to change to 3 once either inventory or gltf releases and cause a conflict
-const S32 UI_FEATURE_FLAGS = 2;
+const S32 UI_FEATURE_FLAGS = 3;
// The agent instance.
LLAgent gAgent;
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 53397978e0..db99f20775 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -1306,8 +1306,9 @@ void LLAgentWearables::findAttachmentsAddRemoveInfo(LLInventoryModel::item_array
}
// Build up list of objects to be removed and items currently attached.
- for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
- iter != gAgentAvatarp->mAttachmentPoints.end();)
+ LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
+ LLVOAvatar::attachment_map_t::iterator end = gAgentAvatarp->mAttachmentPoints.end();
+ while (iter != end)
{
LLVOAvatar::attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
@@ -1526,7 +1527,7 @@ bool LLAgentWearables::moveWearable(const LLViewerInventoryItem* item, bool clos
}
// static
-void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, const LLUUID& parent_id)
+void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, const LLUUID& parent_id, std::function created_cb)
{
if (type == LLWearableType::WT_INVALID || type == LLWearableType::WT_NONE) return;
@@ -1538,7 +1539,7 @@ void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, con
LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);
LLAssetType::EType asset_type = wearable->getAssetType();
- LLPointer cb;
+ LLPointer cb;
if(wear)
{
cb = new LLBoostFuncInventoryCallback(wear_and_edit_cb);
@@ -1547,6 +1548,10 @@ void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, con
{
cb = new LLBoostFuncInventoryCallback(wear_cb);
}
+ if (created_cb != NULL)
+ {
+ cb->addOnFireFunc(created_cb);
+ }
LLUUID folder_id;
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index 2710262910..e20f5df7fa 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -129,7 +129,7 @@ protected:
//--------------------------------------------------------------------
public:
- static void createWearable(LLWearableType::EType type, bool wear = false, const LLUUID& parent_id = LLUUID::null);
+ static void createWearable(LLWearableType::EType type, bool wear = false, const LLUUID& parent_id = LLUUID::null, std::function created_cb = NULL);
static void editWearable(const LLUUID& item_id);
bool moveWearable(const LLViewerInventoryItem* item, bool closer_to_body);
diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp
index 005259bcb8..17e1a27934 100644
--- a/indra/newview/llaisapi.cpp
+++ b/indra/newview/llaisapi.cpp
@@ -29,11 +29,15 @@
#include "llaisapi.h"
#include "llagent.h"
+#include "llappviewer.h"
#include "llcallbacklist.h"
#include "llinventorymodel.h"
+#include "llinventoryobserver.h"
+#include "llnotificationsutil.h"
#include "llsdutil.h"
#include "llviewerregion.h"
-#include "llinventoryobserver.h"
+#include "llvoavatar.h"
+#include "llvoavatarself.h"
#include "llviewercontrol.h"
///----------------------------------------------------------------------------
@@ -43,11 +47,16 @@
//=========================================================================
const std::string AISAPI::INVENTORY_CAP_NAME("InventoryAPIv3");
const std::string AISAPI::LIBRARY_CAP_NAME("LibraryAPIv3");
+const S32 AISAPI::HTTP_TIMEOUT = 180;
std::list AISAPI::sPostponedQuery;
const S32 MAX_SIMULTANEOUS_COROUTINES = 2048;
+// AIS3 allows '*' requests, but in reality those will be cut at some point
+// Specify own depth to be able to anticipate it and mark folders as incomplete
+const S32 MAX_FOLDER_DEPTH_REQUEST = 50;
+
//-------------------------------------------------------------------------
/*static*/
bool AISAPI::isAvailable()
@@ -93,6 +102,10 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
return;
}
@@ -100,7 +113,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
tid.generate();
std::string url = cap + std::string("/category/") + parentId.asString() + "?tid=" + tid.asString();
- LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+ LL_DEBUGS("Inventory") << "url: " << url << " parentID " << parentId << " newInventory " << newInventory << LL_ENDL;
// I may be suffering from golden hammer here, but the first part of this bind
// is actually a static cast for &HttpCoroutineAdapter::postAndSuspend so that
@@ -124,7 +137,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
(&LLCoreHttpUtil::HttpCoroutineAdapter::postAndSuspend), _1, _2, _3, _4, _5, _6);
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
- _1, postFn, url, parentId, newInventory, callback, COPYINVENTORY));
+ _1, postFn, url, parentId, newInventory, callback, CREATEINVENTORY));
EnqueueAISCommand("CreateInventory", proc);
}
@@ -135,6 +148,10 @@ void AISAPI::SlamFolder(const LLUUID& folderId, const LLSD& newInventory, comple
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
return;
}
@@ -170,6 +187,10 @@ void AISAPI::RemoveCategory(const LLUUID &categoryId, completion_t callback)
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
return;
}
@@ -203,6 +224,10 @@ void AISAPI::RemoveItem(const LLUUID &itemId, completion_t callback)
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
return;
}
@@ -235,6 +260,10 @@ void AISAPI::CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, b
if (cap.empty())
{
LL_WARNS("Inventory") << "Library cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
return;
}
@@ -279,6 +308,10 @@ void AISAPI::PurgeDescendents(const LLUUID &categoryId, completion_t callback)
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
return;
}
@@ -313,6 +346,10 @@ void AISAPI::UpdateCategory(const LLUUID &categoryId, const LLSD &updates, compl
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
return;
}
std::string url = cap + std::string("/category/") + categoryId.asString();
@@ -345,6 +382,10 @@ void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
return;
}
std::string url = cap + std::string("/item/") + itemId.asString();
@@ -367,6 +408,380 @@ void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t
EnqueueAISCommand("UpdateItem", proc);
}
+/*static*/
+void AISAPI::FetchItem(const LLUUID &itemId, ITEM_TYPE type, completion_t callback)
+{
+ std::string cap;
+
+ cap = (type == INVENTORY) ? getInvCap() : getLibCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
+ }
+ std::string url = cap + std::string("/item/") + itemId.asString();
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, getFn, url, itemId, LLSD(), callback, FETCHITEM));
+
+ EnqueueAISCommand("FetchItem", proc);
+}
+
+/*static*/
+void AISAPI::FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type, bool recursive, completion_t callback, S32 depth)
+{
+ std::string cap;
+
+ cap = (type == INVENTORY) ? getInvCap() : getLibCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
+ }
+ std::string url = cap + std::string("/category/") + catId.asString() + "/children";
+
+ if (recursive)
+ {
+ // can specify depth=*, but server side is going to cap requests
+ // and reject everything 'over the top',.
+ depth = MAX_FOLDER_DEPTH_REQUEST;
+ }
+ else
+ {
+ depth = llmin(depth, MAX_FOLDER_DEPTH_REQUEST);
+ }
+
+ url += "?depth=" + std::to_string(depth);
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+ // get doesn't use body, can pass additional data
+ LLSD body;
+ body["depth"] = depth;
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, getFn, url, catId, body, callback, FETCHCATEGORYCHILDREN));
+
+ EnqueueAISCommand("FetchCategoryChildren", proc);
+}
+
+// some folders can be requested by name, like
+// animatn | bodypart | clothing | current | favorite | gesture | inbox | landmark | lsltext
+// lstndfnd | my_otfts | notecard | object | outbox | root | snapshot | sound | texture | trash
+void AISAPI::FetchCategoryChildren(const std::string &identifier, bool recursive, completion_t callback, S32 depth)
+{
+ std::string cap;
+
+ cap = getInvCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
+ }
+ std::string url = cap + std::string("/category/") + identifier + "/children";
+
+ if (recursive)
+ {
+ // can specify depth=*, but server side is going to cap requests
+ // and reject everything 'over the top',.
+ depth = MAX_FOLDER_DEPTH_REQUEST;
+ }
+ else
+ {
+ depth = llmin(depth, MAX_FOLDER_DEPTH_REQUEST);
+ }
+
+ url += "?depth=" + std::to_string(depth);
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+ // get doesn't use body, can pass additional data
+ LLSD body;
+ body["depth"] = depth;
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, getFn, url, LLUUID::null, body, callback, FETCHCATEGORYCHILDREN));
+
+ EnqueueAISCommand("FetchCategoryChildren", proc);
+}
+
+/*static*/
+void AISAPI::FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type, bool recursive, completion_t callback, S32 depth)
+{
+ std::string cap;
+
+ cap = (type == INVENTORY) ? getInvCap() : getLibCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
+ }
+ std::string url = cap + std::string("/category/") + catId.asString() + "/categories";
+
+ if (recursive)
+ {
+ // can specify depth=*, but server side is going to cap requests
+ // and reject everything 'over the top',.
+ depth = MAX_FOLDER_DEPTH_REQUEST;
+ }
+ else
+ {
+ depth = llmin(depth, MAX_FOLDER_DEPTH_REQUEST);
+ }
+
+ url += "?depth=" + std::to_string(depth);
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+ // get doesn't use body, can pass additional data
+ LLSD body;
+ body["depth"] = depth;
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, getFn, url, catId, body, callback, FETCHCATEGORYCATEGORIES));
+
+ EnqueueAISCommand("FetchCategoryCategories", proc);
+}
+
+void AISAPI::FetchCategorySubset(const LLUUID& catId,
+ const uuid_vec_t specificChildren,
+ ITEM_TYPE type,
+ bool recursive,
+ completion_t callback,
+ S32 depth)
+{
+ std::string cap = (type == INVENTORY) ? getInvCap() : getLibCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
+ }
+ if (specificChildren.empty())
+ {
+ LL_WARNS("Inventory") << "Empty request!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
+ }
+ // category/any_folder_id/children?depth=*&children=child_id1,child_id2,child_id3
+ std::string url = cap + std::string("/category/") + catId.asString() + "/children";
+
+ if (recursive)
+ {
+ depth = MAX_FOLDER_DEPTH_REQUEST;
+ }
+ else
+ {
+ depth = llmin(depth, MAX_FOLDER_DEPTH_REQUEST);
+ }
+
+ uuid_vec_t::const_iterator iter = specificChildren.begin();
+ uuid_vec_t::const_iterator end = specificChildren.end();
+
+ url += "?depth=" + std::to_string(depth) + "&children=" + iter->asString();
+ iter++;
+
+ while (iter != end)
+ {
+ url += "," + iter->asString();
+ iter++;
+ }
+
+ const S32 MAX_URL_LENGH = 2000; // RFC documentation specifies a maximum length of 2048
+ if (url.length() > MAX_URL_LENGH)
+ {
+ LL_WARNS("Inventory") << "Request url is too long, url: " << url << LL_ENDL;
+ }
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+ // get doesn't use body, can pass additional data
+ LLSD body;
+ body["depth"] = depth;
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, getFn, url, catId, body, callback, FETCHCATEGORYSUBSET));
+
+ EnqueueAISCommand("FetchCategorySubset", proc);
+}
+
+/*static*/
+// Will get COF folder, links in it and items those links point to
+void AISAPI::FetchCOF(completion_t callback)
+{
+ std::string cap = getInvCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
+ }
+ std::string url = cap + std::string("/category/current/links");
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+ LLSD body;
+ // Only cof folder will be full, but cof can contain an outfit
+ // link with embedded outfit folder for request to parse
+ body["depth"] = 0;
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, getFn, url, LLUUID::null, body, callback, FETCHCOF));
+
+ EnqueueAISCommand("FetchCOF", proc);
+}
+
+void AISAPI::FetchCategoryLinks(const LLUUID &catId, completion_t callback)
+{
+ std::string cap = getInvCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
+ }
+ std::string url = cap + std::string("/category/") + catId.asString() + "/links";
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend),
+ _1, _2, _3, _5, _6);
+
+ LLSD body;
+ body["depth"] = 0;
+ LLCoprocedureManager::CoProcedure_t proc(
+ boost::bind(&AISAPI::InvokeAISCommandCoro, _1, getFn, url, LLUUID::null, body, callback, FETCHCATEGORYLINKS));
+
+ EnqueueAISCommand("FetchCategoryLinks", proc);
+}
+
+/*static*/
+void AISAPI::FetchOrphans(completion_t callback)
+{
+ std::string cap = getInvCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
+ }
+ std::string url = cap + std::string("/orphans");
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend) , _1 , _2 , _3 , _5 , _6);
+
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro ,
+ _1 , getFn , url , LLUUID::null , LLSD() , callback , FETCHORPHANS));
+
+ EnqueueAISCommand("FetchOrphans" , proc);
+}
+
/*static*/
void AISAPI::EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc)
{
@@ -417,22 +832,50 @@ void AISAPI::onIdle(void *userdata)
}
}
+/*static*/
+void AISAPI::onUpdateReceived(const LLSD& update, COMMAND_TYPE type, const LLSD& request_body)
+{
+ LLTimer timer;
+ if ( (type == UPDATECATEGORY || type == UPDATEITEM)
+ && gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+ {
+ dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
+ }
+
+ AISUpdate ais_update(update, type, request_body);
+ ais_update.doUpdate(); // execute the updates in the appropriate order.
+ LL_DEBUGS("Inventory", "AIS3") << "Elapsed processing: " << timer.getElapsedTimeF32() << LL_ENDL;
+}
+
/*static*/
void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter,
invokationFn_t invoke, std::string url,
LLUUID targetId, LLSD body, completion_t callback, COMMAND_TYPE type)
{
+ if (gDisconnected)
+ {
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
+ }
+
LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions);
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
LLCore::HttpHeaders::ptr_t httpHeaders;
- httpOptions->setTimeout(LLCoreHttpUtil::HTTP_REQUEST_EXPIRY_SECS);
+ httpOptions->setTimeout(HTTP_TIMEOUT);
- LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+ LL_DEBUGS("Inventory") << "Request url: " << url << LL_ENDL;
- LLSD result = invoke(httpAdapter, httpRequest, url, body, httpOptions, httpHeaders);
- LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
- LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ LLSD result;
+ LLSD httpResults;
+ LLCore::HttpStatus status;
+
+ result = invoke(httpAdapter , httpRequest , url , body , httpOptions , httpHeaders);
+ httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if (!status || !result.isMap())
{
@@ -474,29 +917,127 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
}
}
}
+ else if (status == LLCore::HttpStatus(HTTP_FORBIDDEN) /*403*/)
+ {
+ if (type == FETCHCATEGORYCHILDREN)
+ {
+ if (body.has("depth") && body["depth"].asInteger() == 0)
+ {
+ // Can't fetch a single folder with depth 0, folder is too big.
+ static bool first_call = true;
+ if (first_call)
+ {
+ first_call = false;
+ LLNotificationsUtil::add("InventoryLimitReachedAISAlert");
+ }
+ else
+ {
+ LLNotificationsUtil::add("InventoryLimitReachedAIS");
+ }
+ LL_WARNS("Inventory") << "Fetch failed, content is over limit, url: " << url << LL_ENDL;
+ }
+ else
+ {
+ // Result was too big, but situation is recoverable by requesting with lower depth
+ LL_DEBUGS("Inventory") << "Fetch failed, content is over limit, url: " << url << LL_ENDL;
+ }
+ }
+ }
LL_WARNS("Inventory") << "Inventory error: " << status.toString() << LL_ENDL;
LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL;
}
- gInventory.onAISUpdateReceived("AISCommand", result);
+ LL_DEBUGS("Inventory", "AIS3") << "Result: " << result << LL_ENDL;
+ onUpdateReceived(result, type, body);
if (callback && !callback.empty())
- {
+ {
+ bool needs_callback = true;
LLUUID id(LLUUID::null);
- if (result.has("category_id") && (type == COPYLIBRARYCATEGORY))
- {
- id = result["category_id"];
- }
+ switch (type)
+ {
+ case COPYLIBRARYCATEGORY:
+ case FETCHCATEGORYCATEGORIES:
+ case FETCHCATEGORYCHILDREN:
+ case FETCHCATEGORYSUBSET:
+ case FETCHCATEGORYLINKS:
+ case FETCHCOF:
+ if (result.has("category_id"))
+ {
+ id = result["category_id"];
+ }
+ break;
+ case FETCHITEM:
+ if (result.has("item_id"))
+ {
+ // Error message might contain an item_id!!!
+ id = result["item_id"];
+ }
+ if (result.has("linked_id"))
+ {
+ id = result["linked_id"];
+ }
+ break;
+ case CREATEINVENTORY:
+ // CREATEINVENTORY can have multiple callbacks
+ if (result.has("_created_categories"))
+ {
+ LLSD& cats = result["_created_categories"];
+ LLSD::array_const_iterator cat_iter;
+ for (cat_iter = cats.beginArray(); cat_iter != cats.endArray(); ++cat_iter)
+ {
+ LLUUID cat_id = *cat_iter;
+ callback(cat_id);
+ needs_callback = false;
+ }
+ }
+ if (result.has("_created_items"))
+ {
+ LLSD& items = result["_created_items"];
+ LLSD::array_const_iterator item_iter;
+ for (item_iter = items.beginArray(); item_iter != items.endArray(); ++item_iter)
+ {
+ LLUUID item_id = *item_iter;
+ callback(item_id);
+ needs_callback = false;
+ }
+ }
+ break;
+ default:
+ break;
+ }
- callback(id);
+ if (needs_callback)
+ {
+ // Call callback at least once regardless of failure.
+ // UPDATEITEM doesn't expect an id
+ callback(id);
+ }
}
}
//-------------------------------------------------------------------------
-AISUpdate::AISUpdate(const LLSD& update)
+AISUpdate::AISUpdate(const LLSD& update, AISAPI::COMMAND_TYPE type, const LLSD& request_body)
+: mType(type)
{
+ mFetch = (type == AISAPI::FETCHITEM)
+ || (type == AISAPI::FETCHCATEGORYCHILDREN)
+ || (type == AISAPI::FETCHCATEGORYCATEGORIES)
+ || (type == AISAPI::FETCHCATEGORYSUBSET)
+ || (type == AISAPI::FETCHCOF)
+ || (type == AISAPI::FETCHCATEGORYLINKS)
+ || (type == AISAPI::FETCHORPHANS);
+ // parse update llsd into stuff to do or parse received items.
+ mFetchDepth = MAX_FOLDER_DEPTH_REQUEST;
+ if (mFetch && request_body.has("depth"))
+ {
+ mFetchDepth = request_body["depth"].asInteger();
+ }
+
+ mTimer.setTimerExpirySec(AIS_EXPIRY_SECONDS);
+ mTimer.start();
parseUpdate(update);
}
@@ -506,6 +1047,7 @@ void AISUpdate::clearParseResults()
mCatDescendentsKnown.clear();
mCatVersionsUpdated.clear();
mItemsCreated.clear();
+ mItemsLost.clear();
mItemsUpdated.clear();
mCategoriesCreated.clear();
mCategoriesUpdated.clear();
@@ -514,6 +1056,16 @@ void AISUpdate::clearParseResults()
mCategoryIds.clear();
}
+void AISUpdate::checkTimeout()
+{
+ if (mTimer.hasExpired())
+ {
+ llcoro::suspend();
+ LLCoros::checkStop();
+ mTimer.setTimerExpirySec(AIS_EXPIRY_SECONDS);
+ }
+}
+
void AISUpdate::parseUpdate(const LLSD& update)
{
clearParseResults();
@@ -601,24 +1153,37 @@ void AISUpdate::parseMeta(const LLSD& update)
void AISUpdate::parseContent(const LLSD& update)
{
- if (update.has("linked_id"))
+ // Errors from a fetch request might contain id without
+ // full item or folder.
+ // Todo: Depending on error we might want to do something,
+ // like removing a 404 item or refetching parent folder
+ if (update.has("linked_id") && update.has("parent_id"))
{
- parseLink(update);
+ parseLink(update, mFetchDepth);
}
- else if (update.has("item_id"))
+ else if (update.has("item_id") && update.has("parent_id"))
{
parseItem(update);
}
- if (update.has("category_id"))
- {
- parseCategory(update);
- }
+ if (mType == AISAPI::FETCHCATEGORYSUBSET)
+ {
+ // initial category is incomplete, don't process it,
+ // go for content instead
+ if (update.has("_embedded"))
+ {
+ parseEmbedded(update["_embedded"], mFetchDepth - 1);
+ }
+ }
+ else if (update.has("category_id") && update.has("parent_id"))
+ {
+ parseCategory(update, mFetchDepth);
+ }
else
{
if (update.has("_embedded"))
{
- parseEmbedded(update["_embedded"]);
+ parseEmbedded(update["_embedded"], mFetchDepth);
}
}
}
@@ -636,7 +1201,17 @@ void AISUpdate::parseItem(const LLSD& item_map)
BOOL rv = new_item->unpackMessage(item_map);
if (rv)
{
- if (curr_item)
+ if (mFetch)
+ {
+ mItemsCreated[item_id] = new_item;
+ new_item->setComplete(true);
+
+ if (new_item->getParentUUID().isNull())
+ {
+ mItemsLost[item_id] = new_item;
+ }
+ }
+ else if (curr_item)
{
mItemsUpdated[item_id] = new_item;
// This statement is here to cause a new entry with 0
@@ -648,6 +1223,7 @@ void AISUpdate::parseItem(const LLSD& item_map)
{
mItemsCreated[item_id] = new_item;
mCatDescendentDeltas[new_item->getParentUUID()]++;
+ new_item->setComplete(true);
}
}
else
@@ -657,7 +1233,7 @@ void AISUpdate::parseItem(const LLSD& item_map)
}
}
-void AISUpdate::parseLink(const LLSD& link_map)
+void AISUpdate::parseLink(const LLSD& link_map, S32 depth)
{
LLUUID item_id = link_map["item_id"].asUUID();
LLPointer new_link(new LLViewerInventoryItem);
@@ -671,7 +1247,24 @@ void AISUpdate::parseLink(const LLSD& link_map)
if (rv)
{
const LLUUID& parent_id = new_link->getParentUUID();
- if (curr_link)
+ if (mFetch)
+ {
+ LLPermissions default_perms;
+ default_perms.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
+ default_perms.initMasks(PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE);
+ new_link->setPermissions(default_perms);
+ LLSaleInfo default_sale_info;
+ new_link->setSaleInfo(default_sale_info);
+ //LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL;
+ mItemsCreated[item_id] = new_link;
+ new_link->setComplete(true);
+
+ if (new_link->getParentUUID().isNull())
+ {
+ mItemsLost[item_id] = new_link;
+ }
+ }
+ else if (curr_link)
{
mItemsUpdated[item_id] = new_link;
// This statement is here to cause a new entry with 0
@@ -690,7 +1283,13 @@ void AISUpdate::parseLink(const LLSD& link_map)
//LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL;
mItemsCreated[item_id] = new_link;
mCatDescendentDeltas[parent_id]++;
+ new_link->setComplete(true);
}
+
+ if (link_map.has("_embedded"))
+ {
+ parseEmbedded(link_map["_embedded"], depth);
+ }
}
else
{
@@ -700,19 +1299,30 @@ void AISUpdate::parseLink(const LLSD& link_map)
}
-void AISUpdate::parseCategory(const LLSD& category_map)
+void AISUpdate::parseCategory(const LLSD& category_map, S32 depth)
{
- LLUUID category_id = category_map["category_id"].asUUID();
+ LLUUID category_id = category_map["category_id"].asUUID();
+ S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN;
- // Check descendent count first, as it may be needed
- // to populate newly created categories
- if (category_map.has("_embedded"))
- {
- parseDescendentCount(category_id, category_map["_embedded"]);
- }
+ if (category_map.has("version"))
+ {
+ version = category_map["version"].asInteger();
+ }
+
+ LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id);
+
+ if (curr_cat
+ && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN
+ && curr_cat->getDescendentCount() != LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN
+ && version > LLViewerInventoryCategory::VERSION_UNKNOWN
+ && version < curr_cat->getVersion())
+ {
+ LL_WARNS() << "Got stale folder, known: " << curr_cat->getVersion()
+ << ", received: " << version << LL_ENDL;
+ return;
+ }
LLPointer new_cat;
- LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id);
if (curr_cat)
{
// Default to current values where not provided.
@@ -732,13 +1342,58 @@ void AISUpdate::parseCategory(const LLSD& category_map)
}
BOOL rv = new_cat->unpackMessage(category_map);
// *NOTE: unpackMessage does not unpack version or descendent count.
- //if (category_map.has("version"))
- //{
- // mCatVersionsUpdated[category_id] = category_map["version"].asInteger();
- //}
if (rv)
{
- if (curr_cat)
+ // Check descendent count first, as it may be needed
+ // to populate newly created categories
+ if (category_map.has("_embedded"))
+ {
+ parseDescendentCount(category_id, new_cat->getPreferredType(), category_map["_embedded"]);
+ }
+
+ if (mFetch)
+ {
+ uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id);
+ if (mCatDescendentsKnown.end() != lookup_it)
+ {
+ S32 descendent_count = lookup_it->second;
+ LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count
+ << " for category " << category_id << LL_ENDL;
+ new_cat->setDescendentCount(descendent_count);
+
+ // set version only if we are sure this update has full data and embeded items
+ // since viewer uses version to decide if folder and content still need fetching
+ if (version > LLViewerInventoryCategory::VERSION_UNKNOWN
+ && depth >= 0)
+ {
+ if (curr_cat && curr_cat->getVersion() > version)
+ {
+ LL_WARNS("Inventory") << "Version was " << curr_cat->getVersion()
+ << ", but fetch returned version " << version
+ << " for category " << category_id << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("Inventory") << "Setting version to " << version
+ << " for category " << category_id << LL_ENDL;
+ }
+
+ new_cat->setVersion(version);
+ }
+ }
+ else if (curr_cat
+ && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN
+ && version > curr_cat->getVersion())
+ {
+ // Potentially should new_cat->setVersion(unknown) here,
+ // but might be waiting for a callback that would increment
+ LL_DEBUGS("Inventory") << "Category " << category_id
+ << " is stale. Known version: " << curr_cat->getVersion()
+ << " server version: " << version << LL_ENDL;
+ }
+ mCategoriesCreated[category_id] = new_cat;
+ }
+ else if (curr_cat)
{
mCategoriesUpdated[category_id] = new_cat;
// This statement is here to cause a new entry with 0
@@ -751,20 +1406,22 @@ void AISUpdate::parseCategory(const LLSD& category_map)
else
{
// Set version/descendents for newly created categories.
- if (category_map.has("version"))
- {
- S32 version = category_map["version"].asInteger();
- LL_DEBUGS("Inventory") << "Setting version to " << version
- << " for new category " << category_id << LL_ENDL;
- new_cat->setVersion(version);
- }
- uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id);
- if (mCatDescendentsKnown.end() != lookup_it)
- {
- S32 descendent_count = lookup_it->second;
- LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count
- << " for new category " << category_id << LL_ENDL;
- new_cat->setDescendentCount(descendent_count);
+ uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id);
+ if (mCatDescendentsKnown.end() != lookup_it)
+ {
+ S32 descendent_count = lookup_it->second;
+ LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count
+ << " for new category " << category_id << LL_ENDL;
+ new_cat->setDescendentCount(descendent_count);
+
+ // Don't set version unles correct children count is present
+ if (category_map.has("version"))
+ {
+ S32 version = category_map["version"].asInteger();
+ LL_DEBUGS("Inventory") << "Setting version to " << version
+ << " for new category " << category_id << LL_ENDL;
+ new_cat->setVersion(version);
+ }
}
mCategoriesCreated[category_id] = new_cat;
mCatDescendentDeltas[new_cat->getParentUUID()]++;
@@ -779,28 +1436,35 @@ void AISUpdate::parseCategory(const LLSD& category_map)
// Check for more embedded content.
if (category_map.has("_embedded"))
{
- parseEmbedded(category_map["_embedded"]);
+ parseEmbedded(category_map["_embedded"], depth - 1);
}
}
-void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embedded)
+void AISUpdate::parseDescendentCount(const LLUUID& category_id, LLFolderType::EType type, const LLSD& embedded)
{
- // We can only determine true descendent count if this contains all descendent types.
- if (embedded.has("categories") &&
- embedded.has("links") &&
- embedded.has("items"))
- {
- mCatDescendentsKnown[category_id] = embedded["categories"].size();
- mCatDescendentsKnown[category_id] += embedded["links"].size();
- mCatDescendentsKnown[category_id] += embedded["items"].size();
- }
+ // We can only determine true descendent count if this contains all descendent types.
+ if (embedded.has("categories") &&
+ embedded.has("links") &&
+ embedded.has("items"))
+ {
+ mCatDescendentsKnown[category_id] = embedded["categories"].size();
+ mCatDescendentsKnown[category_id] += embedded["links"].size();
+ mCatDescendentsKnown[category_id] += embedded["items"].size();
+ }
+ else if (mFetch && embedded.has("links") && (type == LLFolderType::FT_CURRENT_OUTFIT || type == LLFolderType::FT_OUTFIT))
+ {
+ // COF and outfits contain links only
+ mCatDescendentsKnown[category_id] = embedded["links"].size();
+ }
}
-void AISUpdate::parseEmbedded(const LLSD& embedded)
+void AISUpdate::parseEmbedded(const LLSD& embedded, S32 depth)
{
+ checkTimeout();
+
if (embedded.has("links")) // _embedded in a category
{
- parseEmbeddedLinks(embedded["links"]);
+ parseEmbeddedLinks(embedded["links"], depth);
}
if (embedded.has("items")) // _embedded in a category
{
@@ -812,11 +1476,11 @@ void AISUpdate::parseEmbedded(const LLSD& embedded)
}
if (embedded.has("categories")) // _embedded in a category
{
- parseEmbeddedCategories(embedded["categories"]);
+ parseEmbeddedCategories(embedded["categories"], depth);
}
if (embedded.has("category")) // _embedded in a link
{
- parseEmbeddedCategory(embedded["category"]);
+ parseEmbeddedCategory(embedded["category"], depth);
}
}
@@ -833,7 +1497,7 @@ void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uui
}
}
-void AISUpdate::parseEmbeddedLinks(const LLSD& links)
+void AISUpdate::parseEmbeddedLinks(const LLSD& links, S32 depth)
{
for(LLSD::map_const_iterator linkit = links.beginMap(),
linkend = links.endMap();
@@ -841,13 +1505,13 @@ void AISUpdate::parseEmbeddedLinks(const LLSD& links)
{
const LLUUID link_id((*linkit).first);
const LLSD& link_map = (*linkit).second;
- if (mItemIds.end() == mItemIds.find(link_id))
+ if (!mFetch && mItemIds.end() == mItemIds.find(link_id))
{
LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL;
}
else
{
- parseLink(link_map);
+ parseLink(link_map, depth);
}
}
}
@@ -857,7 +1521,7 @@ void AISUpdate::parseEmbeddedItem(const LLSD& item)
// a single item (_embedded in a link)
if (item.has("item_id"))
{
- if (mItemIds.end() != mItemIds.find(item["item_id"].asUUID()))
+ if (mFetch || mItemIds.end() != mItemIds.find(item["item_id"].asUUID()))
{
parseItem(item);
}
@@ -873,7 +1537,7 @@ void AISUpdate::parseEmbeddedItems(const LLSD& items)
{
const LLUUID item_id((*itemit).first);
const LLSD& item_map = (*itemit).second;
- if (mItemIds.end() == mItemIds.find(item_id))
+ if (!mFetch && mItemIds.end() == mItemIds.find(item_id))
{
LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL;
}
@@ -884,19 +1548,19 @@ void AISUpdate::parseEmbeddedItems(const LLSD& items)
}
}
-void AISUpdate::parseEmbeddedCategory(const LLSD& category)
+void AISUpdate::parseEmbeddedCategory(const LLSD& category, S32 depth)
{
// a single category (_embedded in a link)
if (category.has("category_id"))
{
- if (mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID()))
+ if (mFetch || mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID()))
{
- parseCategory(category);
+ parseCategory(category, depth);
}
}
}
-void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
+void AISUpdate::parseEmbeddedCategories(const LLSD& categories, S32 depth)
{
// a map of categories (_embedded in a category)
for(LLSD::map_const_iterator categoryit = categories.beginMap(),
@@ -905,19 +1569,21 @@ void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
{
const LLUUID category_id((*categoryit).first);
const LLSD& category_map = (*categoryit).second;
- if (mCategoryIds.end() == mCategoryIds.find(category_id))
+ if (!mFetch && mCategoryIds.end() == mCategoryIds.find(category_id))
{
LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL;
}
else
{
- parseCategory(category_map);
+ parseCategory(category_map, depth);
}
}
}
void AISUpdate::doUpdate()
{
+ checkTimeout();
+
// Do version/descendant accounting.
for (std::map::const_iterator catit = mCatDescendentDeltas.begin();
catit != mCatDescendentDeltas.end(); ++catit)
@@ -959,6 +1625,7 @@ void AISUpdate::doUpdate()
}
// CREATE CATEGORIES
+ const S32 MAX_UPDATE_BACKLOG = 50; // stall prevention
for (deferred_category_map_t::const_iterator create_it = mCategoriesCreated.begin();
create_it != mCategoriesCreated.end(); ++create_it)
{
@@ -967,6 +1634,13 @@ void AISUpdate::doUpdate()
gInventory.updateCategory(new_category, LLInventoryObserver::CREATE);
LL_DEBUGS("Inventory") << "created category " << category_id << LL_ENDL;
+
+ // fetching can receive massive amount of items and folders
+ if (gInventory.getChangedIDs().size() > MAX_UPDATE_BACKLOG)
+ {
+ gInventory.notifyObservers();
+ checkTimeout();
+ }
}
// UPDATE CATEGORIES
@@ -991,6 +1665,24 @@ void AISUpdate::doUpdate()
}
}
+ // LOST ITEMS
+ if (!mItemsLost.empty())
+ {
+ LL_INFOS("Inventory") << "Received " << (S32)mItemsLost.size() << " items without a parent" << LL_ENDL;
+ const LLUUID lost_uuid(gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND));
+ if (lost_uuid.notNull())
+ {
+ for (deferred_item_map_t::const_iterator lost_it = mItemsLost.begin();
+ lost_it != mItemsLost.end(); ++lost_it)
+ {
+ LLPointer new_item = lost_it->second;
+
+ new_item->setParent(lost_uuid);
+ new_item->updateParentOnServer(FALSE);
+ }
+ }
+ }
+
// CREATE ITEMS
for (deferred_item_map_t::const_iterator create_it = mItemsCreated.begin();
create_it != mItemsCreated.end(); ++create_it)
@@ -1003,6 +1695,13 @@ void AISUpdate::doUpdate()
// case this is create.
LL_DEBUGS("Inventory") << "created item " << item_id << LL_ENDL;
gInventory.updateItem(new_item, LLInventoryObserver::CREATE);
+
+ // fetching can receive massive amount of items and folders
+ if (gInventory.getChangedIDs().size() > MAX_UPDATE_BACKLOG)
+ {
+ gInventory.notifyObservers();
+ checkTimeout();
+ }
}
// UPDATE ITEMS
@@ -1063,6 +1762,8 @@ void AISUpdate::doUpdate()
}
}
+ checkTimeout();
+
gInventory.notifyObservers();
}
diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h
index 856f3fc180..f254f21e42 100644
--- a/indra/newview/llaisapi.h
+++ b/indra/newview/llaisapi.h
@@ -38,6 +38,12 @@
class AISAPI
{
public:
+ static const S32 HTTP_TIMEOUT;
+ typedef enum {
+ INVENTORY,
+ LIBRARY
+ } ITEM_TYPE;
+
typedef boost::function completion_t;
static bool isAvailable();
@@ -50,9 +56,16 @@ public:
static void PurgeDescendents(const LLUUID &categoryId, completion_t callback = completion_t());
static void UpdateCategory(const LLUUID &categoryId, const LLSD &updates, completion_t callback = completion_t());
static void UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t callback = completion_t());
+ static void FetchItem(const LLUUID &itemId, ITEM_TYPE type, completion_t callback = completion_t());
+ static void FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
+ static void FetchCategoryChildren(const std::string &identifier, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
+ static void FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
+ static void FetchCategorySubset(const LLUUID& catId, const uuid_vec_t specificChildren, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
+ static void FetchCOF(completion_t callback = completion_t());
+ static void FetchCategoryLinks(const LLUUID &catId, completion_t callback = completion_t());
+ static void FetchOrphans(completion_t callback = completion_t() );
static void CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback = completion_t());
-private:
typedef enum {
COPYINVENTORY,
SLAMFOLDER,
@@ -61,9 +74,18 @@ private:
PURGEDESCENDENTS,
UPDATECATEGORY,
UPDATEITEM,
- COPYLIBRARYCATEGORY
+ COPYLIBRARYCATEGORY,
+ CREATEINVENTORY,
+ FETCHITEM,
+ FETCHCATEGORYCHILDREN,
+ FETCHCATEGORYCATEGORIES,
+ FETCHCATEGORYSUBSET,
+ FETCHCOF,
+ FETCHORPHANS,
+ FETCHCATEGORYLINKS
} COMMAND_TYPE;
+private:
static const std::string INVENTORY_CAP_NAME;
static const std::string LIBRARY_CAP_NAME;
@@ -72,6 +94,7 @@ private:
static void EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc);
static void onIdle(void *userdata); // launches postponed AIS commands
+ static void onUpdateReceived(const LLSD& update, COMMAND_TYPE type, const LLSD& request_body);
static std::string getInvCap();
static std::string getLibCap();
@@ -87,24 +110,29 @@ private:
class AISUpdate
{
public:
- AISUpdate(const LLSD& update);
+ AISUpdate(const LLSD& update, AISAPI::COMMAND_TYPE type, const LLSD& request_body);
void parseUpdate(const LLSD& update);
void parseMeta(const LLSD& update);
void parseContent(const LLSD& update);
void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
- void parseLink(const LLSD& link_map);
+ void parseLink(const LLSD& link_map, S32 depth);
void parseItem(const LLSD& link_map);
- void parseCategory(const LLSD& link_map);
- void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded);
- void parseEmbedded(const LLSD& embedded);
- void parseEmbeddedLinks(const LLSD& links);
+ void parseCategory(const LLSD& link_map, S32 depth);
+ void parseDescendentCount(const LLUUID& category_id, LLFolderType::EType type, const LLSD& embedded);
+ void parseEmbedded(const LLSD& embedded, S32 depth);
+ void parseEmbeddedLinks(const LLSD& links, S32 depth);
void parseEmbeddedItems(const LLSD& items);
- void parseEmbeddedCategories(const LLSD& categories);
+ void parseEmbeddedCategories(const LLSD& categories, S32 depth);
void parseEmbeddedItem(const LLSD& item);
- void parseEmbeddedCategory(const LLSD& category);
+ void parseEmbeddedCategory(const LLSD& category, S32 depth);
void doUpdate();
private:
void clearParseResults();
+ void checkTimeout();
+
+ // Fetch can return large packets of data, throttle it to not cause lags
+ // Todo: make throttle work over all fetch requests isntead of per-request
+ const F32 AIS_EXPIRY_SECONDS = 0.008f;
typedef std::map uuid_int_map_t;
uuid_int_map_t mCatDescendentDeltas;
@@ -113,6 +141,7 @@ private:
typedef std::map > deferred_item_map_t;
deferred_item_map_t mItemsCreated;
+ deferred_item_map_t mItemsLost;
deferred_item_map_t mItemsUpdated;
typedef std::map > deferred_category_map_t;
deferred_category_map_t mCategoriesCreated;
@@ -123,6 +152,10 @@ private:
uuid_list_t mObjectsDeletedIds;
uuid_list_t mItemIds;
uuid_list_t mCategoryIds;
+ bool mFetch;
+ S32 mFetchDepth;
+ LLTimer mTimer;
+ AISAPI::COMMAND_TYPE mType;
};
#endif
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index d0fad07f1c..8010b84c20 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -40,6 +40,7 @@
#include "llgesturemgr.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
+#include "llinventorymodelbackgroundfetch.h"
#include "llinventoryobserver.h"
#include "llmd5.h"
#include "llnotificationsutil.h"
@@ -590,6 +591,71 @@ LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOn
}
}
+class LLBrokenLinkObserver : public LLInventoryObserver
+{
+public:
+ LLUUID mUUID;
+ bool mEnforceItemRestrictions;
+ bool mEnforceOrdering;
+ nullary_func_t mPostUpdateFunc;
+
+ LLBrokenLinkObserver(const LLUUID& uuid,
+ bool enforce_item_restrictions ,
+ bool enforce_ordering ,
+ nullary_func_t post_update_func) :
+ mUUID(uuid),
+ mEnforceItemRestrictions(enforce_item_restrictions),
+ mEnforceOrdering(enforce_ordering),
+ mPostUpdateFunc(post_update_func)
+ {
+ }
+ /* virtual */ void changed(U32 mask);
+ void postProcess();
+};
+
+void LLBrokenLinkObserver::changed(U32 mask)
+{
+ if (mask & LLInventoryObserver::REBUILD)
+ {
+ // This observer should be executed after LLInventoryPanel::itemChanged(),
+ // but if it isn't, consider calling updateAppearanceFromCOF with a delay
+ const uuid_set_t& changed_item_ids = gInventory.getChangedIDs();
+ for (uuid_set_t::const_iterator it = changed_item_ids.begin(); it != changed_item_ids.end(); ++it)
+ {
+ const LLUUID& id = *it;
+ if (id == mUUID)
+ {
+ // Might not be processed yet and it is not a
+ // good idea to update appearane here, postpone.
+ doOnIdleOneTime([this]()
+ {
+ postProcess();
+ });
+
+ gInventory.removeObserver(this);
+ return;
+ }
+ }
+ }
+}
+
+void LLBrokenLinkObserver::postProcess()
+{
+ LLViewerInventoryItem* item = gInventory.getItem(mUUID);
+ llassert(item && !item->getIsBrokenLink()); // the whole point was to get a correct link
+ if (item && item->getIsBrokenLink())
+ {
+ LL_INFOS_ONCE("Avatar") << "Outfit link broken despite being regenerated" << LL_ENDL;
+ LL_DEBUGS("Avatar", "Inventory") << "Outfit link " << mUUID << " \"" << item->getName() << "\" is broken despite being regenerated" << LL_ENDL;
+ }
+
+ LLAppearanceMgr::instance().updateAppearanceFromCOF(
+ mEnforceItemRestrictions ,
+ mEnforceOrdering ,
+ mPostUpdateFunc);
+ delete this;
+}
+
struct LLFoundData
{
@@ -1706,12 +1772,18 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds
{
parent_id = gInventory.getRootFolderID();
}
- LLUUID subfolder_id = gInventory.createNewCategory( parent_id,
- LLFolderType::FT_NONE,
- src_cat->getName());
- shallowCopyCategoryContents(src_id, subfolder_id, cb);
+ gInventory.createNewCategory(
+ parent_id,
+ LLFolderType::FT_NONE,
+ src_cat->getName(),
+ [src_id, cb](const LLUUID &new_id)
+ {
+ LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_id, new_id, cb);
- gInventory.notifyObservers();
+ gInventory.notifyObservers();
+ },
+ src_cat->getThumbnailUUID()
+ );
}
void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id,
@@ -2414,6 +2486,39 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL;
+ if (gInventory.hasPosiblyBrockenLinks())
+ {
+ // Inventory has either broken links or links that
+ // haven't loaded yet.
+ // Check if LLAppearanceMgr needs to wait.
+ LLUUID current_outfit_id = getCOF();
+ LLInventoryModel::item_array_t cof_items;
+ LLInventoryModel::cat_array_t cof_cats;
+ LLFindBrokenLinks is_brocken_link;
+ gInventory.collectDescendentsIf(current_outfit_id,
+ cof_cats,
+ cof_items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_brocken_link);
+
+ if (cof_items.size() > 0)
+ {
+ // Some links haven't loaded yet, but fetch isn't complete so
+ // links are likely fine and we will have to wait for them to
+ // load
+ if (LLInventoryModelBackgroundFetch::getInstance()->folderFetchActive())
+ {
+
+ LLBrokenLinkObserver* observer = new LLBrokenLinkObserver(cof_items.front()->getUUID(),
+ enforce_item_restrictions,
+ enforce_ordering,
+ post_update_func);
+ gInventory.addObserver(observer);
+ return;
+ }
+ }
+ }
+
if (enforce_item_restrictions)
{
// The point here is just to call
@@ -2730,22 +2835,29 @@ void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool ap
{
pid = gInventory.getRootFolderID();
}
-
- LLUUID new_cat_id = gInventory.createNewCategory(
+
+ gInventory.createNewCategory(
pid,
LLFolderType::FT_NONE,
- name);
+ name,
+ [cat_id, append](const LLUUID& new_cat_id)
+ {
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(cat_id, cats, items);
+ // Create a CopyMgr that will copy items, manage its own destruction
+ new LLCallAfterInventoryCopyMgr(
+ *items, new_cat_id, std::string("wear_inventory_category_callback"),
+ boost::bind(&LLAppearanceMgr::wearInventoryCategoryOnAvatar,
+ LLAppearanceMgr::getInstance(),
+ gInventory.getCategory(new_cat_id),
+ append));
- // Create a CopyMgr that will copy items, manage its own destruction
- new LLCallAfterInventoryCopyMgr(
- *items, new_cat_id, std::string("wear_inventory_category_callback"),
- boost::bind(&LLAppearanceMgr::wearInventoryCategoryOnAvatar,
- LLAppearanceMgr::getInstance(),
- gInventory.getCategory(new_cat_id),
- append));
-
- // BAP fixes a lag in display of created dir.
- gInventory.notifyObservers();
+ // BAP fixes a lag in display of created dir.
+ gInventory.notifyObservers();
+ },
+ cat->getThumbnailUUID()
+ );
}
else
{
@@ -3203,7 +3315,7 @@ void LLAppearanceMgr::copyLibraryGestures()
// Copy gestures
LLUUID lib_gesture_cat_id =
- gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE,false);
+ gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE);
if (lib_gesture_cat_id.isNull())
{
LL_WARNS() << "Unable to copy gestures, source category not found" << LL_ENDL;
@@ -3714,7 +3826,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd
if (cofVersion == LLViewerInventoryCategory::VERSION_UNKNOWN)
{
- LL_WARNS("AVatar") << "COF version is unknown... not requesting until COF version is known." << LL_ENDL;
+ LL_INFOS("AVatar") << "COF version is unknown... not requesting until COF version is known." << LL_ENDL;
return;
}
else
@@ -3986,26 +4098,15 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo
// First, make a folder in the My Outfits directory.
const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
- if (AISAPI::isAvailable())
- {
- // cap-based category creation was buggy until recently. use
- // existence of AIS as an indicator the fix is present. Does
- // not actually use AIS to create the category.
- inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel);
- gInventory.createNewCategory(
- parent_id,
- LLFolderType::FT_OUTFIT,
- new_folder_name,
- func);
- }
- else
- {
- LLUUID folder_id = gInventory.createNewCategory(
- parent_id,
- LLFolderType::FT_OUTFIT,
- new_folder_name);
- onOutfitFolderCreated(folder_id, show_panel);
- }
+
+ gInventory.createNewCategory(
+ parent_id,
+ LLFolderType::FT_OUTFIT,
+ new_folder_name,
+ [show_panel](const LLUUID &new_cat_id)
+ {
+ LLAppearanceMgr::getInstance()->onOutfitFolderCreated(new_cat_id, show_panel);
+ });
}
void LLAppearanceMgr::wearBaseOutfit()
@@ -4338,6 +4439,73 @@ public:
~CallAfterCategoryFetchStage1()
{
}
+ /*virtual*/ void startFetch()
+ {
+ bool ais3 = AISAPI::isAvailable();
+ for (uuid_vec_t::const_iterator it = mIDs.begin(); it != mIDs.end(); ++it)
+ {
+ LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
+ if (!cat) continue;
+ if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
+ {
+ // CHECK IT: isCategoryComplete() checks both version and descendant count but
+ // fetch() only works for Unknown version and doesn't care about descentants,
+ // as result fetch won't start and folder will potentially get stuck as
+ // incomplete in observer.
+ // Likely either both should use only version or both should check descendants.
+ cat->fetch(); //blindly fetch it without seeing if anything else is fetching it.
+ mIncomplete.push_back(*it); //Add to list of things being downloaded for this observer.
+ }
+ else if (!isCategoryComplete(cat))
+ {
+ LL_DEBUGS("Inventory") << "Categoty " << *it << " incomplete despite having version" << LL_ENDL;
+ LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch(*it, true);
+ mIncomplete.push_back(*it);
+ }
+ else if (ais3)
+ {
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items);
+
+ if (items)
+ {
+ S32 complete_count = 0;
+ S32 incomplete_count = 0;
+ for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); it < items->end(); ++it)
+ {
+ if (!(*it)->isFinished())
+ {
+ incomplete_count++;
+ }
+ else
+ {
+ complete_count++;
+ }
+ }
+ // AIS can fetch couple items, but if there
+ // is more than a dozen it will be very slow
+ // it's faster to get whole folder in such case
+ if (incomplete_count > LLInventoryFetchItemsObserver::MAX_INDIVIDUAL_ITEM_REQUESTS
+ || (incomplete_count > 1 && complete_count == 0))
+ {
+ LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch(*it, true);
+ mIncomplete.push_back(*it);
+ }
+ else
+ {
+ // let stage2 handle incomplete ones
+ mComplete.push_back(*it);
+ }
+ }
+ // else should have been handled by isCategoryComplete
+ }
+ else
+ {
+ mComplete.push_back(*it);
+ }
+ }
+ }
virtual void done()
{
if (mComplete.size() <= 0)
@@ -4354,13 +4522,11 @@ public:
// What we do here is get the complete information on the
// items in the requested category, and set up an observer
// that will wait for that to happen.
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t item_array;
- gInventory.collectDescendents(mComplete.front(),
- cat_array,
- item_array,
- LLInventoryModel::EXCLUDE_TRASH);
- S32 count = item_array.size();
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(mComplete.front(), cats, items);
+
+ S32 count = items->size();
if(!count)
{
LL_WARNS() << "Nothing fetched in category " << mComplete.front()
@@ -4372,11 +4538,13 @@ public:
return;
}
- LL_INFOS() << "stage1 got " << item_array.size() << " items, passing to stage2 " << LL_ENDL;
+ LLViewerInventoryCategory* cat = gInventory.getCategory(mComplete.front());
+ S32 version = cat ? cat->getVersion() : -2;
+ LL_INFOS() << "stage1, category " << mComplete.front() << " got " << count << " items, version " << version << " passing to stage2 " << LL_ENDL;
uuid_vec_t ids;
for(S32 i = 0; i < count; ++i)
{
- ids.push_back(item_array.at(i)->getUUID());
+ ids.push_back(items->at(i)->getUUID());
}
gInventory.removeObserver(this);
@@ -4401,18 +4569,78 @@ protected:
nullary_func_t mCallable;
};
+void callAfterCOFFetch(nullary_func_t cb)
+{
+ LLUUID cat_id = LLAppearanceMgr::instance().getCOF();
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+
+ if (AISAPI::isAvailable())
+ {
+ // Mark cof (update timer) so that background fetch won't request it
+ cat->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE);
+ // For reliability assume that we have no relevant cache, so
+ // fetch cof along with items cof's links point to.
+ AISAPI::FetchCOF([cb](const LLUUID& id)
+ {
+ cb();
+ LLUUID cat_id = LLAppearanceMgr::instance().getCOF();
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ if (cat)
+ {
+ cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+ }
+ });
+ }
+ else
+ {
+ LL_INFOS() << "AIS API v3 not available, using callAfterCategoryFetch" << LL_ENDL;
+ // startup should have marked folder as fetching, remove that
+ cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+ callAfterCategoryFetch(cat_id, cb);
+ }
+}
+
void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb)
{
- CallAfterCategoryFetchStage1 *stage1 = new CallAfterCategoryFetchStage1(cat_id, cb);
- stage1->startFetch();
- if (stage1->isFinished())
- {
- stage1->done();
- }
- else
- {
- gInventory.addObserver(stage1);
- }
+ CallAfterCategoryFetchStage1* stage1 = new CallAfterCategoryFetchStage1(cat_id, cb);
+ stage1->startFetch();
+ if (stage1->isFinished())
+ {
+ stage1->done();
+ }
+ else
+ {
+ gInventory.addObserver(stage1);
+ }
+}
+
+void callAfterCategoryLinksFetch(const LLUUID &cat_id, nullary_func_t cb)
+{
+ LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
+ if (AISAPI::isAvailable())
+ {
+ // Mark folder (update timer) so that background fetch won't request it
+ cat->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE);
+ // Assume that we have no relevant cache. Fetch folder, and items folder's links point to.
+ AISAPI::FetchCategoryLinks(cat_id,
+ [cb, cat_id](const LLUUID &id)
+ {
+ cb();
+ LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
+ if (cat)
+ {
+ cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+ }
+ });
+ }
+ else
+ {
+ LL_WARNS() << "AIS API v3 not available, can't use AISAPI::FetchCOF" << LL_ENDL;
+ // startup should have marked folder as fetching, remove that
+ cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+ callAfterCategoryFetch(cat_id, cb);
+ }
+
}
void add_wearable_type_counts(const uuid_vec_t& ids,
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index cf953d21ac..43839e47a6 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -338,7 +338,9 @@ public:
LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name);
// Invoke a given callable after category contents are fully fetched.
+void callAfterCOFFetch(nullary_func_t cb);
void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb);
+void callAfterCategoryLinksFetch(const LLUUID &cat_id, nullary_func_t cb);
// Wear all items in a uuid vector.
void wear_multiple(const uuid_vec_t& ids, bool replace);
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 0bece6367e..fbf52ad2d8 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -215,7 +215,7 @@
#include "llcommandlineparser.h"
#include "llfloatermemleak.h"
#include "llfloaterreg.h"
-#include "llfloatersimpleoutfitsnapshot.h"
+#include "llfloatersimplesnapshot.h"
#include "llfloatersnapshot.h"
#include "llsidepanelinventory.h"
#include "llatmosphere.h"
@@ -1520,7 +1520,7 @@ bool LLAppViewer::doFrame()
gPipeline.mReflectionMapManager.update();
gPipeline.mHeroProbeManager.update();
LLFloaterSnapshot::update(); // take snapshots
- LLFloaterSimpleOutfitSnapshot::update();
+ LLFloaterSimpleSnapshot::update();
gGLActive = FALSE;
}
diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp
index 1feefc3ef8..d3fce306bc 100644
--- a/indra/newview/llattachmentsmgr.cpp
+++ b/indra/newview/llattachmentsmgr.cpp
@@ -240,6 +240,13 @@ void LLAttachmentsMgr::linkRecentlyArrivedAttachments()
return;
}
+ if (LLAppearanceMgr::instance().getCOFVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
+ {
+ // Wait for cof to load
+ LL_DEBUGS_ONCE("Avatar") << "Received atachments, but cof isn't loaded yet, postponing processing" << LL_ENDL;
+ return;
+ }
+
LL_DEBUGS("Avatar") << "ATT checking COF linkability for " << mRecentlyArrivedAttachments.size()
<< " recently arrived items" << LL_ENDL;
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 3e450e6dec..313339f131 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -730,39 +730,55 @@ namespace action_give_inventory
/**
* Checks My Inventory visibility.
*/
+ static bool is_give_inventory_acceptable_ids(const std::set inventory_selected_uuids)
+ {
+ if (inventory_selected_uuids.empty()) return false; // nothing selected
+
+ bool acceptable = false;
+ std::set::const_iterator it = inventory_selected_uuids.begin();
+ const std::set::const_iterator it_end = inventory_selected_uuids.end();
+ for (; it != it_end; ++it)
+ {
+ LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
+ // any category can be offered.
+ if (inv_cat)
+ {
+ acceptable = true;
+ continue;
+ }
+
+ LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
+ // check if inventory item can be given
+ if (LLGiveInventory::isInventoryGiveAcceptable(inv_item))
+ {
+ acceptable = true;
+ continue;
+ }
+
+ // there are neither item nor category in inventory
+ acceptable = false;
+ break;
+ }
+ return acceptable;
+ }
static bool is_give_inventory_acceptable(LLInventoryPanel* panel = NULL)
{
// check selection in the panel
- const std::set inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
- if (inventory_selected_uuids.empty()) return false; // nothing selected
+ std::set inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
+ if (inventory_selected_uuids.empty())
+ {
+ if(panel && panel->getRootFolder() && panel->getRootFolder()->isSingleFolderMode())
+ {
+ inventory_selected_uuids.insert(panel->getRootFolderID());
+ }
+ else
+ {
+ return false; // nothing selected
+ }
+ }
- bool acceptable = false;
- std::set::const_iterator it = inventory_selected_uuids.begin();
- const std::set::const_iterator it_end = inventory_selected_uuids.end();
- for (; it != it_end; ++it)
- {
- LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
- // any category can be offered.
- if (inv_cat)
- {
- acceptable = true;
- continue;
- }
-
- LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
- // check if inventory item can be given
- if (LLGiveInventory::isInventoryGiveAcceptable(inv_item))
- {
- acceptable = true;
- continue;
- }
-
- // there are neither item nor category in inventory
- acceptable = false;
- break;
- }
- return acceptable;
+ return is_give_inventory_acceptable_ids(inventory_selected_uuids);
}
static void build_items_string(const std::set& inventory_selected_uuids , std::string& items_string)
@@ -890,46 +906,65 @@ namespace action_give_inventory
* @param avatar_names - avatar names request to be sent.
* @param avatar_uuids - avatar names request to be sent.
*/
- static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector avatar_names, LLInventoryPanel* panel = NULL)
- {
- llassert(avatar_names.size() == avatar_uuids.size());
- const std::set inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
- if (inventory_selected_uuids.empty())
- {
- return;
- }
+ static void give_inventory_ids(const uuid_vec_t& avatar_uuids, const std::vector avatar_names, const uuid_set_t inventory_selected_uuids)
+ {
+ llassert(avatar_names.size() == avatar_uuids.size());
- std::string residents;
- LLAvatarActions::buildResidentsString(avatar_names, residents, true);
+ if (inventory_selected_uuids.empty())
+ {
+ return;
+ }
- std::string items;
- build_items_string(inventory_selected_uuids, items);
+ std::string residents;
+ LLAvatarActions::buildResidentsString(avatar_names, residents, true);
- int folders_count = 0;
- std::set::const_iterator it = inventory_selected_uuids.begin();
+ std::string items;
+ build_items_string(inventory_selected_uuids, items);
- //traverse through selected inventory items and count folders among them
- for ( ; it != inventory_selected_uuids.end() && folders_count <=1 ; ++it)
- {
- LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
- if (NULL != inv_cat)
- {
- folders_count++;
- }
- }
+ int folders_count = 0;
+ std::set::const_iterator it = inventory_selected_uuids.begin();
- // EXP-1599
- // In case of sharing multiple folders, make the confirmation
- // dialog contain a warning that only one folder can be shared at a time.
- std::string notification = (folders_count > 1) ? "ShareFolderConfirmation" : "ShareItemsConfirmation";
- LLSD substitutions;
- substitutions["RESIDENTS"] = residents;
- substitutions["ITEMS"] = items;
- LLShareInfo::instance().mAvatarNames = avatar_names;
- LLShareInfo::instance().mAvatarUuids = avatar_uuids;
- LLNotificationsUtil::add(notification, substitutions, LLSD(), boost::bind(&give_inventory_cb, _1, _2, inventory_selected_uuids));
- }
+ //traverse through selected inventory items and count folders among them
+ for ( ; it != inventory_selected_uuids.end() && folders_count <=1 ; ++it)
+ {
+ LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
+ if (NULL != inv_cat)
+ {
+ folders_count++;
+ }
+ }
+
+ // EXP-1599
+ // In case of sharing multiple folders, make the confirmation
+ // dialog contain a warning that only one folder can be shared at a time.
+ std::string notification = (folders_count > 1) ? "ShareFolderConfirmation" : "ShareItemsConfirmation";
+ LLSD substitutions;
+ substitutions["RESIDENTS"] = residents;
+ substitutions["ITEMS"] = items;
+ LLShareInfo::instance().mAvatarNames = avatar_names;
+ LLShareInfo::instance().mAvatarUuids = avatar_uuids;
+ LLNotificationsUtil::add(notification, substitutions, LLSD(), boost::bind(&give_inventory_cb, _1, _2, inventory_selected_uuids));
+ }
+
+ static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector avatar_names, LLInventoryPanel* panel = NULL)
+ {
+ llassert(avatar_names.size() == avatar_uuids.size());
+ std::set inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);;
+
+ if (inventory_selected_uuids.empty())
+ {
+ if(panel && panel->getRootFolder() && panel->getRootFolder()->isSingleFolderMode())
+ {
+ inventory_selected_uuids.insert(panel->getRootFolderID());
+ }
+ else
+ {
+ return;
+ }
+ }
+ give_inventory_ids(avatar_uuids, avatar_names, inventory_selected_uuids);
+ }
}
// static
@@ -1037,6 +1072,28 @@ void LLAvatarActions::shareWithAvatars(LLView * panel)
LLNotificationsUtil::add("ShareNotification");
}
+//static
+void LLAvatarActions::shareWithAvatars(const uuid_set_t inventory_selected_uuids, LLFloater* root_floater)
+{
+ using namespace action_give_inventory;
+
+ LLFloaterAvatarPicker* picker =
+ LLFloaterAvatarPicker::show(boost::bind(give_inventory_ids, _1, _2, inventory_selected_uuids), TRUE, FALSE, FALSE, root_floater->getName());
+ if (!picker)
+ {
+ return;
+ }
+
+ picker->setOkBtnEnableCb(boost::bind(is_give_inventory_acceptable_ids, inventory_selected_uuids));
+ picker->openFriendsTab();
+
+ if (root_floater)
+ {
+ root_floater->addDependentFloater(picker);
+ }
+ LLNotificationsUtil::add("ShareNotification");
+}
+
// static
bool LLAvatarActions::canShareSelectedItems(LLInventoryPanel* inv_panel /* = NULL*/)
{
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 86183cc119..8a0f40dd52 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -133,6 +133,7 @@ public:
* Share items with the picked avatars.
*/
static void shareWithAvatars(LLView * panel);
+ static void shareWithAvatars(const uuid_set_t inventory_selected_uuids, LLFloater* root_floater);
/**
* Block/unblock the avatar by id.
diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h
index 7c6980a7e6..3f607d434e 100644
--- a/indra/newview/llconversationmodel.h
+++ b/indra/newview/llconversationmodel.h
@@ -111,6 +111,7 @@ public:
virtual void previewItem( void );
virtual void selectItem(void) { }
virtual void showProperties(void);
+ virtual void navigateToFolder(bool new_window = false, bool change_mode = false) {}
// Methods used in sorting (see LLConversationSort::operator())
EConversationType const getType() const { return mConvType; }
@@ -249,7 +250,7 @@ public:
bool check(const LLFolderViewModelItem* item) { return true; }
bool checkFolder(const LLFolderViewModelItem* folder) const { return true; }
void setEmptyLookupMessage(const std::string& message) { }
- std::string getEmptyLookupMessage() const { return mEmpty; }
+ std::string getEmptyLookupMessage(bool is_empty_folder = false) const { return mEmpty; }
bool showAllResults() const { return true; }
std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const { return std::string::npos; }
std::string::size_type getFilterStringSize() const { return 0; }
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index f672d2a6f1..edc7bdef5f 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -2954,12 +2954,20 @@ void LLEnvironment::DayTransition::animate()
setWater(mNextInstance->getWater());
});
+
+ // pause probe updates and reset reflection maps on sky change
+ gPipeline.mReflectionMapManager.pause();
+ gPipeline.mReflectionMapManager.reset();
+
mSky = mStartSky->buildClone();
mBlenderSky = std::make_shared(mSky, mStartSky, mNextInstance->getSky(), mTransitionTime);
mBlenderSky->setOnFinished(
[this](LLSettingsBlender::ptr_t blender) {
mBlenderSky.reset();
+ // resume reflection probe updates
+ gPipeline.mReflectionMapManager.resume();
+
if (!mBlenderSky && !mBlenderWater)
LLEnvironment::instance().mCurrentEnvironment = mNextInstance;
else
@@ -3550,12 +3558,19 @@ namespace
LLSettingsSky::ptr_t target_sky(start_sky->buildClone());
mInjectedSky->setSource(target_sky);
+ // clear reflection probes and pause updates during sky change
+ gPipeline.mReflectionMapManager.pause();
+ gPipeline.mReflectionMapManager.reset();
+
mBlenderSky = std::make_shared(target_sky, start_sky, psky, transition);
mBlenderSky->setOnFinished(
[this, psky](LLSettingsBlender::ptr_t blender)
{
mBlenderSky.reset();
mInjectedSky->setSource(psky);
+
+ // resume updating reflection probes when done animating sky
+ gPipeline.mReflectionMapManager.resume();
setSky(mInjectedSky);
if (!mBlenderWater && (countExperiencesActive() == 0))
{
diff --git a/indra/newview/llfloaterchangeitemthumbnail.cpp b/indra/newview/llfloaterchangeitemthumbnail.cpp
new file mode 100644
index 0000000000..f54240f6f4
--- /dev/null
+++ b/indra/newview/llfloaterchangeitemthumbnail.cpp
@@ -0,0 +1,955 @@
+/**
+ * @file llfloaterchangeitemthumbnail.cpp
+ * @brief LLFloaterChangeItemThumbnail class implementation
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterchangeitemthumbnail.h"
+
+#include "llbutton.h"
+#include "llclipboard.h"
+#include "lliconctrl.h"
+#include "llinventoryfunctions.h"
+#include "llinventoryicon.h"
+#include "llinventorymodel.h"
+#include "llinventoryobserver.h"
+#include "llfloaterreg.h"
+#include "llfloatersimplesnapshot.h"
+#include "lllineeditor.h"
+#include "llnotificationsutil.h"
+#include "lltextbox.h"
+#include "lltexturectrl.h"
+#include "llthumbnailctrl.h"
+#include "llviewerfoldertype.h"
+#include "llviewermenufile.h"
+#include "llviewerobjectlist.h"
+#include "llviewertexturelist.h"
+#include "llwindow.h"
+
+
+class LLThumbnailImagePicker : public LLFilePickerThread
+{
+public:
+ LLThumbnailImagePicker(const LLUUID &item_id);
+ LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id);
+ ~LLThumbnailImagePicker();
+ void notify(const std::vector& filenames) override;
+
+private:
+ LLUUID mInventoryId;
+ LLUUID mTaskId;
+};
+
+LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id)
+ : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE)
+ , mInventoryId(item_id)
+{
+}
+
+LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id)
+ : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE)
+ , mInventoryId(item_id)
+ , mTaskId(task_id)
+{
+}
+
+LLThumbnailImagePicker::~LLThumbnailImagePicker()
+{
+}
+
+void LLThumbnailImagePicker::notify(const std::vector& filenames)
+{
+ if (filenames.empty())
+ {
+ return;
+ }
+ std::string file_path = filenames[0];
+ if (file_path.empty())
+ {
+ return;
+ }
+
+ LLFloaterSimpleSnapshot::uploadThumbnail(file_path, mInventoryId, mTaskId);
+}
+
+LLFloaterChangeItemThumbnail::LLFloaterChangeItemThumbnail(const LLSD& key)
+ : LLFloater(key)
+ , mObserverInitialized(false)
+ , mTooltipState(TOOLTIP_NONE)
+{
+}
+
+LLFloaterChangeItemThumbnail::~LLFloaterChangeItemThumbnail()
+{
+ gInventory.removeObserver(this);
+ removeVOInventoryListener();
+}
+
+BOOL LLFloaterChangeItemThumbnail::postBuild()
+{
+ mItemNameText = getChild("item_name");
+ mItemTypeIcon = getChild("item_type_icon");
+ mThumbnailCtrl = getChild("item_thumbnail");
+ mToolTipTextBox = getChild("tooltip_text");
+
+ LLSD tooltip_text;
+ mToolTipTextBox->setValue(tooltip_text);
+
+ LLButton *upload_local = getChild("upload_local");
+ upload_local->setClickedCallback(onUploadLocal, (void*)this);
+ upload_local->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_UPLOAD_LOCAL));
+ upload_local->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_UPLOAD_LOCAL));
+
+ LLButton *upload_snapshot = getChild("upload_snapshot");
+ upload_snapshot->setClickedCallback(onUploadSnapshot, (void*)this);
+ upload_snapshot->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_UPLOAD_SNAPSHOT));
+ upload_snapshot->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_UPLOAD_SNAPSHOT));
+
+ LLButton *use_texture = getChild("use_texture");
+ use_texture->setClickedCallback(onUseTexture, (void*)this);
+ use_texture->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_USE_TEXTURE));
+ use_texture->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_USE_TEXTURE));
+
+ mCopyToClipboardBtn = getChild("copy_to_clipboard");
+ mCopyToClipboardBtn->setClickedCallback(onCopyToClipboard, (void*)this);
+ mCopyToClipboardBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_COPY_TO_CLIPBOARD));
+ mCopyToClipboardBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_COPY_TO_CLIPBOARD));
+
+ mPasteFromClipboardBtn = getChild("paste_from_clipboard");
+ mPasteFromClipboardBtn->setClickedCallback(onPasteFromClipboard, (void*)this);
+ mPasteFromClipboardBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_COPY_FROM_CLIPBOARD));
+ mPasteFromClipboardBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_COPY_FROM_CLIPBOARD));
+
+ mRemoveImageBtn = getChild("remove_image");
+ mRemoveImageBtn->setClickedCallback(onRemove, (void*)this);
+ mRemoveImageBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_REMOVE));
+ mRemoveImageBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_REMOVE));
+
+ return LLFloater::postBuild();
+}
+
+void LLFloaterChangeItemThumbnail::onOpen(const LLSD& key)
+{
+ if (!key.has("item_id") && !key.isUUID())
+ {
+ closeFloater();
+ }
+
+ if (key.isUUID())
+ {
+ mItemId = key.asUUID();
+ }
+ else
+ {
+ mItemId = key["item_id"].asUUID();
+ mTaskId = key["task_id"].asUUID();
+ }
+
+ refreshFromInventory();
+}
+
+void LLFloaterChangeItemThumbnail::onFocusReceived()
+{
+ mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
+}
+
+void LLFloaterChangeItemThumbnail::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
+}
+
+BOOL LLFloaterChangeItemThumbnail::handleDragAndDrop(
+ S32 x,
+ S32 y,
+ MASK mask,
+ BOOL drop,
+ EDragAndDropType cargo_type,
+ void *cargo_data,
+ EAcceptance *accept,
+ std::string& tooltip_msg)
+{
+ if (cargo_type == DAD_TEXTURE)
+ {
+ LLInventoryItem *item = (LLInventoryItem *)cargo_data;
+ if (item->getAssetUUID().notNull())
+ {
+ if (drop)
+ {
+ assignAndValidateAsset(item->getAssetUUID());
+ }
+
+ *accept = ACCEPT_YES_SINGLE;
+ }
+ else
+ {
+ *accept = ACCEPT_NO;
+ }
+ }
+ else
+ {
+ *accept = ACCEPT_NO;
+ }
+
+ LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFloaterChangeItemThumbnail " << getKey() << LL_ENDL;
+
+ return TRUE;
+}
+
+void LLFloaterChangeItemThumbnail::changed(U32 mask)
+{
+ //LLInventoryObserver
+
+ if (mTaskId.notNull() || mItemId.isNull())
+ {
+ // Task inventory or not set up yet
+ return;
+ }
+
+ const std::set& mChangedItemIDs = gInventory.getChangedIDs();
+ std::set::const_iterator it;
+
+ for (it = mChangedItemIDs.begin(); it != mChangedItemIDs.end(); it++)
+ {
+ // set dirty for 'item profile panel' only if changed item is the item for which 'item profile panel' is shown (STORM-288)
+ if (*it == mItemId)
+ {
+ // if there's a change we're interested in.
+ if ((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
+ {
+ refreshFromInventory();
+ }
+ }
+ }
+}
+
+void LLFloaterChangeItemThumbnail::inventoryChanged(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void* user_data)
+{
+ //LLVOInventoryListener
+ refreshFromInventory();
+}
+
+LLInventoryObject* LLFloaterChangeItemThumbnail::getInventoryObject()
+{
+ LLInventoryObject* obj = NULL;
+ if (mTaskId.isNull())
+ {
+ // it is in agent inventory
+ if (!mObserverInitialized)
+ {
+ gInventory.addObserver(this);
+ mObserverInitialized = true;
+ }
+
+ obj = gInventory.getObject(mItemId);
+ }
+ else
+ {
+ LLViewerObject* object = gObjectList.findObject(mTaskId);
+ if (object)
+ {
+ if (!mObserverInitialized)
+ {
+ registerVOInventoryListener(object, NULL);
+ mObserverInitialized = false;
+ }
+
+ obj = object->getInventoryObject(mItemId);
+ }
+ }
+ return obj;
+}
+
+void LLFloaterChangeItemThumbnail::refreshFromInventory()
+{
+ LLInventoryObject* obj = getInventoryObject();
+ if (!obj)
+ {
+ closeFloater();
+ }
+
+ if (obj)
+ {
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ bool in_trash = gInventory.isObjectDescendentOf(obj->getUUID(), trash_id);
+ if (in_trash && obj->getUUID() != trash_id)
+ {
+ // Close properties when moving to trash
+ // Aren't supposed to view properties from trash
+ closeFloater();
+ }
+ else
+ {
+ refreshFromObject(obj);
+ }
+ }
+ else
+ {
+ closeFloater();
+ }
+}
+
+class LLIsOutfitTextureType : public LLInventoryCollectFunctor
+{
+public:
+ LLIsOutfitTextureType() {}
+ virtual ~LLIsOutfitTextureType() {}
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+};
+
+bool LLIsOutfitTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ return item && (item->getType() == LLAssetType::AT_TEXTURE);
+}
+
+void LLFloaterChangeItemThumbnail::refreshFromObject(LLInventoryObject* obj)
+{
+ LLUIImagePtr icon_img;
+ LLUUID thumbnail_id = obj->getThumbnailUUID();
+
+ LLViewerInventoryItem* item = dynamic_cast(obj);
+ if (item)
+ {
+ setTitle(getString("title_item_thumbnail"));
+
+ icon_img = LLInventoryIcon::getIcon(item->getType(), item->getInventoryType(), item->getFlags(), FALSE);
+ mRemoveImageBtn->setEnabled(thumbnail_id.notNull() && ((item->getActualType() != LLAssetType::AT_TEXTURE) || (item->getAssetUUID() != thumbnail_id)));
+ }
+ else
+ {
+ LLViewerInventoryCategory* cat = dynamic_cast(obj);
+
+ if (cat)
+ {
+ setTitle(getString("title_folder_thumbnail"));
+ icon_img = LLUI::getUIImage(LLViewerFolderType::lookupIconName(cat->getPreferredType(), true));
+
+ if (thumbnail_id.isNull() && (cat->getPreferredType() == LLFolderType::FT_OUTFIT))
+ {
+ // Legacy support, check if there is an image inside
+
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ // Not LLIsOfAssetType, because we allow links
+ LLIsOutfitTextureType f;
+ gInventory.getDirectDescendentsOf(mItemId, cats, items, f);
+
+ if (1 == items.size())
+ {
+ LLViewerInventoryItem* item = items.front();
+ if (item && item->getIsLinkType())
+ {
+ item = item->getLinkedItem();
+ }
+ if (item)
+ {
+ thumbnail_id = item->getAssetUUID();
+ if (thumbnail_id.notNull())
+ {
+ // per SL-19188, set this image as a thumbnail
+ LL_INFOS() << "Setting image " << thumbnail_id
+ << " from outfit as a thumbnail for inventory object " << obj->getUUID()
+ << LL_ENDL;
+ assignAndValidateAsset(thumbnail_id, true);
+ }
+ }
+ }
+ }
+
+ mRemoveImageBtn->setEnabled(thumbnail_id.notNull());
+ }
+ }
+ mItemTypeIcon->setImage(icon_img);
+ mItemNameText->setValue(obj->getName());
+
+ mThumbnailCtrl->setValue(thumbnail_id);
+
+ mCopyToClipboardBtn->setEnabled(thumbnail_id.notNull());
+ mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
+
+ // todo: some elements might not support setting thumbnails
+ // since they already have them
+ // It is unclear how system folders should function
+}
+
+void LLFloaterChangeItemThumbnail::onUploadLocal(void *userdata)
+{
+ LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+
+ (new LLThumbnailImagePicker(self->mItemId, self->mTaskId))->getFile();
+
+ LLFloater* floaterp = self->mPickerHandle.get();
+ if (floaterp)
+ {
+ floaterp->closeFloater();
+ }
+ floaterp = self->mSnapshotHandle.get();
+ if (floaterp)
+ {
+ floaterp->closeFloater();
+ }
+}
+
+void LLFloaterChangeItemThumbnail::onUploadSnapshot(void *userdata)
+{
+ LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+
+ LLFloater* floaterp = self->mSnapshotHandle.get();
+ // Show the dialog
+ if (floaterp)
+ {
+ floaterp->openFloater();
+ }
+ else
+ {
+ LLSD key;
+ key["item_id"] = self->mItemId;
+ key["task_id"] = self->mTaskId;
+ LLFloaterSimpleSnapshot* snapshot_floater = (LLFloaterSimpleSnapshot*)LLFloaterReg::showInstance("simple_snapshot", key, true);
+ if (snapshot_floater)
+ {
+ self->addDependentFloater(snapshot_floater);
+ self->mSnapshotHandle = snapshot_floater->getHandle();
+ snapshot_floater->setOwner(self);
+ }
+ }
+
+ floaterp = self->mPickerHandle.get();
+ if (floaterp)
+ {
+ floaterp->closeFloater();
+ }
+}
+
+void LLFloaterChangeItemThumbnail::onUseTexture(void *userdata)
+{
+ LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+ LLInventoryObject* obj = self->getInventoryObject();
+ if (obj)
+ {
+ self->showTexturePicker(obj->getThumbnailUUID());
+ }
+
+ LLFloater* floaterp = self->mSnapshotHandle.get();
+ if (floaterp)
+ {
+ floaterp->closeFloater();
+ }
+}
+
+void LLFloaterChangeItemThumbnail::onCopyToClipboard(void *userdata)
+{
+ LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+ LLInventoryObject* obj = self->getInventoryObject();
+ if (obj)
+ {
+ LLClipboard::instance().reset();
+ LLClipboard::instance().addToClipboard(obj->getThumbnailUUID(), LLAssetType::AT_NONE);
+ self->mPasteFromClipboardBtn->setEnabled(true);
+ }
+}
+
+void LLFloaterChangeItemThumbnail::onPasteFromClipboard(void *userdata)
+{
+ LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+ std::vector objects;
+ LLClipboard::instance().pasteFromClipboard(objects);
+ if (objects.size() > 0)
+ {
+ LLUUID potential_uuid = objects[0];
+ LLUUID asset_id;
+
+ if (potential_uuid.notNull())
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(potential_uuid);
+ if (item)
+ {
+ // no point checking snapshot?
+ if (item->getType() == LLAssetType::AT_TEXTURE)
+ {
+ bool copy = item->getPermissions().allowCopyBy(gAgent.getID());
+ bool xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID());
+
+ if (copy && xfer)
+ {
+ asset_id = item->getAssetUUID();
+ }
+ else
+ {
+ LLNotificationsUtil::add("ThumbnailInsufficientPermissions");
+ return;
+ }
+ }
+ }
+ else
+ {
+ // assume that this is a texture
+ asset_id = potential_uuid;
+ }
+ }
+
+ LLInventoryObject* obj = self->getInventoryObject();
+ if (obj && obj->getThumbnailUUID() == asset_id)
+ {
+ // nothing to do
+ return;
+ }
+ if (asset_id.notNull())
+ {
+ self->assignAndValidateAsset(asset_id);
+ }
+ // else show 'buffer has no texture' warning?
+ }
+}
+
+void LLFloaterChangeItemThumbnail::onRemove(void *userdata)
+{
+ LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+
+ LLSD payload;
+ payload["item_id"] = self->mItemId;
+ payload["object_id"] = self->mTaskId;
+ LLNotificationsUtil::add("DeleteThumbnail", LLSD(), payload, boost::bind(&LLFloaterChangeItemThumbnail::onRemovalConfirmation, _1, _2, self->getHandle()));
+}
+
+// static
+void LLFloaterChangeItemThumbnail::onRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle handle)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0 && !handle.isDead() && !handle.get()->isDead())
+ {
+ LLFloaterChangeItemThumbnail* self = (LLFloaterChangeItemThumbnail*)handle.get();
+ self->setThumbnailId(LLUUID::null);
+ }
+}
+
+struct ImageLoadedData
+{
+ LLUUID mThumbnailId;
+ LLUUID mObjectId;
+ LLHandle mFloaterHandle;
+ bool mSilent;
+ // Keep image reference to prevent deletion on timeout
+ LLPointer mTexturep;
+};
+
+void LLFloaterChangeItemThumbnail::assignAndValidateAsset(const LLUUID &asset_id, bool silent)
+{
+ LLPointer texturep = LLViewerTextureManager::getFetchedTexture(asset_id);
+ if (texturep->isMissingAsset())
+ {
+ LL_WARNS() << "Attempted to assign missing asset " << asset_id << LL_ENDL;
+ if (!silent)
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ }
+ }
+ else if (texturep->getFullWidth() == 0)
+ {
+ if (silent)
+ {
+ mExpectingAssetId = LLUUID::null;
+ }
+ else
+ {
+ // don't warn user multiple times if some textures took their time
+ mExpectingAssetId = asset_id;
+ }
+ ImageLoadedData *data = new ImageLoadedData();
+ data->mObjectId = mItemId;
+ data->mThumbnailId = asset_id;
+ data->mFloaterHandle = getHandle();
+ data->mSilent = silent;
+ data->mTexturep = texturep;
+
+ texturep->setLoadedCallback(onImageDataLoaded,
+ MAX_DISCARD_LEVEL, // Don't need full image, just size data
+ FALSE,
+ FALSE,
+ (void*)data,
+ NULL,
+ FALSE);
+ }
+ else
+ {
+ if (validateAsset(asset_id))
+ {
+ setThumbnailId(asset_id);
+ }
+ else if (!silent)
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ }
+ }
+}
+bool LLFloaterChangeItemThumbnail::validateAsset(const LLUUID &asset_id)
+{
+ if (asset_id.isNull())
+ {
+ return false;
+ }
+
+ LLPointer texturep = LLViewerTextureManager::findFetchedTexture(asset_id, TEX_LIST_STANDARD);
+
+ if (!texturep)
+ {
+ return false;
+ }
+
+ if (texturep->isMissingAsset())
+ {
+ return false;
+ }
+
+ if (texturep->getFullWidth() != texturep->getFullHeight())
+ {
+ return false;
+ }
+
+ if (texturep->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX
+ || texturep->getFullHeight() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX)
+ {
+ return false;
+ }
+
+ if (texturep->getFullWidth() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN
+ || texturep->getFullHeight() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN)
+ {
+ return false;
+ }
+ return true;
+}
+
+//static
+void LLFloaterChangeItemThumbnail::onImageDataLoaded(
+ BOOL success,
+ LLViewerFetchedTexture *src_vi,
+ LLImageRaw* src,
+ LLImageRaw* aux_src,
+ S32 discard_level,
+ BOOL final,
+ void* userdata)
+{
+ if (!userdata) return;
+
+ if (!final && success) return; //not done yet
+
+ ImageLoadedData* data = (ImageLoadedData*)userdata;
+
+ if (success)
+ {
+ // Update the item, set it even if floater is dead
+ if (validateAsset(data->mThumbnailId))
+ {
+ setThumbnailId(data->mThumbnailId, data->mObjectId);
+ }
+ else if (!data->mSilent)
+ {
+ // Should this only appear if floater is alive?
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ }
+ }
+
+ // Update floater
+ if (!data->mSilent && !data->mFloaterHandle.isDead())
+ {
+ LLFloaterChangeItemThumbnail* self = static_cast(data->mFloaterHandle.get());
+ if (self && self->mExpectingAssetId == data->mThumbnailId)
+ {
+ self->mExpectingAssetId = LLUUID::null;
+ }
+ }
+
+ delete data;
+}
+
+//static
+void LLFloaterChangeItemThumbnail::onFullImageLoaded(
+ BOOL success,
+ LLViewerFetchedTexture* src_vi,
+ LLImageRaw* src,
+ LLImageRaw* aux_src,
+ S32 discard_level,
+ BOOL final,
+ void* userdata)
+{
+ if (!userdata) return;
+
+ if (!final && success) return; //not done yet
+
+ ImageLoadedData* data = (ImageLoadedData*)userdata;
+
+ if (success)
+ {
+ if (src_vi->getFullWidth() != src_vi->getFullHeight()
+ || src_vi->getFullWidth() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN)
+ {
+ if (!data->mSilent)
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ }
+ }
+ else if (src_vi->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX)
+ {
+ LLFloaterSimpleSnapshot::uploadThumbnail(src, data->mObjectId, LLUUID::null);
+ }
+ else
+ {
+ setThumbnailId(data->mThumbnailId, data->mObjectId);
+ }
+ }
+
+ delete data;
+}
+
+void LLFloaterChangeItemThumbnail::showTexturePicker(const LLUUID &thumbnail_id)
+{
+ // show hourglass cursor when loading inventory window
+ getWindow()->setCursor(UI_CURSOR_WAIT);
+
+ LLFloater* floaterp = mPickerHandle.get();
+ // Show the dialog
+ if (floaterp)
+ {
+ floaterp->openFloater();
+ }
+ else
+ {
+ floaterp = new LLFloaterTexturePicker(
+ this,
+ thumbnail_id,
+ thumbnail_id,
+ thumbnail_id,
+ FALSE,
+ TRUE,
+ "SELECT PHOTO",
+ PERM_NONE,
+ PERM_NONE,
+ FALSE,
+ NULL);
+
+ mPickerHandle = floaterp->getHandle();
+
+ LLFloaterTexturePicker* texture_floaterp = dynamic_cast(floaterp);
+ if (texture_floaterp)
+ {
+ //texture_floaterp->setTextureSelectedCallback();
+ //texture_floaterp->setOnUpdateImageStatsCallback();
+ texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLPickerSource, const LLUUID&, const LLUUID&)
+ {
+ if (op == LLTextureCtrl::TEXTURE_SELECT)
+ {
+ onTexturePickerCommit();
+ }
+ }
+ );
+
+ texture_floaterp->setLocalTextureEnabled(FALSE);
+ texture_floaterp->setBakeTextureEnabled(FALSE);
+ texture_floaterp->setCanApplyImmediately(false);
+ texture_floaterp->setCanApply(false, true, false /*Hide 'preview disabled'*/);
+ texture_floaterp->setMinDimentionsLimits(LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN);
+
+ addDependentFloater(texture_floaterp);
+ }
+
+ floaterp->openFloater();
+ }
+ floaterp->setFocus(TRUE);
+}
+
+void LLFloaterChangeItemThumbnail::onTexturePickerCommit()
+{
+ LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mPickerHandle.get();
+
+ if (floaterp)
+ {
+ LLUUID asset_id = floaterp->getAssetID();
+
+ if (asset_id.isNull())
+ {
+ setThumbnailId(asset_id);
+ return;
+ }
+
+ LLInventoryObject* obj = getInventoryObject();
+ if (obj && obj->getThumbnailUUID() == asset_id)
+ {
+ // nothing to do
+ return;
+ }
+
+ LLPointer texturep = LLViewerTextureManager::findFetchedTexture(asset_id, TEX_LIST_STANDARD);
+ if (!texturep)
+ {
+ LL_WARNS() << "Image " << asset_id << " doesn't exist" << LL_ENDL;
+ return;
+ }
+
+ if (texturep->isMissingAsset())
+ {
+ LL_WARNS() << "Image " << asset_id << " is missing" << LL_ENDL;
+ return;
+ }
+
+ if (texturep->getFullWidth() != texturep->getFullHeight())
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ return;
+ }
+
+ if (texturep->getFullWidth() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN
+ && texturep->getFullWidth() > 0)
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ return;
+ }
+
+ if (texturep->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX
+ || texturep->getFullWidth() == 0)
+ {
+ if (texturep->isFullyLoaded()
+ && (texturep->getCachedRawImageLevel() == 0 || texturep->getRawImageLevel() == 0)
+ && (texturep->isCachedRawImageReady() || texturep->isRawImageValid()))
+ {
+ if (texturep->isRawImageValid())
+ {
+ LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getRawImage(), mItemId, mTaskId);
+ }
+ else
+ {
+ LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getCachedRawImage(), mItemId, mTaskId);
+ }
+ }
+ else
+ {
+ ImageLoadedData* data = new ImageLoadedData();
+ data->mObjectId = mItemId;
+ data->mThumbnailId = asset_id;
+ data->mFloaterHandle = getHandle();
+ data->mSilent = false;
+ data->mTexturep = texturep;
+
+ texturep->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
+ texturep->setMinDiscardLevel(0);
+ texturep->setLoadedCallback(onFullImageLoaded,
+ 0, // Need best quality
+ TRUE,
+ FALSE,
+ (void*)data,
+ NULL,
+ FALSE);
+ texturep->forceToSaveRawImage(0);
+ }
+ return;
+ }
+
+ setThumbnailId(asset_id);
+ }
+}
+
+
+void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID &new_thumbnail_id)
+{
+ LLInventoryObject* obj = getInventoryObject();
+ if (!obj)
+ {
+ return;
+ }
+
+ if (mTaskId.notNull())
+ {
+ LL_ERRS() << "Not implemented yet" << LL_ENDL;
+ return;
+ }
+
+ setThumbnailId(new_thumbnail_id, mItemId, obj);
+}
+
+void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id)
+{
+ LLInventoryObject* obj = gInventory.getObject(object_id);
+ if (!obj)
+ {
+ return;
+ }
+
+ setThumbnailId(new_thumbnail_id, object_id, obj);
+}
+void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id, LLInventoryObject* obj)
+{
+ if (obj->getThumbnailUUID() != new_thumbnail_id)
+ {
+ LLSD updates;
+ if (new_thumbnail_id.notNull())
+ {
+ // At the moment server expects id as a string
+ updates["thumbnail"] = LLSD().with("asset_id", new_thumbnail_id.asString());
+ }
+ else
+ {
+ // No thumbnail isntead of 'null id thumbnail'
+ updates["thumbnail"] = LLSD();
+ }
+ LLViewerInventoryCategory* view_folder = dynamic_cast(obj);
+ if (view_folder)
+ {
+ update_inventory_category(object_id, updates, NULL);
+ }
+ LLViewerInventoryItem* view_item = dynamic_cast(obj);
+ if (view_item)
+ {
+ update_inventory_item(object_id, updates, NULL);
+ }
+ }
+}
+
+void LLFloaterChangeItemThumbnail::onButtonMouseEnter(LLUICtrl* button, const LLSD& param, EToolTipState state)
+{
+ mTooltipState = state;
+
+ std::string tooltip_text;
+ std::string tooltip_name = "tooltip_" + button->getName();
+ if (hasString(tooltip_name))
+ {
+ tooltip_text = getString(tooltip_name);
+ }
+
+ mToolTipTextBox->setValue(tooltip_text);
+}
+
+void LLFloaterChangeItemThumbnail::onButtonMouseLeave(LLUICtrl* button, const LLSD& param, EToolTipState state)
+{
+ if (mTooltipState == state)
+ {
+ mTooltipState = TOOLTIP_NONE;
+ LLSD tooltip_text;
+ mToolTipTextBox->setValue(tooltip_text);
+ }
+}
+
diff --git a/indra/newview/llfloaterchangeitemthumbnail.h b/indra/newview/llfloaterchangeitemthumbnail.h
new file mode 100644
index 0000000000..a91e9b8ee9
--- /dev/null
+++ b/indra/newview/llfloaterchangeitemthumbnail.h
@@ -0,0 +1,139 @@
+/**
+ * @file llfloaterchangeitemthumbnail.h
+ * @brief LLFloaterChangeItemThumbnail class definition
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
+#define LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
+
+#include "llfloater.h"
+#include "llinventoryobserver.h"
+#include "llvoinventorylistener.h"
+
+class LLButton;
+class LLIconCtrl;
+class LLTextBox;
+class LLThumbnailCtrl;
+class LLUICtrl;
+class LLViewerInventoryItem;
+class LLViewerFetchedTexture;
+
+class LLFloaterChangeItemThumbnail : public LLFloater, public LLInventoryObserver, public LLVOInventoryListener
+{
+public:
+ LLFloaterChangeItemThumbnail(const LLSD& key);
+ ~LLFloaterChangeItemThumbnail();
+
+ BOOL postBuild() override;
+ void onOpen(const LLSD& key) override;
+ void onFocusReceived() override;
+ void onMouseEnter(S32 x, S32 y, MASK mask) override;
+
+ BOOL handleDragAndDrop(
+ S32 x,
+ S32 y,
+ MASK mask,
+ BOOL drop,
+ EDragAndDropType cargo_type,
+ void *cargo_data,
+ EAcceptance *accept,
+ std::string& tooltip_msg) override;
+
+ void changed(U32 mask) override;
+ void inventoryChanged(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void* user_data) override;
+
+ static bool validateAsset(const LLUUID &asset_id);
+
+private:
+
+ LLInventoryObject* getInventoryObject();
+ void refreshFromInventory();
+ void refreshFromObject(LLInventoryObject* obj);
+
+ static void onUploadLocal(void*);
+ static void onUploadSnapshot(void*);
+ static void onUseTexture(void*);
+ static void onCopyToClipboard(void*);
+ static void onPasteFromClipboard(void*);
+ static void onRemove(void*);
+ static void onRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle handle);
+
+ void assignAndValidateAsset(const LLUUID &asset_id, bool silent = false);
+ static void onImageDataLoaded(BOOL success,
+ LLViewerFetchedTexture *src_vi,
+ LLImageRaw* src,
+ LLImageRaw* aux_src,
+ S32 discard_level,
+ BOOL final,
+ void* userdata);
+ static void onFullImageLoaded(BOOL success,
+ LLViewerFetchedTexture* src_vi,
+ LLImageRaw* src,
+ LLImageRaw* aux_src,
+ S32 discard_level,
+ BOOL final,
+ void* userdata);
+
+ void showTexturePicker(const LLUUID &thumbnail_id);
+ void onTexturePickerCommit();
+
+ void setThumbnailId(const LLUUID &new_thumbnail_id);
+ static void setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id);
+ static void setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id, LLInventoryObject* obj);
+
+ enum EToolTipState
+ {
+ TOOLTIP_NONE,
+ TOOLTIP_UPLOAD_LOCAL,
+ TOOLTIP_UPLOAD_SNAPSHOT,
+ TOOLTIP_USE_TEXTURE,
+ TOOLTIP_COPY_TO_CLIPBOARD,
+ TOOLTIP_COPY_FROM_CLIPBOARD,
+ TOOLTIP_REMOVE,
+ };
+
+ void onButtonMouseEnter(LLUICtrl* button, const LLSD& param, EToolTipState state);
+ void onButtonMouseLeave(LLUICtrl* button, const LLSD& param, EToolTipState state);
+
+ bool mObserverInitialized;
+ EToolTipState mTooltipState;
+ LLUUID mItemId;
+ LLUUID mTaskId;
+ LLUUID mExpectingAssetId;
+
+ LLIconCtrl *mItemTypeIcon;
+ LLUICtrl *mItemNameText;
+ LLThumbnailCtrl *mThumbnailCtrl;
+ LLTextBox *mToolTipTextBox;
+ LLButton *mCopyToClipboardBtn;
+ LLButton *mPasteFromClipboardBtn;
+ LLButton *mRemoveImageBtn;
+
+ LLHandle mPickerHandle;
+ LLHandle mSnapshotHandle;
+};
+#endif // LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
diff --git a/indra/newview/llfloatereditenvironmentbase.cpp b/indra/newview/llfloatereditenvironmentbase.cpp
index 2850951668..cd24d79b7f 100644
--- a/indra/newview/llfloatereditenvironmentbase.cpp
+++ b/indra/newview/llfloatereditenvironmentbase.cpp
@@ -260,7 +260,7 @@ void LLFloaterEditEnvironmentBase::onSaveAsCommit(const LLSD& notification, cons
}
else if (mInventoryItem)
{
- const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
LLUUID parent_id = mInventoryItem->getParentUUID();
if (marketplacelistings_id == parent_id || gInventory.isObjectDescendentOf(mInventoryItem->getUUID(), gInventory.getLibraryRootFolderID()))
{
diff --git a/indra/newview/llfloaterforgetuser.cpp b/indra/newview/llfloaterforgetuser.cpp
index 97b022699f..f576ce7a76 100644
--- a/indra/newview/llfloaterforgetuser.cpp
+++ b/indra/newview/llfloaterforgetuser.cpp
@@ -164,6 +164,12 @@ bool LLFloaterForgetUser::onConfirmLogout(const LLSD& notification, const LLSD&
if (option == 0)
{
// Remove creds
+ std::string grid_id = LLGridManager::getInstance()->getGridId(grid);
+ if (grid_id.empty())
+ {
+ grid_id = grid;
+ }
+ gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid_id, LLStartUp::getUserId()); // doesn't write
gSecAPIHandler->removeFromCredentialMap("login_list", grid, LLStartUp::getUserId());
LLPointer cred = gSecAPIHandler->loadCredential(grid);
@@ -228,7 +234,13 @@ void LLFloaterForgetUser::processForgetUser()
void LLFloaterForgetUser::forgetUser(const std::string &userid, const std::string &fav_id, const std::string &grid, bool delete_data)
{
// Remove creds
- gSecAPIHandler->removeFromCredentialMap("login_list", grid, userid);
+ std::string grid_id = LLGridManager::getInstance()->getGridId(grid);
+ if (grid_id.empty())
+ {
+ grid_id = grid;
+ }
+ gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid_id, userid); // doesn't write
+ gSecAPIHandler->removeFromCredentialMap("login_list", grid, userid); // write operation
LLPointer cred = gSecAPIHandler->loadCredential(grid);
if (cred.notNull() && cred->userID() == userid)
diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp
index d17889bed1..f29046c513 100644
--- a/indra/newview/llfloatergesture.cpp
+++ b/indra/newview/llfloatergesture.cpp
@@ -211,7 +211,7 @@ BOOL LLFloaterGesture::postBuild()
getChildView("play_btn")->setVisible( true);
getChildView("stop_btn")->setVisible( false);
setDefaultBtn("play_btn");
- mGestureFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE, false);
+ mGestureFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
uuid_vec_t folders;
folders.push_back(mGestureFolderID);
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 2720b7fcf7..011ad67011 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -289,6 +289,9 @@ void LLFloaterIMContainer::onOpen(const LLSD& key)
LLMultiFloater::onOpen(key);
reSelectConversation();
assignResizeLimits();
+
+ LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(mSelectedSession);
+ session_floater->onOpen(key);
}
// virtual
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index af4e7f5aff..0b0dce29fb 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -986,6 +986,8 @@ void LLFloaterIMSessionTab::onOpen(const LLSD& key)
}
mInputButtonPanel->setVisible(isTornOff());
+
+ setFocus(TRUE);
}
diff --git a/indra/newview/llfloaterinventorysettings.cpp b/indra/newview/llfloaterinventorysettings.cpp
new file mode 100644
index 0000000000..29d6e90a33
--- /dev/null
+++ b/indra/newview/llfloaterinventorysettings.cpp
@@ -0,0 +1,44 @@
+/**
+ * @file llfloaterinventorysettings.cpp
+ * @brief LLFloaterInventorySettings class implementation
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterinventorysettings.h"
+
+LLFloaterInventorySettings::LLFloaterInventorySettings(const LLSD& key)
+ : LLFloater(key)
+{
+}
+
+LLFloaterInventorySettings::~LLFloaterInventorySettings()
+{}
+
+BOOL LLFloaterInventorySettings::postBuild()
+{
+ getChild("ok_btn")->setCommitCallback(boost::bind(&LLFloater::closeFloater, this, false));
+ return TRUE;
+}
+
diff --git a/indra/newview/llfloaterinventorysettings.h b/indra/newview/llfloaterinventorysettings.h
new file mode 100644
index 0000000000..50304276c7
--- /dev/null
+++ b/indra/newview/llfloaterinventorysettings.h
@@ -0,0 +1,45 @@
+/**
+ * @file llfloaterinventorysettings.h
+ * @brief LLFloaterInventorySettings class definition
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERINVENTORYSETTINGS_H
+#define LL_LLFLOATERINVENTORYSETTINGS_H
+
+#include "llfloater.h"
+
+class LLFloaterInventorySettings
+ : public LLFloater
+{
+ friend class LLFloaterReg;
+
+public:
+ virtual BOOL postBuild();
+
+private:
+ LLFloaterInventorySettings(const LLSD& key);
+ ~LLFloaterInventorySettings();
+};
+
+#endif
diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp
index 8ee7a72055..b42c49c607 100644
--- a/indra/newview/llfloaterlinkreplace.cpp
+++ b/indra/newview/llfloaterlinkreplace.cpp
@@ -335,8 +335,8 @@ BOOL LLFloaterLinkReplace::tick()
void LLFloaterLinkReplace::processBatch(LLInventoryModel::item_array_t items)
{
const LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID);
- const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
- const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+ const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it)
{
diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp
index e755e9924c..71b3b16809 100644
--- a/indra/newview/llfloatermarketplacelistings.cpp
+++ b/indra/newview/llfloatermarketplacelistings.cpp
@@ -41,8 +41,11 @@
#include "llnotificationmanager.h"
#include "llnotificationsutil.h"
#include "llsidepaneliteminfo.h"
+#include "llsidepaneltaskinfo.h"
+#include "lltabcontainer.h"
#include "lltextbox.h"
#include "lltrans.h"
+#include "llviewerwindow.h"
///----------------------------------------------------------------------------
/// LLPanelMarketplaceListings
@@ -227,18 +230,31 @@ void LLPanelMarketplaceListings::onTabChange()
void LLPanelMarketplaceListings::onAddButtonClicked()
{
- // Find active panel
- LLInventoryPanel* panel = (LLInventoryPanel*)getChild("marketplace_filter_tabs")->getCurrentPanel();
- if (panel)
- {
- LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
- llassert(marketplacelistings_id.notNull());
- LLFolderType::EType preferred_type = LLFolderType::lookup("category");
- LLUUID category = gInventory.createNewCategory(marketplacelistings_id, preferred_type, LLStringUtil::null);
- gInventory.notifyObservers();
- panel->setSelectionByID(category, TRUE);
- panel->getRootFolder()->setNeedsAutoRename(TRUE);
+ LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ llassert(marketplacelistings_id.notNull());
+ LLFolderType::EType preferred_type = LLFolderType::lookup("category");
+ LLHandle handle = getHandle();
+ gInventory.createNewCategory(
+ marketplacelistings_id,
+ preferred_type,
+ LLStringUtil::null,
+ [handle](const LLUUID &new_cat_id)
+ {
+ // Find active panel
+ LLPanel *marketplace_panel = handle.get();
+ if (!marketplace_panel)
+ {
+ return;
+ }
+ LLInventoryPanel* panel = (LLInventoryPanel*)marketplace_panel->getChild("marketplace_filter_tabs")->getCurrentPanel();
+ if (panel)
+ {
+ gInventory.notifyObservers();
+ panel->setSelectionByID(new_cat_id, TRUE);
+ panel->getRootFolder()->setNeedsAutoRename(TRUE);
+ }
}
+ );
}
void LLPanelMarketplaceListings::onAuditButtonClicked()
@@ -359,6 +375,7 @@ LLFloaterMarketplaceListings::LLFloaterMarketplaceListings(const LLSD& key)
, mInventoryTitle(NULL)
, mPanelListings(NULL)
, mPanelListingsSet(false)
+, mRootFolderCreating(false)
{
}
@@ -431,7 +448,7 @@ void LLFloaterMarketplaceListings::fetchContents()
{
LLMarketplaceData::instance().setDataFetchedSignal(boost::bind(&LLFloaterMarketplaceListings::updateView, this));
LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_LOADING);
- LLInventoryModelBackgroundFetch::instance().start(mRootFolderId);
+ LLInventoryModelBackgroundFetch::instance().start(mRootFolderId, true);
LLMarketplaceData::instance().getSLMListings();
}
}
@@ -444,15 +461,50 @@ void LLFloaterMarketplaceListings::setRootFolder()
// If we are *not* a merchant or we have no market place connection established yet, do nothing
return;
}
+ if (!gInventory.isInventoryUsable())
+ {
+ return;
+ }
+ LLFolderType::EType preferred_type = LLFolderType::FT_MARKETPLACE_LISTINGS;
// We are a merchant. Get the Marketplace listings folder, create it if needs be.
- LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true);
- if (marketplacelistings_id.isNull())
- {
- // We should never get there unless the inventory fails badly
- LL_ERRS("SLM") << "Inventory problem: failure to create the marketplace listings folder for a merchant!" << LL_ENDL;
- return;
- }
+ LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(preferred_type);
+
+ if (marketplacelistings_id.isNull())
+ {
+ if (!mRootFolderCreating)
+ {
+ mRootFolderCreating = true;
+ gInventory.createNewCategory(
+ gInventory.getRootFolderID(),
+ preferred_type,
+ LLStringUtil::null,
+ [](const LLUUID &new_cat_id)
+ {
+ LLFloaterMarketplaceListings* marketplace = LLFloaterReg::findTypedInstance("marketplace_listings");
+ if (marketplace)
+ {
+ if (new_cat_id.notNull())
+ {
+ // will call setRootFolder again
+ marketplace->updateView();
+ }
+ // don't update in case of failure, createNewCategory can return
+ // immediately if cap is missing and will cause a loop
+ else
+ {
+ // unblock
+ marketplace->mRootFolderCreating = false;
+ LL_WARNS("SLM") << "Inventory warning: Failed to create marketplace listings folder for a merchant" << LL_ENDL;
+ }
+ }
+ }
+ );
+ }
+ return;
+ }
+
+ mRootFolderCreating = false;
// No longer need to observe new category creation
if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
@@ -540,6 +592,11 @@ void LLFloaterMarketplaceListings::updateView()
{
setRootFolder();
}
+ if (mRootFolderCreating)
+ {
+ // waiting for callback
+ return;
+ }
// Update the bottom initializing status and progress dial if we are initializing or if we're a merchant and still loading
if ((mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) || (is_merchant && (data_fetched <= MarketplaceFetchCodes::MARKET_FETCH_LOADING)) )
@@ -843,14 +900,17 @@ void LLFloaterMarketplaceValidation::onOpen(const LLSD& key)
LLUUID cat_id(key.asUUID());
if (cat_id.isNull())
{
- cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
}
// Validates the folder
if (cat_id.notNull())
{
- LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
- validate_marketplacelistings(cat, boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3), false);
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ cat_id,
+ NULL,
+ boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3),
+ false);
}
// Handle the listing folder being processed
@@ -954,18 +1014,44 @@ LLFloaterItemProperties::~LLFloaterItemProperties()
BOOL LLFloaterItemProperties::postBuild()
{
- // On the standalone properties floater, we have no need for a back button...
- LLSidepanelItemInfo* panel = getChild("item_panel");
- LLButton* back_btn = panel->getChild("back_btn");
- back_btn->setVisible(FALSE);
-
return LLFloater::postBuild();
}
void LLFloaterItemProperties::onOpen(const LLSD& key)
{
// Tell the panel which item it needs to visualize
- LLSidepanelItemInfo* panel = getChild("item_panel");
- panel->setItemID(key["id"].asUUID());
+ LLPanel* panel = findChild("sidepanel");
+
+ LLSidepanelItemInfo* item_panel = dynamic_cast(panel);
+ if (item_panel)
+ {
+ item_panel->setItemID(key["id"].asUUID());
+ if (key.has("object"))
+ {
+ item_panel->setObjectID(key["object"].asUUID());
+ }
+ item_panel->setParentFloater(this);
+ }
+
+ LLSidepanelTaskInfo* task_panel = dynamic_cast(panel);
+ if (task_panel)
+ {
+ task_panel->setObjectSelection(LLSelectMgr::getInstance()->getSelection());
+ }
}
+LLMultiItemProperties::LLMultiItemProperties(const LLSD& key)
+ : LLMultiFloater(LLSD())
+{
+ // start with a small rect in the top-left corner ; will get resized
+ LLRect rect;
+ rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 350, 350);
+ setRect(rect);
+ LLFloater* last_floater = LLFloaterReg::getLastFloaterInGroup(key.asString());
+ if (last_floater)
+ {
+ stackWith(*last_floater);
+ }
+ setTitle(LLTrans::getString("MultiPropertiesTitle"));
+ buildTabContainer();
+}
diff --git a/indra/newview/llfloatermarketplacelistings.h b/indra/newview/llfloatermarketplacelistings.h
index ffc098e28a..085e517a9d 100644
--- a/indra/newview/llfloatermarketplacelistings.h
+++ b/indra/newview/llfloatermarketplacelistings.h
@@ -33,6 +33,7 @@
#include "llinventorypanel.h"
#include "llnotificationptr.h"
#include "llmodaldialog.h"
+#include "llmultifloater.h"
#include "lltexteditor.h"
class LLInventoryCategoriesObserver;
@@ -139,6 +140,7 @@ private:
LLTextBox * mInventoryTitle;
LLUUID mRootFolderId;
+ bool mRootFolderCreating;
LLPanelMarketplaceListings * mPanelListings;
bool mPanelListingsSet;
};
@@ -223,4 +225,10 @@ public:
private:
};
+class LLMultiItemProperties : public LLMultiFloater
+{
+public:
+ LLMultiItemProperties(const LLSD& key);
+};
+
#endif // LL_LLFLOATERMARKETPLACELISTINGS_H
diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp
index a682064dad..d3ab22f792 100644
--- a/indra/newview/llfloateropenobject.cpp
+++ b/indra/newview/llfloateropenobject.cpp
@@ -164,34 +164,12 @@ void LLFloaterOpenObject::moveToInventory(bool wear, bool replace)
}
inventory_func_type func = boost::bind(LLFloaterOpenObject::callbackCreateInventoryCategory,_1,object_id,wear,replace);
- LLUUID category_id = gInventory.createNewCategory(parent_category_id,
- LLFolderType::FT_NONE,
- name,
- func);
-
- //If we get a null category ID, we are using a capability in createNewCategory and we will
- //handle the following in the callbackCreateInventoryCategory routine.
- if ( category_id.notNull() )
- {
- LLCatAndWear* data = new LLCatAndWear;
- data->mCatID = category_id;
- data->mWear = wear;
- data->mFolderResponded = false;
- data->mReplace = replace;
-
- // Copy and/or move the items into the newly created folder.
- // Ignore any "you're going to break this item" messages.
- BOOL success = move_inv_category_world_to_agent(object_id, category_id, TRUE,
- callbackMoveInventory,
- (void*)data);
- if (!success)
- {
- delete data;
- data = NULL;
-
- LLNotificationsUtil::add("OpenObjectCannotCopy");
- }
- }
+ // D567 copy thumbnail info
+ gInventory.createNewCategory(
+ parent_category_id,
+ LLFolderType::FT_NONE,
+ name,
+ func);
}
// static
@@ -206,9 +184,14 @@ void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLUUID& category
// Copy and/or move the items into the newly created folder.
// Ignore any "you're going to break this item" messages.
- BOOL success = move_inv_category_world_to_agent(object_id, category_id, TRUE,
- callbackMoveInventory,
- (void*)wear_data);
+ BOOL success = move_inv_category_world_to_agent(object_id,
+ category_id,
+ TRUE,
+ [](S32 result, void* data, const LLMoveInv*)
+ {
+ callbackMoveInventory(result, data);
+ },
+ (void*)wear_data);
if (!success)
{
delete wear_data;
diff --git a/indra/newview/llfloateroutfitphotopreview.cpp b/indra/newview/llfloateroutfitphotopreview.cpp
deleted file mode 100644
index ade258aef7..0000000000
--- a/indra/newview/llfloateroutfitphotopreview.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/**
- * @file llfloateroutfitphotopreview.cpp
- * @brief LLFloaterOutfitPhotoPreview class implementation
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llwindow.h"
-
-#include "llfloateroutfitphotopreview.h"
-
-#include "llagent.h"
-#include "llappearancemgr.h"
-#include "llbutton.h"
-#include "llcombobox.h"
-#include "llfilepicker.h"
-#include "llfloaterreg.h"
-#include "llimagetga.h"
-#include "llimagepng.h"
-#include "llinventory.h"
-#include "llinventorymodel.h"
-#include "llnotificationsutil.h"
-#include "llresmgr.h"
-#include "lltrans.h"
-#include "lltextbox.h"
-#include "lltextureview.h"
-#include "llui.h"
-#include "llviewerinventory.h"
-#include "llviewertexture.h"
-#include "llviewertexturelist.h"
-#include "lluictrlfactory.h"
-#include "llviewerwindow.h"
-#include "lllineeditor.h"
-
-const S32 MAX_OUTFIT_PHOTO_WIDTH = 256;
-const S32 MAX_OUTFIT_PHOTO_HEIGHT = 256;
-
-const S32 CLIENT_RECT_VPAD = 4;
-
-LLFloaterOutfitPhotoPreview::LLFloaterOutfitPhotoPreview(const LLSD& key)
- : LLPreview(key),
- mUpdateDimensions(TRUE),
- mImage(NULL),
- mOutfitID(LLUUID()),
- mImageOldBoostLevel(LLGLTexture::BOOST_NONE),
- mExceedLimits(FALSE)
-{
- updateImageID();
-}
-
-LLFloaterOutfitPhotoPreview::~LLFloaterOutfitPhotoPreview()
-{
- LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ;
-
- if (mImage.notNull())
- {
- mImage->setBoostLevel(mImageOldBoostLevel);
- mImage = NULL;
- }
-}
-
-// virtual
-BOOL LLFloaterOutfitPhotoPreview::postBuild()
-{
- getChild("ok_btn")->setClickedCallback(boost::bind(&LLFloaterOutfitPhotoPreview::onOkBtn, this));
- getChild("cancel_btn")->setClickedCallback(boost::bind(&LLFloaterOutfitPhotoPreview::onCancelBtn, this));
-
- return LLPreview::postBuild();
-}
-
-void LLFloaterOutfitPhotoPreview::draw()
-{
- updateDimensions();
-
- LLPreview::draw();
-
- if (!isMinimized())
- {
- LLGLSUIDefault gls_ui;
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- const LLRect& border = mClientRect;
- LLRect interior = mClientRect;
- interior.stretch( -PREVIEW_BORDER_WIDTH );
-
- // ...border
- gl_rect_2d( border, LLColor4(0.f, 0.f, 0.f, 1.f));
- gl_rect_2d_checkerboard( interior );
-
- if ( mImage.notNull() )
- {
- // Draw the texture
- gGL.diffuseColor3f( 1.f, 1.f, 1.f );
- gl_draw_scaled_image(interior.mLeft,
- interior.mBottom,
- interior.getWidth(),
- interior.getHeight(),
- mImage);
-
- // Pump the texture priority
- F32 pixel_area = (F32)(interior.getWidth() * interior.getHeight() );
- mImage->addTextureStats( pixel_area );
-
- S32 int_width = interior.getWidth();
- S32 int_height = interior.getHeight();
- mImage->setKnownDrawSize(int_width, int_height);
- }
- }
-
-}
-
-// virtual
-void LLFloaterOutfitPhotoPreview::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
- LLPreview::reshape(width, height, called_from_parent);
-
- LLRect dim_rect(getChildView("dimensions")->getRect());
-
- S32 horiz_pad = 2 * (LLPANEL_BORDER_WIDTH + PREVIEW_PAD) + PREVIEW_RESIZE_HANDLE_SIZE;
-
- S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD;
-
- LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0);
- client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD);
- client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ;
-
- S32 client_width = client_rect.getWidth();
- S32 client_height = client_width;
-
- if(client_height > client_rect.getHeight())
- {
- client_height = client_rect.getHeight();
- client_width = client_height;
- }
- mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() + (client_height / 2), client_width, client_height);
-
-}
-
-
-void LLFloaterOutfitPhotoPreview::updateDimensions()
-{
- if (!mImage)
- {
- return;
- }
- if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0)
- {
- return;
- }
-
- if (mAssetStatus != PREVIEW_ASSET_LOADED)
- {
- mAssetStatus = PREVIEW_ASSET_LOADED;
- mUpdateDimensions = TRUE;
- }
-
- getChild("dimensions")->setTextArg("[WIDTH]", llformat("%d", mImage->getFullWidth()));
- getChild("dimensions")->setTextArg("[HEIGHT]", llformat("%d", mImage->getFullHeight()));
-
- if ((mImage->getFullWidth() <= MAX_OUTFIT_PHOTO_WIDTH) && (mImage->getFullHeight() <= MAX_OUTFIT_PHOTO_HEIGHT))
- {
- getChild("ok_btn")->setEnabled(TRUE);
- mExceedLimits = FALSE;
- }
- else
- {
- mExceedLimits = TRUE;
- LLStringUtil::format_map_t args;
- args["MAX_WIDTH"] = llformat("%d", MAX_OUTFIT_PHOTO_WIDTH);
- args["MAX_HEIGHT"] = llformat("%d", MAX_OUTFIT_PHOTO_HEIGHT);
- std::string label = getString("exceed_limits", args);
- getChild("notification")->setValue(label);
- getChild("notification")->setColor(LLColor4::yellow);
- getChild("ok_btn")->setEnabled(FALSE);
- }
-
- if (mUpdateDimensions)
- {
- mUpdateDimensions = FALSE;
-
- reshape(getRect().getWidth(), getRect().getHeight());
- gFloaterView->adjustToFitScreen(this, FALSE);
- }
-}
-
-void LLFloaterOutfitPhotoPreview::loadAsset()
-{
- if (mImage.notNull())
- {
- mImage->setBoostLevel(mImageOldBoostLevel);
- }
- mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
- mImageOldBoostLevel = mImage->getBoostLevel();
- mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
- mImage->forceToSaveRawImage(0) ;
- mAssetStatus = PREVIEW_ASSET_LOADING;
- mUpdateDimensions = TRUE;
- updateDimensions();
-}
-
-LLPreview::EAssetStatus LLFloaterOutfitPhotoPreview::getAssetStatus()
-{
- if (mImage.notNull() && (mImage->getFullWidth() * mImage->getFullHeight() > 0))
- {
- mAssetStatus = PREVIEW_ASSET_LOADED;
- }
- return mAssetStatus;
-}
-
-void LLFloaterOutfitPhotoPreview::updateImageID()
-{
- const LLViewerInventoryItem *item = static_cast(getItem());
- if(item)
- {
- mImageID = item->getAssetUUID();
- }
- else
- {
- mImageID = mItemUUID;
- }
-
-}
-
-/* virtual */
-void LLFloaterOutfitPhotoPreview::setObjectID(const LLUUID& object_id)
-{
- mObjectUUID = object_id;
-
- const LLUUID old_image_id = mImageID;
-
- updateImageID();
- if (mImageID != old_image_id)
- {
- mAssetStatus = PREVIEW_ASSET_UNLOADED;
- loadAsset();
- }
- refreshFromItem();
-}
-
-void LLFloaterOutfitPhotoPreview::setOutfitID(const LLUUID& outfit_id)
-{
- mOutfitID = outfit_id;
- LLViewerInventoryCategory* outfit_folder = gInventory.getCategory(mOutfitID);
- if(outfit_folder && !mExceedLimits)
- {
- getChild("notification")->setValue( getString("photo_confirmation"));
- getChild("notification")->setTextArg("[OUTFIT]", outfit_folder->getName());
- getChild("notification")->setColor(LLColor4::white);
- }
-
-}
-
-void LLFloaterOutfitPhotoPreview::onOkBtn()
-{
- if(mOutfitID.notNull() && getItem())
- {
- LLAppearanceMgr::instance().removeOutfitPhoto(mOutfitID);
- LLPointer cb = NULL;
- link_inventory_object(mOutfitID, LLConstPointer(getItem()), cb);
- }
- closeFloater();
-}
-
-void LLFloaterOutfitPhotoPreview::onCancelBtn()
-{
- closeFloater();
-}
diff --git a/indra/newview/llfloateroutfitphotopreview.h b/indra/newview/llfloateroutfitphotopreview.h
deleted file mode 100644
index a1e7b58abe..0000000000
--- a/indra/newview/llfloateroutfitphotopreview.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * @file llfloateroutfitphotopreview.h
- * @brief LLFloaterOutfitPhotoPreview class definition
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLFLOATEROUTFITPHOTOPREVIEW_H
-#define LL_LLFLOATEROUTFITPHOTOPREVIEW_H
-
-#include "llpreview.h"
-#include "llbutton.h"
-#include "llframetimer.h"
-#include "llviewertexture.h"
-
-class LLComboBox;
-class LLImageRaw;
-
-class LLFloaterOutfitPhotoPreview : public LLPreview
-{
-public:
- LLFloaterOutfitPhotoPreview(const LLSD& key);
- ~LLFloaterOutfitPhotoPreview();
-
- virtual void draw();
-
- virtual void loadAsset();
- virtual EAssetStatus getAssetStatus();
-
- virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
-
- /*virtual*/ void setObjectID(const LLUUID& object_id);
-
- void setOutfitID(const LLUUID& outfit_id);
- void onOkBtn();
- void onCancelBtn();
-
-protected:
- void init();
- /* virtual */ BOOL postBuild();
-
-private:
- void updateImageID(); // set what image is being uploaded.
- void updateDimensions();
- LLUUID mImageID;
- LLUUID mOutfitID;
- LLPointer mImage;
- S32 mImageOldBoostLevel;
-
- // This is stored off in a member variable, because the save-as
- // button and drag and drop functionality need to know.
- BOOL mUpdateDimensions;
-
- BOOL mExceedLimits;
-
- LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ;
-};
-#endif // LL_LLFLOATEROUTFITPHOTOPREVIEW_H
diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp
deleted file mode 100644
index 64ad40f419..0000000000
--- a/indra/newview/llfloaterproperties.cpp
+++ /dev/null
@@ -1,891 +0,0 @@
-/**
- * @file llfloaterproperties.cpp
- * @brief A floater which shows an inventory item's properties.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llfloaterproperties.h"
-
-#include
-#include
-#include "llcachename.h"
-#include "llavatarnamecache.h"
-#include "lldbstrings.h"
-#include "llfloaterreg.h"
-
-#include "llagent.h"
-#include "llbutton.h"
-#include "llcheckboxctrl.h"
-#include "llcombobox.h"
-#include "llavataractions.h"
-#include "llinventorydefines.h"
-#include "llinventoryobserver.h"
-#include "llinventorymodel.h"
-#include "lllineeditor.h"
-//#include "llspinctrl.h"
-#include "llradiogroup.h"
-#include "llresmgr.h"
-#include "roles_constants.h"
-#include "llselectmgr.h"
-#include "lltextbox.h"
-#include "lltrans.h"
-#include "lluiconstants.h"
-#include "llviewerinventory.h"
-#include "llviewerobjectlist.h"
-#include "llviewerregion.h"
-#include "llviewercontrol.h"
-#include "llviewerwindow.h"
-#include "llgroupactions.h"
-
-#include "lluictrlfactory.h"
-
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLPropertiesObserver
-//
-// helper class to watch the inventory.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-// Ugh. This can't be a singleton because it needs to remove itself
-// from the inventory observer list when destroyed, which could
-// happen after gInventory has already been destroyed if a singleton.
-// Instead, do our own ref counting and create / destroy it as needed
-class LLPropertiesObserver : public LLInventoryObserver
-{
-public:
- LLPropertiesObserver(LLFloaterProperties* floater)
- : mFloater(floater)
- {
- gInventory.addObserver(this);
- }
- virtual ~LLPropertiesObserver()
- {
- gInventory.removeObserver(this);
- }
- virtual void changed(U32 mask);
-private:
- LLFloaterProperties* mFloater; // Not a handle because LLFloaterProperties is managing LLPropertiesObserver
-};
-
-void LLPropertiesObserver::changed(U32 mask)
-{
- // if there's a change we're interested in.
- if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
- {
- mFloater->dirty();
- }
-}
-
-
-
-///----------------------------------------------------------------------------
-/// Class LLFloaterProperties
-///----------------------------------------------------------------------------
-
-// Default constructor
-LLFloaterProperties::LLFloaterProperties(const LLUUID& item_id)
- : LLFloater(mItemID),
- mItemID(item_id),
- mDirty(TRUE)
-{
- mPropertiesObserver = new LLPropertiesObserver(this);
-}
-
-// Destroys the object
-LLFloaterProperties::~LLFloaterProperties()
-{
- delete mPropertiesObserver;
- mPropertiesObserver = NULL;
-}
-
-// virtual
-BOOL LLFloaterProperties::postBuild()
-{
- // build the UI
- // item name & description
- getChild("LabelItemName")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
- getChild("LabelItemName")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitName,this));
- getChild("LabelItemDesc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
- getChild("LabelItemDesc")->setCommitCallback(boost::bind(&LLFloaterProperties:: onCommitDescription, this));
- // Creator information
- getChild("BtnCreator")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickCreator,this));
- // owner information
- getChild("BtnOwner")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickOwner,this));
- // acquired date
- // owner permissions
- // Permissions debug text
- // group permissions
- getChild("CheckShareWithGroup")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
- // everyone permissions
- getChild("CheckEveryoneCopy")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
- // next owner permissions
- getChild("CheckNextOwnerModify")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
- getChild("CheckNextOwnerCopy")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
- getChild("CheckNextOwnerTransfer")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
- // Mark for sale or not, and sale info
- getChild("CheckPurchase")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleInfo, this));
- getChild("ComboBoxSaleType")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleType, this));
- // "Price" label for edit
- getChild("Edit Cost")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleInfo, this));
- // The UI has been built, now fill in all the values
- refresh();
-
- return TRUE;
-}
-
-// virtual
-void LLFloaterProperties::onOpen(const LLSD& key)
-{
- refresh();
-}
-
-void LLFloaterProperties::refresh()
-{
- LLInventoryItem* item = findItem();
- if(item)
- {
- refreshFromItem(item);
- }
- else
- {
- //RN: it is possible that the container object is in the middle of an inventory refresh
- // causing findItem() to fail, so just temporarily disable everything
-
- mDirty = TRUE;
-
- const char* enableNames[]={
- "LabelItemName",
- "LabelItemDesc",
- "LabelCreatorName",
- "BtnCreator",
- "LabelOwnerName",
- "BtnOwner",
- "CheckOwnerModify",
- "CheckOwnerCopy",
- "CheckOwnerTransfer",
- "CheckShareWithGroup",
- "CheckEveryoneCopy",
- "CheckNextOwnerModify",
- "CheckNextOwnerCopy",
- "CheckNextOwnerTransfer",
- "CheckPurchase",
- "ComboBoxSaleType",
- "Edit Cost"
- };
- for(size_t t=0; tsetEnabled(false);
- }
- const char* hideNames[]={
- "BaseMaskDebug",
- "OwnerMaskDebug",
- "GroupMaskDebug",
- "EveryoneMaskDebug",
- "NextMaskDebug"
- };
- for(size_t t=0; tsetVisible(false);
- }
- }
-}
-
-void LLFloaterProperties::draw()
-{
- if (mDirty)
- {
- // RN: clear dirty first because refresh can set dirty to TRUE
- mDirty = FALSE;
- refresh();
- }
-
- LLFloater::draw();
-}
-
-void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
-{
- ////////////////////////
- // PERMISSIONS LOOKUP //
- ////////////////////////
-
- // do not enable the UI for incomplete items.
- LLViewerInventoryItem* i = (LLViewerInventoryItem*)item;
- BOOL is_complete = i->isFinished();
- const BOOL cannot_restrict_permissions = LLInventoryType::cannotRestrictPermissions(i->getInventoryType());
- const BOOL is_calling_card = (i->getInventoryType() == LLInventoryType::IT_CALLINGCARD);
- const LLPermissions& perm = item->getPermissions();
- const BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm,
- GP_OBJECT_MANIPULATE);
- const BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm,
- GP_OBJECT_SET_SALE) &&
- !cannot_restrict_permissions;
- const BOOL is_link = i->getIsLinkType();
-
- // You need permission to modify the object to modify an inventory
- // item in it.
- LLViewerObject* object = NULL;
- if(!mObjectID.isNull()) object = gObjectList.findObject(mObjectID);
- BOOL is_obj_modify = TRUE;
- if(object)
- {
- is_obj_modify = object->permOwnerModify();
- }
-
- //////////////////////
- // ITEM NAME & DESC //
- //////////////////////
- BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY, perm,
- GP_OBJECT_MANIPULATE)
- && is_obj_modify && is_complete;
-
- getChildView("LabelItemNameTitle")->setEnabled(TRUE);
- getChildView("LabelItemName")->setEnabled(is_modifiable && !is_calling_card); // for now, don't allow rename of calling cards
- getChild("LabelItemName")->setValue(item->getName());
- getChildView("LabelItemDescTitle")->setEnabled(TRUE);
- getChildView("LabelItemDesc")->setEnabled(is_modifiable);
- getChildView("IconLocked")->setVisible(!is_modifiable);
- getChild("LabelItemDesc")->setValue(item->getDescription());
-
- //////////////////
- // CREATOR NAME //
- //////////////////
- if(!gCacheName) return;
- if(!gAgent.getRegion()) return;
-
- if (item->getCreatorUUID().notNull())
- {
- LLAvatarName av_name;
- LLAvatarNameCache::get(item->getCreatorUUID(), &av_name);
- getChildView("BtnCreator")->setEnabled(TRUE);
- getChildView("LabelCreatorTitle")->setEnabled(TRUE);
- getChildView("LabelCreatorName")->setEnabled(TRUE);
- getChild("LabelCreatorName")->setValue(av_name.getUserName());
- }
- else
- {
- getChildView("BtnCreator")->setEnabled(FALSE);
- getChildView("LabelCreatorTitle")->setEnabled(FALSE);
- getChildView("LabelCreatorName")->setEnabled(FALSE);
- getChild("LabelCreatorName")->setValue(getString("unknown"));
- }
-
- ////////////////
- // OWNER NAME //
- ////////////////
- if(perm.isOwned())
- {
- std::string name;
- if (perm.isGroupOwned())
- {
- gCacheName->getGroupName(perm.getGroup(), name);
- }
- else
- {
- LLAvatarName av_name;
- LLAvatarNameCache::get(perm.getOwner(), &av_name);
- name = av_name.getUserName();
- }
- getChildView("BtnOwner")->setEnabled(TRUE);
- getChildView("LabelOwnerTitle")->setEnabled(TRUE);
- getChildView("LabelOwnerName")->setEnabled(TRUE);
- getChild("LabelOwnerName")->setValue(name);
- }
- else
- {
- getChildView("BtnOwner")->setEnabled(FALSE);
- getChildView("LabelOwnerTitle")->setEnabled(FALSE);
- getChildView("LabelOwnerName")->setEnabled(FALSE);
- getChild("LabelOwnerName")->setValue(getString("public"));
- }
-
- //////////////////
- // ACQUIRE DATE //
- //////////////////
-
- time_t time_utc = item->getCreationDate();
- if (0 == time_utc)
- {
- getChild("LabelAcquiredDate")->setValue(getString("unknown"));
- }
- else
- {
- std::string timeStr = getString("acquiredDate");
- LLSD substitution;
- substitution["datetime"] = (S32) time_utc;
- LLStringUtil::format (timeStr, substitution);
- getChild("LabelAcquiredDate")->setValue(timeStr);
- }
-
- ///////////////////////
- // OWNER PERMISSIONS //
- ///////////////////////
- if(can_agent_manipulate)
- {
- getChild("OwnerLabel")->setValue(getString("you_can"));
- }
- else
- {
- getChild("OwnerLabel")->setValue(getString("owner_can"));
- }
-
- U32 base_mask = perm.getMaskBase();
- U32 owner_mask = perm.getMaskOwner();
- U32 group_mask = perm.getMaskGroup();
- U32 everyone_mask = perm.getMaskEveryone();
- U32 next_owner_mask = perm.getMaskNextOwner();
-
- getChildView("OwnerLabel")->setEnabled(TRUE);
- getChildView("CheckOwnerModify")->setEnabled(FALSE);
- getChild("CheckOwnerModify")->setValue(LLSD((BOOL)(owner_mask & PERM_MODIFY)));
- getChildView("CheckOwnerCopy")->setEnabled(FALSE);
- getChild("CheckOwnerCopy")->setValue(LLSD((BOOL)(owner_mask & PERM_COPY)));
- getChildView("CheckOwnerTransfer")->setEnabled(FALSE);
- getChild("CheckOwnerTransfer")->setValue(LLSD((BOOL)(owner_mask & PERM_TRANSFER)));
-
- ///////////////////////
- // DEBUG PERMISSIONS //
- ///////////////////////
-
- if( gSavedSettings.getBOOL("DebugPermissions") )
- {
- BOOL slam_perm = FALSE;
- BOOL overwrite_group = FALSE;
- BOOL overwrite_everyone = FALSE;
-
- if (item->getType() == LLAssetType::AT_OBJECT)
- {
- U32 flags = item->getFlags();
- slam_perm = flags & LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_PERM;
- overwrite_everyone = flags & LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
- overwrite_group = flags & LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
- }
-
- std::string perm_string;
-
- perm_string = "B: ";
- perm_string += mask_to_string(base_mask);
- getChild("BaseMaskDebug")->setValue(perm_string);
- getChildView("BaseMaskDebug")->setVisible(TRUE);
-
- perm_string = "O: ";
- perm_string += mask_to_string(owner_mask);
- getChild("OwnerMaskDebug")->setValue(perm_string);
- getChildView("OwnerMaskDebug")->setVisible(TRUE);
-
- perm_string = "G";
- perm_string += overwrite_group ? "*: " : ": ";
- perm_string += mask_to_string(group_mask);
- getChild("GroupMaskDebug")->setValue(perm_string);
- getChildView("GroupMaskDebug")->setVisible(TRUE);
-
- perm_string = "E";
- perm_string += overwrite_everyone ? "*: " : ": ";
- perm_string += mask_to_string(everyone_mask);
- getChild("EveryoneMaskDebug")->setValue(perm_string);
- getChildView("EveryoneMaskDebug")->setVisible(TRUE);
-
- perm_string = "N";
- perm_string += slam_perm ? "*: " : ": ";
- perm_string += mask_to_string(next_owner_mask);
- getChild("NextMaskDebug")->setValue(perm_string);
- getChildView("NextMaskDebug")->setVisible(TRUE);
- }
- else
- {
- getChildView("BaseMaskDebug")->setVisible(FALSE);
- getChildView("OwnerMaskDebug")->setVisible(FALSE);
- getChildView("GroupMaskDebug")->setVisible(FALSE);
- getChildView("EveryoneMaskDebug")->setVisible(FALSE);
- getChildView("NextMaskDebug")->setVisible(FALSE);
- }
-
- /////////////
- // SHARING //
- /////////////
-
- // Check for ability to change values.
- if (is_link || cannot_restrict_permissions)
- {
- getChildView("CheckShareWithGroup")->setEnabled(FALSE);
- getChildView("CheckEveryoneCopy")->setEnabled(FALSE);
- }
- else if (is_obj_modify && can_agent_manipulate)
- {
- getChildView("CheckShareWithGroup")->setEnabled(TRUE);
- getChildView("CheckEveryoneCopy")->setEnabled((owner_mask & PERM_COPY) && (owner_mask & PERM_TRANSFER));
- }
- else
- {
- getChildView("CheckShareWithGroup")->setEnabled(FALSE);
- getChildView("CheckEveryoneCopy")->setEnabled(FALSE);
- }
-
- // Set values.
- BOOL is_group_copy = (group_mask & PERM_COPY) ? TRUE : FALSE;
- BOOL is_group_modify = (group_mask & PERM_MODIFY) ? TRUE : FALSE;
- BOOL is_group_move = (group_mask & PERM_MOVE) ? TRUE : FALSE;
-
- if (is_group_copy && is_group_modify && is_group_move)
- {
- getChild("CheckShareWithGroup")->setValue(LLSD((BOOL)TRUE));
-
- LLCheckBoxCtrl* ctl = getChild("CheckShareWithGroup");
- if(ctl)
- {
- ctl->setTentative(FALSE);
- }
- }
- else if (!is_group_copy && !is_group_modify && !is_group_move)
- {
- getChild("CheckShareWithGroup")->setValue(LLSD((BOOL)FALSE));
- LLCheckBoxCtrl* ctl = getChild("CheckShareWithGroup");
- if(ctl)
- {
- ctl->setTentative(FALSE);
- }
- }
- else
- {
- LLCheckBoxCtrl* ctl = getChild("CheckShareWithGroup");
- if(ctl)
- {
- ctl->setTentative(TRUE);
- ctl->set(TRUE);
- }
- }
-
- getChild("CheckEveryoneCopy")->setValue(LLSD((BOOL)(everyone_mask & PERM_COPY)));
-
- ///////////////
- // SALE INFO //
- ///////////////
-
- const LLSaleInfo& sale_info = item->getSaleInfo();
- BOOL is_for_sale = sale_info.isForSale();
- LLComboBox* combo_sale_type = getChild("ComboBoxSaleType");
- LLUICtrl* edit_cost = getChild("Edit Cost");
-
- // Check for ability to change values.
- if (is_obj_modify && can_agent_sell
- && gAgent.allowOperation(PERM_TRANSFER, perm, GP_OBJECT_MANIPULATE))
- {
- getChildView("CheckPurchase")->setEnabled(is_complete);
-
- getChildView("NextOwnerLabel")->setEnabled(TRUE);
- getChildView("CheckNextOwnerModify")->setEnabled((base_mask & PERM_MODIFY) && !cannot_restrict_permissions);
- getChildView("CheckNextOwnerCopy")->setEnabled((base_mask & PERM_COPY) && !cannot_restrict_permissions);
- getChildView("CheckNextOwnerTransfer")->setEnabled((next_owner_mask & PERM_COPY) && !cannot_restrict_permissions);
-
- combo_sale_type->setEnabled(is_complete && is_for_sale);
- edit_cost->setEnabled(is_complete && is_for_sale);
- }
- else
- {
- getChildView("CheckPurchase")->setEnabled(FALSE);
-
- getChildView("NextOwnerLabel")->setEnabled(FALSE);
- getChildView("CheckNextOwnerModify")->setEnabled(FALSE);
- getChildView("CheckNextOwnerCopy")->setEnabled(FALSE);
- getChildView("CheckNextOwnerTransfer")->setEnabled(FALSE);
-
- combo_sale_type->setEnabled(FALSE);
- edit_cost->setEnabled(FALSE);
- }
-
- // Set values.
- getChild("CheckPurchase")->setValue(is_for_sale);
- getChild("CheckNextOwnerModify")->setValue(LLSD(BOOL(next_owner_mask & PERM_MODIFY)));
- getChild("CheckNextOwnerCopy")->setValue(LLSD(BOOL(next_owner_mask & PERM_COPY)));
- getChild("CheckNextOwnerTransfer")->setValue(LLSD(BOOL(next_owner_mask & PERM_TRANSFER)));
-
- if (is_for_sale)
- {
- S32 numerical_price;
- numerical_price = sale_info.getSalePrice();
- edit_cost->setValue(llformat("%d",numerical_price));
- combo_sale_type->setValue(sale_info.getSaleType());
- }
- else
- {
- edit_cost->setValue(llformat("%d",0));
- combo_sale_type->setValue(LLSaleInfo::FS_COPY);
- }
-}
-
-void LLFloaterProperties::onClickCreator()
-{
- LLInventoryItem* item = findItem();
- if(!item) return;
- if(!item->getCreatorUUID().isNull())
- {
- LLAvatarActions::showProfile(item->getCreatorUUID());
- }
-}
-
-// static
-void LLFloaterProperties::onClickOwner()
-{
- LLInventoryItem* item = findItem();
- if(!item) return;
- if(item->getPermissions().isGroupOwned())
- {
- LLGroupActions::show(item->getPermissions().getGroup());
- }
- else
- {
- LLAvatarActions::showProfile(item->getPermissions().getOwner());
- }
-}
-
-// static
-void LLFloaterProperties::onCommitName()
-{
- //LL_INFOS() << "LLFloaterProperties::onCommitName()" << LL_ENDL;
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
- if(!item)
- {
- return;
- }
- LLLineEditor* labelItemName = getChild("LabelItemName");
-
- if(labelItemName&&
- (item->getName() != labelItemName->getText()) &&
- (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)) )
- {
- LLPointer new_item = new LLViewerInventoryItem(item);
- new_item->rename(labelItemName->getText());
- if(mObjectID.isNull())
- {
- new_item->updateServer(FALSE);
- gInventory.updateItem(new_item);
- gInventory.notifyObservers();
- }
- else
- {
- LLViewerObject* object = gObjectList.findObject(mObjectID);
- if(object)
- {
- object->updateInventory(
- new_item,
- TASK_INVENTORY_ITEM_KEY,
- false);
- }
- }
- }
-}
-
-void LLFloaterProperties::onCommitDescription()
-{
- //LL_INFOS() << "LLFloaterProperties::onCommitDescription()" << LL_ENDL;
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
- if(!item) return;
-
- LLLineEditor* labelItemDesc = getChild("LabelItemDesc");
- if(!labelItemDesc)
- {
- return;
- }
- if((item->getDescription() != labelItemDesc->getText()) &&
- (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)))
- {
- LLPointer new_item = new LLViewerInventoryItem(item);
-
- new_item->setDescription(labelItemDesc->getText());
- if(mObjectID.isNull())
- {
- new_item->updateServer(FALSE);
- gInventory.updateItem(new_item);
- gInventory.notifyObservers();
- }
- else
- {
- LLViewerObject* object = gObjectList.findObject(mObjectID);
- if(object)
- {
- object->updateInventory(
- new_item,
- TASK_INVENTORY_ITEM_KEY,
- false);
- }
- }
- }
-}
-
-// static
-void LLFloaterProperties::onCommitPermissions()
-{
- //LL_INFOS() << "LLFloaterProperties::onCommitPermissions()" << LL_ENDL;
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
- if(!item) return;
- LLPermissions perm(item->getPermissions());
-
-
- LLCheckBoxCtrl* CheckShareWithGroup = getChild("CheckShareWithGroup");
-
- if(CheckShareWithGroup)
- {
- perm.setGroupBits(gAgent.getID(), gAgent.getGroupID(),
- CheckShareWithGroup->get(),
- PERM_MODIFY | PERM_MOVE | PERM_COPY);
- }
- LLCheckBoxCtrl* CheckEveryoneCopy = getChild("CheckEveryoneCopy");
- if(CheckEveryoneCopy)
- {
- perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(),
- CheckEveryoneCopy->get(), PERM_COPY);
- }
-
- LLCheckBoxCtrl* CheckNextOwnerModify = getChild("CheckNextOwnerModify");
- if(CheckNextOwnerModify)
- {
- perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
- CheckNextOwnerModify->get(), PERM_MODIFY);
- }
- LLCheckBoxCtrl* CheckNextOwnerCopy = getChild("CheckNextOwnerCopy");
- if(CheckNextOwnerCopy)
- {
- perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
- CheckNextOwnerCopy->get(), PERM_COPY);
- }
- LLCheckBoxCtrl* CheckNextOwnerTransfer = getChild("CheckNextOwnerTransfer");
- if(CheckNextOwnerTransfer)
- {
- perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
- CheckNextOwnerTransfer->get(), PERM_TRANSFER);
- }
- if(perm != item->getPermissions()
- && item->isFinished())
- {
- LLPointer new_item = new LLViewerInventoryItem(item);
- new_item->setPermissions(perm);
- U32 flags = new_item->getFlags();
- // If next owner permissions have changed (and this is an object)
- // then set the slam permissions flag so that they are applied on rez.
- if((perm.getMaskNextOwner()!=item->getPermissions().getMaskNextOwner())
- && (item->getType() == LLAssetType::AT_OBJECT))
- {
- flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_PERM;
- }
- // If everyone permissions have changed (and this is an object)
- // then set the overwrite everyone permissions flag so they
- // are applied on rez.
- if ((perm.getMaskEveryone()!=item->getPermissions().getMaskEveryone())
- && (item->getType() == LLAssetType::AT_OBJECT))
- {
- flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
- }
- // If group permissions have changed (and this is an object)
- // then set the overwrite group permissions flag so they
- // are applied on rez.
- if ((perm.getMaskGroup()!=item->getPermissions().getMaskGroup())
- && (item->getType() == LLAssetType::AT_OBJECT))
- {
- flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
- }
- new_item->setFlags(flags);
- if(mObjectID.isNull())
- {
- new_item->updateServer(FALSE);
- gInventory.updateItem(new_item);
- gInventory.notifyObservers();
- }
- else
- {
- LLViewerObject* object = gObjectList.findObject(mObjectID);
- if(object)
- {
- object->updateInventory(
- new_item,
- TASK_INVENTORY_ITEM_KEY,
- false);
- }
- }
- }
- else
- {
- // need to make sure we don't just follow the click
- refresh();
- }
-}
-
-// static
-void LLFloaterProperties::onCommitSaleInfo()
-{
- //LL_INFOS() << "LLFloaterProperties::onCommitSaleInfo()" << LL_ENDL;
- updateSaleInfo();
-}
-
-// static
-void LLFloaterProperties::onCommitSaleType()
-{
- //LL_INFOS() << "LLFloaterProperties::onCommitSaleType()" << LL_ENDL;
- updateSaleInfo();
-}
-
-void LLFloaterProperties::updateSaleInfo()
-{
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
- if(!item) return;
- LLSaleInfo sale_info(item->getSaleInfo());
- if(!gAgent.allowOperation(PERM_TRANSFER, item->getPermissions(), GP_OBJECT_SET_SALE))
- {
- getChild("CheckPurchase")->setValue(LLSD((BOOL)FALSE));
- }
-
- if((BOOL)getChild("CheckPurchase")->getValue())
- {
- // turn on sale info
- LLSaleInfo::EForSale sale_type = LLSaleInfo::FS_COPY;
-
- LLComboBox* combo_sale_type = getChild("ComboBoxSaleType");
- if (combo_sale_type)
- {
- sale_type = static_cast(combo_sale_type->getValue().asInteger());
- }
-
- if (sale_type == LLSaleInfo::FS_COPY
- && !gAgent.allowOperation(PERM_COPY, item->getPermissions(),
- GP_OBJECT_SET_SALE))
- {
- sale_type = LLSaleInfo::FS_ORIGINAL;
- }
-
-
-
- S32 price = -1;
- price = getChild("Edit Cost")->getValue().asInteger();;
-
- // Invalid data - turn off the sale
- if (price < 0)
- {
- sale_type = LLSaleInfo::FS_NOT;
- price = 0;
- }
-
- sale_info.setSaleType(sale_type);
- sale_info.setSalePrice(price);
- }
- else
- {
- sale_info.setSaleType(LLSaleInfo::FS_NOT);
- }
- if(sale_info != item->getSaleInfo()
- && item->isFinished())
- {
- LLPointer new_item = new LLViewerInventoryItem(item);
-
- // Force an update on the sale price at rez
- if (item->getType() == LLAssetType::AT_OBJECT)
- {
- U32 flags = new_item->getFlags();
- flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_SALE;
- new_item->setFlags(flags);
- }
-
- new_item->setSaleInfo(sale_info);
- if(mObjectID.isNull())
- {
- // This is in the agent's inventory.
- new_item->updateServer(FALSE);
- gInventory.updateItem(new_item);
- gInventory.notifyObservers();
- }
- else
- {
- // This is in an object's contents.
- LLViewerObject* object = gObjectList.findObject(mObjectID);
- if(object)
- {
- object->updateInventory(
- new_item,
- TASK_INVENTORY_ITEM_KEY,
- false);
- }
- }
- }
- else
- {
- // need to make sure we don't just follow the click
- refresh();
- }
-}
-
-LLInventoryItem* LLFloaterProperties::findItem() const
-{
- LLInventoryItem* item = NULL;
- if(mObjectID.isNull())
- {
- // it is in agent inventory
- item = gInventory.getItem(mItemID);
- }
- else
- {
- LLViewerObject* object = gObjectList.findObject(mObjectID);
- if(object)
- {
- item = (LLInventoryItem*)object->getInventoryObject(mItemID);
- }
- }
- return item;
-}
-
-//static
-void LLFloaterProperties::dirtyAll()
-{
- LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("properties");
- for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin();
- iter != inst_list.end(); ++iter)
- {
- LLFloaterProperties* floater = dynamic_cast(*iter);
- llassert(floater); // else cast failed - wrong type D:
- if (floater)
- {
- floater->dirty();
- }
- }
-}
-
-///----------------------------------------------------------------------------
-/// LLMultiProperties
-///----------------------------------------------------------------------------
-
-LLMultiProperties::LLMultiProperties()
- : LLMultiFloater(LLSD())
-{
- // start with a small rect in the top-left corner ; will get resized
- LLRect rect;
- rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 20, 20);
- setRect(rect);
- LLFloater* last_floater = LLFloaterReg::getLastFloaterInGroup("properties");
- if (last_floater)
- {
- stackWith(*last_floater);
- }
- setTitle(LLTrans::getString("MultiPropertiesTitle"));
- buildTabContainer();
-}
-
-///----------------------------------------------------------------------------
-/// Local function definitions
-///----------------------------------------------------------------------------
diff --git a/indra/newview/llfloaterproperties.h b/indra/newview/llfloaterproperties.h
deleted file mode 100644
index aa3fcec337..0000000000
--- a/indra/newview/llfloaterproperties.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * @file llfloaterproperties.h
- * @brief A floater which shows an inventory item's properties.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLFLOATERPROPERTIES_H
-#define LL_LLFLOATERPROPERTIES_H
-
-#include