From a4acd02e10aef0c25e1bfbc026aad49e114e9624 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 5 Dec 2017 17:38:43 +0100 Subject: [PATCH 01/75] Add some more debug messages to the LSL bridge --- indra/newview/fslslbridge.cpp | 37 +++++++++++++++++++++++++++-------- indra/newview/llstartup.cpp | 9 ++++++++- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/indra/newview/fslslbridge.cpp b/indra/newview/fslslbridge.cpp index 752d28aad8..296967ca62 100644 --- a/indra/newview/fslslbridge.cpp +++ b/indra/newview/fslslbridge.cpp @@ -536,6 +536,8 @@ void FSLSLBridge::recreateBridge() void FSLSLBridge::cleanUpPreCreation() { + LL_INFOS("FSLSLBridge") << "Starting clean up prior creation - bridge category has been loaded" << LL_ENDL; + LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; NameCollectFunctor namefunctor(mCurrentFullName); @@ -547,6 +549,7 @@ void FSLSLBridge::cleanUpPreCreation() LLUUID item_id= (*it)->getUUID(); if (get_is_item_worn(item_id)) { + LL_INFOS("FSLSLBridge") << "Found worn object " << item_id << " bridge category - detaching..." << LL_ENDL; mAllowedDetachables.push_back(item_id); LLVOAvatarSelf::detachAttachmentIntoInventory(item_id); } @@ -556,14 +559,21 @@ void FSLSLBridge::cleanUpPreCreation() // any attachments we need to wait for until they got detached if (mAllowedDetachables.size() == 0) { + LL_INFOS("FSLSLBridge") << "Not waiting for any objects to get detached. Starting pre-creation cleanup immediately" << LL_ENDL; finishCleanUpPreCreation(); } + else + { + LL_INFOS("FSLSLBridge") << "Waiting for any objects to get detached. Pre-creation cleanup will start after objects got detached" << LL_ENDL; + } } // Called either by cleanUpPreCreation directly or via FSLSLBridgeStartCreationTimer // after all pending detachments have been processed void FSLSLBridge::finishCleanUpPreCreation() { + LL_INFOS("FSLSLBridge") << "Finishing cleanup prior creation" << LL_ENDL; + LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; NameCollectFunctor namefunctor(mCurrentFullName); @@ -571,13 +581,14 @@ void FSLSLBridge::finishCleanUpPreCreation() for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) { - remove_inventory_object((*it)->getUUID(), NULL); + LL_INFOS("FSLSLBridge") << "Bridge folder cleanup: Deleting " << (*it)->getName() << " (" << (*it)->getUUID() << ")" << LL_ENDL; + remove_inventory_item((*it)->getUUID(), NULL, true); // Don't wait for callback from server to update inventory model } gInventory.notifyObservers(); // clear the stored bridge ID - we are starting over. mpBridge = NULL; //the object itself will get cleaned up when new one is created. - mCurrentURL = ""; + mCurrentURL.clear(); setBridgeCreating(true); mFinishCreation = false; @@ -755,6 +766,8 @@ void FSLSLBridge::processAttach(LLViewerObject* object, const LLViewerJointAttac if (!mpBridge) //user is attaching an existing bridge? { + LL_INFOS("FSLSLBridge") << "mpBridge is NULL" << LL_ENDL; + //is it the right version? if (fsObject->getName() != mCurrentFullName) { @@ -787,8 +800,7 @@ void FSLSLBridge::processAttach(LLViewerObject* object, const LLViewerJointAttac mpBridge = fsObject; } - LL_DEBUGS("FSLSLBridge") << "Bridge container is attached, mpBridge not NULL, avatar is self, point is bridge, all is good." << LL_ENDL; - + LL_INFOS("FSLSLBridge") << "Bridge container is attached, mpBridge not NULL, avatar is self, point is bridge, all is good." << LL_ENDL; if (fsObject->getUUID() != mpBridge->getUUID()) { @@ -1228,7 +1240,7 @@ void FSLSLBridgeScriptCallback::fire(const LLUUID& inv_item) FSLSLBridge::instance().cleanUpBridge(); //also clean up script remains - remove_inventory_object(item->getUUID(), NULL); + remove_inventory_item(item->getUUID(), NULL, true); gInventory.notifyObservers(); LL_WARNS("FSLSLBridge") << "Can't update bridge script. Purging bridge." << LL_ENDL; return; @@ -1331,7 +1343,7 @@ void FSLSLBridge::cleanUpBridge() if (isBridgeValid()) { - remove_inventory_object(mpBridge->getUUID(), NULL); + remove_inventory_item(mpBridge->getUUID(), NULL, true); } gInventory.notifyObservers(); @@ -1348,10 +1360,18 @@ void FSLSLBridge::finishBridge() mIsFirstCallDone = false; cleanUpOldVersions(); cleanUpBridgeFolder(); + LL_INFOS("FSLSLBridge") << "Bridge cleaned up. Detaching bridge" << LL_ENDL; mAllowDetach = true; mFinishCreation = true; - LLVOAvatarSelf::detachAttachmentIntoInventory(getBridge()->getUUID()); + if (getBridge()) + { + LLVOAvatarSelf::detachAttachmentIntoInventory(getBridge()->getUUID()); + } + else + { + LL_WARNS("FSLSLBridge") << "Cannot detach bridge - mpBridge = NULL" << LL_ENDL; + } } // @@ -1507,7 +1527,8 @@ void FSLSLBridge::cleanUpBridgeFolder(const std::string& nameToCleanUp) const LLViewerInventoryItem* itemp = *it; if (!itemp->getIsLinkType() && (itemp->getUUID() != mpBridge->getUUID())) { - remove_inventory_object(itemp->getUUID(), NULL); + LL_INFOS("FSLSLBridge") << "Bridge folder cleanup: Deleting " << itemp->getName() << " (" << itemp->getUUID() << ")" << LL_ENDL; + remove_inventory_item(itemp->getUUID(), NULL, true); } } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 572f330320..e30bf28e87 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2895,7 +2895,14 @@ bool idle_startup() // Client LSL Bridge if (gSavedSettings.getBOOL("UseLSLBridge")) { - FSLSLBridge::instance().initBridge(); + if (!FSLSLBridge::instance().getBridgeCreating()) + { + FSLSLBridge::instance().initBridge(); + } + else + { + LL_INFOS("FSLSLBridge") << "LSL bridge already getting created - skipping bridge init" << LL_ENDL; + } } // From 0f9af6462d3502dc49e734ae6f832c9d3b487228 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 6 Dec 2017 09:46:16 +0100 Subject: [PATCH 02/75] Allow showing random MOTDs during TP Selection rules for MOTD: * if main MOTD is defined, show this at login and during TPs * if random MOTDs are defined and main MOTD not set, show a random MOTD at login and every TP * if event MOTD is defined, show event MOTD at login. For TPs, either show main MOTD if defined, or show a random MOTD if defined --- indra/newview/fsdata.cpp | 49 +++++++++++++++++++++++-------- indra/newview/fsdata.h | 21 +++++++------ indra/newview/llviewerdisplay.cpp | 2 ++ 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/indra/newview/fsdata.cpp b/indra/newview/fsdata.cpp index 8214443689..f7d4ae729d 100644 --- a/indra/newview/fsdata.cpp +++ b/indra/newview/fsdata.cpp @@ -390,15 +390,16 @@ void FSData::downloadAgents() void FSData::processData(const LLSD& fs_data) { // Set Message Of The Day if present - if(fs_data.has("MOTD")) + if (fs_data.has("MOTD") && !fs_data["MOTD"].asString().empty()) { - gAgent.mMOTD.assign(fs_data["MOTD"]); + mSecondLifeMOTD = fs_data["MOTD"]; + gAgent.mMOTD.assign(mSecondLifeMOTD); } - else if(fs_data.has("RandomMOTD")) // only used if MOTD is not presence in the xml file. + else if (fs_data.has("RandomMOTD") && fs_data["RandomMOTD"].isArray() && fs_data["RandomMOTD"].size() > 0) // only used if MOTD is not present or empty in the xml file. { - const LLSD& motd = fs_data["RandomMOTD"]; - LLSD::array_const_iterator iter = motd.beginArray(); - gAgent.mMOTD.assign((iter + (ll_rand((S32)motd.size())))->asString()); + mRandomMOTDs = fs_data["RandomMOTD"]; + LLSD::array_const_iterator iter = mRandomMOTDs.beginArray(); + gAgent.mMOTD.assign((iter + (ll_rand((S32)mRandomMOTDs.size())))->asString()); } // If the event falls withen the current date, use that for MOTD instead. @@ -419,12 +420,12 @@ void FSData::processData(const LLSD& fs_data) } } - if(fs_data.has("OpensimMOTD")) + if (fs_data.has("OpensimMOTD")) { - mOpensimMOTD.assign(fs_data["OpensimMOTD"]); + mOpenSimMOTD.assign(fs_data["OpensimMOTD"]); } - if(fs_data.has("BlockedReleases")) + if (fs_data.has("BlockedReleases")) { const LLSD& blocked = fs_data["BlockedReleases"]; for (LLSD::map_const_iterator iter = blocked.beginMap(); iter != blocked.endMap(); ++iter) @@ -441,24 +442,24 @@ void FSData::processData(const LLSD& fs_data) // FSUseLegacyClienttags: 0=Off, 1=Local Clienttags, 2=Download Clienttags static LLCachedControl use_legacy_tags(gSavedSettings, "FSUseLegacyClienttags"); - if(use_legacy_tags > 1) + if (use_legacy_tags > 1) { time_t last_modified = 0; llstat stat_data; - if(!LLFile::stat(mClientTagsFilename, &stat_data)) + if (!LLFile::stat(mClientTagsFilename, &stat_data)) { last_modified = stat_data.st_mtime; } LL_INFOS("fsdata") << "Downloading client_list_v2.xml from " << LEGACY_CLIENT_LIST_URL << " with last modified of " << last_modified << LL_ENDL; FSCoreHttpUtil::callbackHttpGet(LEGACY_CLIENT_LIST_URL, last_modified, boost::bind(downloadComplete, _1, LEGACY_CLIENT_LIST_URL, true), boost::bind(downloadComplete, _1, LEGACY_CLIENT_LIST_URL, false)); } - else if(use_legacy_tags) + else if (use_legacy_tags) { updateClientTagsLocal(); } // [RLVa:KB] - if ( (RlvActions::isRlvEnabled()) && (fs_data.has("rlva_compat_list")) ) + if ((RlvActions::isRlvEnabled()) && (fs_data.has("rlva_compat_list"))) { RlvSettings::initCompatibilityMode(fs_data["rlva_compat_list"].asString()); } @@ -551,6 +552,28 @@ void FSData::processClientTags(const LLSD& tags) } } +// Selection rules for MOTD: +// * if main MOTD is defined, show this at login and during TPs +// * if random MOTDs are defined and main MOTD not set, show a random MOTD +// at login and every TP +// * if event MOTD is defined, show event MOTD at login. For TPs, either +// show main MOTD if defined, or show a random MOTD if defined +void FSData::selectNextMOTD() +{ + if (LLGridManager::instance().isInSLMain()) + { + if (!mSecondLifeMOTD.empty()) + { + gAgent.mMOTD.assign(mSecondLifeMOTD); + } + else if (mRandomMOTDs.isArray() && mRandomMOTDs.size() > 0) + { + LLSD::array_const_iterator iter = mRandomMOTDs.beginArray(); + gAgent.mMOTD.assign((iter + (ll_rand((S32)mRandomMOTDs.size())))->asString()); + } + } +} + //WS: Create a new LLSD based on the data from the mLegacyClientList if LLSD FSData::resolveClientTag(const LLUUID& id, bool new_system, const LLColor4& color) { diff --git a/indra/newview/fsdata.h b/indra/newview/fsdata.h index 88c231130e..78bb3cd8df 100644 --- a/indra/newview/fsdata.h +++ b/indra/newview/fsdata.h @@ -40,7 +40,6 @@ class FSData : public LLSingleton virtual ~FSData(); public: - void startDownload(); void downloadAgents(); void processResponder(const LLSD& content, const std::string& url, bool save_to_file, const LLDate& last_modified); @@ -52,12 +51,12 @@ public: { SUPPORT = (1 << 0), //0x01 1 DEVELOPER = (1 << 1), //0x02 2 - QA = (1 << 2), //0x04 4 + QA = (1 << 2), //0x04 4 CHAT_COLOR = (1 << 3), //0x08 8 NO_SUPPORT = (1 << 4), //0x10 16 NO_USE = (1 << 5), //0x20 32 - NO_SPAM = (1 << 6), //0x40 64 - GATEWAY = (1 << 7), //0x80 128 + NO_SPAM = (1 << 6), //0x40 64 + GATEWAY = (1 << 7), //0x80 128 }; std::set mSupportGroup; @@ -76,7 +75,9 @@ public: static LLSD getSystemInfo(); static void callbackReqInfo(const LLSD ¬ification, const LLSD &response); - std::string getOpenSimMOTD() { return mOpensimMOTD; } + std::string getOpenSimMOTD() { return mOpenSimMOTD; } + void selectNextMOTD(); + bool getFSDataDone() { return mFSDataDone; } bool getAgentsDone() { return mAgentsDone; } @@ -98,21 +99,23 @@ private: LLSD mHeaders; LLSD mLegacyClientList; - + LLSD mRandomMOTDs; + std::string mFSdataFilename; std::string mFSdataDefaultsFilename; std::string mFSdataDefaultsUrl; std::string mAgentsFilename; std::string mAssestsFilename; std::string mClientTagsFilename; - + std::string mBaseURL; std::string mFSDataURL; std::string mAgentsURL; std::string mAssetsURL; - std::string mOpensimMOTD; - + std::string mSecondLifeMOTD; + std::string mOpenSimMOTD; + bool mLegacySearch; bool mFSDataDone; bool mAgentsDone; diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 9515d63c5d..4f4eb5a1a3 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -82,6 +82,7 @@ #include "rlvlocks.h" // [/RLVa:KB] #include "llpresetsmanager.h" +#include "fsdata.h" extern LLPointer gStartTexture; extern bool gShiftFrame; @@ -501,6 +502,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) gAgent.setTeleportMessage( LLAgent::sTeleportProgressMessages["requesting"]); gViewerWindow->setProgressString(LLAgent::sTeleportProgressMessages["requesting"]); + FSData::instance().selectNextMOTD(); gViewerWindow->setProgressMessage(gAgent.mMOTD); break; From 8a9eb53dc30e209e1a4d3dffb549c80cc2b7a0bb Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 6 Dec 2017 11:06:53 +0100 Subject: [PATCH 03/75] Fix typo in command line packager --- indra/newview/chatbar_as_cmdline.cpp | 261 +++++++++++++-------------- 1 file changed, 127 insertions(+), 134 deletions(-) diff --git a/indra/newview/chatbar_as_cmdline.cpp b/indra/newview/chatbar_as_cmdline.cpp index a8052fab0c..b2392b1fed 100644 --- a/indra/newview/chatbar_as_cmdline.cpp +++ b/indra/newview/chatbar_as_cmdline.cpp @@ -147,7 +147,6 @@ public: } } - private: std::stack mStack; LLUUID mDestination; @@ -236,143 +235,143 @@ public: BOOL tick() { + switch (mState) { - switch (mState) { - case ZTS_COUNTDOWN: - report_to_nearby_chat(llformat("%i...", mCountdown--)); - if (mCountdown == 0) mState = ZTS_SELECTION; - break; - - case ZTS_SELECTION: - for (LLObjectSelection::root_iterator itr = LLSelectMgr::getInstance()->getSelection()->root_begin(); - itr != LLSelectMgr::getInstance()->getSelection()->root_end(); ++itr) + case ZTS_COUNTDOWN: + report_to_nearby_chat(llformat("%i...", mCountdown--)); + if (mCountdown == 0) mState = ZTS_SELECTION; + break; + + case ZTS_SELECTION: + for (LLObjectSelection::root_iterator itr = LLSelectMgr::getInstance()->getSelection()->root_begin(); + itr != LLSelectMgr::getInstance()->getSelection()->root_end(); ++itr) + { + LLSelectNode* node = (*itr); + LLViewerObject* objectp = node->getObject(); + U32 localid = objectp->getLocalID(); + if (mDonePrims.find(localid) == mDonePrims.end()) { - LLSelectNode* node = (*itr); - LLViewerObject* objectp = node->getObject(); - U32 localid = objectp->getLocalID(); - if (mDonePrims.find(localid) == mDonePrims.end()) - { - mDonePrims.insert(localid); - mToTake.push_back(localid); - } + mDonePrims.insert(localid); + mToTake.push_back(localid); } - if (mToTake.size() > 0) mState = ZTS_TAKE; - break; - - case ZTS_TAKE: - if (mToTake.size() > 0) + } + if (mToTake.size() > 0) mState = ZTS_TAKE; + break; + + case ZTS_TAKE: + if (mToTake.size() > 0) + { + std::vector > inventory = findInventoryInFolder(mFolderName); + mPackSize = mToTake.size() + inventory.size(); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_DeRezObject); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgentID); + msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); + msg->nextBlockFast(_PREHASH_AgentBlock); + msg->addUUIDFast(_PREHASH_GroupID, LLUUID::null); + msg->addU8Fast(_PREHASH_Destination, mDest); + msg->addUUIDFast(_PREHASH_DestinationID, mTarget); + LLUUID rand; + rand.generate(); + msg->addUUIDFast(_PREHASH_TransactionID, rand); + msg->addU8Fast(_PREHASH_PacketCount, 1); + msg->addU8Fast(_PREHASH_PacketNumber, 0); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, mToTake[0]); + gAgent.sendReliableMessage(); + mToTake.erase(mToTake.begin()); + + if (mToTake.size() % 10 == 0) { - std::vector > inventory = findInventoryInFolder(mFolderName); - mPackSize = mToTake.size() + inventory.size(); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_DeRezObject); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgentID); - msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); - msg->nextBlockFast(_PREHASH_AgentBlock); - msg->addUUIDFast(_PREHASH_GroupID, LLUUID::null); - msg->addU8Fast(_PREHASH_Destination, mDest); - msg->addUUIDFast(_PREHASH_DestinationID, mTarget); - LLUUID rand; - rand.generate(); - msg->addUUIDFast(_PREHASH_TransactionID, rand); - msg->addU8Fast(_PREHASH_PacketCount, 1); - msg->addU8Fast(_PREHASH_PacketNumber, 0); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_ObjectLocalID, mToTake[0]); - gAgent.sendReliableMessage(); - mToTake.erase(mToTake.begin()); - - if (mToTake.size() % 10 == 0) + if (mToTake.size() == 0) { - if (mToTake.size() == 0) + if (mPackage) { - if (mPackage) + if (mPackageDest.notNull()) { - if (mPackageDest != LLUUID::null) - { - mPeriod = 1.0f; - mCountdown = 45; //reused for a basic timeout - mState = ZTS_DROP; - } - else - { - report_to_nearby_chat("Ktake has taken all selected objects."); - doZtCleanup(); - mState = ZTS_DONE; - } + mPeriod = 1.0f; + mCountdown = 45; //reused for a basic timeout + mState = ZTS_DROP; } else { - report_to_nearby_chat("Ztake has taken all selected objects. Say \"ztake off\" to deactivate ztake or select more objects to continue."); - } - } - else - { - if (mPackage) - { - report_to_nearby_chat(llformat("Packager: %i objects left to take.", mToTake.size())); - } - else - { - report_to_nearby_chat(llformat("Ztake: %i objects left to take.", mToTake.size())); + report_to_nearby_chat("Ktake has taken all selected objects."); + doZtCleanup(); + mState = ZTS_DONE; } } - } - } - else - { - if (mPackage) - { - report_to_nearby_chat(llformat("Packager: no objects to take.")); - doZtCleanup(); + else + { + report_to_nearby_chat("Ztake has taken all selected objects. Say \"ztake off\" to deactivate ztake or select more objects to continue."); + } } else { - report_to_nearby_chat(llformat("Ztake: no objects to take.")); - } - } - break; - - case ZTS_DROP: - { - mCountdown --; - - std::stack itemstack; - std::vector > inventory = findInventoryInFolder(mFolderName); - for (std::vector >::iterator it = inventory.begin(); it != inventory.end(); ++it) - { - LLViewerInventoryItem* item = *it; - itemstack.push(item); - } - - if (itemstack.size() >= mPackSize || mCountdown == 0) - { - if (itemstack.size() < mPackSize) { - report_to_nearby_chat("Phase 1 of the packager finished, but some items mave have been missed."); + if (mPackage) + { + report_to_nearby_chat(llformat("Packager: %i objects left to take.", mToTake.size())); } else { - report_to_nearby_chat("Phase 1 of the packager finished."); + report_to_nearby_chat(llformat("Ztake: %i objects left to take.", mToTake.size())); } - - report_to_nearby_chat("Do not have the destination prim selected while transfer is running to reduce the chances of \"Inventory creation on in-world object failed.\""); - - LLUUID sdest = LLUUID(mPackageDest); - new JCZdrop(itemstack, sdest, mFolderName.c_str(), mPackageDest.asString().c_str(), true); - - doZtCleanup(); - mState = ZTS_DONE; } } - break; + } + else + { + if (mPackage) + { + report_to_nearby_chat(llformat("Packager: no objects to take.")); + doZtCleanup(); + } + else + { + report_to_nearby_chat(llformat("Ztake: no objects to take.")); + } + } + break; - case ZTS_DONE: - /* nothing left to do */ - break; - } + case ZTS_DROP: + { + mCountdown --; + + std::stack itemstack; + std::vector > inventory = findInventoryInFolder(mFolderName); + for (std::vector >::iterator it = inventory.begin(); it != inventory.end(); ++it) + { + LLViewerInventoryItem* item = *it; + itemstack.push(item); + } + + if (itemstack.size() >= mPackSize || mCountdown == 0) + { + if (itemstack.size() < mPackSize) { + report_to_nearby_chat("Phase 1 of the packager finished, but some items mave have been missed."); + } + else + { + report_to_nearby_chat("Phase 1 of the packager finished."); + } + + report_to_nearby_chat("Do not have the destination prim selected while transfer is running to reduce the chances of \"Inventory creation on in-world object failed.\""); + + LLUUID sdest = LLUUID(mPackageDest); + new JCZdrop(itemstack, sdest, mFolderName.c_str(), mPackageDest.asString().c_str(), true); + + doZtCleanup(); + mState = ZTS_DONE; + } + } + break; + + case ZTS_DONE: + /* nothing left to do */ + break; } + return mRunning; } @@ -418,7 +417,6 @@ class TMZtake : public LLEventTimer public: BOOL mRunning; - TMZtake(const LLUUID& target) : LLEventTimer(0.33f), mTarget(target), mRunning(FALSE), mCountdown(5) { report_to_nearby_chat("Mtake activated. Taking selected in-world objects into inventory in: "); @@ -783,7 +781,7 @@ bool cmd_line_chat(const std::string& revised_text, EChatType type, bool from_ge } if ((!RlvActions::isRlvEnabled()) || (RlvActions::canSit(myObject, LLVector3::zero))) { - LLMessageSystem *msg = gMessageSystem; + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_AgentRequestSit); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgentID); @@ -830,7 +828,6 @@ bool cmd_line_chat(const std::string& revised_text, EChatType type, bool from_ge } return false; } - else if (command == sFSCmdLineGround()) { LLVector3 agentPos = gAgent.getPositionAgent(); @@ -911,7 +908,6 @@ bool cmd_line_chat(const std::string& revised_text, EChatType type, bool from_ge F32 result = 0.f; if (revised_text.length() > command.length() + 1) { - std::string expr = revised_text.substr(command.length()+1); LLStringUtil::toUpper(expr); std::string original_expr = expr; @@ -983,7 +979,7 @@ bool cmd_line_chat(const std::string& revised_text, EChatType type, bool from_ge else if (command == sFSCmdLineClearChat()) { - FSFloaterNearbyChat* chat = LLFloaterReg::getTypedInstance("fs_nearby_chat", LLSD()); + FSFloaterNearbyChat* chat = LLFloaterReg::findTypedInstance("fs_nearby_chat", LLSD()); if (chat) { chat->clearChatHistory(); @@ -1237,11 +1233,9 @@ bool cmd_line_chat(const std::string& revised_text, EChatType type, bool from_ge if (folder.notNull()) { std::vector to_take; - std::string take; while (i >> take) { - if (!LLUUID::validate(take)) { report_to_nearby_chat("Entered UUID is invalid! (Hint: use the \"copy key\" button in the build menu.)"); @@ -1265,7 +1259,7 @@ bool cmd_line_chat(const std::string& revised_text, EChatType type, bool from_ge } } } - + if (to_take.empty()) { report_to_nearby_chat("No objects to take."); @@ -1346,8 +1340,10 @@ bool cmd_line_chat(const std::string& revised_text, EChatType type, bool from_ge } return false; } - else if (command == "kpackagerstop") { - if (!cmd_line_mPackagerDest.isNull()) { + else if (command == "kpackagerstop") + { + if (!cmd_line_mPackagerDest.isNull()) + { cmd_line_mPackagerToTake.clear(); cmd_line_mPackagerTargetFolderName = ""; cmd_line_mPackagerTargetFolder.setNull(); @@ -1371,7 +1367,6 @@ bool cmd_line_chat(const std::string& revised_text, EChatType type, bool from_ge std::string take; while (i >> take) { - if (!LLUUID::validate(take)) { report_to_nearby_chat("Entered UUID is invalid! (Hint: use the \"copy key\" button in the build menu.)"); @@ -1395,7 +1390,7 @@ bool cmd_line_chat(const std::string& revised_text, EChatType type, bool from_ge } } } - + if (to_take.empty()) { report_to_nearby_chat("No objects to take."); @@ -1555,7 +1550,6 @@ bool cmd_line_chat(const std::string& revised_text, EChatType type, bool from_ge S32 die_penetrated = 0; while (die_iter <= dice) { - // Each die may have a different value rolled result_per_die = 1 + (rand() % faces); if (die_penetrated == 1) @@ -1774,17 +1768,16 @@ void cmdline_rezplat(bool use_saved_value, F32 visual_radius) //cmdline_rezplat( msg->sendReliable(gAgent.getRegionHost()); } -bool cmdline_packager(const std::string& message, const LLUUID& fromID, const LLUUID& ownerID) { - +bool cmdline_packager(const std::string& message, const LLUUID& fromID, const LLUUID& ownerID) +{ if (message.empty() || cmd_line_mPackagerDest.isNull() || fromID != cmd_line_mPackagerDest) { return false; } - + std::string cmd = message.substr(0, 12); - + if (cmd == "kpackageradd") { - // std::string csv = message.substr(13, -1); std::string::size_type start = 0; std::string::size_type comma = 0; @@ -1821,7 +1814,7 @@ bool cmdline_packager(const std::string& message, const LLUUID& fromID, const LL } else if (cmd == "kpackagerend") { - report_to_nearby_chat("Packager: finilizing."); + report_to_nearby_chat("Packager: finalizing."); ztake = new JCZtake(cmd_line_mPackagerTargetFolder, true, cmd_line_mPackagerDest, cmd_line_mPackagerTargetFolderName, DRD_ACQUIRE_TO_AGENT_INVENTORY, false, cmd_line_mPackagerToTake); cmd_line_mPackagerToTake.clear(); cmd_line_mPackagerTargetFolderName = ""; From ae15fbad42df0990337d3b4ff8adb7fd7422ba54 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 6 Dec 2017 11:32:28 +0100 Subject: [PATCH 04/75] Fix XUI parser warning: LLView::getChild: Making dummy class LLButton named "edit_wearable_btn" in panel_outfit_edit --- indra/newview/llpaneloutfitedit.cpp | 10 ++++++---- indra/newview/llpaneloutfitedit.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 580a7e1df0..e9a0d32034 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -539,10 +539,12 @@ BOOL LLPanelOutfitEdit::postBuild() mPlusBtn = getChild("plus_btn"); mPlusBtn->setClickedCallback(boost::bind(&LLPanelOutfitEdit::onPlusBtnClicked, this)); - mEditWearableBtn = getChild("edit_wearable_btn"); - mEditWearableBtn->setEnabled(FALSE); - mEditWearableBtn->setVisible(FALSE); - mEditWearableBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this)); + // Unused as of 06-12-2017 + //mEditWearableBtn = getChild("edit_wearable_btn"); + //mEditWearableBtn->setEnabled(FALSE); + //mEditWearableBtn->setVisible(FALSE); + //mEditWearableBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this)); + // childSetAction(REVERT_BTN, boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance())); diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index bf53ef9d61..c8b7033b6c 100644 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -217,7 +217,7 @@ private: LLFilterEditor* mSearchFilter; LLSaveFolderState* mSavedFolderState; std::string mSearchString; - LLButton* mEditWearableBtn; + //LLButton* mEditWearableBtn; // Unused as of 06-12-2017 LLButton* mFolderViewBtn; LLButton* mListViewBtn; LLButton* mPlusBtn; From 2bb855d13795672302486fef1e4fa5b132054dcf Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 6 Dec 2017 15:28:30 +0100 Subject: [PATCH 05/75] Fix a bunch of XUI warnings and as a result the long-standing bug of camera not switching properly when editing appearance LLView::getChild: Found child named "wearable_accordion" but of wrong type class LLTabContainer, expecting class LLAccordionCtrl * __ptr64 LLView::getChild: Making dummy class LLAccordionCtrl named "wearable_accordion" in edit_shape_panel LLView::getChild: Found child named "wearable_accordion" but of wrong type class LLTabContainer, expecting class LLAccordionCtrl * __ptr64 LLView::getChild: Making dummy class LLAccordionCtrl named "wearable_accordion" in edit_skin_panel LLView::getChild: Making dummy class LLAccordionCtrl named "wearable_accordion" in edit_eyes_panel LLView::getChild: Found child named "wearable_accordion" but of wrong type class LLTabContainer, expecting class LLAccordionCtrl * __ptr64 LLView::getChild: Making dummy class LLAccordionCtrl named "wearable_accordion" in edit_hair_panel LLView::getChild: Making dummy class LLAccordionCtrlTab named "shape_ears_tab" in panel_edit_wearable LLView::getChild: Making dummy class LLAccordionCtrlTab named "alpha_main_tab" in panel_edit_wearable LLView::getChild: Making dummy class LLAccordionCtrlTab named "tattoo_main_tab" in panel_edit_wearable LLView::getChild: Making dummy class LLAccordionCtrlTab named "physics_belly_updown_tab" in panel_edit_wearable LLView::getChild: Making dummy class LLAccordionCtrlTab named "physics_butt_updown_tab" in panel_edit_wearable --- indra/newview/llpaneleditwearable.cpp | 102 ++++++++++++++++-- indra/newview/llpaneleditwearable.h | 1 + .../ansastorm/xui/de/panel_edit_shape.xml | 2 +- .../ansastorm/xui/en/panel_edit_shape.xml | 2 +- .../ansastorm/xui/es/panel_edit_shape.xml | 2 +- .../ansastorm/xui/pl/panel_edit_shape.xml | 2 +- .../ansastorm/xui/ru/panel_edit_shape.xml | 2 +- .../firestorm/xui/de/panel_edit_shape.xml | 2 +- .../firestorm/xui/en/panel_edit_shape.xml | 2 +- .../firestorm/xui/es/panel_edit_shape.xml | 2 +- .../firestorm/xui/fr/panel_edit_shape.xml | 2 +- .../firestorm/xui/it/panel_edit_shape.xml | 2 +- .../firestorm/xui/pl/panel_edit_shape.xml | 2 +- .../firestorm/xui/ru/panel_edit_shape.xml | 2 +- .../skins/vintage/xui/en/panel_edit_shape.xml | 2 +- 15 files changed, 107 insertions(+), 22 deletions(-) diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index aee99a39d2..48822f0451 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -64,6 +64,7 @@ // [FS:CR] FIRE-10986 #include "llfilepicker.h" +#include "lltabcontainer.h" // register panel with appropriate XML static LLPanelInjector t_edit_wearable("panel_edit_wearable"); @@ -315,13 +316,21 @@ LLEditWearableDictionary::Subparts::Subparts() addEntry(SUBPART_GLOVES, new SubpartEntry(SUBPART_GLOVES, "mTorso", "gloves", "gloves_main_param_list", "gloves_main_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(-1.f, 0.15f, 0.f),SEX_BOTH)); addEntry(SUBPART_UNDERSHIRT, new SubpartEntry(SUBPART_UNDERSHIRT, "mTorso", "undershirt", "undershirt_main_param_list", "undershirt_main_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH)); addEntry(SUBPART_UNDERPANTS, new SubpartEntry(SUBPART_UNDERPANTS, "mPelvis", "underpants", "underpants_main_param_list", "underpants_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); - addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha", "alpha_main_param_list", "alpha_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); - addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", "tattoo_main_param_list", "tattoo_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + // Alpha and tattoo don't adhere to the usual panel layout and don't have a param list and main tab + //addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha", "alpha_main_param_list", "alpha_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + //addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", "tattoo_main_param_list", "tattoo_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha", "", "", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", "", "", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + // addEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, "mTorso", "physics_breasts_updown", "physics_breasts_updown_param_list", "physics_breasts_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_FEMALE)); addEntry(SUBPART_PHYSICS_BREASTS_INOUT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_INOUT, "mTorso", "physics_breasts_inout", "physics_breasts_inout_param_list", "physics_breasts_inout_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_FEMALE)); addEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, "mTorso", "physics_breasts_leftright", "physics_breasts_leftright_param_list", "physics_breasts_leftright_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_FEMALE)); - addEntry(SUBPART_PHYSICS_BELLY_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BELLY_UPDOWN, "mTorso", "physics_belly_updown", "physics_belly_updown_param_list", "physics_belly_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); - addEntry(SUBPART_PHYSICS_BUTT_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BUTT_UPDOWN, "mTorso", "physics_butt_updown", "physics_butt_updown_param_list", "physics_butt_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); + // Fix XUI warning + //addEntry(SUBPART_PHYSICS_BELLY_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BELLY_UPDOWN, "mTorso", "physics_belly_updown", "physics_belly_updown_param_list", "physics_belly_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); + //addEntry(SUBPART_PHYSICS_BUTT_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BUTT_UPDOWN, "mTorso", "physics_butt_updown", "physics_butt_updown_param_list", "physics_butt_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BELLY_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BELLY_UPDOWN, "mTorso", "physics_belly_updown", "physics_belly_updown_param_list", "physics_belly_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BUTT_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BUTT_UPDOWN, "mTorso", "physics_butt_updown", "physics_butt_updown_param_list", "physics_butt_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); + // addEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, "mTorso", "physics_butt_leftright", "physics_butt_leftright_param_list", "physics_butt_leftright_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); addEntry(SUBPART_PHYSICS_ADVANCED, new SubpartEntry(SUBPART_PHYSICS_ADVANCED, "mTorso", "physics_advanced", "physics_advanced_param_list", "physics_advanced_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); } @@ -748,10 +757,16 @@ BOOL LLPanelEditWearable::postBuild() // Setting the visibility callback is applied only to the bodyparts panel // because currently they are the only ones whose 'wearable_accordion' has // multiple accordion tabs (see EXT-8164 for details). - setWearablePanelVisibilityChangeCallback(mPanelShape); - setWearablePanelVisibilityChangeCallback(mPanelSkin); - setWearablePanelVisibilityChangeCallback(mPanelEyes); - setWearablePanelVisibilityChangeCallback(mPanelHair); + // Commenting out these calls fix XUI parser warnings. + // While it would be easy to fix those by using the correct + // widget classes, we comment it out because the LL default + // behavior is to always switch to the first tab when editing + // appearance which is highly annoying when fine-tuning shapes + //setWearablePanelVisibilityChangeCallback(mPanelShape); + //setWearablePanelVisibilityChangeCallback(mPanelSkin); + //setWearablePanelVisibilityChangeCallback(mPanelEyes); + //setWearablePanelVisibilityChangeCallback(mPanelHair); + // //clothes mPanelShirt = getChild("edit_shirt_panel"); @@ -788,6 +803,9 @@ BOOL LLPanelEditWearable::postBuild() continue; } U8 num_subparts = wearable_entry->mSubparts.size(); + + // Appearance panel not updating camera position + bool tab_container_cb_set = false; for (U8 index = 0; index < num_subparts; ++index) { @@ -803,7 +821,16 @@ BOOL LLPanelEditWearable::postBuild() const std::string accordion_tab = subpart_entry->mAccordionTab; - LLAccordionCtrlTab *tab = getChild(accordion_tab); + // Alpha and tattoo don't adhere to the usual panel layout and don't have a param list and main tab + // We can safely skip here as the wearables having no accordion tabs only have one sub-part, + // so no camera switch is needed + //LLAccordionCtrlTab *tab = getChild(accordion_tab); + if (accordion_tab.empty()) + { + continue; + } + LLAccordionCtrlTab *tab = findChild(accordion_tab); + // if (!tab) { @@ -813,6 +840,19 @@ BOOL LLPanelEditWearable::postBuild() // initialize callback to ensure camera view changes appropriately. tab->setDropDownStateChangedCallback(boost::bind(&LLPanelEditWearable::onTabExpandedCollapsed,this,_2,index)); + + // Appearance panel not updating camera position; Some skins use tabs - in this case + // set a callback on the tab container when the tab is changed to switch the camera position + if (!tab_container_cb_set) + { + LLTabContainer* tab_container = dynamic_cast(tab->getParent()->getParent()->getParent()); + if (tab_container) + { + tab_container->setCommitCallback(boost::bind(&LLPanelEditWearable::onTabChanged, this, _1, type)); + tab_container_cb_set = true; + } + } + // } // initialize texture and color picker controls @@ -1227,6 +1267,14 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO const std::string scrolling_panel = subpart_entry->mParamList; const std::string accordion_tab = subpart_entry->mAccordionTab; + + // Alpha and tattoo don't adhere to the usual panel layout and don't have a param list and main tab + // Since there are no sex-based differences, we can skip here + if (scrolling_panel.empty() || accordion_tab.empty()) + { + continue; + } + // LLScrollingPanelList *panel_list = getChild(scrolling_panel); LLAccordionCtrlTab *tab = getChild(accordion_tab); @@ -1306,6 +1354,42 @@ void LLPanelEditWearable::onTabExpandedCollapsed(const LLSD& param, U8 index) } +// Appearance panel not updating camera position +void LLPanelEditWearable::onTabChanged(LLUICtrl* ctrl, LLWearableType::EType type) +{ + LLTabContainer* container = dynamic_cast(ctrl); + if (!container) + { + return; + } + + if (!mWearablePtr || !gAgentCamera.cameraCustomizeAvatar()) + { + // we don't have a valid wearable we're editing, or we've left the wearable editor + return; + } + + const LLEditWearableDictionary::WearableEntry* wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type); + if (!wearable_entry) + { + return; + } + + U8 num_subparts = wearable_entry->mSubparts.size(); + for (U8 index = 0; index < num_subparts; ++index) + { + ESubpart subpart_e = wearable_entry->mSubparts[index]; + const LLEditWearableDictionary::SubpartEntry* subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + + if (subpart_entry && container->getCurrentPanel()->hasChild(subpart_entry->mAccordionTab, TRUE)) + { + changeCamera(index); + break; + } + } +} +// + void LLPanelEditWearable::changeCamera(U8 subpart) { // Don't change the camera if this type doesn't have a camera switch. diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h index 26983ad2fa..8d859dcc35 100644 --- a/indra/newview/llpaneleditwearable.h +++ b/indra/newview/llpaneleditwearable.h @@ -72,6 +72,7 @@ public: void showDefaultSubpart(); void onTabExpandedCollapsed(const LLSD& param, U8 index); + void onTabChanged(LLUICtrl* ctrl, LLWearableType::EType type); // Appearance panel not updating camera position void updateScrollingPanelList(); diff --git a/indra/newview/skins/ansastorm/xui/de/panel_edit_shape.xml b/indra/newview/skins/ansastorm/xui/de/panel_edit_shape.xml index 29508b30d2..21d7b18fd6 100644 --- a/indra/newview/skins/ansastorm/xui/de/panel_edit_shape.xml +++ b/indra/newview/skins/ansastorm/xui/de/panel_edit_shape.xml @@ -29,7 +29,7 @@ - + diff --git a/indra/newview/skins/ansastorm/xui/en/panel_edit_shape.xml b/indra/newview/skins/ansastorm/xui/en/panel_edit_shape.xml index a61a1d5c26..4a388598d6 100644 --- a/indra/newview/skins/ansastorm/xui/en/panel_edit_shape.xml +++ b/indra/newview/skins/ansastorm/xui/en/panel_edit_shape.xml @@ -184,7 +184,7 @@ header_visible="false" layout="topleft" min_height="150" - name="shape_head_tab" + name="shape_ears_tab" fit_panel="false" title="Ears"> diff --git a/indra/newview/skins/ansastorm/xui/es/panel_edit_shape.xml b/indra/newview/skins/ansastorm/xui/es/panel_edit_shape.xml index ba9c8a4553..d4e788056b 100644 --- a/indra/newview/skins/ansastorm/xui/es/panel_edit_shape.xml +++ b/indra/newview/skins/ansastorm/xui/es/panel_edit_shape.xml @@ -27,7 +27,7 @@ - + diff --git a/indra/newview/skins/ansastorm/xui/pl/panel_edit_shape.xml b/indra/newview/skins/ansastorm/xui/pl/panel_edit_shape.xml index e7f962d7c4..4815ed42b1 100644 --- a/indra/newview/skins/ansastorm/xui/pl/panel_edit_shape.xml +++ b/indra/newview/skins/ansastorm/xui/pl/panel_edit_shape.xml @@ -27,7 +27,7 @@ - + diff --git a/indra/newview/skins/ansastorm/xui/ru/panel_edit_shape.xml b/indra/newview/skins/ansastorm/xui/ru/panel_edit_shape.xml index 94b7e39aae..df88c137ff 100644 --- a/indra/newview/skins/ansastorm/xui/ru/panel_edit_shape.xml +++ b/indra/newview/skins/ansastorm/xui/ru/panel_edit_shape.xml @@ -27,7 +27,7 @@ - + diff --git a/indra/newview/skins/firestorm/xui/de/panel_edit_shape.xml b/indra/newview/skins/firestorm/xui/de/panel_edit_shape.xml index 29508b30d2..21d7b18fd6 100644 --- a/indra/newview/skins/firestorm/xui/de/panel_edit_shape.xml +++ b/indra/newview/skins/firestorm/xui/de/panel_edit_shape.xml @@ -29,7 +29,7 @@ - + diff --git a/indra/newview/skins/firestorm/xui/en/panel_edit_shape.xml b/indra/newview/skins/firestorm/xui/en/panel_edit_shape.xml index 7308778ee1..f00f6192b9 100644 --- a/indra/newview/skins/firestorm/xui/en/panel_edit_shape.xml +++ b/indra/newview/skins/firestorm/xui/en/panel_edit_shape.xml @@ -180,7 +180,7 @@ diff --git a/indra/newview/skins/firestorm/xui/es/panel_edit_shape.xml b/indra/newview/skins/firestorm/xui/es/panel_edit_shape.xml index 5473963097..ba764afbef 100644 --- a/indra/newview/skins/firestorm/xui/es/panel_edit_shape.xml +++ b/indra/newview/skins/firestorm/xui/es/panel_edit_shape.xml @@ -24,7 +24,7 @@ - + diff --git a/indra/newview/skins/firestorm/xui/fr/panel_edit_shape.xml b/indra/newview/skins/firestorm/xui/fr/panel_edit_shape.xml index d0136f3012..6dfc7d460a 100644 --- a/indra/newview/skins/firestorm/xui/fr/panel_edit_shape.xml +++ b/indra/newview/skins/firestorm/xui/fr/panel_edit_shape.xml @@ -21,7 +21,7 @@ - + diff --git a/indra/newview/skins/firestorm/xui/it/panel_edit_shape.xml b/indra/newview/skins/firestorm/xui/it/panel_edit_shape.xml index 7a5297d55f..56210c665d 100644 --- a/indra/newview/skins/firestorm/xui/it/panel_edit_shape.xml +++ b/indra/newview/skins/firestorm/xui/it/panel_edit_shape.xml @@ -24,7 +24,7 @@ - + diff --git a/indra/newview/skins/firestorm/xui/pl/panel_edit_shape.xml b/indra/newview/skins/firestorm/xui/pl/panel_edit_shape.xml index e7f962d7c4..4815ed42b1 100644 --- a/indra/newview/skins/firestorm/xui/pl/panel_edit_shape.xml +++ b/indra/newview/skins/firestorm/xui/pl/panel_edit_shape.xml @@ -27,7 +27,7 @@ - + diff --git a/indra/newview/skins/firestorm/xui/ru/panel_edit_shape.xml b/indra/newview/skins/firestorm/xui/ru/panel_edit_shape.xml index 94b7e39aae..df88c137ff 100644 --- a/indra/newview/skins/firestorm/xui/ru/panel_edit_shape.xml +++ b/indra/newview/skins/firestorm/xui/ru/panel_edit_shape.xml @@ -27,7 +27,7 @@ - + diff --git a/indra/newview/skins/vintage/xui/en/panel_edit_shape.xml b/indra/newview/skins/vintage/xui/en/panel_edit_shape.xml index 7308778ee1..f00f6192b9 100644 --- a/indra/newview/skins/vintage/xui/en/panel_edit_shape.xml +++ b/indra/newview/skins/vintage/xui/en/panel_edit_shape.xml @@ -180,7 +180,7 @@ From 81f242a2308262f87b0b392f9b8e6226f4159ff8 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 6 Dec 2017 15:45:35 +0100 Subject: [PATCH 06/75] Fix XUI warning: LLViewerTextureList::getImageFromFile: Failed to find local image file: PushButton_Disabled_Selected --- indra/newview/skins/default/xui/en/panel_scrolling_param.xml | 4 ++-- indra/newview/skins/default/xui/en/widgets/drop_down.xml | 2 +- indra/newview/skins/starlight/xui/en/widgets/drop_down.xml | 2 +- indra/newview/skins/starlightcui/xui/en/widgets/drop_down.xml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/indra/newview/skins/default/xui/en/panel_scrolling_param.xml b/indra/newview/skins/default/xui/en/panel_scrolling_param.xml index e1a1970ab2..f70b456777 100644 --- a/indra/newview/skins/default/xui/en/panel_scrolling_param.xml +++ b/indra/newview/skins/default/xui/en/panel_scrolling_param.xml @@ -84,7 +84,7 @@ enabled="false" height="132" image_disabled="PushButton_Disabled" - image_disabled_selected="PushButton_Disabled_Selected" + image_disabled_selected="PushButton_Selected_Disabled" image_selected="PushButton_Selected" image_unselected="PushButton_Off" layout="topleft" @@ -97,7 +97,7 @@ enabled="false" height="132" image_disabled="PushButton_Disabled" - image_disabled_selected="PushButton_Disabled_Selected" + image_disabled_selected="PushButton_Selected_Disabled" image_selected="PushButton_Selected" image_unselected="PushButton_Off" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/widgets/drop_down.xml b/indra/newview/skins/default/xui/en/widgets/drop_down.xml index e85a8b158c..df48eda814 100644 --- a/indra/newview/skins/default/xui/en/widgets/drop_down.xml +++ b/indra/newview/skins/default/xui/en/widgets/drop_down.xml @@ -12,7 +12,7 @@ image_unselected="PushButton_Off" image_selected="PushButton_Selected" image_disabled="PushButton_Disabled" - image_disabled_selected="PushButton_Disabled_Selected" + image_disabled_selected="PushButton_Selected_Disabled" image_overlay="Combobox_Over" image_overlay_alignment="right" /> diff --git a/indra/newview/skins/starlight/xui/en/widgets/drop_down.xml b/indra/newview/skins/starlight/xui/en/widgets/drop_down.xml index 0703b6ccef..5260e080cb 100644 --- a/indra/newview/skins/starlight/xui/en/widgets/drop_down.xml +++ b/indra/newview/skins/starlight/xui/en/widgets/drop_down.xml @@ -12,7 +12,7 @@ image_unselected="PushButton_Off" image_selected="PushButton_Selected" image_disabled="PushButton_Disabled" - image_disabled_selected="PushButton_Disabled_Selected" + image_disabled_selected="PushButton_Selected_Disabled" image_overlay="Combobox_Over" image_overlay_alignment="right" /> diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/drop_down.xml b/indra/newview/skins/starlightcui/xui/en/widgets/drop_down.xml index 0703b6ccef..5260e080cb 100644 --- a/indra/newview/skins/starlightcui/xui/en/widgets/drop_down.xml +++ b/indra/newview/skins/starlightcui/xui/en/widgets/drop_down.xml @@ -12,7 +12,7 @@ image_unselected="PushButton_Off" image_selected="PushButton_Selected" image_disabled="PushButton_Disabled" - image_disabled_selected="PushButton_Disabled_Selected" + image_disabled_selected="PushButton_Selected_Disabled" image_overlay="Combobox_Over" image_overlay_alignment="right" /> From 29c627746040d29eddfc70632dd8df4cc08fa1fa Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 6 Dec 2017 16:40:58 +0100 Subject: [PATCH 07/75] Remember and apply the correct camera position for the last subpart in appearance editor since we don't switch to the first subpart automatically --- indra/newview/llpaneleditwearable.cpp | 10 ++++++++++ indra/newview/llpaneleditwearable.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 48822f0451..71de6ae3aa 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1334,6 +1334,14 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO void LLPanelEditWearable::showDefaultSubpart() { + // Correct camera position for last subpart + std::map::iterator found = mLastShownSubpartIndex.find(mWearablePtr->getType()); + if (found != mLastShownSubpartIndex.end()) + { + changeCamera(found->second); + } + else + // changeCamera(0); } @@ -1349,6 +1357,7 @@ void LLPanelEditWearable::onTabExpandedCollapsed(const LLSD& param, U8 index) if (expanded) { + mLastShownSubpartIndex[mWearablePtr->getType()] = index; // Correct camera position for last subpart changeCamera(index); } @@ -1383,6 +1392,7 @@ void LLPanelEditWearable::onTabChanged(LLUICtrl* ctrl, LLWearableType::EType typ if (subpart_entry && container->getCurrentPanel()->hasChild(subpart_entry->mAccordionTab, TRUE)) { + mLastShownSubpartIndex[type] = index; // Correct camera position for last subpart changeCamera(index); break; } diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h index 8d859dcc35..b0d5623308 100644 --- a/indra/newview/llpaneleditwearable.h +++ b/indra/newview/llpaneleditwearable.h @@ -183,6 +183,8 @@ private: typedef std::map s32_uuid_map_t; s32_uuid_map_t mPreviousAlphaTexture; + + std::map mLastShownSubpartIndex; }; #endif From a5cb8fdbee72b5522975373eebde12aaeb832f19 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 6 Dec 2017 16:57:08 +0100 Subject: [PATCH 08/75] Sync LLImageJ2C for upcoming fix with LL --- indra/llimage/llimagej2c.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 43d6f730ff..1ee6deaa87 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -374,11 +374,6 @@ bool LLImageJ2C::loadAndValidate(const std::string &filename) else { U8 *data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), file_size); - if(!data) - { - LL_WARNS() << "couldn't allocate memory for loading file: " << filename << " size: " << file_size << LL_ENDL; - return FALSE; - } apr_size_t bytes_read = file_size; apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read infile.close() ; From 083b93d2f9da00c2471be5e737d501c9fe58667e Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Tue, 5 Dec 2017 17:54:17 +0200 Subject: [PATCH 09/75] MAINT-2124 Texture allocation issues --- indra/llimage/llimagej2c.cpp | 25 +++++++++++++------ indra/newview/lltexturecache.cpp | 43 ++++++++++++++++++++------------ indra/newview/lltexturefetch.cpp | 16 +++++++++--- 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 1ee6deaa87..08aea988db 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -374,19 +374,28 @@ bool LLImageJ2C::loadAndValidate(const std::string &filename) else { U8 *data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), file_size); - apr_size_t bytes_read = file_size; - apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read - infile.close() ; - - if (s != APR_SUCCESS || (S32)bytes_read != file_size) + if (!data) { - FREE_MEM(LLImageBase::getPrivatePool(), data); - setLastError("Unable to read entire file"); + infile.close(); + setLastError("Out of memory", filename); res = false; } else { - res = validate(data, file_size); + apr_size_t bytes_read = file_size; + apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read + infile.close(); + + if (s != APR_SUCCESS || (S32)bytes_read != file_size) + { + FREE_MEM(LLImageBase::getPrivatePool(), data); + setLastError("Unable to read entire file"); + res = false; + } + else + { + res = validate(data, file_size); + } } } diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 3f3a2691cf..2f6d023500 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -452,26 +452,37 @@ bool LLTextureCacheRemoteWorker::doRead() size = llmin(size, mDataSize); // Allocate the read buffer mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), size); - S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, - mReadData, offset, size, mCache->getLocalAPRFilePool()); - if (bytes_read != size) + if (mReadData) { - LL_WARNS() << "LLTextureCacheWorker: " << mID - << " incorrect number of bytes read from header: " << bytes_read - << " / " << size << LL_ENDL; - FREE_MEM(LLImageBase::getPrivatePool(), mReadData); - mReadData = NULL; - mDataSize = -1; // failed - done = true; - } - // If we already read all we expected, we're actually done - if (mDataSize <= bytes_read) - { - done = true; + S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, + mReadData, offset, size, mCache->getLocalAPRFilePool()); + if (bytes_read != size) + { + LL_WARNS() << "LLTextureCacheWorker: " << mID + << " incorrect number of bytes read from header: " << bytes_read + << " / " << size << LL_ENDL; + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); + mReadData = NULL; + mDataSize = -1; // failed + done = true; + } + // If we already read all we expected, we're actually done + if (mDataSize <= bytes_read) + { + done = true; + } + else + { + mState = BODY; + } } else { - mState = BODY; + LL_WARNS() << "LLTextureCacheWorker: " << mID + << " failed to allocate memory for reading: " << mDataSize << LL_ENDL; + mReadData = NULL; + mDataSize = -1; // failed + done = true; } } diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 69dbca1986..286dfe2f77 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1781,7 +1781,17 @@ bool LLTextureFetchWorker::doWork(S32 param) mRequestedSize -= src_offset; // Make requested values reflect useful part mRequestedOffset += src_offset; } - + + U8 * buffer = (U8 *)ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_size); + if (!buffer) + { + // abort. If we have no space for packet, we have not enough space to decode image + setState(DONE); + LL_WARNS(LOG_TXT) << mID << " abort: out of memory" << LL_ENDL; + releaseHttpSemaphore(); + return true; + } + if (mFormattedImage.isNull()) { // For now, create formatted image based on extension @@ -1801,10 +1811,10 @@ bool LLTextureFetchWorker::doWork(S32 param) { mFileSize = total_size + 1 ; //flag the file is not fully loaded. } - - U8 * buffer = (U8 *) ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_size); + if (cur_size > 0) { + // Copy previously collected data into buffer memcpy(buffer, mFormattedImage->getData(), cur_size); } mHttpBufferArray->read(src_offset, (char *) buffer + cur_size, append_size); From fd834b39d7ca0c74823b75130721651b09f82292 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 6 Dec 2017 17:15:16 +0100 Subject: [PATCH 10/75] Fix Linux build --- indra/newview/fsdata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/fsdata.cpp b/indra/newview/fsdata.cpp index f7d4ae729d..abd5b119aa 100644 --- a/indra/newview/fsdata.cpp +++ b/indra/newview/fsdata.cpp @@ -392,7 +392,7 @@ void FSData::processData(const LLSD& fs_data) // Set Message Of The Day if present if (fs_data.has("MOTD") && !fs_data["MOTD"].asString().empty()) { - mSecondLifeMOTD = fs_data["MOTD"]; + mSecondLifeMOTD = fs_data["MOTD"].asString(); gAgent.mMOTD.assign(mSecondLifeMOTD); } else if (fs_data.has("RandomMOTD") && fs_data["RandomMOTD"].isArray() && fs_data["RandomMOTD"].size() > 0) // only used if MOTD is not present or empty in the xml file. From 658d08aed53e3ad6cc436d17742d3e802e085f34 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Thu, 7 Dec 2017 00:00:14 +0100 Subject: [PATCH 11/75] Change SignaledTyped signal to pass the new value to the callback method --- indra/newview/lfsimfeaturehandler.cpp | 14 +++++++------- indra/newview/lfsimfeaturehandler.h | 21 +++++++++++---------- indra/newview/llfloateravatar.cpp | 6 +++--- indra/newview/llfloateravatar.h | 2 +- indra/newview/llfloaterdestinations.cpp | 8 ++++---- indra/newview/llfloaterdestinations.h | 2 +- 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/indra/newview/lfsimfeaturehandler.cpp b/indra/newview/lfsimfeaturehandler.cpp index 96a3473015..9838a1b365 100644 --- a/indra/newview/lfsimfeaturehandler.cpp +++ b/indra/newview/lfsimfeaturehandler.cpp @@ -271,37 +271,37 @@ void LFSimFeatureHandler::updateCurrencySymbols() } // -boost::signals2::connection LFSimFeatureHandler::setSupportsExportCallback(const boost::signals2::signal::slot_type& slot) +boost::signals2::connection LFSimFeatureHandler::setSupportsExportCallback(const SignaledType::changed_signal_t& slot) { return mSupportsExport.connect(slot); } -boost::signals2::connection LFSimFeatureHandler::setSearchURLCallback(const boost::signals2::signal::slot_type& slot) +boost::signals2::connection LFSimFeatureHandler::setSearchURLCallback(const SignaledType::changed_signal_t& slot) { return mSearchURL.connect(slot); } -boost::signals2::connection LFSimFeatureHandler::setSayRangeCallback(const boost::signals2::signal::slot_type& slot) +boost::signals2::connection LFSimFeatureHandler::setSayRangeCallback(const SignaledType::changed_signal_t& slot) { return mSayRange.connect(slot); } -boost::signals2::connection LFSimFeatureHandler::setShoutRangeCallback(const boost::signals2::signal::slot_type& slot) +boost::signals2::connection LFSimFeatureHandler::setShoutRangeCallback(const SignaledType::changed_signal_t& slot) { return mShoutRange.connect(slot); } -boost::signals2::connection LFSimFeatureHandler::setWhisperRangeCallback(const boost::signals2::signal::slot_type& slot) +boost::signals2::connection LFSimFeatureHandler::setWhisperRangeCallback(const SignaledType::changed_signal_t& slot) { return mWhisperRange.connect(slot); } -boost::signals2::connection LFSimFeatureHandler::setAvatarPickerCallback(const boost::signals2::signal::slot_type& slot) +boost::signals2::connection LFSimFeatureHandler::setAvatarPickerCallback(const SignaledType::changed_signal_t& slot) { return mAvatarPickerURL.connect(slot); } -boost::signals2::connection LFSimFeatureHandler::setDestinationGuideCallback(const boost::signals2::signal::slot_type& slot) +boost::signals2::connection LFSimFeatureHandler::setDestinationGuideCallback(const SignaledType::changed_signal_t& slot) { return mDestinationGuideURL.connect(slot); } diff --git a/indra/newview/lfsimfeaturehandler.h b/indra/newview/lfsimfeaturehandler.h index 6a2d600bb9..4fd3eb983e 100644 --- a/indra/newview/lfsimfeaturehandler.h +++ b/indra/newview/lfsimfeaturehandler.h @@ -21,21 +21,22 @@ #include "llsingleton.h" #include "llpermissions.h" // ExportPolicy -template > +template > class SignaledType { public: SignaledType() : mValue() {} SignaledType(Type b) : mValue(b) {} - boost::signals2::connection connect(const typename Signal::slot_type& slot) { return mSignal.connect(slot); } + typedef typename Signal::slot_type changed_signal_t; + boost::signals2::connection connect(const typename changed_signal_t& slot) { return mSignal.connect(slot); } SignaledType& operator =(Type val) { if (val != mValue) { mValue = val; - mSignal(); + mSignal(mValue); } return *this; } @@ -76,13 +77,13 @@ public: // // Connection setters - boost::signals2::connection setSupportsExportCallback(const boost::signals2::signal::slot_type& slot); - boost::signals2::connection setSearchURLCallback(const boost::signals2::signal::slot_type& slot); - boost::signals2::connection setSayRangeCallback(const boost::signals2::signal::slot_type& slot); - boost::signals2::connection setShoutRangeCallback(const boost::signals2::signal::slot_type& slot); - boost::signals2::connection setWhisperRangeCallback(const boost::signals2::signal::slot_type& slot); - boost::signals2::connection setAvatarPickerCallback(const boost::signals2::signal::slot_type& slot); - boost::signals2::connection setDestinationGuideCallback(const boost::signals2::signal::slot_type& slot); + boost::signals2::connection setSupportsExportCallback(const SignaledType::changed_signal_t& slot); + boost::signals2::connection setSearchURLCallback(const SignaledType::changed_signal_t& slot); + boost::signals2::connection setSayRangeCallback(const SignaledType::changed_signal_t& slot); + boost::signals2::connection setShoutRangeCallback(const SignaledType::changed_signal_t& slot); + boost::signals2::connection setWhisperRangeCallback(const SignaledType::changed_signal_t& slot); + boost::signals2::connection setAvatarPickerCallback(const SignaledType::changed_signal_t& slot); + boost::signals2::connection setDestinationGuideCallback(const SignaledType::changed_signal_t& slot); // Accessors bool simSupportsExport() const { return mSupportsExport; } diff --git a/indra/newview/llfloateravatar.cpp b/indra/newview/llfloateravatar.cpp index 63ddcee7ef..d5f341e705 100644 --- a/indra/newview/llfloateravatar.cpp +++ b/indra/newview/llfloateravatar.cpp @@ -80,13 +80,13 @@ void LLFloaterAvatar::onOpen(const LLSD& key) // region the avatar logs into as well. if (!mAvatarPickerUrlChangedSignal.connected()) { - mAvatarPickerUrlChangedSignal = LFSimFeatureHandler::instance().setAvatarPickerCallback(boost::bind(&LLFloaterAvatar::handleUrlChanged, this)); + mAvatarPickerUrlChangedSignal = LFSimFeatureHandler::instance().setAvatarPickerCallback(boost::bind(&LLFloaterAvatar::handleUrlChanged, this, _1)); } } -void LLFloaterAvatar::handleUrlChanged() +void LLFloaterAvatar::handleUrlChanged(const std::string& url) { - getChild("avatar_picker_contents")->navigateTo(LLWeb::expandURLSubstitutions(LFSimFeatureHandler::instance().avatarPickerURL(), LLSD()), HTTP_CONTENT_TEXT_HTML); + getChild("avatar_picker_contents")->navigateTo(LLWeb::expandURLSubstitutions(url, LLSD()), HTTP_CONTENT_TEXT_HTML); } // diff --git a/indra/newview/llfloateravatar.h b/indra/newview/llfloateravatar.h index 6f9d6413ec..331a6b5ade 100644 --- a/indra/newview/llfloateravatar.h +++ b/indra/newview/llfloateravatar.h @@ -41,7 +41,7 @@ private: // Avatar chooser does not change between OpenSim grids /*virtual*/ void onOpen(const LLSD& key); - void handleUrlChanged(); + void handleUrlChanged(const std::string& url); boost::signals2::connection mAvatarPickerUrlChangedSignal; // diff --git a/indra/newview/llfloaterdestinations.cpp b/indra/newview/llfloaterdestinations.cpp index f1aaa8c3f6..e8a6a478ff 100644 --- a/indra/newview/llfloaterdestinations.cpp +++ b/indra/newview/llfloaterdestinations.cpp @@ -72,14 +72,14 @@ void LLFloaterDestinations::onOpen(const LLSD& key) // region the avatar logs into as well. if (!mDestinationGuideUrlChangedSignal.connected()) { - mDestinationGuideUrlChangedSignal = LFSimFeatureHandler::instance().setDestinationGuideCallback(boost::bind(&LLFloaterDestinations::handleUrlChanged, this)); + mDestinationGuideUrlChangedSignal = LFSimFeatureHandler::instance().setDestinationGuideCallback(boost::bind(&LLFloaterDestinations::handleUrlChanged, this, _1)); } - handleUrlChanged(); + handleUrlChanged(LFSimFeatureHandler::instance().destinationGuideURL()); } -void LLFloaterDestinations::handleUrlChanged() +void LLFloaterDestinations::handleUrlChanged(const std::string& url) { - getChild("destination_guide_contents")->navigateTo(LLWeb::expandURLSubstitutions(LFSimFeatureHandler::instance().destinationGuideURL(), LLSD()), HTTP_CONTENT_TEXT_HTML); + getChild("destination_guide_contents")->navigateTo(LLWeb::expandURLSubstitutions(url, LLSD()), HTTP_CONTENT_TEXT_HTML); } // diff --git a/indra/newview/llfloaterdestinations.h b/indra/newview/llfloaterdestinations.h index 1de0e9d7d8..f75a9c0054 100644 --- a/indra/newview/llfloaterdestinations.h +++ b/indra/newview/llfloaterdestinations.h @@ -41,7 +41,7 @@ private: // FIRE-16833: Destination guide does not change between OpenSim grids /*virtual*/ void onOpen(const LLSD& key); - void handleUrlChanged(); + void handleUrlChanged(const std::string& url); boost::signals2::connection mDestinationGuideUrlChangedSignal; // From eea1badc53de158636c4b84408593f6059b89cb3 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Thu, 7 Dec 2017 10:19:18 +0100 Subject: [PATCH 12/75] Fix build again... --- indra/newview/lfsimfeaturehandler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/lfsimfeaturehandler.h b/indra/newview/lfsimfeaturehandler.h index 4fd3eb983e..06096ab9d6 100644 --- a/indra/newview/lfsimfeaturehandler.h +++ b/indra/newview/lfsimfeaturehandler.h @@ -29,7 +29,7 @@ public: SignaledType(Type b) : mValue(b) {} typedef typename Signal::slot_type changed_signal_t; - boost::signals2::connection connect(const typename changed_signal_t& slot) { return mSignal.connect(slot); } + boost::signals2::connection connect(const changed_signal_t& slot) { return mSignal.connect(slot); } SignaledType& operator =(Type val) { From 2d1e5cf246b62e10cfdce39c5a64728c6021825b Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 6 Dec 2017 17:48:01 +0200 Subject: [PATCH 13/75] MAINT-8042 Crash in LLViewerRegion::capabilitiesReceived() --- indra/newview/llvoicevivox.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index bac5e68ac1..ffd64b2810 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -875,13 +875,8 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() bool LLVivoxVoiceClient::provisionVoiceAccount() { LL_INFOS("Voice") << "Provisioning voice account." << LL_ENDL; - while (!gAgent.getRegion()) - { - // *TODO* Set up a call back on agent that sends a message to a pump we can use to wake up. - llcoro::suspend(); - } - while (!gAgent.getRegion()->capabilitiesReceived()) + while (!gAgent.getRegion() || !gAgent.getRegion()->capabilitiesReceived()) { // *TODO* Pump a message for wake up. llcoro::suspend(); From b5d8138ec0d21c4c611d09422c30f59a1ee5d945 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 7 Dec 2017 11:10:51 +0200 Subject: [PATCH 14/75] MAINT-8059 New head attachment slots are not rendered invisible in mouselook --- indra/newview/character/avatar_lad.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index 131da49d2c..d5c5b05b27 100644 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -532,7 +532,7 @@ location="ATTACH_FACE_JAW" position="0.000 0.000 0.000" rotation="0 0 0" - visible_in_first_person="true"/> + visible_in_first_person="false"/> + visible_in_first_person="false"/> + visible_in_first_person="false"/> + visible_in_first_person="false"/> + visible_in_first_person="false"/> + visible_in_first_person="false"/> Date: Fri, 8 Dec 2017 10:11:13 +0100 Subject: [PATCH 15/75] Fix avatar names often not showing on first open of properties floater --- indra/newview/llfloaterproperties.cpp | 124 ++++++++++++++++++-------- indra/newview/llfloaterproperties.h | 14 +++ 2 files changed, 102 insertions(+), 36 deletions(-) diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index 7deb450137..5a33ea2d38 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -114,6 +114,11 @@ void LLPropertiesObserver::changed(U32 mask) LLFloaterProperties::LLFloaterProperties(const LLSD& key) : LLFloater(key), mDirty(TRUE) + // Avatar names often not showing on first open + ,mCreatorNameCbConnection(), + mOwnerNameCbConnection(), + mGroupOwnerNameCbConnection() + // { if (key.has("item_id")) { @@ -129,6 +134,21 @@ LLFloaterProperties::~LLFloaterProperties() { delete mPropertiesObserver; mPropertiesObserver = NULL; + + // Avatar names often not showing on first open + if (mCreatorNameCbConnection.connected()) + { + mCreatorNameCbConnection.disconnect(); + } + if (mOwnerNameCbConnection.connected()) + { + mOwnerNameCbConnection.disconnect(); + } + if (mGroupOwnerNameCbConnection.connected()) + { + mGroupOwnerNameCbConnection.disconnect(); + } + // } // virtual @@ -303,23 +323,19 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) if (item->getCreatorUUID().notNull()) { - LLAvatarName av_name; - LLAvatarNameCache::get(item->getCreatorUUID(), &av_name); - getChildView("BtnCreator")->setEnabled(TRUE); + // Avatar names often not showing on first open + //LLAvatarName av_name; + //LLAvatarNameCache::get(item->getCreatorUUID(), &av_name); + //getChildView("BtnCreator")->setEnabled(TRUE); + // getChildView("LabelCreatorTitle")->setEnabled(TRUE); getChildView("LabelCreatorName")->setEnabled(TRUE); -// [RLVa:KB] - Checked: RLVa-2.0.1 - std::string name = av_name.getUserName(); - // If the object creator matches the object owner we need to anonymize the creator field as well - if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, item->getCreatorUUID())) && - ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == item->getCreatorUUID()) ) || (RlvUtil::isNearbyAgent(item->getCreatorUUID())) ) ) - { - childSetEnabled("BtnCreator", FALSE); - name = RlvStrings::getAnonym(av_name); - } - getChild("LabelCreatorName")->setValue(name); -// [/RLVa:KB] -// getChild("LabelCreatorName")->setValue(av_name.getUserName()); + // Avatar names often not showing on first open + //getChild("LabelCreatorName")->setValue(av_name.getUserName()); + getChildView("BtnCreator")->setEnabled(FALSE); + getChild("LabelCreatorName")->setValue(LLTrans::getString("AvatarNameWaiting")); + mCreatorNameCbConnection = LLAvatarNameCache::get(item->getCreatorUUID(), boost::bind(&LLFloaterProperties::onCreatorNameCallback, this, _1, _2, perm)); + // } else { @@ -334,35 +350,31 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) //////////////// if(perm.isOwned()) { -// [RLVa:KB] - Checked: RVLa-2.0.1 - bool fRlvCanShowOwner = true; -// [/RLVa:KB] - std::string name; + // Avatar names often not showing on first open + //std::string name; + getChildView("BtnOwner")->setEnabled(FALSE); + getChild("LabelOwnerName")->setValue(LLTrans::getString("AvatarNameWaiting")); + // if (perm.isGroupOwned()) { - gCacheName->getGroupName(perm.getGroup(), name); + // Avatar names often not showing on first open + //gCacheName->getGroupName(perm.getGroup(), name); + mGroupOwnerNameCbConnection = gCacheName->getGroup(perm.getGroup(), boost::bind(&LLFloaterProperties::onGroupOwnerNameCallback, this, _2)); + // } else { - LLAvatarName av_name; - LLAvatarNameCache::get(perm.getOwner(), &av_name); - name = av_name.getUserName(); -// [RLVa:KB] - Checked: RLVa-2.0.1 - if (RlvActions::isRlvEnabled()) - { - fRlvCanShowOwner = RlvActions::canShowName(RlvActions::SNC_DEFAULT, perm.getOwner()); - if (!fRlvCanShowOwner) - name = RlvStrings::getAnonym(av_name); - } -// [/RLVa:KB] + // Avatar names often not showing on first open + //LLAvatarName av_name; + //LLAvatarNameCache::get(perm.getOwner(), &av_name); + //name = av_name.getUserName(); + mOwnerNameCbConnection = LLAvatarNameCache::get(perm.getOwner(), boost::bind(&LLFloaterProperties::onOwnerNameCallback, this, _1, _2)); + // } -// getChildView("BtnOwner")->setEnabled(TRUE); -// [RLVa:KB] - Checked: RLVa-2.0.1 - getChildView("BtnOwner")->setEnabled(fRlvCanShowOwner); -// [/RLVa:KB] + //getChildView("BtnOwner")->setEnabled(TRUE); // Avatar names often not showing on first open getChildView("LabelOwnerTitle")->setEnabled(TRUE); getChildView("LabelOwnerName")->setEnabled(TRUE); - getChild("LabelOwnerName")->setValue(name); + //getChild("LabelOwnerName")->setValue(name); // Avatar names often not showing on first open } else { @@ -979,6 +991,46 @@ void LLFloaterProperties::dirtyAll() } } +// Avatar names often not showing on first open +void LLFloaterProperties::onCreatorNameCallback(const LLUUID& av_id, const LLAvatarName& av_name, const LLPermissions& perm) +{ + bool enabled = true; + std::string name = av_name.getUserName(); + // If the object creator matches the object owner we need to anonymize the creator field as well + if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, av_id)) && + ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == av_id) ) || (RlvUtil::isNearbyAgent(av_id)) ) ) + { + enabled = false; + name = RlvStrings::getAnonym(av_name); + } + getChild("LabelCreatorName")->setValue(name); + childSetEnabled("BtnCreator", enabled); +} + +void LLFloaterProperties::onOwnerNameCallback(const LLUUID& av_id, const LLAvatarName& av_name) +{ + bool fRlvCanShowOwner = true; + std::string name = av_name.getUserName(); + if (RlvActions::isRlvEnabled()) + { + fRlvCanShowOwner = RlvActions::canShowName(RlvActions::SNC_DEFAULT, av_id); + if (!fRlvCanShowOwner) + { + name = RlvStrings::getAnonym(av_name); + } + } + + getChild("LabelOwnerName")->setValue(name); + getChildView("BtnOwner")->setEnabled(fRlvCanShowOwner); +} + +void LLFloaterProperties::onGroupOwnerNameCallback(const std::string& name) +{ + getChild("LabelOwnerName")->setValue(name); + getChildView("BtnOwner")->setEnabled(TRUE); +} +// + ///---------------------------------------------------------------------------- /// LLMultiProperties ///---------------------------------------------------------------------------- diff --git a/indra/newview/llfloaterproperties.h b/indra/newview/llfloaterproperties.h index 3612887a47..b8099b6525 100644 --- a/indra/newview/llfloaterproperties.h +++ b/indra/newview/llfloaterproperties.h @@ -44,6 +44,11 @@ class LLTextBox; class LLPropertiesObserver; +// Avatar names often not showing on first open +class LLAvatarName; +class LLPermissions; +// + class LLFloaterProperties : public LLFloater { public: @@ -90,6 +95,15 @@ protected: BOOL mDirty; LLPropertiesObserver* mPropertiesObserver; + + // Avatar names often not showing on first open + boost::signals2::connection mCreatorNameCbConnection; + boost::signals2::connection mOwnerNameCbConnection; + boost::signals2::connection mGroupOwnerNameCbConnection; + void onCreatorNameCallback(const LLUUID& av_id, const LLAvatarName& av_name, const LLPermissions& perm); + void onOwnerNameCallback(const LLUUID& av_id, const LLAvatarName& av_name); + void onGroupOwnerNameCallback(const std::string& name); + // }; class LLMultiProperties : public LLMultiFloater From 465cb628fff759e11f1401df622897c5836a0a8e Mon Sep 17 00:00:00 2001 From: Ansariel Date: Fri, 8 Dec 2017 11:52:14 +0100 Subject: [PATCH 16/75] Fix position of lock icon in properties floater --- .../skins/default/xui/en/floater_inventory_item_properties.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml index ed6b462e00..f0622ff8aa 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml @@ -40,7 +40,7 @@ left="276" mouse_opaque="true" name="IconLocked" - top="4" + top="1" width="18" /> Date: Fri, 8 Dec 2017 12:12:57 +0100 Subject: [PATCH 17/75] FIRE-21917: Fix linking against wrong FmodEx library on Linux64, patch by Lord Drakeo --- indra/cmake/Copy3rdPartyLibs.cmake | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 45f686fff0..2fcf1ca6f1 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -258,9 +258,18 @@ elseif(LINUX) set(release_files ${release_files} "libtcmalloc_minimal.so") endif (USE_TCMALLOC) + #if (FMODEX) + # set(debug_files ${debug_files} "libfmodexL.so") + # set(release_files ${release_files} "libfmodex.so") + #endif (FMODEX) if (FMODEX) - set(debug_files ${debug_files} "libfmodexL.so") - set(release_files ${release_files} "libfmodex.so") + if( NOT ND_BUILD64BIT_ARCH ) + set(debug_files ${debug_files} "libfmodexL.so") + set(release_files ${release_files} "libfmodex.so") + else( NOT ND_BUILD64BIT_ARCH ) + set(debug_files ${debug_files} "libfmodexL64.so") + set(release_files ${release_files} "libfmodex64.so") + endif( NOT ND_BUILD64BIT_ARCH ) endif (FMODEX) else(WINDOWS) From facc8881f9dbd6de1176b37c03efec7303964e68 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 9 Dec 2017 21:06:21 +0100 Subject: [PATCH 18/75] Set correct hide empty system folder option when resetting filter --- indra/newview/llpanelmaininventory.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 6ff1320ad9..8a78d401f0 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -507,6 +507,7 @@ void LLPanelMainInventory::resetFilters() filter.setSearchType(LLInventoryFilter::SEARCHTYPE_NAME); filter.setFilterTransferable(FALSE); getActivePanel()->updateShowInboxFolder(gSavedSettings.getBOOL("FSShowInboxFolder")); + getActivePanel()->updateHideEmptySystemFolders(gSavedSettings.getBOOL("DebugHideEmptySystemFolders")); updateFilterDropdown(&filter); // if (finder) From 5780758ec94339f56dd79a04ab8b44ea719036db Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 9 Dec 2017 22:08:19 +0100 Subject: [PATCH 19/75] Fix "Find all links" unhiding hidden empty system folders --- indra/newview/llinventoryfilter.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 154a3ef598..ffc7b5cee3 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -866,6 +866,16 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) { mFilterOps.mFilterTypes &= ~FILTERTYPE_UUID; mFilterOps.mFilterUUID = LLUUID::null; + // Find all links unhiding hidden empty system folders + if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders")) + { + setFilterEmptySystemFolders(); + } + else + { + removeFilterEmptySystemFolders(); + } + // setModified(FILTER_RESTART); } } From e9ca4489c26ac80d19efbf075dcf270fe92973f5 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 9 Dec 2017 22:42:44 +0100 Subject: [PATCH 20/75] Improve fix for hidden empty system folders unhiding when using "Find all links": Save filter settings and restore them when changing (clearing) the search box text --- indra/newview/llinventoryfilter.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index ffc7b5cee3..4c053e9c14 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -864,17 +864,10 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) // Cancel out UUID once the search string is modified if (mFilterOps.mFilterTypes == FILTERTYPE_UUID) { - mFilterOps.mFilterTypes &= ~FILTERTYPE_UUID; - mFilterOps.mFilterUUID = LLUUID::null; // Find all links unhiding hidden empty system folders - if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders")) - { - setFilterEmptySystemFolders(); - } - else - { - removeFilterEmptySystemFolders(); - } + //mFilterOps.mFilterTypes &= ~FILTERTYPE_UUID; + //mFilterOps.mFilterUUID = LLUUID::null; + mFilterOps = mBackupFilterOps; // setModified(FILTER_RESTART); } @@ -1098,7 +1091,7 @@ void LLInventoryFilter::setFindAllLinksMode(const std::string &search_name, cons { // Save a copy of settings so that we will be able to restore it later // but make sure we are not searching for links already - if(mFilterOps.mFilterLinks != FILTERLINK_ONLY_LINKS) + //if(mFilterOps.mFilterLinks != FILTERLINK_ONLY_LINKS) // Find all links unhiding hidden empty system folders { mBackupFilterOps = mFilterOps; } From 80ec7f6b35af76f6bd3b0f43fce39cfbf568db0c Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 11 Dec 2017 19:41:02 +0100 Subject: [PATCH 21/75] Restore old event poll behavior only for OpenSim --- indra/newview/lleventpoll.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index b04429dfbd..35c72ac068 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -43,6 +43,7 @@ #include "boost/make_shared.hpp" #include "llsdutil.h" // for ll_pretty_print_sd +#include "llviewernetwork.h" namespace LLEventPolling { @@ -103,8 +104,13 @@ namespace Details mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_LONG_POLL); // Restore pre-coro behavior (60s timeout, no retries) mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); - mHttpOptions->setRetries(0); - mHttpOptions->setTransferTimeout(60); +#ifdef OPENSIM + if (LLGridManager::instance().isInOpenSim()) + { + mHttpOptions->setRetries(0); + mHttpOptions->setTransferTimeout(60); + } +#endif // mSenderIp = sender.getIPandPort(); } @@ -197,13 +203,15 @@ namespace Details continue; } // Restore pre-coro behavior (60s timeout, no retries) - else if (status == LLCore::HttpStatus(HTTP_BAD_GATEWAY)) +#ifdef OPENSIM + else if (status == LLCore::HttpStatus(HTTP_BAD_GATEWAY) && LLGridManager::instance().isInOpenSim()) { // Pre-coro says this is the default answer for timeouts and it can happen // frequently on OpenSim - assume this is normal and issue a new request immediately LL_DEBUGS("LLEventPollImpl") << "Received HTTP 502 - start new request." << LL_ENDL; errorCount = 0; continue; } +#endif // else if ((status == LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_OP_CANCELED)) || (status == LLCore::HttpStatus(HTTP_NOT_FOUND))) From b425ccf160b32882de3239ed474c045d94336faa Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 11 Dec 2017 20:17:56 +0100 Subject: [PATCH 22/75] Print out FMOD_ERR_INVALID_HANDLE FmodEx errors as debug level since handles always seem to become invalid when a sound stops --- indra/llaudio/llaudioengine_fmodex.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp index b6107f5838..1eb3676e01 100644 --- a/indra/llaudio/llaudioengine_fmodex.cpp +++ b/indra/llaudio/llaudioengine_fmodex.cpp @@ -111,7 +111,14 @@ inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) return false; // Always print out error //LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; - LL_WARNS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + if (result != FMOD_ERR_INVALID_HANDLE) + { + LL_WARNS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + } + else + { + LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + } // return true; } From 3f2e137bc717f6a20aa0fd91a7c7885e085347ce Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 11 Dec 2017 22:34:49 +0100 Subject: [PATCH 23/75] Reduce more log spam --- indra/llmessage/llcoproceduremanager.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index 74cdff2b00..ce8d643a3e 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -334,7 +334,7 @@ LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoproced LLUUID id(LLUUID::generateNewID()); mPendingCoprocs.push_back(QueuedCoproc::ptr_t(new QueuedCoproc(name, id, proc))); - LL_INFOS() << "Coprocedure(" << name << ") enqueued with id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL; + LL_DEBUGS("CoprocedurePool") << "Coprocedure(" << name << ") enqueued with id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL; mWakeupTrigger.post(LLSD()); @@ -347,7 +347,7 @@ bool LLCoprocedurePool::cancelCoprocedure(const LLUUID &id) ActiveCoproc_t::iterator itActive = mActiveCoprocs.find(id); if (itActive != mActiveCoprocs.end()) { - LL_INFOS() << "Found and canceling active coprocedure with id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL; + LL_DEBUGS("CoprocedurePool") << "Found and canceling active coprocedure with id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL; (*itActive).second->cancelSuspendedOperation(); mActiveCoprocs.erase(itActive); return true; @@ -357,13 +357,13 @@ bool LLCoprocedurePool::cancelCoprocedure(const LLUUID &id) { if ((*it)->mId == id) { - LL_INFOS() << "Found and removing queued coroutine(" << (*it)->mName << ") with Id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL; + LL_DEBUGS("CoprocedurePool") << "Found and removing queued coroutine(" << (*it)->mName << ") with Id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL; mPendingCoprocs.erase(it); return true; } } - LL_INFOS() << "Coprocedure with Id=" << id.asString() << " was not found in pool \"" << mPoolName << "\"" << LL_ENDL; + LL_WARNS("CoprocedurePool") << "Coprocedure with Id=" << id.asString() << " was not found in pool \"" << mPoolName << "\"" << LL_ENDL; return false; } @@ -384,7 +384,7 @@ void LLCoprocedurePool::coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdap mPendingCoprocs.pop_front(); ActiveCoproc_t::iterator itActive = mActiveCoprocs.insert(ActiveCoproc_t::value_type(coproc->mId, httpAdapter)).first; - LL_INFOS() << "Dequeued and invoking coprocedure(" << coproc->mName << ") with id=" << coproc->mId.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL; + LL_DEBUGS("CoprocedurePool") << "Dequeued and invoking coprocedure(" << coproc->mName << ") with id=" << coproc->mId.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL; try { @@ -400,7 +400,7 @@ void LLCoprocedurePool::coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdap throw; } - LL_INFOS() << "Finished coprocedure(" << coproc->mName << ")" << " in pool \"" << mPoolName << "\"" << LL_ENDL; + LL_DEBUGS("CoprocedurePool") << "Finished coprocedure(" << coproc->mName << ")" << " in pool \"" << mPoolName << "\"" << LL_ENDL; mActiveCoprocs.erase(itActive); } From f0b781173e4a222f043de968a031460e318562e3 Mon Sep 17 00:00:00 2001 From: Beq Date: Tue, 12 Dec 2017 08:11:47 +0000 Subject: [PATCH 24/75] Add an ignorable alert modal each time that the currency URI changes. --- indra/newview/lfsimfeaturehandler.cpp | 5 +++++ indra/newview/llpanelobject.cpp | 3 --- .../newview/skins/default/xui/en/notifications.xml | 13 +++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/indra/newview/lfsimfeaturehandler.cpp b/indra/newview/lfsimfeaturehandler.cpp index 9838a1b365..9c62b17010 100644 --- a/indra/newview/lfsimfeaturehandler.cpp +++ b/indra/newview/lfsimfeaturehandler.cpp @@ -26,6 +26,7 @@ #include "llviewerregion.h" // +#include "llnotificationsutil.h" #include "tea.h" #include "llstatusbar.h" #include "llfloaterbuycurrency.h" @@ -169,6 +170,10 @@ void LFSimFeatureHandler::setSupportedFeatures() // if (extras.has("currency-base-uri")) { + if (mHelperUriOverride != extras["currency-base-uri"].asString()) + { + LLNotificationsUtil::add("CurrencyURIOverrideReceived"); + } mHelperUriOverride = extras["currency-base-uri"].asString(); } else diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 0adf074021..8833feb188 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1643,9 +1643,6 @@ void LLPanelObject::deactivateMeshFields() childSetVisible("LOD_swap_usr_label", false); childSetVisible("LOD_swap_label", false); childSetVisible("LOD_swap_LOD_Change_label", false); - childSetVisible("LOD_swap_H2M_label", false); - childSetVisible("LOD_swap_M2L_label", false); - childSetVisible("LOD_swap_L2I_label", false); childSetVisible("LODSwapTableDscriptionsText", false); childSetVisible("LOD_swap_ll_default", false); childSetVisible("LOD_swap_fs_default", false); diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index a5edf40629..7ad0833c59 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -13205,4 +13205,17 @@ For everyday use, LOD set to 2 should suffice. If you own some objects that look name="okignore" yestext="OK"/> + +This region has elected to specify a third-party currency portal. +Please note that currency purchases made through Firestorm Viewer are transactions between you (the user) and the provider(s) or seller(s) of the currency. +Neither Firestorm Viewer, the Phoenix Firestorm Viewer Project Inc., nor its team shall be liable for any cost or damage arising either directly or indirectly from any such transaction. +If you do not agree to these terms of use, then no financial transactions should be conducted using this viewer. + + From 4b9586bb7459ecf0ceccf2374faf383a64f699ee Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 12 Dec 2017 09:30:49 +0100 Subject: [PATCH 25/75] Update German translation --- indra/newview/skins/default/xui/de/notifications.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index 7ae4521a12..a6c05952f8 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -5316,4 +5316,11 @@ Werte höher als 8 sind bedeutungslos und erzeugen keine Verbesserung. Sie sollt Für den normalen Gebrauch sollte ein Wert von 2 ausreichen. Sollten Sie einige Objekte besitzen, die bei diesem Wert deformiert aussehen, sollten Sie in Erwägung ziehen, diese zu ersetzen. + +Diese Region hat sich dazu entschieden, das Währungsportal eines Drittanbieters zu nutzen. +Bitte beachten Sie, dass es sich bei Käufen von Währung innerhalb des Firestorm Viewers um Transaktionen zwischen Ihnen (dem Nutzer) und den Anbietern oder Verkäufern der Währung handelt. +Weder Firestorm Viewer, Phoenix Firestorm Viewer Project Inc. noch dessen Team können für jegliche Kosten oder Schäden haftbar gemacht werden, die direkt oder indirekt aus solchen Transaktionen entstehen. +Falls Sie diesen Nutzungsbestimmungen nicht zustimmen, sollten keinerlei finanzielle Transaktionen im Rahmen der Nutzung dieses Viewers durchgeführt werden. + + From 09e3cab8622be3a0416bfc61e5ea1510e4087567 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 12 Dec 2017 20:07:12 +0100 Subject: [PATCH 26/75] Add suggestion what to do in case of "Must supply a comment for control x" error to error message --- indra/llxml/llcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index 56e5b9f97d..805aff7e4c 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -149,7 +149,7 @@ LLControlVariable::LLControlVariable(const std::string& name, eControlType type, { if ((persist != PERSIST_NO) && mComment.empty()) { - LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL; + LL_ERRS() << "Must supply a comment for control " << mName << ". Please perform a clean installation!" << LL_ENDL; } //Push back versus setValue'ing here, since we don't want to call a signal yet mValues.push_back(initial); From 6eab7d0dbb4db3e8d9971a743ac82935b701b794 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 13 Dec 2017 12:58:25 +0100 Subject: [PATCH 27/75] Pull relevant part of MAINT-8061 to show item count for folders in inventory with improvements and fixes --- indra/newview/llinventorybridge.cpp | 32 +++++++++++- indra/newview/llinventorybridge.h | 6 ++- indra/newview/llinventorypanel.cpp | 50 +++++++++++++++++++ indra/newview/llinventorypanel.h | 2 + .../newview/skins/default/xui/de/strings.xml | 3 ++ .../newview/skins/default/xui/en/strings.xml | 1 + 6 files changed, 91 insertions(+), 3 deletions(-) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index ed0e73a087..7b8eb245d3 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -100,6 +100,7 @@ // #include "fsfloaterplacedetails.h" #include "llviewerattachmenu.h" +#include "llresmgr.h" #include @@ -2428,8 +2429,35 @@ std::string LLFolderBridge::getLabelSuffix() const { return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()); } - - return LLInvFVBridge::getLabelSuffix(); + std::string suffix = ""; + if(mShowDescendantsCount) + { + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(getUUID(), cat_array, item_array, TRUE); + // Fix item count formatting + //S32 count = item_array.size(); + //if(count > 0) + //{ + // std::ostringstream oss; + // oss << count; + // suffix = " ( " + oss.str() + " Items )"; + //} + if (cat_array.size() > 0 || item_array.size() > 0) + { + LLLocale locale(""); + LLStringUtil::format_map_t args; + std::string count_str; + LLResMgr::getInstance()->getIntegerString(count_str, item_array.size()); + args["ITEMS"] = count_str; + LLResMgr::getInstance()->getIntegerString(count_str, cat_array.size()); + args["FOLDERS"] = count_str; + suffix = " " + LLTrans::getString("FolderItemCount", args); + } + // + } + + return LLInvFVBridge::getLabelSuffix() + suffix; } LLFontGL::StyleFlags LLFolderBridge::getLabelStyle() const diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index a95969952e..868822d592 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -286,7 +286,8 @@ public: : LLInvFVBridge(inventory, root, uuid), mCallingCards(FALSE), mWearables(FALSE), - mIsLoading(false) + mIsLoading(false), + mShowDescendantsCount(false) {} BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE); @@ -311,6 +312,8 @@ public: virtual std::string getLabelSuffix() const; virtual LLFontGL::StyleFlags getLabelStyle() const; + void setShowDescendantsCount(bool show_count) {mShowDescendantsCount = show_count;} + virtual BOOL renameItem(const std::string& new_name); virtual BOOL removeItem(); @@ -397,6 +400,7 @@ protected: bool mCallingCards; bool mWearables; bool mIsLoading; + bool mShowDescendantsCount; LLTimer mTimeSinceRequestStart; std::string mMessage; LLRootHandle mHandle; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index cec1543d46..476b6e9548 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1182,6 +1182,56 @@ void LLInventoryPanel::onSelectionChange(const std::deque& it fv->startRenamingSelectedItem(); } } + + std::set selected_items = mFolderRoot.get()->getSelectionList(); + LLFolderViewItem* prev_folder_item = getItemByID(mPreviousSelectedFolder); + + if (selected_items.size() == 1) + { + std::set::const_iterator iter = selected_items.begin(); + LLFolderViewItem* folder_item = (*iter); + if(folder_item && (folder_item != prev_folder_item)) + { + LLFolderViewModelItemInventory* fve_listener = static_cast(folder_item->getViewModelItem()); + if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY)) + { + if(prev_folder_item) + { + LLFolderBridge* prev_bridge = (LLFolderBridge*)prev_folder_item->getViewModelItem(); + if(prev_bridge) + { + prev_bridge->clearDisplayName(); + prev_bridge->setShowDescendantsCount(false); + prev_folder_item->refresh(); + } + } + + LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getViewModelItem(); + if(bridge) + { + bridge->clearDisplayName(); + bridge->setShowDescendantsCount(true); + folder_item->refresh(); + mPreviousSelectedFolder = bridge->getUUID(); + } + } + } + } + else + { + if(prev_folder_item) + { + LLFolderBridge* prev_bridge = (LLFolderBridge*)prev_folder_item->getViewModelItem(); + if(prev_bridge) + { + prev_bridge->clearDisplayName(); + prev_bridge->setShowDescendantsCount(false); + prev_folder_item->refresh(); + } + } + mPreviousSelectedFolder = LLUUID(); + } + } void LLInventoryPanel::doCreate(const LLSD& userdata) diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 522a387eea..58604276a5 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -263,6 +263,8 @@ protected: LLHandle mFolderRoot; LLScrollContainer* mScroller; + LLUUID mPreviousSelectedFolder; + LLFolderViewModelInventory mInventoryViewModel; LLPointer mGroupedItemBridge; Params mParams; // stored copy of parameter block diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index 8de7518274..5c10ebe583 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -6849,4 +6849,7 @@ Setzen Sie den Editorpfad in Anführungszeichen [ASSET_NAME] + + ([ITEMS]/[FOLDERS] Elemente) + diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 2cba8ff8df..143e9daf88 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3080,4 +3080,5 @@ Try enclosing path to the editor with double quotes. [ASSET_NAME] + ([ITEMS]/[FOLDERS] Elements) From 0c144e950dc9c048aca823b44dd4524a9e9d62a4 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 13 Dec 2017 13:07:07 +0100 Subject: [PATCH 28/75] Fix filter status text not updated if filter changed via quick filter dropdown list --- indra/newview/llpanelmaininventory.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 8a78d401f0..c9354ebdd7 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -798,6 +798,8 @@ void LLPanelMainInventory::onFilterTypeSelected(const std::string& filter_type_n { finder->updateElementsFromFilter(); } + + setFilterTextFromFilter(); } // reflect state of current filter selection in the dropdown list From 7f0e6976d1437b813d829f9397d4e2da7ed04f49 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 13 Dec 2017 13:20:29 +0100 Subject: [PATCH 29/75] Draw ellipses in inventory status text if it gets too long --- indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml | 3 ++- indra/newview/skins/default/xui/en/panel_main_inventory.xml | 3 ++- indra/newview/skins/starlight/xui/en/panel_main_inventory.xml | 3 ++- .../newview/skins/starlightcui/xui/en/panel_main_inventory.xml | 3 ++- indra/newview/skins/vintage/xui/en/panel_main_inventory.xml | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml b/indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml index 29540636fe..88928d8c29 100644 --- a/indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml @@ -651,8 +651,9 @@ font="SansSerifMedium" top_pad="6" tool_tip="[ITEMS] Items, [CATEGORIES] Folders" + use_ellipses="true" follows="bottom|left|right" - width="240"> + right="-8"> Elements + right="-8"> Elements Elements: diff --git a/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml b/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml index 26fec9a330..cdb2f557f9 100644 --- a/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml @@ -29,7 +29,7 @@ Elements: diff --git a/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml b/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml index 6f91a45779..62bc845182 100644 --- a/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml @@ -538,8 +538,9 @@ left_delta="2" name="ItemcountText" right="-1" + use_ellipses="true" font="SansSerifMedium" - follows="bottom|left"> + follows="bottom|left|right"> Elements From 7471d086b20cfbffa81cc8564162da24ac5c9881 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 13 Dec 2017 14:00:21 +0100 Subject: [PATCH 30/75] Synchronize a bit more with MAINT-8061 --- indra/newview/llinventorybridge.cpp | 12 +++++++----- indra/newview/skins/default/xui/de/strings.xml | 3 +++ indra/newview/skins/default/xui/en/strings.xml | 3 +-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 7b8eb245d3..1b626a62c2 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2427,7 +2427,7 @@ std::string LLFolderBridge::getLabelSuffix() const if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay()) { - return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()); + return llformat(" (%s) ", LLTrans::getString("LoadingData").c_str()); } std::string suffix = ""; if(mShowDescendantsCount) @@ -2441,7 +2441,9 @@ std::string LLFolderBridge::getLabelSuffix() const //{ // std::ostringstream oss; // oss << count; - // suffix = " ( " + oss.str() + " Items )"; + // LLStringUtil::format_map_t args; + // args["[ITEMS_COUNT]"] = oss.str(); + // suffix = " " + LLTrans::getString("InventoryItemsCount", args); //} if (cat_array.size() > 0 || item_array.size() > 0) { @@ -2451,8 +2453,8 @@ std::string LLFolderBridge::getLabelSuffix() const LLResMgr::getInstance()->getIntegerString(count_str, item_array.size()); args["ITEMS"] = count_str; LLResMgr::getInstance()->getIntegerString(count_str, cat_array.size()); - args["FOLDERS"] = count_str; - suffix = " " + LLTrans::getString("FolderItemCount", args); + args["CATEGORIES"] = count_str; + suffix = " " + LLTrans::getString("InventoryItemsCount", args); } // } @@ -4889,7 +4891,7 @@ std::string LLMarketplaceFolderBridge::getLabelSuffix() const if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay()) { - return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()); + return llformat(" (%s) ", LLTrans::getString("LoadingData").c_str()); } std::string suffix = ""; diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index 5c10ebe583..e8b8561633 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -1704,6 +1704,9 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich unter http://suppo Ziehen Sie Ordner in diesen Bereich, um sie im [[MARKETPLACE_DASHBOARD_URL] Marktplatz] zum Verkauf anzubieten. + + ([ITEMS]/[CATEGORIES] Elemente) + Bestandsordner müssen in einem Versionsordner gespeichert sein diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 143e9daf88..0499c97a3b 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -773,7 +773,7 @@ If you continue to receive this message, please contact Second Life support for Drag folders to this area to list them for sale on the [[MARKETPLACE_DASHBOARD_URL] Marketplace]. - + ([ITEMS]/[CATEGORIES] Elements) stock folder must be contained by a version folder : Error: all items in a stock folder must be no-copy and of the same type @@ -3080,5 +3080,4 @@ Try enclosing path to the editor with double quotes. [ASSET_NAME] - ([ITEMS]/[FOLDERS] Elements) From 09ebb5ddabc9bc33b99865d18c19d7321d42d77b Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 13 Dec 2017 14:01:38 +0100 Subject: [PATCH 31/75] Forgot to remove this... --- indra/newview/skins/default/xui/de/strings.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index e8b8561633..815b22f634 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -6852,7 +6852,4 @@ Setzen Sie den Editorpfad in Anführungszeichen [ASSET_NAME] - - ([ITEMS]/[FOLDERS] Elemente) - From a784fa46e56709aa3c38f94174abc8e3a969d0a5 Mon Sep 17 00:00:00 2001 From: PanteraPolnocy Date: Wed, 13 Dec 2017 20:02:37 +0100 Subject: [PATCH 32/75] Updated Polish translation --- indra/newview/skins/default/xui/pl/notifications.xml | 7 +++++++ indra/newview/skins/default/xui/pl/strings.xml | 3 +++ 2 files changed, 10 insertions(+) diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml index a2b40645b6..766d78a84a 100644 --- a/indra/newview/skins/default/xui/pl/notifications.xml +++ b/indra/newview/skins/default/xui/pl/notifications.xml @@ -4942,4 +4942,11 @@ Wartości wyższe niż 8 są bez znaczenia i nie powodują żadnej poprawy. Nie Do codziennego użytku LOD ustawiony na 2 powinien wystarczyć. Jeśli posiadasz obiekty, które wyglądają na zdeformowane z taką wartością, to powinieneś/aś rozważyć ich wymianę. + + W tym regionie wybrano portal walutowy strony trzeciej. +Należy pamiętać, że zakupy w walucie dokonywane za pośrednictwem Firestorm Viewer są transakcjami między Tobą (użytkownikiem) a dostawcą (-ami) lub sprzedawcą (-ami) waluty. +Ani Firestorm Viewer, ani Phoenix Firestorm Viewer Project Inc., ani jego zespół nie ponoszą odpowiedzialności za jakiekolwiek koszty lub szkody wynikające bezpośrednio lub pośrednio z takich transakcji. +Jeśli nie zgadzasz się z niniejszymi warunkami użytkowania, nie należy przeprowadzać transakcji finansowych za pomocą tej przeglądarki. + + diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml index c7ede68b64..32c799d03b 100644 --- a/indra/newview/skins/default/xui/pl/strings.xml +++ b/indra/newview/skins/default/xui/pl/strings.xml @@ -1619,6 +1619,9 @@ Jeśli ciągle otrzymujesz tą wiadomość, to skontaktuj się z pomocą technic Przeciągnij foldery do tego obszaru, aby dodać je na listę sprzedaży w [[MARKETPLACE_DASHBOARD_URL] Marketplace]. + + ([ITEMS]/[FOLDERS] elementów) + folder Magazynowy musi być zawarty w folderze wersji From ced6c2d9fbfb20738c529f76735f8ecd52002c8e Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 14 Dec 2017 15:48:02 +0200 Subject: [PATCH 33/75] MAINT-8089 FIXED User A can't unblock text from user B when use right-click menu in chat --- indra/newview/llavataractions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 729c889d33..4dcd06ce88 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -1249,7 +1249,7 @@ void LLAvatarActions::toggleMute(const LLUUID& id, U32 flags) LLAvatarNameCache::get(id, &av_name); LLMuteList* mute_list = LLMuteList::getInstance(); - bool is_muted = mute_list->isMuted(id, LLMute::flagVoiceChat); + bool is_muted = mute_list->isMuted(id, flags); LLMute mute(id, av_name.getUserName(), LLMute::AGENT); if (!is_muted) From 61e67f24d17c5f32625147c584762a34b7c51a91 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 11 Dec 2017 13:50:24 +0000 Subject: [PATCH 34/75] Merged in MAINT-8066 "Breasts Bounce" increases at low fps. Approved-by: Andrey Lihatskiy Approved-by: Simon Linden Approved-by: Maxim Nikolenko --- indra/newview/llphysicsmotion.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index b6996e808b..7aedbd7421 100644 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -44,7 +44,7 @@ typedef std::map controller_map_t; typedef std::map default_controller_map_t; #define MIN_REQUIRED_PIXEL_AREA_AVATAR_PHYSICS_MOTION 0.f -#define TIME_ITERATION_STEP 0.1f +#define TIME_ITERATION_STEP 0.05f inline F64 llsgn(const F64 a) { @@ -559,6 +559,18 @@ BOOL LLPhysicsMotion::onUpdate(F32 time) // Break up the physics into a bunch of iterations so that differing framerates will show // roughly the same behavior. + // Explanation/example: Lets assume we have a bouncing object. Said abjects bounces at a + // trajectory that has points A>B>C. Object bounces from A to B with specific speed. + // It needs time T to move from A to B. + // As long as our frame's time significantly smaller then T our motion will be split into + // multiple parts. with each part speed will decrease. Object will reach B position (roughly) + // and bounce/fall back to A. + // But if frame's time (F_T) is larger then T, object will move with same speed for whole F_T + // and will jump over point B up to C ending up with increased amplitude. To avoid that we + // split F_T into smaller portions so that when frame's time is too long object can virtually + // bounce at right (relatively) position. + // Note: this doesn't look to be optimal, since it provides only "roughly same" behavior, but + // irregularity at higher fps looks to be insignificant so it works good enough for low fps. for (F32 time_iteration = 0; time_iteration <= time_delta; time_iteration += TIME_ITERATION_STEP) { F32 time_iteration_step = TIME_ITERATION_STEP; From 78afaf4eb8de94f46e524f00724225de35b47184 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Fri, 15 Dec 2017 19:41:34 +0200 Subject: [PATCH 35/75] MAINT-8064 Crashes in lodReceived() --- indra/newview/llmeshrepository.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 65cd225333..5c4f984454 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1817,8 +1817,17 @@ bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U } LLPointer volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod)); - std::string mesh_string((char*) data, data_size); - std::istringstream stream(mesh_string); + std::istringstream stream; + try + { + std::string mesh_string((char*)data, data_size); + stream.str(mesh_string); + } + catch (std::bad_alloc) + { + // out of memory, we won't be able to process this mesh + return false; + } if (volume->unpackVolumeFaces(stream, data_size)) { From cffc2e80eecb8ad235087f18334fd0ad8505bee7 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 16 Dec 2017 12:21:17 +0100 Subject: [PATCH 36/75] Bump version to 5.0.12 --- indra/newview/VIEWER_VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index b07ada5862..718db1c46f 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -5.0.10 +5.0.12 From 8af9363e89dbaeeec58f2de5557b6fe5c95b1401 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 15 Dec 2017 12:43:54 +0000 Subject: [PATCH 37/75] MAINT-4354 Render stalls in object heavy regions --- indra/newview/llviewerobjectlist.cpp | 10 +++++++--- indra/newview/llviewertexturelist.cpp | 5 +---- indra/newview/llviewertexturelist.h | 3 --- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index cab0b71d5b..30881602ed 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -819,9 +819,9 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) S32 num_updates, max_value; if (NUM_BINS - 1 == mCurBin) { + // Remainder (mObjects.size() could have changed) num_updates = (S32) mObjects.size() - mCurLazyUpdateIndex; max_value = (S32) mObjects.size(); - gTextureList.setUpdateStats(TRUE); } else { @@ -878,10 +878,14 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) mCurLazyUpdateIndex = max_value; if (mCurLazyUpdateIndex == mObjects.size()) { + // restart mCurLazyUpdateIndex = 0; + mCurBin = 0; // keep in sync with index (mObjects.size() could have changed) + } + else + { + mCurBin = (mCurBin + 1) % NUM_BINS; } - - mCurBin = (mCurBin + 1) % NUM_BINS; LLVOAvatar::cullAvatarsByPixelArea(); } diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index ec211a4e06..53ecdcac15 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -95,7 +95,6 @@ LLTextureKey::LLTextureKey(LLUUID id, ETexListType tex_type) LLViewerTextureList::LLViewerTextureList() : mForceResetTextureStats(FALSE), - mUpdateStats(FALSE), mMaxResidentTexMemInMegaBytes(0), mMaxTotalTextureMemInMegaBytes(0), mInitialized(FALSE) @@ -106,7 +105,6 @@ void LLViewerTextureList::init() { mInitialized = TRUE ; sNumImages = 0; - mUpdateStats = TRUE; mMaxResidentTexMemInMegaBytes = (U32Bytes)0; mMaxTotalTextureMemInMegaBytes = (U32Bytes)0; @@ -1170,7 +1168,7 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time) void LLViewerTextureList::updateImagesUpdateStats() { - if (mUpdateStats && mForceResetTextureStats) + if (mForceResetTextureStats) { for (image_priority_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ) @@ -1178,7 +1176,6 @@ void LLViewerTextureList::updateImagesUpdateStats() LLViewerFetchedTexture* imagep = *iter++; imagep->resetTextureStats(); } - mUpdateStats = FALSE; mForceResetTextureStats = FALSE; } } diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index ec32ac9b28..4eff6e67e6 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -124,8 +124,6 @@ public: void handleIRCallback(void **data, const S32 number); - void setUpdateStats(BOOL b) { mUpdateStats = b; } - S32Megabytes getMaxResidentTexMem() const { return mMaxResidentTexMemInMegaBytes; } S32Megabytes getMaxTotalTextureMem() const { return mMaxTotalTextureMemInMegaBytes;} S32 getNumImages() { return mImageList.size(); } @@ -231,7 +229,6 @@ private: std::set > mImagePreloads; BOOL mInitialized ; - BOOL mUpdateStats; S32Megabytes mMaxResidentTexMemInMegaBytes; S32Megabytes mMaxTotalTextureMemInMegaBytes; LLFrameTimer mForceDecodeTimer; From 47b304b91cfdc50f1a0168675125975051509161 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 16 Dec 2017 18:30:06 +0100 Subject: [PATCH 38/75] Transplant MAINT-8098 FIXED The Viewer uses http: for the splash page even when configured for https: --- indra/newview/fspanellogin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/fspanellogin.cpp b/indra/newview/fspanellogin.cpp index 2748ebff1c..61b698c746 100644 --- a/indra/newview/fspanellogin.cpp +++ b/indra/newview/fspanellogin.cpp @@ -858,7 +858,8 @@ void FSPanelLogin::loadLoginPage() params["login_content_version"] = gSavedSettings.getString("LoginContentVersion"); // Make an LLURI with this augmented info - LLURI login_uri(LLURI::buildHTTP(login_page.authority(), + std::string url = login_page.scheme().empty()? login_page.authority() : login_page.scheme() + "://" + login_page.authority(); + LLURI login_uri(LLURI::buildHTTP(url, login_page.path(), params)); From eba0a1133f4d7b0280bd0942928931bdcab14d38 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 16 Dec 2017 19:24:37 +0100 Subject: [PATCH 39/75] Use timer for cleaning up dead objects --- indra/newview/llviewerobjectlist.cpp | 34 +++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 30881602ed..6684b046c3 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1517,6 +1517,11 @@ void LLViewerObjectList::cleanDeadObjects(BOOL use_timer) S32 num_removed = 0; LLViewerObject *objectp; + + // Use timer for cleaning up dead objects + static const F64 max_time = 0.01; // Let's try 10ms per frame + LLTimer timer; + // vobj_list_t::reverse_iterator target = mObjects.rbegin(); @@ -1532,12 +1537,16 @@ void LLViewerObjectList::cleanDeadObjects(BOOL use_timer) if (objectp->isDead()) { + mDeadObjects.erase(objectp->mID); // Use timer for cleaning up dead objects LLPointer::swap(*iter, *target); *target = NULL; ++target; num_removed++; - if (num_removed == mNumDeadObjects || iter->isNull()) + // Use timer for cleaning up dead objects + //if (num_removed == mNumDeadObjects || iter->isNull()) + if (num_removed == mNumDeadObjects || iter->isNull() || (use_timer && timer.getElapsedTimeF64() > max_time)) + // { // We've cleaned up all of the dead objects or caught up to the dead tail break; @@ -1549,15 +1558,24 @@ void LLViewerObjectList::cleanDeadObjects(BOOL use_timer) } } - llassert(num_removed == mNumDeadObjects); + // Use timer for cleaning up dead objects + //llassert(num_removed == mNumDeadObjects); - //erase as a block - mObjects.erase(mObjects.begin()+(mObjects.size()-mNumDeadObjects), mObjects.end()); + ////erase as a block + //mObjects.erase(mObjects.begin()+(mObjects.size()-mNumDeadObjects), mObjects.end()); - // We've cleaned the global object list, now let's do some paranoia testing on objects - // before blowing away the dead list. - mDeadObjects.clear(); - mNumDeadObjects = 0; + //// We've cleaned the global object list, now let's do some paranoia testing on objects + //// before blowing away the dead list. + //mDeadObjects.clear(); + //mNumDeadObjects = 0; + mObjects.erase(mObjects.begin()+(mObjects.size()-num_removed), mObjects.end()); + mNumDeadObjects -= num_removed; + + if (mNumDeadObjects != mDeadObjects.size()) + { + LL_WARNS() << "Num dead objects != dead object list size" << LL_ENDL; + } + // } void LLViewerObjectList::removeFromActiveList(LLViewerObject* objectp) From 5e1c9a92a803d9b63027bb9ffce9d83827bb95b2 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 16 Dec 2017 19:34:03 +0100 Subject: [PATCH 40/75] Add support for FMOD Studio, originally by Drake Arconis (Alchemy Viewer), with FS-specific additions by Drakeo --- autobuild.xml | 68 +- indra/cmake/CMakeLists.txt | 2 + indra/cmake/Copy3rdPartyLibs.cmake | 31 +- indra/cmake/FMODSTUDIO.cmake | 53 ++ indra/cmake/FindFMODSTUDIO.cmake | 65 ++ indra/llaudio/CMakeLists.txt | 18 + indra/llaudio/llaudioengine_fmodstudio.cpp | 749 ++++++++++++++++++ indra/llaudio/llaudioengine_fmodstudio.h | 137 ++++ indra/llaudio/lllistener_fmodstudio.cpp | 127 +++ indra/llaudio/lllistener_fmodstudio.h | 64 ++ indra/llaudio/llstreamingaudio_fmodstudio.cpp | 526 ++++++++++++ indra/llaudio/llstreamingaudio_fmodstudio.h | 86 ++ indra/newview/CMakeLists.txt | 18 + indra/newview/app_settings/settings.xml | 11 + indra/newview/llstartup.cpp | 17 +- indra/newview/viewer_manifest.py | 27 + scripts/configure_firestorm.sh | 15 +- 17 files changed, 2002 insertions(+), 12 deletions(-) create mode 100644 indra/cmake/FMODSTUDIO.cmake create mode 100644 indra/cmake/FindFMODSTUDIO.cmake create mode 100644 indra/llaudio/llaudioengine_fmodstudio.cpp create mode 100644 indra/llaudio/llaudioengine_fmodstudio.h create mode 100644 indra/llaudio/lllistener_fmodstudio.cpp create mode 100644 indra/llaudio/lllistener_fmodstudio.h create mode 100644 indra/llaudio/llstreamingaudio_fmodstudio.cpp create mode 100644 indra/llaudio/llstreamingaudio_fmodstudio.h diff --git a/autobuild.xml b/autobuild.xml index c15b62fc06..3015184439 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -586,6 +586,66 @@ version 2.0.1.297014 + fmodstudio + + copyright + FMOD Studio, copyright (c) Firelight Technologies Pty, Ltd., 2012-2017. + description + FMOD Studio audio system library + license + fmodstudio + license_file + LICENSES/fmodstudio.txt + name + fmodstudio + platforms + + darwin + + archive + + hash + 6324120be383af3564f2b46b07f1b765 + hash_algorithm + md5 + url + file:///opt/firestorm/fmodstudio-1.10.02-darwin-.tar.bz2 + + name + darwin + + linux + + archive + + hash + 1331456a3df95294eaf44fab990f62cd + hash_algorithm + md5 + url + file:///opt/firestorm/fmodstudio-1.10.02-linux-.tar.bz2 + + name + linux + + windows + + archive + + hash + 206f34d4a262a09323bc9d03cd81a2f6 + hash_algorithm + md5 + url + file:///c:/cygwin/opt/firestorm/fmodstudio-1.10.02-windows-173500059.tar.bz2 + + name + windows + + + version + 1.10.00 + fmodex copyright @@ -3488,7 +3548,7 @@ options - --fmodex + --fmodstudio --kdu --version --btype RelWithDebInfo @@ -3562,7 +3622,7 @@ options - --fmodex + --fmodstudio --kdu --version --platform win32 @@ -3598,7 +3658,7 @@ options - --fmodex + --fmodstudio --kdu --version --platform win32 @@ -3634,7 +3694,7 @@ options - --fmodex + --fmodstudio --kdu --version --platform win32 diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 43e05aeee2..857a6499ef 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -26,6 +26,7 @@ set(cmake_SOURCE_FILES FindAPR.cmake FindAutobuild.cmake FindBerkeleyDB.cmake + FindFMODSTUDIO.cmake FindFMODEX.cmake FindGLH.cmake FindGoogleBreakpad.cmake @@ -38,6 +39,7 @@ set(cmake_SOURCE_FILES FindURIPARSER.cmake FindXmlRpcEpi.cmake FindZLIB.cmake + FMODSTUDIO.cmake FMODEX.cmake FreeType.cmake GLEXT.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 2fcf1ca6f1..ee2d333121 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -57,7 +57,7 @@ if(WINDOWS) if( NOT ND_USE_OPENJPEG2 ) set(debug_files ${debug_files} openjpegd.dll ) set(release_files ${release_files} openjpeg.dll ) - else() + else() set(debug_files ${debug_files} openjp2.dll ) set(release_files ${release_files} openjp2.dll ) endif( NOT ND_USE_OPENJPEG2 ) @@ -70,6 +70,16 @@ if(WINDOWS) set(release_files ${release_files} libtcmalloc_minimal.dll) endif(USE_TCMALLOC) + if (FMODSTUDIO) + if( NOT ND_BUILD64BIT_ARCH ) + set(debug_files ${debug_files} fmodL.dll) + set(release_files ${release_files} fmod.dll) + else( NOT ND_BUILD64BIT_ARCH ) + set(debug_files ${debug_files} fmodL64.dll) + set(release_files ${release_files} fmod64.dll) + endif( NOT ND_BUILD64BIT_ARCH ) + endif (FMODSTUDIO) + if (FMODEX) if( NOT ND_BUILD64BIT_ARCH ) set(debug_files ${debug_files} fmodexL.dll) @@ -185,10 +195,15 @@ elseif(DARWIN) libGLOD.dylib libhunspell-1.3.0.dylib libndofdev.dylib - libgrowl.dylib + libgrowl.dylib libgrowl++.dylib ) + if (FMODSTUDIO) + set(debug_files ${debug_files} libfmodL.dylib) + set(release_files ${release_files} libfmod.dylib) + endif (FMODSTUDIO) + if (FMODEX) set(debug_files ${debug_files} libfmodexL.dylib) set(release_files ${release_files} libfmodex.dylib) @@ -247,7 +262,7 @@ elseif(LINUX) libdb-5.1.so libfreetype.so.6.6.2 libfreetype.so.6 - ) + ) endif( NOT ND_BUILD64BIT_ARCH ) if( NOT ND_USE_OPENJPEG2 ) set(release_files ${release_files} libopenjpeg.so ) @@ -258,6 +273,16 @@ elseif(LINUX) set(release_files ${release_files} "libtcmalloc_minimal.so") endif (USE_TCMALLOC) + if (FMODSTUDIO) + if( NOT ND_BUILD64BIT_ARCH ) + set(debug_files ${debug_files} "libfmodL.so") + set(release_files ${release_files} "libfmod.so") + else( NOT ND_BUILD64BIT_ARCH ) + set(debug_files ${debug_files} "libfmodL64.so") + set(release_files ${release_files} "libfmod64.so") + endif( NOT ND_BUILD64BIT_ARCH ) + endif (FMODSTUDIO) + #if (FMODEX) # set(debug_files ${debug_files} "libfmodexL.so") # set(release_files ${release_files} "libfmodex.so") diff --git a/indra/cmake/FMODSTUDIO.cmake b/indra/cmake/FMODSTUDIO.cmake new file mode 100644 index 0000000000..76e05c5e47 --- /dev/null +++ b/indra/cmake/FMODSTUDIO.cmake @@ -0,0 +1,53 @@ +# -*- cmake -*- + +# FMOD can be set when launching the make using the argument -DFMOD:BOOL=ON +# When building using proprietary binaries though (i.e. having access to LL private servers), +# we always build with FMODSTUDIO. +# Open source devs should use the -DFMODSTUDIO:BOOL=ON then if they want to build with FMOD, whether +# they are using USESYSTEMLIBS or not. +if (INSTALL_PROPRIETARY) + set(FMODSTUDIO ON CACHE BOOL "Using FMOD Studio sound library.") +endif (INSTALL_PROPRIETARY) + + +if (FMODSTUDIO) + if (USESYSTEMLIBS) + # In that case, we use the version of the library installed on the system + set(FMODSTUDIO_FIND_REQUIRED ON) + include(FindFMODSTUDIO) + else (USESYSTEMLIBS) + if (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) + # If the path have been specified in the arguments, use that + set(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY}) + MESSAGE(STATUS "Using FMODSTUDIO path: ${FMODSTUDIO_LIBRARIES}, ${FMODSTUDIO_INCLUDE_DIR}") + else (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) + # If not, we're going to try to get the package listed in autobuild.xml + # Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL) + # as accessing the private LL location will fail if you don't have the credential + include(Prebuilt) + use_prebuilt_binary(fmodstudio) + if (WINDOWS) + if (NOT ND_BUILD64BIT_ARCH) + set(FMODSTUDIO_LIBRARY + debug fmodL_vc + optimized fmod_vc) + elseif (ND_BUILD64BIT_ARCH) + set(FMODSTUDIO_LIBRARY + debug fmodL64_vc + optimized fmod64_vc) + endif(NOT ND_BUILD64BIT_ARCH) + elseif (DARWIN) + set(FMODSTUDIO_LIBRARY + debug fmodL + optimized fmod) + elseif (LINUX) + set(FMODSTUDIO_LIBRARY + debug fmodL + optimized fmod) + endif (WINDOWS) + set(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY}) + set(FMODSTUDIO_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodstudio) + endif (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) + endif (USESYSTEMLIBS) +endif (FMODSTUDIO) + diff --git a/indra/cmake/FindFMODSTUDIO.cmake b/indra/cmake/FindFMODSTUDIO.cmake new file mode 100644 index 0000000000..4562b0ae45 --- /dev/null +++ b/indra/cmake/FindFMODSTUDIO.cmake @@ -0,0 +1,65 @@ +# -*- cmake -*- + +# - Find FMODSTUDIO +# Find the FMODSTUDIO includes and library +# This module defines +# FMODSTUDIO_INCLUDE_DIR, where to find fmod.h and fmod_errors.h +# FMODSTUDIO_LIBRARIES, the libraries needed to use FMODSTUDIO. +# FMODSTUDIO, If false, do not try to use FMODSTUDIO. +# also defined, but not for general use are +# FMODSTUDIO_LIBRARY, where to find the FMODSTUDIO library. + +FIND_PATH(FMODSTUDIO_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod) + +SET(FMODSTUDIO_NAMES ${FMODSTUDIO_NAMES} fmod fmod_vc) +FIND_LIBRARY(FMODSTUDIO_LIBRARY + NAMES ${FMODSTUDIO_NAMES} + PATH_SUFFIXES fmod + ) + +IF (FMODSTUDIO_SDK_DIR OR WINDOWS) + if(WINDOWS) + set(FMODSTUDIO_SDK_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows" CACHE PATH "Path to FMODSTUDIO") + STRING(REGEX REPLACE "\\\\" "/" FMODSTUDIO_SDK_DIR ${FMODSTUDIO_SDK_DIR}) + endif(WINDOWS) + find_library(FMODSTUDIO_LIBRARY + fmod_vc fmodL_vc + PATHS + ${FMODSTUDIO_SDK_DIR}/api/lib + ${FMODSTUDIO_SDK_DIR}/api + ${FMODSTUDIO_SDK_DIR} + ) + find_path(FMODSTUDIO_INCLUDE_DIR fmod.h + ${FMODSTUDIO_SDK_DIR}/api/inc + ${FMODSTUDIO_SDK_DIR}/api + ${FMODSTUDIO_SDK_DIR} + ) + find_path(FMODSTUDIO_INCLUDE_DIR fmod.h + ${FMODSTUDIO_SDK_DIR}/api/inc + ${FMODSTUDIO_SDK_DIR}/api + ${FMODSTUDIO_SDK_DIR} + ) + IF (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) + SET(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY}) + SET(FMODSTUDIO_FOUND "YES") + endif (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) +ENDIF (FMODSTUDIO_SDK_DIR OR WINDOWS) + +IF (FMODSTUDIO_FOUND) + IF (NOT FMODSTUDIO_FIND_QUIETLY) + MESSAGE(STATUS "Found FMODSTUDIO: ${FMODSTUDIO_LIBRARIES}") + ENDIF (NOT FMODSTUDIO_FIND_QUIETLY) +ELSE (FMODSTUDIO_FOUND) + IF (FMODSTUDIO_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find FMODSTUDIO library") + ENDIF (FMODSTUDIO_FIND_REQUIRED) +ENDIF (FMODSTUDIO_FOUND) + +# Deprecated declarations. +SET (NATIVE_FMODSTUDIO_INCLUDE_PATH ${FMODSTUDIO_INCLUDE_DIR} ) +GET_FILENAME_COMPONENT (NATIVE_FMODSTUDIO_LIB_PATH ${FMODSTUDIO_LIBRARY} PATH) + +MARK_AS_ADVANCED( + FMODSTUDIO_LIBRARY + FMODSTUDIO_INCLUDE_DIR + ) diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index e943dd5d5c..0df1be69b9 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -4,6 +4,7 @@ project(llaudio) include(00-Common) include(LLAudio) +include(FMODSTUDIO) include(FMODEX) include(OPENAL) include(LLCommon) @@ -42,6 +43,23 @@ set(llaudio_HEADER_FILES llwindgen.h ) +if (FMODSTUDIO) + include_directories( + ${FMODSTUDIO_INCLUDE_DIR} + ) + list(APPEND llaudio_SOURCE_FILES + llaudioengine_fmodstudio.cpp + lllistener_fmodstudio.cpp + llstreamingaudio_fmodstudio.cpp + ) + + list(APPEND llaudio_HEADER_FILES + llaudioengine_fmodstudio.h + lllistener_fmodstudio.h + llstreamingaudio_fmodstudio.h + ) +endif (FMODSTUDIO) + if (FMODEX) include_directories( ${FMODEX_INCLUDE_DIR} diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp new file mode 100644 index 0000000000..9d7b0509ac --- /dev/null +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -0,0 +1,749 @@ +/** + * @file audioengine_fmodstudio.cpp + * @brief Implementation of LLAudioEngine class abstracting the audio + * support as a FMOD Studio implementation + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llstreamingaudio.h" +#include "llstreamingaudio_fmodstudio.h" + +#include "llaudioengine_fmodstudio.h" +#include "lllistener_fmodstudio.h" + +#include "llerror.h" +#include "llmath.h" +#include "llrand.h" + +#include "fmod.hpp" +#include "fmod_errors.h" +#include "lldir.h" + +#include "sound_ids.h" + +#include "indra_constants.h" + +const U32 EXTRA_SOUND_CHANNELS = 10; + +FMOD_RESULT F_CALLBACK windDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels); + +FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0}; + +LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler, U32 resample_method) + : mInited(false) + , mWindGen(NULL) + , mWindDSPDesc(NULL) + , mWindDSP(NULL) + , mSystem(NULL) + , mEnableProfiler(enable_profiler) + , mResampleMethod(resample_method) +{ +} + +LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO() +{ +} + +static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) +{ + if(result == FMOD_OK) + return false; + + if (result != FMOD_ERR_INVALID_HANDLE) + { + LL_WARNS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + } + else + { + LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + } + + return true; +} + +bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) +{ + U32 version; + FMOD_RESULT result; + + LL_DEBUGS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() initializing FMOD" << LL_ENDL; + + result = FMOD::System_Create(&mSystem); + if(Check_FMOD_Error(result, "FMOD::System_Create")) + return false; + + //will call LLAudioEngine_FMODSTUDIO::allocateListener, which needs a valid mSystem pointer. + LLAudioEngine::init(num_channels, userdata); + + result = mSystem->getVersion(&version); + Check_FMOD_Error(result, "FMOD::System::getVersion"); + + if (version < FMOD_VERSION) + { + LL_WARNS("AppInit") << "Error : You are using the wrong FMOD Studio version (" << version + << ")! You should be using FMOD Studio" << FMOD_VERSION << LL_ENDL; + } + + // In this case, all sounds, PLUS wind and stream will be software. + result = mSystem->setSoftwareChannels(num_channels + EXTRA_SOUND_CHANNELS); + Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels"); + + FMOD_ADVANCEDSETTINGS adv_settings = { }; + adv_settings.cbSize = sizeof(FMOD_ADVANCEDSETTINGS); + switch (mResampleMethod) + { + default: + case RESAMPLE_LINEAR: + adv_settings.resamplerMethod = FMOD_DSP_RESAMPLER_LINEAR; + break; + case RESAMPLE_CUBIC: + adv_settings.resamplerMethod = FMOD_DSP_RESAMPLER_CUBIC; + break; + case RESAMPLE_SPLINE: + adv_settings.resamplerMethod = FMOD_DSP_RESAMPLER_SPLINE; + break; + } + + // In this case, all sounds, PLUS wind and stream will be software. + result = mSystem->setSoftwareChannels(num_channels + 2); + Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels"); + + U32 fmod_flags = FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED | FMOD_INIT_THREAD_UNSAFE; + if(mEnableProfiler) + { + fmod_flags |= FMOD_INIT_PROFILE_ENABLE; + } + +#if LL_LINUX + bool audio_ok = false; + + if (!audio_ok) + { + if (NULL == getenv("LL_BAD_FMOD_PULSEAUDIO")) /*Flawfinder: ignore*/ + { + LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; + if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO)) == FMOD_OK && + (result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, const_cast(APP_NAME.c_str()))) == FMOD_OK) + { + LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL; + audio_ok = true; + } + else + { + Check_FMOD_Error(result, "PulseAudio audio output FAILED to initialize"); + } + } + else + { + LL_DEBUGS("AppInit") << "PulseAudio audio output SKIPPED" << LL_ENDL; + } + } + if (!audio_ok) + { + if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/ + { + LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; + if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA)) == FMOD_OK && + (result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, 0)) == FMOD_OK) + { + LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL; + audio_ok = true; + } + else + { + Check_FMOD_Error(result, "ALSA audio output FAILED to initialize"); + } + } + else + { + LL_DEBUGS("AppInit") << "ALSA audio output SKIPPED" << LL_ENDL; + } + } + if (!audio_ok) + { + LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL; + return false; + } + + // We're interested in logging which output method we + // ended up with, for QA purposes. + FMOD_OUTPUTTYPE output_type; + if(!Check_FMOD_Error(mSystem->getOutput(&output_type), "FMOD::System::getOutput")) + { + switch (output_type) + { + case FMOD_OUTPUTTYPE_NOSOUND: + LL_INFOS("AppInit") << "Audio output: NoSound" << LL_ENDL; break; + case FMOD_OUTPUTTYPE_PULSEAUDIO: + LL_INFOS("AppInit") << "Audio output: PulseAudio" << LL_ENDL; break; + case FMOD_OUTPUTTYPE_ALSA: + LL_INFOS("AppInit") << "Audio output: ALSA" << LL_ENDL; break; + default: + LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; + }; + } +#else // LL_LINUX + + // initialize the FMOD engine + result = mSystem->init( num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, 0); + if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) + { + /* + Ok, the speaker mode selected isn't supported by this soundcard. Switch it + back to stereo... + */ + result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0); + Check_FMOD_Error(result,"Error falling back to stereo mode"); + /* + ... and re-init. + */ + result = mSystem->init( num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, 0); + } + if(Check_FMOD_Error(result, "Error initializing FMOD Studio")) + return false; +#endif + + if (mEnableProfiler) + { + Check_FMOD_Error(mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]), "FMOD::System::createChannelGroup"); + } + + // set up our favourite FMOD-native streaming audio implementation if none has already been added + if (!getStreamingAudioImpl()) // no existing implementation added + setStreamingAudioImpl(new LLStreamingAudio_FMODSTUDIO(mSystem)); + + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL; + + int r_numbuffers, r_samplerate, r_channels; + unsigned int r_bufferlength; + mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers); + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_bufferlength=" << r_bufferlength << " bytes" << LL_ENDL; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_numbuffers=" << r_numbuffers << LL_ENDL; + + char r_name[512]; + mSystem->getDriverInfo(0, r_name, 511, NULL, &r_samplerate, NULL, &r_channels); + r_name[511] = '\0'; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_name=\"" << r_name << "\"" << LL_ENDL; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_samplerate=" << r_samplerate << "Hz" << LL_ENDL; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_channels=" << r_channels << LL_ENDL; + + int latency = 100; // optimistic default - i suspect if sample rate is 0, everything breaks. + if ( r_samplerate != 0 ) + latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate); + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): latency=" << latency << "ms" << LL_ENDL; + + mInited = true; + + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): initialization complete." << LL_ENDL; + + return true; +} + + +std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose) +{ + llassert_always(mSystem); + if (verbose) + { + U32 version; + if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion")) + { + return llformat("FMOD Studio %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF); + } + } + return "FMOD Studio"; +} + + +void LLAudioEngine_FMODSTUDIO::allocateListener(void) +{ + try + { + mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem); + } + catch (const std::bad_alloc& e) + { + LL_WARNS() << "Listener allocation failed due to: " << e.what() << LL_ENDL; + } +} + + +void LLAudioEngine_FMODSTUDIO::shutdown() +{ + LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; + LLAudioEngine::shutdown(); + + LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL; + if ( mSystem ) // speculative fix for MAINT-2657 + { + Check_FMOD_Error(mSystem->close(), "FMOD::System::close"); + Check_FMOD_Error(mSystem->release(), "FMOD::System::release"); + } + LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() done closing FMOD Studio" << LL_ENDL; + + delete mListenerp; + mListenerp = NULL; +} + + +LLAudioBuffer * LLAudioEngine_FMODSTUDIO::createBuffer() +{ + return new LLAudioBufferFMODSTUDIO(mSystem); +} + + +LLAudioChannel * LLAudioEngine_FMODSTUDIO::createChannel() +{ + return new LLAudioChannelFMODSTUDIO(mSystem); +} + +bool LLAudioEngine_FMODSTUDIO::initWind() +{ + mNextWindUpdate = 0.0; + + cleanupWind(); + + mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); + memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero + mWindDSPDesc->pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; + strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); //Set name to "Wind Unit" + mWindDSPDesc->numoutputbuffers = 1; + mWindDSPDesc->read = &windDSPCallback; //Assign callback. + if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP") || !mWindDSP) + return false; + + int frequency = 44100; + FMOD_SPEAKERMODE mode; + if (!Check_FMOD_Error(mSystem->getSoftwareFormat(&frequency, &mode, nullptr), "FMOD::System::getSoftwareFormat")) + { + mWindGen = new LLWindGen((U32)frequency); + + if (!Check_FMOD_Error(mWindDSP->setUserData((void*)mWindGen), "FMOD::DSP::setUserData") && + !Check_FMOD_Error(mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode), "FMOD::DSP::setChannelFormat") && + !Check_FMOD_Error(mSystem->playDSP(mWindDSP, nullptr, false, nullptr), "FMOD::System::playDSP")) + return true; //Success + } + + cleanupWind(); + return false; +} + + +void LLAudioEngine_FMODSTUDIO::cleanupWind() +{ + if (mWindDSP) + { + FMOD::ChannelGroup* mastergroup = NULL; + if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&mastergroup), "FMOD::System::getMasterChannelGroup") && mastergroup) + Check_FMOD_Error(mastergroup->removeDSP(mWindDSP), "FMOD::ChannelGroup::removeDSP"); + Check_FMOD_Error(mWindDSP->release(), "FMOD::DSP::release"); + mWindDSP = NULL; + } + + delete mWindDSPDesc; + mWindDSPDesc = NULL; + + delete mWindGen; + mWindGen = NULL; +} + + +//----------------------------------------------------------------------- +void LLAudioEngine_FMODSTUDIO::updateWind(LLVector3 wind_vec, F32 camera_height_above_water) +{ + LLVector3 wind_pos; + F64 pitch; + F64 center_freq; + + if (!mEnableWind) + { + return; + } + + if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) + { + + // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) + // need to convert this to the conventional orientation DS3D and OpenAL use + // where +X = right, +Y = up, +Z = backwards + + wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); + + // cerr << "Wind update" << endl; + + pitch = 1.0 + mapWindVecToPitch(wind_vec); + center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); + + mWindGen->mTargetFreq = (F32)center_freq; + mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; + mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); + } +} + +//----------------------------------------------------------------------- +void LLAudioEngine_FMODSTUDIO::setInternalGain(F32 gain) +{ + if (!mInited) + { + return; + } + + gain = llclamp( gain, 0.0f, 1.0f ); + + FMOD::ChannelGroup *master_group; + if(Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup")) + return; + + master_group->setVolume(gain); + + LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); + if ( saimpl ) + { + // fmod likes its streaming audio channel gain re-asserted after + // master volume change. + saimpl->setGain(saimpl->getGain()); + } +} + +// +// LLAudioChannelFMODSTUDIO implementation +// + +LLAudioChannelFMODSTUDIO::LLAudioChannelFMODSTUDIO(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0) +{ +} + + +LLAudioChannelFMODSTUDIO::~LLAudioChannelFMODSTUDIO() +{ + cleanup(); +} + +bool LLAudioChannelFMODSTUDIO::updateBuffer() +{ + if (mCurrentSourcep) + { + if (LLAudioChannel::updateBuffer()) + { + // Base class update returned true, which means that we need to actually + // set up the channel for a different buffer. + + LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *) mCurrentSourcep->getCurrentBuffer(); + + // Grab the FMOD sample associated with the buffer + FMOD::Sound *soundp = bufferp->getSound(); + if (!soundp) + { + // This is bad, there should ALWAYS be a sound associated with a legit + // buffer. + LL_ERRS() << "No FMOD sound!" << LL_ENDL; + return false; + } + + + // Actually play the sound. Start it off paused so we can do all the necessary + // setup. + if (!mChannelp) + { + FMOD_RESULT result = getSystem()->playSound(soundp, nullptr, true, &mChannelp); + Check_FMOD_Error(result, "FMOD::System::playSound"); + } + + //LL_INFOS() << "Setting up channel " << std::hex << mChannelID << std::dec << LL_ENDL; + } + + //FMOD_RESULT result; + + mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain()); + //Check_FMOD_Error(result, "FMOD::Channel::setVolume"); + + mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); + /*if(Check_FMOD_Error(result, "FMOD::Channel::setMode")) + { + S32 index; + mChannelp->getIndex(&index); + LL_WARNS() << "Channel " << index << "Source ID: " << mCurrentSourcep->getID() + << " at " << mCurrentSourcep->getPositionGlobal() << LL_ENDL; + }*/ + } + else + { + LL_DEBUGS() << "No source buffer!" << LL_ENDL; + return false; + } + + return true; +} + + +void LLAudioChannelFMODSTUDIO::update3DPosition() +{ + if (!mChannelp) + { + // We're not actually a live channel (i.e., we're not playing back anything) + return; + } + + LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *)mCurrentBufferp; + if (!bufferp) + { + // We don't have a buffer associated with us (should really have been picked up + // by the above if. + return; + } + + if (mCurrentSourcep->isAmbient()) + { + // Ambient sound, don't need to do any positional updates. + set3DMode(false); + } + else + { + // Localized sound. Update the position and velocity of the sound. + set3DMode(true); + + LLVector3 float_pos; + float_pos.setVec(mCurrentSourcep->getPositionGlobal()); + FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV); + Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes"); + } +} + + +void LLAudioChannelFMODSTUDIO::updateLoop() +{ + if (!mChannelp) + { + // May want to clear up the loop/sample counters. + return; + } + + // + // Hack: We keep track of whether we looped or not by seeing when the + // sample position looks like it's going backwards. Not reliable; may + // yield false negatives. + // + U32 cur_pos; + Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES),"FMOD::Channel::getPosition"); + + if (cur_pos < (U32)mLastSamplePos) + { + mLoopedThisFrame = true; + } + mLastSamplePos = cur_pos; +} + + +void LLAudioChannelFMODSTUDIO::cleanup() +{ + if (!mChannelp) + { + //LL_INFOS() << "Aborting cleanup with no channel handle." << LL_ENDL; + return; + } + + //LL_INFOS() << "Cleaning up channel: " << mChannelID << LL_ENDL; + Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop"); + + mCurrentBufferp = NULL; + mChannelp = NULL; +} + + +void LLAudioChannelFMODSTUDIO::play() +{ + if (!mChannelp) + { + LL_WARNS() << "Playing without a channel handle, aborting" << LL_ENDL; + return; + } + + Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::setPaused"); + + getSource()->setPlayedOnce(true); + + if(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]) + Check_FMOD_Error(mChannelp->setChannelGroup(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]),"FMOD::Channel::setChannelGroup"); +} + + +void LLAudioChannelFMODSTUDIO::playSynced(LLAudioChannel *channelp) +{ + LLAudioChannelFMODSTUDIO *fmod_channelp = (LLAudioChannelFMODSTUDIO*)channelp; + if (!(fmod_channelp->mChannelp && mChannelp)) + { + // Don't have channels allocated to both the master and the slave + return; + } + + U32 cur_pos; + if(Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position")) + return; + + cur_pos %= mCurrentBufferp->getLength(); + + // Try to match the position of our sync master + Check_FMOD_Error(mChannelp->setPosition(cur_pos,FMOD_TIMEUNIT_PCMBYTES),"Unable to set current position"); + + // Start us playing + play(); +} + + +bool LLAudioChannelFMODSTUDIO::isPlaying() +{ + if (!mChannelp) + { + return false; + } + + bool paused, playing; + Check_FMOD_Error(mChannelp->getPaused(&paused),"FMOD::Channel::getPaused"); + Check_FMOD_Error(mChannelp->isPlaying(&playing),"FMOD::Channel::isPlaying"); + return !paused && playing; +} + + +// +// LLAudioChannelFMODSTUDIO implementation +// + + +LLAudioBufferFMODSTUDIO::LLAudioBufferFMODSTUDIO(FMOD::System *system) : mSystemp(system), mSoundp(NULL) +{ +} + + +LLAudioBufferFMODSTUDIO::~LLAudioBufferFMODSTUDIO() +{ + if(mSoundp) + { + Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::Release"); + mSoundp = NULL; + } +} + + +bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename) +{ + // Try to open a wav file from disk. This will eventually go away, as we don't + // really want to block doing this. + if (filename.empty()) + { + // invalid filename, abort. + return false; + } + + if (!gDirUtilp->fileExists(filename)) + { + // File not found, abort. + return false; + } + + if (mSoundp) + { + // If there's already something loaded in this buffer, clean it up. + Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::release"); + mSoundp = NULL; + } + + FMOD_MODE base_mode = FMOD_LOOP_NORMAL; + FMOD_CREATESOUNDEXINFO exinfo; + memset(&exinfo,0,sizeof(exinfo)); + exinfo.cbsize = sizeof(exinfo); + exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading. + // Load up the wav file into an fmod sample + FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp); + if (result != FMOD_OK) + { + // We failed to load the file for some reason. + LL_WARNS() << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << LL_ENDL; + + // + // If we EVER want to load wav files provided by end users, we need + // to rethink this! + // + // file is probably corrupt - remove it. + LLFile::remove(filename); + return false; + } + + // Everything went well, return true + return true; +} + + +U32 LLAudioBufferFMODSTUDIO::getLength() +{ + if (!mSoundp) + { + return 0; + } + + U32 length; + Check_FMOD_Error(mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES),"FMOD::Sound::getLength"); + return length; +} + + +void LLAudioChannelFMODSTUDIO::set3DMode(bool use3d) +{ + FMOD_MODE current_mode; + if(Check_FMOD_Error(mChannelp->getMode(¤t_mode),"FMOD::Channel::getMode")) + return; + FMOD_MODE new_mode = current_mode; + new_mode &= ~(use3d ? FMOD_2D : FMOD_3D); + new_mode |= use3d ? FMOD_3D : FMOD_2D; + + if(current_mode != new_mode) + { + Check_FMOD_Error(mChannelp->setMode(new_mode),"FMOD::Channel::setMode"); + } +} + +// *NOTE: This is almost certainly being called on the mixer thread, +// not the main thread. May have implications for callees or audio +// engine shutdown. + +FMOD_RESULT F_CALLBACK windDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) +{ + // inbuffer = incomming data. + // newbuffer = outgoing data. AKA this DSP's output. + // length = length in samples at this mix time. True buffer size, in bytes, would be (length * sizeof(float) * inchannels). + // userdata = user-provided data attached this DSP via FMOD::DSP::setUserData. + + LLWindGen *windgen; + FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance; + + thisdsp->getUserData((void **)&windgen); + + if (windgen) + windgen->windGenerate((LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT *)outbuffer, length); + + return FMOD_OK; +} diff --git a/indra/llaudio/llaudioengine_fmodstudio.h b/indra/llaudio/llaudioengine_fmodstudio.h new file mode 100644 index 0000000000..fb1b8ae2cd --- /dev/null +++ b/indra/llaudio/llaudioengine_fmodstudio.h @@ -0,0 +1,137 @@ +/** + * @file audioengine_fmodstudio.h + * @brief Definition of LLAudioEngine class abstracting the audio + * support as a FMOD Studio implementation + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, 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_AUDIOENGINE_FMODSTUDIO_H +#define LL_AUDIOENGINE_FMODSTUDIO_H + +#include "llaudioengine.h" +#include "llwindgen.h" + +//Stubs +class LLAudioStreamManagerFMODSTUDIO; +namespace FMOD +{ + class System; + class Channel; + class ChannelGroup; + class Sound; + class DSP; +} +typedef struct FMOD_DSP_DESCRIPTION FMOD_DSP_DESCRIPTION; + +//Interfaces +class LLAudioEngine_FMODSTUDIO : public LLAudioEngine +{ +public: + enum + { + RESAMPLE_LINEAR=0, + RESAMPLE_CUBIC, + RESAMPLE_SPLINE + }; + LLAudioEngine_FMODSTUDIO(bool enable_profiler, U32 resample_method); + virtual ~LLAudioEngine_FMODSTUDIO(); + + // initialization/startup/shutdown + virtual bool init(const S32 num_channels, void *user_data); + virtual std::string getDriverName(bool verbose); + virtual void allocateListener(); + + virtual void shutdown(); + + /*virtual*/ bool initWind(); + /*virtual*/ void cleanupWind(); + + /*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water); + + typedef F32 MIXBUFFERFORMAT; + + FMOD::System *getSystem() const {return mSystem;} +protected: + /*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to. + /*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel. + + /*virtual*/ void setInternalGain(F32 gain); + + bool mInited; + + LLWindGen *mWindGen; + + FMOD_DSP_DESCRIPTION *mWindDSPDesc; + FMOD::DSP *mWindDSP; + FMOD::System *mSystem; + bool mEnableProfiler; + U32 mResampleMethod; + +public: + static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT]; +}; + + +class LLAudioChannelFMODSTUDIO : public LLAudioChannel +{ +public: + LLAudioChannelFMODSTUDIO(FMOD::System *audioengine); + virtual ~LLAudioChannelFMODSTUDIO(); + +protected: + /*virtual*/ void play(); + /*virtual*/ void playSynced(LLAudioChannel *channelp); + /*virtual*/ void cleanup(); + /*virtual*/ bool isPlaying(); + + /*virtual*/ bool updateBuffer(); + /*virtual*/ void update3DPosition(); + /*virtual*/ void updateLoop(); + + void set3DMode(bool use3d); +protected: + FMOD::System *getSystem() const {return mSystemp;} + FMOD::System *mSystemp; + FMOD::Channel *mChannelp; + S32 mLastSamplePos; +}; + + +class LLAudioBufferFMODSTUDIO : public LLAudioBuffer +{ +public: + LLAudioBufferFMODSTUDIO(FMOD::System *audioengine); + virtual ~LLAudioBufferFMODSTUDIO(); + + /*virtual*/ bool loadWAV(const std::string& filename); + /*virtual*/ U32 getLength(); + friend class LLAudioChannelFMODSTUDIO; +protected: + FMOD::System *getSystem() const {return mSystemp;} + FMOD::System *mSystemp; + FMOD::Sound *getSound() const{ return mSoundp; } + FMOD::Sound *mSoundp; +}; + + +#endif // LL_AUDIOENGINE_FMODSTUDIO_H diff --git a/indra/llaudio/lllistener_fmodstudio.cpp b/indra/llaudio/lllistener_fmodstudio.cpp new file mode 100644 index 0000000000..f5a10442dc --- /dev/null +++ b/indra/llaudio/lllistener_fmodstudio.cpp @@ -0,0 +1,127 @@ +/** + * @file listener_fmodstudio.cpp + * @brief Implementation of LISTENER class abstracting the audio + * support as a FMOD Studio 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 "linden_common.h" +#include "llaudioengine.h" +#include "lllistener_fmodstudio.h" +#include "fmod.hpp" + +//----------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------- +LLListener_FMODSTUDIO::LLListener_FMODSTUDIO(FMOD::System *system) + : LLListener(), + mDopplerFactor(1.0f), + mRolloffFactor(1.0f) +{ + mSystem = system; +} + +//----------------------------------------------------------------------- +LLListener_FMODSTUDIO::~LLListener_FMODSTUDIO() +{ +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::translate(LLVector3 offset) +{ + LLListener::translate(offset); + + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::setPosition(LLVector3 pos) +{ + LLListener::setPosition(pos); + + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::setVelocity(LLVector3 vel) +{ + LLListener::setVelocity(vel); + + mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL); +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::orient(LLVector3 up, LLVector3 at) +{ + LLListener::orient(up, at); + + mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV); +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::commitDeferredChanges() +{ + if(!mSystem) + { + return; + } + + mSystem->update(); +} + + +void LLListener_FMODSTUDIO::setRolloffFactor(F32 factor) +{ + //An internal FMOD Studio optimization skips 3D updates if there have not been changes to the 3D sound environment. + //Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well. + //In short: Changing the position ticks a dirtyflag inside fmod studio, which makes it not skip 3D processing next update call. + if(mRolloffFactor != factor) + { + LLVector3 tmp_pos = mPosition - LLVector3(0.f,0.f,.1f); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*) tmp_pos.mV, NULL, NULL, NULL); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*) mPosition.mV, NULL, NULL, NULL); + } + mRolloffFactor = factor; + mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); +} + + +F32 LLListener_FMODSTUDIO::getRolloffFactor() +{ + return mRolloffFactor; +} + + +void LLListener_FMODSTUDIO::setDopplerFactor(F32 factor) +{ + mDopplerFactor = factor; + mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); +} + + +F32 LLListener_FMODSTUDIO::getDopplerFactor() +{ + return mDopplerFactor; +} + + diff --git a/indra/llaudio/lllistener_fmodstudio.h b/indra/llaudio/lllistener_fmodstudio.h new file mode 100644 index 0000000000..ebe42f0e38 --- /dev/null +++ b/indra/llaudio/lllistener_fmodstudio.h @@ -0,0 +1,64 @@ +/** + * @file listener_fmodstudio.h + * @brief Description of LISTENER class abstracting the audio support + * as an FMOD Studio implementation (windows and Linux) + * + * $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_LISTENER_FMODSTUDIO_H +#define LL_LISTENER_FMODSTUDIO_H + +#include "lllistener.h" + +//Stubs +namespace FMOD +{ + class System; +} + +//Interfaces +class LLListener_FMODSTUDIO : public LLListener +{ + public: + LLListener_FMODSTUDIO(FMOD::System *system); + virtual ~LLListener_FMODSTUDIO(); + + virtual void translate(LLVector3 offset); + virtual void setPosition(LLVector3 pos); + virtual void setVelocity(LLVector3 vel); + virtual void orient(LLVector3 up, LLVector3 at); + virtual void commitDeferredChanges(); + + virtual void setDopplerFactor(F32 factor); + virtual F32 getDopplerFactor(); + virtual void setRolloffFactor(F32 factor); + virtual F32 getRolloffFactor(); + protected: + FMOD::System *mSystem; + F32 mDopplerFactor; + F32 mRolloffFactor; +}; + +#endif + + diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.cpp b/indra/llaudio/llstreamingaudio_fmodstudio.cpp new file mode 100644 index 0000000000..654dcd519a --- /dev/null +++ b/indra/llaudio/llstreamingaudio_fmodstudio.cpp @@ -0,0 +1,526 @@ +/** + * @file streamingaudio_fmodstudio.cpp + * @brief LLStreamingAudio_FMODSTUDIO 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 "linden_common.h" + +#include "llmath.h" + +#include "fmod.hpp" +#include "fmod_errors.h" + +#include "llstreamingaudio_fmodstudio.h" + +inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) +{ + if (result == FMOD_OK) + return false; + LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + return true; +} + +class LLAudioStreamManagerFMODSTUDIO +{ +public: + LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url); + FMOD::Channel* startStream(); + bool stopStream(); // Returns true if the stream was successfully stopped. + bool ready(); + + const std::string& getURL() { return mInternetStreamURL; } + + FMOD_RESULT getOpenState(FMOD_OPENSTATE& openstate, unsigned int* percentbuffered = NULL, bool* starving = NULL, bool* diskbusy = NULL); +protected: + FMOD::System* mSystem; + FMOD::ChannelGroup* mChannelGroup; + FMOD::Channel* mStreamChannel; + FMOD::Sound* mInternetStream; + bool mReady; + + std::string mInternetStreamURL; +}; + + + +//--------------------------------------------------------------------------- +// Internet Streaming +//--------------------------------------------------------------------------- +LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) : + mSystem(system), + mCurrentInternetStreamp(NULL), + mStreamGroup(NULL), + mFMODInternetStreamChannelp(NULL), + mGain(1.0f) +{ + FMOD_RESULT result; + + // Number of milliseconds of audio to buffer for the audio card. + // Must be larger than the usual Second Life frame stutter time. + const U32 buffer_seconds = 10; //sec + const U32 estimated_bitrate = 128; //kbit/sec + result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); + Check_FMOD_Error(result, "FMOD::System::setStreamBufferSize"); + + Check_FMOD_Error(system->createChannelGroup("stream", &mStreamGroup), "FMOD::System::createChannelGroup"); +} + +LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO() +{ + stop(); + for (U32 i = 0; i < 100; ++i) + { + if (releaseDeadStreams()) + break; + ms_sleep(10); + } + +} + +void LLStreamingAudio_FMODSTUDIO::start(const std::string& url) +{ + //if (!mInited) + //{ + // LL_WARNS() << "startInternetStream before audio initialized" << LL_ENDL; + // return; + //} + + // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL + stop(); + + if (!url.empty()) + { + if(mDeadStreams.empty()) + { + LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, url); + mURL = url; + } + else + { + LL_INFOS() << "Deferring stream load until buffer release: " << url << LL_ENDL; + mPendingURL = url; + } + } + else + { + LL_INFOS() << "Set internet stream to null" << LL_ENDL; + mURL.clear(); + } +} + + +void LLStreamingAudio_FMODSTUDIO::update() +{ + if (!releaseDeadStreams()) + { + llassert_always(mCurrentInternetStreamp == NULL); + return; + } + + if(!mPendingURL.empty()) + { + llassert_always(mCurrentInternetStreamp == NULL); + LL_INFOS() << "Starting internet stream: " << mPendingURL << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, mPendingURL); + mURL = mPendingURL; + mPendingURL.clear(); + } + + // Don't do anything if there are no streams playing + if (!mCurrentInternetStreamp) + { + return; + } + + unsigned int progress; + bool starving; + bool diskbusy; + FMOD_OPENSTATE open_state; + FMOD_RESULT result = mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy); + + if (result != FMOD_OK || open_state == FMOD_OPENSTATE_ERROR) + { + stop(); + return; + } + else if (open_state == FMOD_OPENSTATE_READY) + { + // Stream is live + + // start the stream if it's ready + if (!mFMODInternetStreamChannelp && + (mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream())) + { + // Reset volume to previously set volume + setGain(getGain()); + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); + } + } + + + if(mFMODInternetStreamChannelp) + { + FMOD::Sound *sound = NULL; + + // FmodEX Error checking + //if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound) + if (!Check_FMOD_Error(mFMODInternetStreamChannelp->getCurrentSound(&sound), "FMOD::Channel::getCurrentSound") && sound) + // + { + FMOD_TAG tag; + S32 tagcount, dirtytagcount; + + // FmodEX Error checking + //if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount) + if (!Check_FMOD_Error(sound->getNumTags(&tagcount, &dirtytagcount), "FMOD::Sound::getNumTags") && dirtytagcount) + // + { + // Stream metadata - originally by Shyotl Khur + mMetadata.clear(); + mNewMetadata = true; + // + for(S32 i = 0; i < tagcount; ++i) + { + if(sound->getTag(NULL, i, &tag) != FMOD_OK) + continue; + + std::string name = tag.name; + switch(tag.type) + { + case(FMOD_TAGTYPE_ID3V2): + { + if(name == "TIT2") name = "TITLE"; + else if(name == "TPE1") name = "ARTIST"; + break; + } + case(FMOD_TAGTYPE_ASF): + { + if(name == "Title") name = "TITLE"; + else if(name == "WM/AlbumArtist") name = "ARTIST"; + break; + } + case(FMOD_TAGTYPE_FMOD): + { + if (!strcmp(tag.name, "Sample Rate Change")) + { + LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; + mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); + } + continue; + } + default: + break; + } + switch(tag.datatype) + { + case(FMOD_TAGDATATYPE_INT): + { + (mMetadata)[name]=*(LLSD::Integer*)(tag.data); + LL_DEBUGS("StreamMetadata") << tag.name << ": " << *(int*)(tag.data) << LL_ENDL; + break; + } + case(FMOD_TAGDATATYPE_FLOAT): + { + (mMetadata)[name]=*(LLSD::Real*)(tag.data); + LL_DEBUGS("StreamMetadata") << tag.name << ": " << *(float*)(tag.data) << LL_ENDL; + break; + } + case(FMOD_TAGDATATYPE_STRING): + { + std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen)); + (mMetadata)[name]=out; + LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; + break; + } + case(FMOD_TAGDATATYPE_STRING_UTF16): + { + std::string out((char*)tag.data,tag.datalen); + (mMetadata)[std::string(tag.name)]=out; + LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; + break; + } + case(FMOD_TAGDATATYPE_STRING_UTF16BE): + { + std::string out((char*)tag.data,tag.datalen); + //U16* buf = (U16*)out.c_str(); + //for(U32 j = 0; j < out.size()/2; ++j) + //(((buf[j] & 0xff)<<8) | ((buf[j] & 0xff00)>>8)); + (mMetadata)[std::string(tag.name)]=out; + LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; + break; + } + default: + break; + } + } + } + + if(starving) + { + bool paused = false; + if (mFMODInternetStreamChannelp->getPaused(&paused) == FMOD_OK && !paused) + { + LL_INFOS() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; + LL_INFOS() << " (diskbusy="<setPaused(true), "FMOD::Channel::setPaused"); + } + } + else if(progress > 80) + { + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); + } + } + } +} + +void LLStreamingAudio_FMODSTUDIO::stop() +{ + mPendingURL.clear(); + + if (mFMODInternetStreamChannelp) + { + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(true), "FMOD::Channel::setPaused"); + Check_FMOD_Error(mFMODInternetStreamChannelp->setPriority(0), "FMOD::Channel::setPriority"); + mFMODInternetStreamChannelp = NULL; + } + + if (mCurrentInternetStreamp) + { + LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; + if (mCurrentInternetStreamp->stopStream()) + { + delete mCurrentInternetStreamp; + } + else + { + LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL; + mDeadStreams.push_back(mCurrentInternetStreamp); + } + mCurrentInternetStreamp = NULL; + } +} + +void LLStreamingAudio_FMODSTUDIO::pause(int pauseopt) +{ + if (pauseopt < 0) + { + pauseopt = mCurrentInternetStreamp ? 1 : 0; + } + + if (pauseopt) + { + if (mCurrentInternetStreamp) + { + stop(); + } + } + else + { + start(getURL()); + } +} + + +// A stream is "playing" if it has been requested to start. That +// doesn't necessarily mean audio is coming out of the speakers. +int LLStreamingAudio_FMODSTUDIO::isPlaying() +{ + if (mCurrentInternetStreamp) + { + return 1; // Active and playing + } + else if (!mURL.empty() || !mPendingURL.empty()) + { + return 2; // "Paused" + } + else + { + return 0; + } +} + + +F32 LLStreamingAudio_FMODSTUDIO::getGain() +{ + return mGain; +} + + +std::string LLStreamingAudio_FMODSTUDIO::getURL() +{ + return mURL; +} + + +void LLStreamingAudio_FMODSTUDIO::setGain(F32 vol) +{ + mGain = vol; + + if (mFMODInternetStreamChannelp) + { + vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here? + + Check_FMOD_Error(mFMODInternetStreamChannelp->setVolume(vol), "FMOD::Channel::setVolume"); + } +} +// Streamtitle display +// virtual +bool LLStreamingAudio_FMODSTUDIO::getNewMetadata(LLSD& metadata) +{ + if (mCurrentInternetStreamp) + { + if (mNewMetadata) + { + metadata = mMetadata; + mNewMetadata = false; + return true; + } + + return mNewMetadata; + } + + metadata = LLSD(); + return false; +} +// +/////////////////////////////////////////////////////// +// manager of possibly-multiple internet audio streams + +LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url) : + mSystem(system), + mChannelGroup(group), + mStreamChannel(NULL), + mInternetStream(NULL), + mReady(false) +{ + mInternetStreamURL = url; + + FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream); + + if (result!= FMOD_OK) + { + LL_WARNS() << "Couldn't open fmod stream, error " + << FMOD_ErrorString(result) + << LL_ENDL; + mReady = false; + return; + } + + mReady = true; +} + +FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream() +{ + // We need a live and opened stream before we try and play it. + FMOD_OPENSTATE open_state; + if (getOpenState(open_state) != FMOD_OK || open_state != FMOD_OPENSTATE_READY) + { + LL_WARNS() << "No internet stream to start playing!" << LL_ENDL; + return NULL; + } + + if(mStreamChannel) + return mStreamChannel; //Already have a channel for this stream. + + Check_FMOD_Error(mSystem->playSound(mInternetStream, mChannelGroup, true, &mStreamChannel), "FMOD::System::playSound"); + return mStreamChannel; +} + +bool LLAudioStreamManagerFMODSTUDIO::stopStream() +{ + if (mInternetStream) + { + bool close = true; + FMOD_OPENSTATE open_state; + if (getOpenState(open_state) == FMOD_OK) + { + switch (open_state) + { + case FMOD_OPENSTATE_CONNECTING: + close = false; + break; + default: + close = true; + } + } + + if (close && mInternetStream->release() == FMOD_OK) + { + mStreamChannel = NULL; + mInternetStream = NULL; + return true; + } + else + { + return false; + } + } + else + { + return true; + } +} + +FMOD_RESULT LLAudioStreamManagerFMODSTUDIO::getOpenState(FMOD_OPENSTATE& state, unsigned int* percentbuffered, bool* starving, bool* diskbusy) +{ + if (!mInternetStream) + return FMOD_ERR_INVALID_HANDLE; + FMOD_RESULT result = mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); + Check_FMOD_Error(result, "FMOD::Sound::getOpenState"); + return result; +} + +void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) +{ + Check_FMOD_Error(mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES), "FMOD::System::setStreamBufferSize"); + FMOD_ADVANCEDSETTINGS settings; + memset(&settings,0,sizeof(settings)); + settings.cbSize=sizeof(settings); + settings.defaultDecodeBufferSize = decodebuffertime;//ms + Check_FMOD_Error(mSystem->setAdvancedSettings(&settings), "FMOD::System::setAdvancedSettings"); +} + +bool LLStreamingAudio_FMODSTUDIO::releaseDeadStreams() +{ + // Kill dead internet streams, if possible + std::list::iterator iter; + for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) + { + LLAudioStreamManagerFMODSTUDIO *streamp = *iter; + if (streamp->stopStream()) + { + LL_INFOS() << "Closed dead stream" << LL_ENDL; + delete streamp; + mDeadStreams.erase(iter++); + } + else + { + iter++; + } + } + + return mDeadStreams.empty(); +} diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.h b/indra/llaudio/llstreamingaudio_fmodstudio.h new file mode 100644 index 0000000000..d220ddd02c --- /dev/null +++ b/indra/llaudio/llstreamingaudio_fmodstudio.h @@ -0,0 +1,86 @@ +/** + * @file streamingaudio_fmodstudio.h + * @brief Definition of LLStreamingAudio_FMODSTUDIO 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$ + */ + +#ifndef LL_STREAMINGAUDIO_FMODSTUDIO_H +#define LL_STREAMINGAUDIO_FMODSTUDIO_H + +#include "stdtypes.h" // from llcommon + +#include "llstreamingaudio.h" +#include "lltimer.h" + +//Stubs +class LLAudioStreamManagerFMODSTUDIO; +namespace FMOD +{ + class System; + class Channel; + class ChannelGroup; + class DSP; +} + +//Interfaces +class LLStreamingAudio_FMODSTUDIO : public LLStreamingAudioInterface +{ + public: + LLStreamingAudio_FMODSTUDIO(FMOD::System *system); + /*virtual*/ ~LLStreamingAudio_FMODSTUDIO(); + + /*virtual*/ void start(const std::string& url); + /*virtual*/ void stop(); + /*virtual*/ void pause(S32 pause); + /*virtual*/ void update(); + /*virtual*/ S32 isPlaying(); + /*virtual*/ void setGain(F32 vol); + /*virtual*/ F32 getGain(); + /*virtual*/ std::string getURL(); + + /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} + /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); + //Streamtitle display DKO + virtual bool getNewMetadata(LLSD& metadata); + // DKO +private: + bool releaseDeadStreams(); + + FMOD::System *mSystem; + + LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp; + FMOD::ChannelGroup* mStreamGroup; + FMOD::Channel *mFMODInternetStreamChannelp; + std::list mDeadStreams; + + std::string mURL; + std::string mPendingURL; + F32 mGain; + // Streamtitle display + bool mNewMetadata; + LLSD mMetadata; + // Streamtitle display +}; + + +#endif // LL_STREAMINGAUDIO_FMODSTUDIO_H diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 4dfee491a6..44fd5e6328 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -11,6 +11,7 @@ include(DBusGlib) include(DirectX) include(DragDrop) include(EXPAT) +include(FMODSTUDIO) include(FMODEX) include(GLOD) include(GooglePerfTools) @@ -66,6 +67,10 @@ endif (NOT HAVOK_TPV) endif( LLPHYSICSEXTENSIONS_SRC_DIR ) # +if(FMODSTUDIO) + include_directories(${FMODSTUDIO_INCLUDE_DIR}) +endif(FMODSTUDIO) + if(FMODEX) include_directories(${FMODEX_INCLUDE_DIR}) endif(FMODEX) @@ -2018,6 +2023,11 @@ if (OPENAL) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL") endif (OPENAL) +if (FMODSTUDIO) + set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODSTUDIO") + set(FMODWRAPPER_LIBRARY ${FMODSTUDIO_LIBRARY}) +endif (FMODSTUDIO) + if (FMODEX) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX") set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY}) @@ -2151,6 +2161,14 @@ if (WINDOWS) set( VIEWERMANIFEST_PACKAGE_FLAGS ) endif( ND_BUILD64BIT_ARCH ) + if (FMODSTUDIO) + list(APPEND COPY_INPUT_DEPENDENCIES + ${SHARED_LIB_STAGING_DIR}/Release/fmod.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod.dll + ${SHARED_LIB_STAGING_DIR}/Debug/fmodL.dll + ) + endif (FMODSTUDIO) + if (FMODEX) list(APPEND COPY_INPUT_DEPENDENCIES ${SHARED_LIB_STAGING_DIR}/Release/fmodex.dll diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 60a312aa21..947b8ffd37 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -19992,6 +19992,17 @@ Change of this parameter will affect the layout of buttons in notification toast Value 7000 + FMODResampleMethod + + Comment + Sets the method used for internal resampler 0(Linear), 1(Cubic), 2(Spline) + Persist + 1 + Type + U32 + Value + 0 + DisablePrecacheDelayAfterTeleporting Comment diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index e30bf28e87..b4e53bb781 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -39,6 +39,10 @@ #include "llviewermedia_streamingaudio.h" #include "llaudioengine.h" +#ifdef LL_FMODSTUDIO +# include "llaudioengine_fmodstudio.h" +#endif + #ifdef LL_FMODEX # include "llaudioengine_fmodex.h" #endif @@ -955,7 +959,16 @@ bool idle_startup() delete gAudiop; gAudiop = NULL; -#ifdef LL_FMODEX +#ifdef LL_FMODSTUDIO +#if !LL_WINDOWS + if (NULL == getenv("LL_BAD_FMODSTUDIO_DRIVER")) +#endif // !LL_WINDOWS + { + gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(gSavedSettings.getBOOL("FMODExProfilerEnable"), gSavedSettings.getU32("FMODResampleMethod")); + } +#endif + +#ifdef LL_FMODEX #if !LL_WINDOWS if (NULL == getenv("LL_BAD_FMODEX_DRIVER")) #endif // !LL_WINDOWS @@ -977,7 +990,7 @@ bool idle_startup() if (gAudiop) { #if LL_WINDOWS - // FMOD Ex on Windows needs the window handle to stop playing audio + // FMOD Studio and FMOD Ex on Windows needs the window handle to stop playing audio // when window is minimized. JC void* window_handle = (HWND)gViewerWindow->getPlatformWindow(); #else diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 4d8a62518c..ac829705ca 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -433,6 +433,17 @@ class Windows_i686_Manifest(ViewerManifest): print err.message print "Skipping GLOD library (assumming linked statically)" + # Get fmodstudio dll, continue if missing + try: + if self.args['configuration'].lower() == 'debug': + self.path("fmodL.dll") + self.path("fmodL64.dll") + else: + self.path("fmod.dll") + self.path("fmod64.dll") + except: + print "Skipping fmodstudio audio library(assuming other audio engine)" + # Get fmodex dll, continue if missing try: if self.args['configuration'].lower() == 'debug': @@ -941,6 +952,18 @@ class DarwinManifest(ViewerManifest): ): self.path2basename(relpkgdir, libfile) + # dylibs that vary based on configuration + if self.args['configuration'].lower() == 'debug': + for libfile in ( + "libfmodL.dylib", + ): + dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) + else: + for libfile in ( + "libfmod.dylib", + ): + dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) + # dylibs that vary based on configuration if self.args['configuration'].lower() == 'debug': for libfile in ( @@ -1636,6 +1659,7 @@ class Linux_i686_Manifest(LinuxManifest): try: self.path("libfmodex-*.so") self.path("libfmodex.so") + self.path("libfmodex.so*") pass except: print "Skipping libfmodex.so - not found" @@ -1677,6 +1701,9 @@ class Linux_x86_64_Manifest(LinuxManifest): try: self.path("libfmodex64-*.so") self.path("libfmodex64.so") + self.path("libfmod64.so") + self.path("libfmod.so") + self.path("libfmod.so*") pass except: print "Skipping libfmodex.so - not found" diff --git a/scripts/configure_firestorm.sh b/scripts/configure_firestorm.sh index fbf43c59e2..89e22c1c96 100755 --- a/scripts/configure_firestorm.sh +++ b/scripts/configure_firestorm.sh @@ -16,6 +16,7 @@ FALSE=1 # -DROOT_PROJECT_NAME:STRING=SecondLife # -DINSTALL_PROPRIETARY=FALSE # -DUSE_KDU=TRUE +# -DFMODSTUDIO:BOOL=ON # -DFMODEX:BOOL=ON # -DOPENSIM:BOOL=ON # -DUSE_AVX_OPTIMIZATION:BOOL=OFF @@ -33,6 +34,7 @@ WANTS_CONFIG=$FALSE WANTS_PACKAGE=$FALSE WANTS_VERSION=$FALSE WANTS_KDU=$FALSE +WANTS_FMODSTUDIO=$FALSE WANTS_FMODEX=$FALSE WANTS_OPENSIM=$TRUE WANTS_AVX=$FALSE @@ -66,6 +68,7 @@ showUsage() echo " --kdu : Build with KDU" echo " --package : Build installer" echo " --no-package : Build without installer (Overrides --package)" + echo " --fmodstudio : Build with FMOD Studio" echo " --fmodex : Build with FMOD Ex" echo " --quicktime : Build with Quicktime (Windows)" echo " --opensim : Build with OpenSim support (Disables Havok features)" @@ -84,7 +87,7 @@ getArgs() # $* = the options passed in from main { if [ $# -gt 0 ]; then - while getoptex "clean build config version package no-package fmodex ninja jobs: platform: kdu quicktime opensim no-opensim avx avx2 testbuild: help chan: btype:" "$@" ; do + while getoptex "clean build config version package no-package fmodstudio fmodex ninja jobs: platform: kdu quicktime opensim no-opensim avx avx2 testbuild: help chan: btype:" "$@" ; do #insure options are valid if [ -z "$OPTOPT" ] ; then @@ -102,6 +105,7 @@ getArgs() fi ;; kdu) WANTS_KDU=$TRUE;; + fmodstudio) WANTS_FMODSTUDIO=$TRUE;; fmodex) WANTS_FMODEX=$TRUE;; opensim) WANTS_OPENSIM=$TRUE;; no-opensim) WANTS_OPENSIM=$FALSE;; @@ -281,6 +285,7 @@ fi echo -e "configure_firestorm.py" > $LOG echo -e " PLATFORM: '$PLATFORM'" | tee -a $LOG echo -e " KDU: `b2a $WANTS_KDU`" | tee -a $LOG +echo -e " FMODSTUDIO: `b2a $WANTS_FMODSTUDIO`" | tee -a $LOG echo -e " FMODEX: `b2a $WANTS_FMODEX`" | tee -a $LOG echo -e " OPENSIM: `b2a $WANTS_OPENSIM`" | tee -a $LOG echo -e " AVX: `b2a $WANTS_AVX`" | tee -a $LOG @@ -376,12 +381,16 @@ if [ $WANTS_CONFIG -eq $TRUE ] ; then else KDU="-DUSE_KDU:BOOL=OFF" fi + if [ $WANTS_FMODSTUDIO -eq $TRUE ] ; then + FMODSTUDIO="-DFMODSTUDIO:BOOL=ON" + else + FMODSTUDIO="-DFMODSTUDIO:BOOL=OFF" + fi if [ $WANTS_FMODEX -eq $TRUE ] ; then FMODEX="-DFMODEX:BOOL=ON" else FMODEX="-DFMODEX:BOOL=OFF" fi - if [ $WANTS_OPENSIM -eq $TRUE ] ; then OPENSIM="-DOPENSIM:BOOL=ON" else @@ -457,7 +466,7 @@ if [ $WANTS_CONFIG -eq $TRUE ] ; then UNATTENDED="-DUNATTENDED=ON" fi - cmake -G "$TARGET" ../indra $CHANNEL $FMODEX $KDU $OPENSIM $AVX_OPTIMIZATION $AVX2_OPTIMIZATION $TESTBUILD $PACKAGE $UNATTENDED -DLL_TESTS:BOOL=OFF -DWORD_SIZE:STRING=$WORD_SIZE -DCMAKE_BUILD_TYPE:STRING=$BTYPE \ + cmake -G "$TARGET" ../indra $CHANNEL $FMODSTUDIO $FMODEX $KDU $OPENSIM $AVX_OPTIMIZATION $AVX2_OPTIMIZATION $TESTBUILD $PACKAGE $UNATTENDED -DLL_TESTS:BOOL=OFF -DWORD_SIZE:STRING=$WORD_SIZE -DCMAKE_BUILD_TYPE:STRING=$BTYPE \ -DNDTARGET_ARCH:STRING="${TARGET_ARCH}" -DROOT_PROJECT_NAME:STRING=Firestorm $LL_ARGS_PASSTHRU | tee $LOG if [ $PLATFORM == "win32" ] ; then From b1bacf084f427b37a36ee2e9aabfe184f1ae7271 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 16 Dec 2017 19:45:34 +0100 Subject: [PATCH 41/75] Rename FMODEx* debug settings to FMOD* --- indra/newview/app_settings/settings.xml | 8 ++++---- indra/newview/llstartup.cpp | 4 ++-- indra/newview/llvieweraudio.cpp | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 947b8ffd37..dbbade44dd 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -19959,10 +19959,10 @@ Change of this parameter will affect the layout of buttons in notification toast Value 1.0 - FMODExProfilerEnable + FMODProfilerEnable Comment - Enable profiler tool if using FMOD Ex + Enable profiler tool if using FMOD Persist 1 Type @@ -19970,7 +19970,7 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 - FMODExDecodeBufferSize + FMODDecodeBufferSize Comment Sets the streaming decode buffer size (in milliseconds) @@ -19981,7 +19981,7 @@ Change of this parameter will affect the layout of buttons in notification toast Value 1000 - FMODExStreamBufferSize + FMODStreamBufferSize Comment Sets the streaming buffer size (in milliseconds) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index b4e53bb781..a2ca0bf8d5 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -964,7 +964,7 @@ bool idle_startup() if (NULL == getenv("LL_BAD_FMODSTUDIO_DRIVER")) #endif // !LL_WINDOWS { - gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(gSavedSettings.getBOOL("FMODExProfilerEnable"), gSavedSettings.getU32("FMODResampleMethod")); + gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(gSavedSettings.getBOOL("FMODProfilerEnable"), gSavedSettings.getU32("FMODResampleMethod")); } #endif @@ -973,7 +973,7 @@ bool idle_startup() if (NULL == getenv("LL_BAD_FMODEX_DRIVER")) #endif // !LL_WINDOWS { - gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX(gSavedSettings.getBOOL("FMODExProfilerEnable")); + gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX(gSavedSettings.getBOOL("FMODProfilerEnable")); } #endif diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index d95ce7f6d2..5019a3b58b 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -127,7 +127,7 @@ void LLViewerAudio::startInternetStreamWithAutoFade(std::string streamURI) LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); if(stream && stream->supportsAdjustableBufferSizes()) - stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize")); + stream->setBufferSizes(gSavedSettings.getU32("FMODStreamBufferSize"),gSavedSettings.getU32("FMODDecodeBufferSize")); gAudiop->startInternetStream(mNextStreamURI); startFading(); @@ -192,7 +192,7 @@ bool LLViewerAudio::onIdleUpdate() { LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); if(stream && stream->supportsAdjustableBufferSizes()) - stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize")); + stream->setBufferSizes(gSavedSettings.getU32("FMODStreamBufferSize"),gSavedSettings.getU32("FMODDecodeBufferSize")); gAudiop->startInternetStream(mNextStreamURI); } From 1c11071f381cf77408eb2aa06216d58660acda18 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sun, 17 Dec 2017 00:10:35 +0100 Subject: [PATCH 42/75] Fixed some copy&paste typos --- indra/cmake/FMODEX.cmake | 2 +- indra/cmake/FMODSTUDIO.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/cmake/FMODEX.cmake b/indra/cmake/FMODEX.cmake index 06f7ecff81..21fd92016b 100644 --- a/indra/cmake/FMODEX.cmake +++ b/indra/cmake/FMODEX.cmake @@ -1,6 +1,6 @@ # -*- cmake -*- -# FMOD can be set when launching the make using the argument -DFMOD:BOOL=ON +# FMOD can be set when launching the make using the argument -DFMODEX:BOOL=ON # When building using proprietary binaries though (i.e. having access to LL private servers), # we always build with FMODEX. # Open source devs should use the -DFMODEX:BOOL=ON then if they want to build with FMOD, whether diff --git a/indra/cmake/FMODSTUDIO.cmake b/indra/cmake/FMODSTUDIO.cmake index 76e05c5e47..bbf7bb7ff9 100644 --- a/indra/cmake/FMODSTUDIO.cmake +++ b/indra/cmake/FMODSTUDIO.cmake @@ -1,6 +1,6 @@ # -*- cmake -*- -# FMOD can be set when launching the make using the argument -DFMOD:BOOL=ON +# FMOD can be set when launching the make using the argument -DFMODSTUDIO:BOOL=ON # When building using proprietary binaries though (i.e. having access to LL private servers), # we always build with FMODSTUDIO. # Open source devs should use the -DFMODSTUDIO:BOOL=ON then if they want to build with FMOD, whether From 763939b25455bedd25333fa70b88a95dadaa3ccd Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 20 Dec 2017 17:01:47 +0200 Subject: [PATCH 43/75] MAINT-8061 update folder label when item count changes --- indra/newview/llinventorypanel.cpp | 29 +++++++++++++++++++++++++++++ indra/newview/llinventorypanel.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 476b6e9548..fc5665231c 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -608,6 +608,7 @@ void LLInventoryPanel::modelChanged(U32 mask) { setSelection(item_id, FALSE); } + updateFolderLabel(model_item->getParentUUID()); } ////////////////////////////// @@ -619,6 +620,7 @@ void LLInventoryPanel::modelChanged(U32 mask) // Don't process the item if it is the root if (old_parent) { + LLFolderViewModelItemInventory* viewmodel_folder = static_cast(old_parent->getViewModelItem()); LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getItemByID(model_item->getParentUUID()); // Item has been moved. if (old_parent != new_parent) @@ -636,6 +638,7 @@ void LLInventoryPanel::modelChanged(U32 mask) setSelection(item_id, FALSE); } } + updateFolderLabel(model_item->getParentUUID()); } else { @@ -647,6 +650,10 @@ void LLInventoryPanel::modelChanged(U32 mask) // doesn't include trash). Just remove the item's UI. view_item->destroyView(); } + if(viewmodel_folder) + { + updateFolderLabel(viewmodel_folder->getUUID()); + } old_parent->getViewModelItem()->dirtyDescendantsFilter(); } } @@ -664,6 +671,11 @@ void LLInventoryPanel::modelChanged(U32 mask) if(parent) { parent->getViewModelItem()->dirtyDescendantsFilter(); + LLFolderViewModelItemInventory* viewmodel_folder = static_cast(parent->getViewModelItem()); + if(viewmodel_folder) + { + updateFolderLabel(viewmodel_folder->getUUID()); + } } } } @@ -1234,6 +1246,23 @@ void LLInventoryPanel::onSelectionChange(const std::deque& it } +void LLInventoryPanel::updateFolderLabel(const LLUUID& folder_id) +{ + if(folder_id != mPreviousSelectedFolder) return; + + LLFolderViewItem* folder_item = getItemByID(mPreviousSelectedFolder); + if(folder_item) + { + LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getViewModelItem(); + if(bridge) + { + bridge->clearDisplayName(); + bridge->setShowDescendantsCount(true); + folder_item->refresh(); + } + } +} + void LLInventoryPanel::doCreate(const LLSD& userdata) { // FIRE-20108: Can't create new folder in secondary inventory if view is filtered diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 58604276a5..4e420a753e 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -218,6 +218,8 @@ public: // Optional hiding of Inbox folder void updateShowInboxFolder(const LLSD &data); + void updateFolderLabel(const LLUUID& folder_id); + // DEBUG ONLY: static void dumpSelectionInformation(void* user_data); From 1363e7630fd97432e8c4bc9700cfe21c8bcb3304 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 26 Dec 2017 19:19:22 +0100 Subject: [PATCH 44/75] Fix unknown CMake macro; Thanks to Cinder Roxley for pointing at this --- indra/cmake/Variables.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 4c8ea563e1..a320d61209 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -177,7 +177,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(CMAKE_OSX_SYSROOT macosx10.9) message(STATUS "OS X SDK 10.9 found.") else(IS_DIRECTORY "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk") - error("Unable to determine which OS X SDK to use. Giving up.") + message(FATAL_ERROR "Unable to determine which OS X SDK to use. Giving up.") endif(IS_DIRECTORY "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk") set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvm.clang.1_0") From 0e03f91a4abfbb20dad46308bffcd6435b2190d0 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 1 Jan 2018 21:50:13 +0100 Subject: [PATCH 45/75] Don't create estate floater pointlessly --- indra/newview/llfloaterregioninfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 16cdc28060..fe3b72d86f 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -314,7 +314,7 @@ void LLFloaterRegionInfo::requestRegionInfo() void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**) { static LLDispatcher dispatch; - LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance("region_info"); + LLFloaterRegionInfo* floater = LLFloaterReg::findTypedInstance("region_info"); if(!floater) { return; @@ -350,7 +350,7 @@ void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**) void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) { LLPanel* panel; - LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance("region_info"); + LLFloaterRegionInfo* floater = LLFloaterReg::findTypedInstance("region_info"); if(!floater) { return; From 2c743b12c6ff86064dc682c12f63025ff0ccaf0e Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Thu, 4 Jan 2018 19:52:42 +0200 Subject: [PATCH 46/75] MAINT-8107 Fixed Framerate drops when facing away from objects Don't clear buffers if they are already free --- indra/newview/llvovolume.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 979a6ec33d..56d73c108c 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -743,7 +743,7 @@ void LLVOVolume::updateTextures() if (mDrawable.notNull() && !isVisible() && !mDrawable->isActive()) { //delete vertex buffer to free up some VRAM LLSpatialGroup* group = mDrawable->getSpatialGroup(); - if (group) + if (group && (group->mVertexBuffer.notNull() || !group->mBufferMap.empty() || !group->mDrawMap.empty())) { group->destroyGL(true); From 65097fa14eb9d4b9e45effe69afafbceec4cd945 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Fri, 5 Jan 2018 13:55:36 +0100 Subject: [PATCH 47/75] Add /zoffset_up and /zoffset_down command line command to increase / decrease avatar Z offset by 0.05 that can be invoked via user-definable gestures --- indra/newview/chatbar_as_cmdline.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/indra/newview/chatbar_as_cmdline.cpp b/indra/newview/chatbar_as_cmdline.cpp index b2392b1fed..9e6a86afeb 100644 --- a/indra/newview/chatbar_as_cmdline.cpp +++ b/indra/newview/chatbar_as_cmdline.cpp @@ -805,6 +805,16 @@ bool cmd_line_chat(const std::string& revised_text, EChatType type, bool from_ge } return false; } + else if (command == "/zoffset_up") + { + gSavedPerAccountSettings.setF32("AvatarHoverOffsetZ", gSavedPerAccountSettings.getF32("AvatarHoverOffsetZ") + 0.05f); + return false; + } + else if (command == "/zoffset_down") + { + gSavedPerAccountSettings.setF32("AvatarHoverOffsetZ", gSavedPerAccountSettings.getF32("AvatarHoverOffsetZ") - 0.05f); + return false; + } else if (command == sFSCmdLineOfferTp()) { LLUUID target_key; From 4f400bad6d65a20d6b703df4e573b31557b3a164 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sun, 7 Jan 2018 04:50:04 +0100 Subject: [PATCH 48/75] FIRE-21546: Don't close docked script floater if IMs arrive, but only if IMs shown in tabs - still hide when using docked windows! --- indra/newview/llscriptfloater.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp index 608507a0d2..98b253f291 100644 --- a/indra/newview/llscriptfloater.cpp +++ b/indra/newview/llscriptfloater.cpp @@ -72,7 +72,10 @@ LLUUID notification_id_to_object_id(const LLUUID& notification_id) LLScriptFloater::LLScriptFloater(const LLSD& key) -: LLDockableFloater(NULL, true, key) +// FIRE-21546: Don't close docked floater if IMs arrive, but only if IMs shown in tabs - still hide when using docked windows! +//: LLDockableFloater(NULL, true, key) +: LLDockableFloater(NULL, gSavedSettings.getS32("FSChatWindow") != 1, key) +// , mScriptForm(NULL) , mSaveFloaterPosition(false) { From d6b1eadf2ddb7d4c2d21c711ebf6cd3e271eaac9 Mon Sep 17 00:00:00 2001 From: Beq Date: Sun, 7 Jan 2018 23:26:10 +0000 Subject: [PATCH 49/75] Changes for FIRE-22130 - re-baselining RenderolumeLODFactor advice and warnings. updates phototools to limit range to < 8 as values much above that can cause errors updates warning to appear above 4 not at 4 updates the language used in warnings/tool_tips etc across the viewer --- indra/newview/app_settings/settings.xml | 4 ++-- indra/newview/llstartup.cpp | 14 ++++++++++---- indra/newview/llviewercontrol.cpp | 2 +- .../skins/default/xui/en/floater_phototools.xml | 12 ++++++------ .../newview/skins/default/xui/en/notifications.xml | 14 ++++++++------ .../default/xui/en/panel_preferences_graphics1.xml | 1 + .../skins/starlight/xui/en/floater_phototools.xml | 12 ++++++------ .../starlightcui/xui/en/floater_phototools.xml | 12 ++++++------ 8 files changed, 40 insertions(+), 31 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b2e109064a..347926ec50 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -13022,13 +13022,13 @@ Change of this parameter will affect the layout of buttons in notification toast RenderVolumeLODFactor Comment - Controls level of detail of primitives (multiplier for current screen area when calculated level of detail) + Influences the distance at which the viewer will display a lower detail model. Higher values = more lag. IMPORTANT: Please disregard advice to increase this value, such as is commonly distributed in notecards. Persist 1 Type F32 Value - 1.0 + 2.0 SanityCheckType LessThanEquals SanityValue diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index e30bf28e87..b9411f00b2 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3039,12 +3039,18 @@ void login_show() FSPanelLogin::show( gViewerWindow->getWindowRectScaled(), login_callback, NULL ); // [FS Login Panel] - // Warning about too high LOD on startup - if (gSavedSettings.getF32("RenderVolumeLODFactor") >= 4.0f) + // [FIRE-22130] for LOD Factors > 4 reset to the detected dafault + F32 old_val = gSavedSettings.getF32("RenderVolumeLODFactor"); + if (old_val > 4.0f) { - LLNotificationsUtil::add("RenderVolumeLODFactorWarning"); + U32 gfx_level = gSavedSettings.getU32("RenderQualityPerformance"); + F32 new_val = 2.0; //majority + if (gfx_level == 0) new_val = 1.125; // low = 0 + if (gfx_level > 5) new_val = 3.0; // ultra = 6 + gSavedSettings.setF32("RenderVolumeLODFactor", new_val); + LL_INFOS("AppInit") << "LOD Factor reset to sane value. Was " << old_val << " now " << gSavedSettings.getF32("RenderVolumeLODFactor") << LL_ENDL; } - // + // } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 291745ae7a..5c9aacb58e 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -286,7 +286,7 @@ static bool handleVolumeLODChanged(const LLSD& newvalue) LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f; // Warning about too high LOD on LOD change - if (LLVOVolume::sLODFactor >= 4.0f) + if (LLVOVolume::sLODFactor > 4.0f) { LLNotificationsUtil::add("RenderVolumeLODFactorWarning"); } diff --git a/indra/newview/skins/default/xui/en/floater_phototools.xml b/indra/newview/skins/default/xui/en/floater_phototools.xml index d4a940c43b..f7acd9c24f 100644 --- a/indra/newview/skins/default/xui/en/floater_phototools.xml +++ b/indra/newview/skins/default/xui/en/floater_phototools.xml @@ -2676,7 +2676,7 @@ layout="topleft" left="5" top_pad="5" - tool_tip="Controls the detail of prims. Higher values produce greater detail for objects." + tool_tip="Controls when lower-detail objects can be used to reduce rendering cost. Higher values cause lag, use with care." width="80"> Obj. Detail @@ -2685,11 +2685,11 @@ control_name="RenderVolumeLODFactor" follows="left|top" height="16" - increment="1" + increment="0.125" layout="topleft" left_pad="-20" min_val="0" - max_val="15" + max_val="8.0" top_delta="-2" width="127"/> + increment="0.125"/>