From 641067c3991d1bfa17a5d6ae21ce71010ea8319c Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Sat, 27 Jul 2013 15:47:04 -0400 Subject: [PATCH 001/115] [Voice Update] Apply updates from Viewer-Vivox2 Applies the following commits: 4c13e7c - Interim version with SLIM removed from voice. https://bitbucket.org/obscurestar/viewer-vivox2/commits/4c13e7c7535cbae2767181844a014897c85f254a 9cad21a - Thanks mercurial. https://bitbucket.org/obscurestar/viewer-vivox2/commits/9cad21adc15947f74a1beda31264730361fc6569 Only the changes that should have been in 4c13e7c (removal of LLVivoxVoiceClient::accountListBlockRulesSendMessage() and LLVivoxVoiceClient::accountListAutoAcceptRulesSendMessage()) 9c94b96 - Removed debugging. https://bitbucket.org/obscurestar/viewer-vivox2/commits/9c94b96ed3ac20987f308b5296fba1cc51a875b1 ec77595 - Turn off logging. https://bitbucket.org/obscurestar/viewer-vivox2/commits/ec775958ef8c2923ddc03ed051e322310dc278cd 857cab1 - Kill all the vivox logs https://bitbucket.org/obscurestar/viewer-vivox2/commits/857cab153e835211d0a76e66d627a14de0f4706b --- indra/newview/llgesturemgr.cpp | 2 +- indra/newview/llinventorybridge.cpp | 2 +- indra/newview/llvoiceclient.cpp | 7 - indra/newview/llvoiceclient.h | 1 - indra/newview/llvoicevivox.cpp | 787 +--------------------------- indra/newview/llvoicevivox.h | 26 +- 6 files changed, 8 insertions(+), 817 deletions(-) diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index c0f37fe5f..f94872837 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -170,7 +170,7 @@ void LLGestureMgr::activateGestures(LLViewerInventoryItem::item_array_t& items) continue; } else - { // Make gesture active and persistent through login sessions. -spatters 07-12-06 + { // Make gesture active and persistent through login sessions. -Aura 07-12-06 activateGesture(item->getUUID()); } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 2a07cb82f..d020454fd 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -3327,7 +3327,7 @@ void LLFolderBridge::buildContextMenuBaseOptions(U32 flags) } } - //Added by spatters to force inventory pull on right-click to display folder options correctly. 07-17-06 + //Added by aura to force inventory pull on right-click to display folder options correctly. 07-17-06 mCallingCards = mWearables = FALSE; LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index dd1b7c662..d9fb9610d 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -711,14 +711,7 @@ BOOL LLVoiceClient::isParticipantAvatar(const LLUUID& id) BOOL LLVoiceClient::isOnlineSIP(const LLUUID& id) { - if (mVoiceModule) - { - return mVoiceModule->isOnlineSIP(id); - } - else - { return FALSE; - } } BOOL LLVoiceClient::getIsSpeaking(const LLUUID& id) diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index 761a1a768..06bfeb3a4 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -198,7 +198,6 @@ public: //@{ virtual BOOL getVoiceEnabled(const LLUUID& id)=0; // true if we've received data for this avatar virtual std::string getDisplayName(const LLUUID& id)=0; - virtual BOOL isOnlineSIP(const LLUUID &id)=0; virtual BOOL isParticipantAvatar(const LLUUID &id)=0; virtual BOOL getIsSpeaking(const LLUUID& id)=0; virtual BOOL getIsModeratorMuted(const LLUUID& id)=0; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index e0cf09e26..b6be06d64 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -177,17 +177,9 @@ class LLVivoxVoiceClientMuteListObserver : public LLMuteListObserver /* virtual */ void onChange() { LLVivoxVoiceClient::getInstance()->muteListChanged();} }; -class LLVivoxVoiceClientFriendsObserver : public LLFriendObserver -{ -public: - /* virtual */ void changed(U32 mask) { LLVivoxVoiceClient::getInstance()->updateFriends(mask);} -}; - static LLVivoxVoiceClientMuteListObserver mutelist_listener; static bool sMuteListListener_listening = false; -static LLVivoxVoiceClientFriendsObserver *friendslist_listener = NULL; - /////////////////////////////////////////////////////////////////////////////////////////////// class LLVivoxVoiceClientCapResponder : public LLHTTPClient::ResponderWithResult @@ -424,7 +416,6 @@ void LLVivoxVoiceClient::terminate() void LLVivoxVoiceClient::cleanUp() { deleteAllSessions(); - deleteAllBuddies(); deleteAllVoiceFonts(); deleteVoiceFontTemplates(); } @@ -510,10 +501,10 @@ void LLVivoxVoiceClient::connectorCreate() std::string savedLogLevel = gSavedSettings.getString("VivoxDebugLevel"); - if(savedLogLevel != "-1") + if(savedLogLevel != "-0") { LL_DEBUGS("Voice") << "creating connector with logging enabled" << LL_ENDL; - loglevel = "10"; + loglevel = "0"; } stream @@ -861,7 +852,7 @@ void LLVivoxVoiceClient::stateMachine() if(loglevel.empty()) { - loglevel = "-1"; // turn logging off completely + loglevel = "-0"; // turn logging off completely } args += " -ll "; @@ -1338,12 +1329,6 @@ void LLVivoxVoiceClient::stateMachine() setState(stateVoiceFontsReceived); } - // request the current set of block rules (we'll need them when updating the friends list) - accountListBlockRulesSendMessage(); - - // request the current set of auto-accept rules - accountListAutoAcceptRulesSendMessage(); - // Set up the mute list observer if it hasn't been set up already. if((!sMuteListListener_listening)) { @@ -1351,13 +1336,6 @@ void LLVivoxVoiceClient::stateMachine() sMuteListListener_listening = true; } - // Set up the friends list observer if it hasn't been set up already. - if(friendslist_listener == NULL) - { - friendslist_listener = new LLVivoxVoiceClientFriendsObserver; - LLAvatarTracker::instance().addObserver(friendslist_listener); - } - // Set the initial state of mic mute, local speaker volume, etc. { std::ostringstream stream; @@ -1427,9 +1405,7 @@ void LLVivoxVoiceClient::stateMachine() case stateNoChannel: LL_DEBUGS("Voice") << "State No Channel" << LL_ENDL; mSpatialJoiningNum = 0; - // Do this here as well as inside sendPositionalUpdate(). - // Otherwise, if you log in but don't join a proximal channel (such as when your login location has voice disabled), your friends list won't sync. - sendFriendsListUpdates(); + if(mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized)) { @@ -1626,7 +1602,6 @@ void LLVivoxVoiceClient::stateMachine() mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS); sendPositionalUpdate(); } - mIsInitialized = true; } break; @@ -1801,7 +1776,7 @@ void LLVivoxVoiceClient::loginSendMessage() << "" << mAccountName << "" << "" << mAccountPassword << "" << "VerifyAnswer" - << "true" + << "false" << "Application" << "5" << (autoPostCrashDumps?"true":"") @@ -1837,42 +1812,6 @@ void LLVivoxVoiceClient::logoutSendMessage() } } -void LLVivoxVoiceClient::accountListBlockRulesSendMessage() -{ - if(!mAccountHandle.empty()) - { - std::ostringstream stream; - - LL_DEBUGS("Voice") << "requesting block rules" << LL_ENDL; - - stream - << "" - << "" << mAccountHandle << "" - << "" - << "\n\n\n"; - - writeString(stream.str()); - } -} - -void LLVivoxVoiceClient::accountListAutoAcceptRulesSendMessage() -{ - if(!mAccountHandle.empty()) - { - std::ostringstream stream; - - LL_DEBUGS("Voice") << "requesting auto-accept rules" << LL_ENDL; - - stream - << "" - << "" << mAccountHandle << "" - << "" - << "\n\n\n"; - - writeString(stream.str()); - } -} - void LLVivoxVoiceClient::sessionGroupCreateSendMessage() { if(!mAccountHandle.empty()) @@ -2705,9 +2644,6 @@ void LLVivoxVoiceClient::sendPositionalUpdate(void) writeString(stream.str()); } - // Friends list updates can be huge, especially on the first voice login of an account with lots of friends. - // Batching them all together can choke SLVoice, so send them in separate writes. - sendFriendsListUpdates(); } void LLVivoxVoiceClient::buildSetCaptureDevice(std::ostringstream &stream) @@ -2805,275 +2741,6 @@ void LLVivoxVoiceClient::buildLocalAudioUpdates(std::ostringstream &stream) } -void LLVivoxVoiceClient::checkFriend(const LLUUID& id) -{ - buddyListEntry *buddy = findBuddy(id); - - // Make sure we don't add a name before it's been looked up. - LLAvatarName av_name; - if(LLAvatarNameCache::get(id, &av_name)) - { - // *NOTE: We feed legacy names to Vivox because we don't know if their service - // can support a mix of new and old clients with different sorts of names. - std::string name = av_name.getLegacyName(); - - if(buddy) - { - // This buddy is already in both lists (vivox buddies and avatar cache). - // Trust the avatar cache more for the display name (vivox display name are notoriously wrong) - buddy->mDisplayName = name; - } - else - { - // This buddy was not in the vivox list, needs to be added. - buddy = addBuddy(sipURIFromID(id), name); - buddy->mUUID = id; - } - - const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id); - buddy->mCanSeeMeOnline = (relationInfo && relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS)); - // In all the above cases, the buddy is in the SL friends list and tha name has been resolved (which is how we got here). - buddy->mNameResolved = true; - buddy->mInSLFriends = true; - } - else - { - // This name hasn't been looked up yet in the avatar cache. Don't do anything with this buddy list entry until it has. - if(buddy) - { - buddy->mNameResolved = false; - } - // Initiate a lookup. - // The "lookup completed" callback will ensure that the friends list is rechecked after it completes. - lookupName(id); - } -} - -void LLVivoxVoiceClient::clearAllLists() -{ - // FOR TESTING ONLY - - // This will send the necessary commands to delete ALL buddies, autoaccept rules, and block rules SLVoice tells us about. - buddyListMap::iterator buddy_it; - for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();) - { - buddyListEntry *buddy = buddy_it->second; - buddy_it++; - - std::ostringstream stream; - - if(buddy->mInVivoxBuddies) - { - // delete this entry from the vivox buddy list - buddy->mInVivoxBuddies = false; - LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - } - - if(buddy->mHasBlockListEntry) - { - // Delete the associated block list entry (so the block list doesn't fill up with junk) - buddy->mHasBlockListEntry = false; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - } - if(buddy->mHasAutoAcceptListEntry) - { - // Delete the associated auto-accept list entry (so the auto-accept list doesn't fill up with junk) - buddy->mHasAutoAcceptListEntry = false; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - } - - writeString(stream.str()); - - } -} - -void LLVivoxVoiceClient::sendFriendsListUpdates() -{ - if(mBuddyListMapPopulated && mBlockRulesListReceived && mAutoAcceptRulesListReceived && mFriendsListDirty) - { - mFriendsListDirty = false; - - if(0) - { - // FOR TESTING ONLY -- clear all buddy list, block list, and auto-accept list entries. - clearAllLists(); - return; - } - - LL_INFOS("Voice") << "Checking vivox buddy list against friends list..." << LL_ENDL; - - buddyListMap::iterator buddy_it; - for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++) - { - // reset the temp flags in the local buddy list - buddy_it->second->mInSLFriends = false; - } - - // correlate with the friends list - { - LLCollectAllBuddies collect; - LLAvatarTracker::instance().applyFunctor(collect); - LLCollectAllBuddies::buddy_map_t::const_iterator it = collect.mOnline.begin(); - LLCollectAllBuddies::buddy_map_t::const_iterator end = collect.mOnline.end(); - - for ( ; it != end; ++it) - { - checkFriend(it->second); - } - it = collect.mOffline.begin(); - end = collect.mOffline.end(); - for ( ; it != end; ++it) - { - checkFriend(it->second); - } - } - - LL_INFOS("Voice") << "Sending friend list updates..." << LL_ENDL; - - for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();) - { - buddyListEntry *buddy = buddy_it->second; - buddy_it++; - - // Ignore entries that aren't resolved yet. - if(buddy->mNameResolved) - { - std::ostringstream stream; - - if(buddy->mInSLFriends && !buddy->mInVivoxBuddies) - { - if(mNumberOfAliases > 0) - { - // Add (or update) this entry in the vivox buddy list - buddy->mInVivoxBuddies = true; - LL_DEBUGS("Voice") << "add/update " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; - stream - << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "" << buddy->mDisplayName << "" - << "" // Without this, SLVoice doesn't seem to parse the command. - << "0" - << "\n\n\n"; - } - } - else if(!buddy->mInSLFriends) - { - // This entry no longer exists in your SL friends list. Remove all traces of it from the Vivox buddy list. - if(buddy->mInVivoxBuddies) - { - // delete this entry from the vivox buddy list - buddy->mInVivoxBuddies = false; - LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - } - - if(buddy->mHasBlockListEntry) - { - // Delete the associated block list entry, if any - buddy->mHasBlockListEntry = false; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - } - if(buddy->mHasAutoAcceptListEntry) - { - // Delete the associated auto-accept list entry, if any - buddy->mHasAutoAcceptListEntry = false; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - } - } - - if(buddy->mInSLFriends) - { - - if(buddy->mCanSeeMeOnline) - { - // Buddy should not be blocked. - - // If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent. - - // If the buddy has a block list entry, delete it. - if(buddy->mHasBlockListEntry) - { - buddy->mHasBlockListEntry = false; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - - - // If we just deleted a block list entry, add an auto-accept entry. - if(!buddy->mHasAutoAcceptListEntry) - { - buddy->mHasAutoAcceptListEntry = true; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "0" - << "\n\n\n"; - } - } - } - else - { - // Buddy should be blocked. - - // If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent. - - // If this buddy has an autoaccept entry, delete it - if(buddy->mHasAutoAcceptListEntry) - { - buddy->mHasAutoAcceptListEntry = false; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - - // If we just deleted an auto-accept entry, add a block list entry. - if(!buddy->mHasBlockListEntry) - { - buddy->mHasBlockListEntry = true; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "1" - << "\n\n\n"; - } - } - } - - if(!buddy->mInSLFriends && !buddy->mInVivoxBuddies) - { - // Delete this entry from the local buddy list. This should NOT invalidate the iterator, - // since it has already been incremented to the next entry. - deleteBuddy(buddy->mURI); - } - - } - writeString(stream.str()); - } - } - } -} - ///////////////////////////// // Response/Event handlers @@ -3876,83 +3543,6 @@ void LLVivoxVoiceClient::participantUpdatedEvent( } } -void LLVivoxVoiceClient::buddyPresenceEvent( - std::string &uriString, - std::string &alias, - std::string &statusString, - std::string &applicationString) -{ - buddyListEntry *buddy = findBuddy(uriString); - - if(buddy) - { - LL_DEBUGS("Voice") << "Presence event for " << buddy->mDisplayName << " status \"" << statusString << "\", application \"" << applicationString << "\""<< LL_ENDL; - LL_DEBUGS("Voice") << "before: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL; - - if(applicationString.empty()) - { - // This presence event is from a client that doesn't set up the Application string. Do things the old-skool way. - // NOTE: this will be needed to support people who aren't on the 3010-class SDK yet. - - if ( stricmp("Unknown", statusString.c_str())== 0) - { - // User went offline with a non-SLim-enabled viewer. - buddy->mOnlineSL = false; - } - else if ( stricmp("Online", statusString.c_str())== 0) - { - // User came online with a non-SLim-enabled viewer. - buddy->mOnlineSL = true; - } - else - { - // If the user is online through SLim, their status will be "Online-slc", "Away", or something else. - // NOTE: we should never see this unless someone is running an OLD version of SLim -- the versions that should be in use now all set the application string. - buddy->mOnlineSLim = true; - } - } - else if(applicationString.find("SecondLifeViewer") != std::string::npos) - { - // This presence event is from a viewer that sets the application string - if ( stricmp("Unknown", statusString.c_str())== 0) - { - // Viewer says they're offline - buddy->mOnlineSL = false; - } - else - { - // Viewer says they're online - buddy->mOnlineSL = true; - } - } - else - { - // This presence event is from something which is NOT the SL viewer (assume it's SLim). - if ( stricmp("Unknown", statusString.c_str())== 0) - { - // SLim says they're offline - buddy->mOnlineSLim = false; - } - else - { - // SLim says they're online - buddy->mOnlineSLim = true; - } - } - - LL_DEBUGS("Voice") << "after: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL; - - // HACK -- increment the internal change serial number in the LLRelationship (without changing the actual status), so the UI notices the change. - LLAvatarTracker::instance().setBuddyOnline(buddy->mUUID,LLAvatarTracker::instance().isBuddyOnline(buddy->mUUID)); - - notifyFriendObservers(); - } - else - { - LL_DEBUGS("Voice") << "Presence for unknown buddy " << uriString << LL_ENDL; - } -} - void LLVivoxVoiceClient::messageEvent( std::string &sessionHandle, std::string &uriString, @@ -4142,70 +3732,12 @@ void LLVivoxVoiceClient::sessionNotificationEvent(std::string &sessionHandle, st } } -void LLVivoxVoiceClient::subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType) -{ - buddyListEntry *buddy = findBuddy(buddyURI); - - if(!buddy) - { - // Couldn't find buddy by URI, try converting the alias... - if(!alias.empty()) - { - LLUUID id; - if(IDFromName(alias, id)) - { - buddy = findBuddy(id); - } - } - } - - if(buddy) - { - std::ostringstream stream; - - if(buddy->mCanSeeMeOnline) - { - // Sending the response will create an auto-accept rule - buddy->mHasAutoAcceptListEntry = true; - } - else - { - // Sending the response will create a block rule - buddy->mHasBlockListEntry = true; - } - - if(buddy->mInSLFriends) - { - buddy->mInVivoxBuddies = true; - } - - stream - << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "" << (buddy->mCanSeeMeOnline?"Allow":"Hide") << "" - << ""<< (buddy->mInSLFriends?"1":"0")<< "" - << "" << subscriptionHandle << "" - << "" - << "\n\n\n"; - - writeString(stream.str()); - } -} - void LLVivoxVoiceClient::auxAudioPropertiesEvent(F32 energy) { LL_DEBUGS("Voice") << "got energy " << energy << LL_ENDL; mTuningEnergy = energy; } -void LLVivoxVoiceClient::buddyListChanged() -{ - // This is called after we receive a BuddyAndGroupListChangedEvent. - mBuddyListMapPopulated = true; - mFriendsListDirty = true; -} - void LLVivoxVoiceClient::muteListChanged() { // The user's mute list has been updated. Go through the current participant list and sync it with the mute list. @@ -4224,15 +3756,6 @@ void LLVivoxVoiceClient::muteListChanged() } } -void LLVivoxVoiceClient::updateFriends(U32 mask) -{ - if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::POWERS)) - { - // Just resend the whole friend list to the daemon - mFriendsListDirty = true; - } -} - ///////////////////////////// // Managing list of participants LLVivoxVoiceClient::participantState::participantState(const std::string &uri) : @@ -4832,34 +4355,6 @@ bool LLVivoxVoiceClient::answerInvite(std::string &sessionHandle) return false; } -BOOL LLVivoxVoiceClient::isOnlineSIP(const LLUUID &id) -{ - bool result = false; - buddyListEntry *buddy = findBuddy(id); - if(buddy) - { - result = buddy->mOnlineSLim; - LL_DEBUGS("Voice") << "Buddy " << buddy->mDisplayName << " is SIP " << (result?"online":"offline") << LL_ENDL; - } - - if(!result) - { - // This user isn't on the buddy list or doesn't show online status through the buddy list, but could be a participant in an existing session if they initiated a text IM. - sessionState *session = findSession(id); - if(session && !session->mHandle.empty()) - { - if((session->mTextStreamState != streamStateUnknown) || (session->mMediaStreamState > streamStateIdle)) - { - LL_DEBUGS("Voice") << "Open session with " << id << " found, returning SIP online state" << LL_ENDL; - // we have a p2p text session open with this user, so by definition they're online. - result = true; - } - } - } - - return result; -} - bool LLVivoxVoiceClient::isVoiceWorking() const { //Added stateSessionTerminated state to avoid problems with call in parcels with disabled voice (EXT-4758) @@ -5967,224 +5462,6 @@ void LLVivoxVoiceClient::verifySessionState(void) } } -LLVivoxVoiceClient::buddyListEntry::buddyListEntry(const std::string &uri) : - mURI(uri) -{ - mOnlineSL = false; - mOnlineSLim = false; - mCanSeeMeOnline = true; - mHasBlockListEntry = false; - mHasAutoAcceptListEntry = false; - mNameResolved = false; - mInVivoxBuddies = false; - mInSLFriends = false; -} - -void LLVivoxVoiceClient::processBuddyListEntry(const std::string &uri, const std::string &displayName) -{ - buddyListEntry *buddy = addBuddy(uri, displayName); - buddy->mInVivoxBuddies = true; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::addBuddy(const std::string &uri) -{ - std::string empty; - buddyListEntry *buddy = addBuddy(uri, empty); - if(buddy->mDisplayName.empty()) - { - buddy->mNameResolved = false; - } - return buddy; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::addBuddy(const std::string &uri, const std::string &displayName) -{ - buddyListEntry *result = NULL; - buddyListMap::iterator iter = mBuddyListMap.find(uri); - - if(iter != mBuddyListMap.end()) - { - // Found a matching buddy already in the map. - LL_DEBUGS("Voice") << "adding existing buddy " << uri << LL_ENDL; - result = iter->second; - } - - if(!result) - { - // participant isn't already in one list or the other. - LL_DEBUGS("Voice") << "adding new buddy " << uri << LL_ENDL; - result = new buddyListEntry(uri); - result->mDisplayName = displayName; - - if (!IDFromName(uri, result->mUUID)) - { - LL_DEBUGS("Voice") << "Couldn't find ID for buddy " << uri << " (\"" << displayName << "\")" << LL_ENDL; - } - - mBuddyListMap.insert(buddyListMap::value_type(result->mURI, result)); - } - - return result; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::findBuddy(const std::string &uri) -{ - buddyListEntry *result = NULL; - buddyListMap::iterator iter = mBuddyListMap.find(uri); - if(iter != mBuddyListMap.end()) - { - result = iter->second; - } - - return result; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::findBuddy(const LLUUID &id) -{ - buddyListEntry *result = NULL; - buddyListMap::iterator iter; - - for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++) - { - if(iter->second->mUUID == id) - { - result = iter->second; - break; - } - } - - return result; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::findBuddyByDisplayName(const std::string &name) -{ - buddyListEntry *result = NULL; - buddyListMap::iterator iter; - - for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++) - { - if(iter->second->mDisplayName == name) - { - result = iter->second; - break; - } - } - - return result; -} - -void LLVivoxVoiceClient::deleteBuddy(const std::string &uri) -{ - buddyListMap::iterator iter = mBuddyListMap.find(uri); - if(iter != mBuddyListMap.end()) - { - LL_DEBUGS("Voice") << "deleting buddy " << uri << LL_ENDL; - buddyListEntry *buddy = iter->second; - mBuddyListMap.erase(iter); - delete buddy; - } - else - { - LL_DEBUGS("Voice") << "attempt to delete nonexistent buddy " << uri << LL_ENDL; - } - -} - -void LLVivoxVoiceClient::deleteAllBuddies(void) -{ - while(!mBuddyListMap.empty()) - { - deleteBuddy(mBuddyListMap.begin()->first); - } - - // Don't want to correlate with friends list when we've emptied the buddy list. - mBuddyListMapPopulated = false; - - // Don't want to correlate with friends list when we've reset the block rules. - mBlockRulesListReceived = false; - mAutoAcceptRulesListReceived = false; -} - -void LLVivoxVoiceClient::deleteAllBlockRules(void) -{ - // Clear the block list entry flags from all local buddy list entries - buddyListMap::iterator buddy_it; - for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++) - { - buddy_it->second->mHasBlockListEntry = false; - } -} - -void LLVivoxVoiceClient::deleteAllAutoAcceptRules(void) -{ - // Clear the auto-accept list entry flags from all local buddy list entries - buddyListMap::iterator buddy_it; - for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++) - { - buddy_it->second->mHasAutoAcceptListEntry = false; - } -} - -void LLVivoxVoiceClient::addBlockRule(const std::string &blockMask, const std::string &presenceOnly) -{ - buddyListEntry *buddy = NULL; - - // blockMask is the SIP URI of a friends list entry - buddyListMap::iterator iter = mBuddyListMap.find(blockMask); - if(iter != mBuddyListMap.end()) - { - LL_DEBUGS("Voice") << "block list entry for " << blockMask << LL_ENDL; - buddy = iter->second; - } - - if(buddy == NULL) - { - LL_DEBUGS("Voice") << "block list entry for unknown buddy " << blockMask << LL_ENDL; - buddy = addBuddy(blockMask); - } - - if(buddy != NULL) - { - buddy->mHasBlockListEntry = true; - } -} - -void LLVivoxVoiceClient::addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy) -{ - buddyListEntry *buddy = NULL; - - // blockMask is the SIP URI of a friends list entry - buddyListMap::iterator iter = mBuddyListMap.find(autoAcceptMask); - if(iter != mBuddyListMap.end()) - { - LL_DEBUGS("Voice") << "auto-accept list entry for " << autoAcceptMask << LL_ENDL; - buddy = iter->second; - } - - if(buddy == NULL) - { - LL_DEBUGS("Voice") << "auto-accept list entry for unknown buddy " << autoAcceptMask << LL_ENDL; - buddy = addBuddy(autoAcceptMask); - } - - if(buddy != NULL) - { - buddy->mHasAutoAcceptListEntry = true; - } -} - -void LLVivoxVoiceClient::accountListBlockRulesResponse(int statusCode, const std::string &statusString) -{ - // Block list entries were updated via addBlockRule() during parsing. Just flag that we're done. - mBlockRulesListReceived = true; -} - -void LLVivoxVoiceClient::accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString) -{ - // Block list entries were updated via addBlockRule() during parsing. Just flag that we're done. - mAutoAcceptRulesListReceived = true; -} - void LLVivoxVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer) { mParticipantObservers.insert(observer); @@ -6333,11 +5610,6 @@ void LLVivoxVoiceClient::onAvatarNameCache(const LLUUID& agent_id, void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name) { - // If the avatar whose name just resolved is on our friends list, resync the friends list. - if(LLAvatarTracker::instance().getBuddyInfo(id) != NULL) - { - mFriendsListDirty = true; - } // Iterate over all sessions. for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) { @@ -6856,7 +6128,6 @@ void LLVivoxVoiceClient::removeObserver(LLVoiceEffectObserver* observer) { mVoiceFontObservers.erase(observer); } - void LLVivoxVoiceClient::notifyVoiceFontObservers() { LL_DEBUGS("Voice") << "Notifying voice effect observers. Lists changed: " << mVoiceFontListDirty << LL_ENDL; @@ -7245,18 +6516,6 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr) { deviceString.clear(); } - else if (!stricmp("Buddies", tag)) - { - LLVivoxVoiceClient::getInstance()->deleteAllBuddies(); - } - else if (!stricmp("BlockRules", tag)) - { - LLVivoxVoiceClient::getInstance()->deleteAllBlockRules(); - } - else if (!stricmp("AutoAcceptRules", tag)) - { - LLVivoxVoiceClient::getInstance()->deleteAllAutoAcceptRules(); - } else if (!stricmp("SessionFont", tag)) { id = 0; @@ -7388,24 +6647,10 @@ void LLVivoxProtocolParser::EndTag(const char *tag) { LLVivoxVoiceClient::getInstance()->addRenderDevice(deviceString); } - else if (!stricmp("Buddy", tag)) - { - // NOTE : Vivox does *not* give reliable display name for Buddy tags - // We don't take those very seriously as a result... - LLVivoxVoiceClient::getInstance()->processBuddyListEntry(uriString, displayNameString); - } - else if (!stricmp("BlockRule", tag)) - { - LLVivoxVoiceClient::getInstance()->addBlockRule(blockMask, presenceOnly); - } else if (!stricmp("BlockMask", tag)) blockMask = string; else if (!stricmp("PresenceOnly", tag)) presenceOnly = string; - else if (!stricmp("AutoAcceptRule", tag)) - { - LLVivoxVoiceClient::getInstance()->addAutoAcceptRule(autoAcceptMask, autoAddAsBuddy); - } else if (!stricmp("AutoAcceptMask", tag)) autoAcceptMask = string; else if (!stricmp("AutoAddAsBuddy", tag)) @@ -7637,16 +6882,6 @@ void LLVivoxProtocolParser::processResponse(std::string tag) LLVivoxVoiceClient::getInstance()->auxAudioPropertiesEvent(energy); } - else if (!stricmp(eventTypeCstr, "BuddyPresenceEvent")) - { - LLVivoxVoiceClient::getInstance()->buddyPresenceEvent(uriString, alias, statusString, applicationString); - } - else if (!stricmp(eventTypeCstr, "BuddyAndGroupListChangedEvent")) - { - // The buddy list was updated during parsing. - // Need to recheck against the friends list. - LLVivoxVoiceClient::getInstance()->buddyListChanged(); - } else if (!stricmp(eventTypeCstr, "BuddyChangedEvent")) { /* @@ -7669,10 +6904,6 @@ void LLVivoxProtocolParser::processResponse(std::string tag) { LLVivoxVoiceClient::getInstance()->sessionNotificationEvent(sessionHandle, uriString, notificationType); } - else if (!stricmp(eventTypeCstr, "SubscriptionEvent")) - { - LLVivoxVoiceClient::getInstance()->subscriptionEvent(uriString, subscriptionHandle, alias, displayNameString, applicationString, subscriptionType); - } else if (!stricmp(eventTypeCstr, "SessionUpdatedEvent")) { /* @@ -7736,14 +6967,6 @@ void LLVivoxProtocolParser::processResponse(std::string tag) { LLVivoxVoiceClient::getInstance()->connectorShutdownResponse(statusCode, statusString); } - else if (!stricmp(actionCstr, "Account.ListBlockRules.1")) - { - LLVivoxVoiceClient::getInstance()->accountListBlockRulesResponse(statusCode, statusString); - } - else if (!stricmp(actionCstr, "Account.ListAutoAcceptRules.1")) - { - LLVivoxVoiceClient::getInstance()->accountListAutoAcceptRulesResponse(statusCode, statusString); - } else if (!stricmp(actionCstr, "Session.Set3DPosition.1")) { // We don't need to process these, but they're so spammy we don't want to log them. diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 49b2132ac..1ab7a9796 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -163,7 +163,6 @@ public: //@{ virtual BOOL getVoiceEnabled(const LLUUID& id); // true if we've received data for this avatar virtual std::string getDisplayName(const LLUUID& id); - virtual BOOL isOnlineSIP(const LLUUID &id); virtual BOOL isParticipantAvatar(const LLUUID &id); virtual BOOL getIsSpeaking(const LLUUID& id); virtual BOOL getIsModeratorMuted(const LLUUID& id); @@ -470,14 +469,10 @@ protected: void participantRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString); void participantUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, bool isModeratorMuted, bool isSpeaking, int volume, F32 energy); void auxAudioPropertiesEvent(F32 energy); - void buddyPresenceEvent(std::string &uriString, std::string &alias, std::string &statusString, std::string &applicationString); void messageEvent(std::string &sessionHandle, std::string &uriString, std::string &alias, std::string &messageHeader, std::string &messageBody, std::string &applicationString); void sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string ¬ificationType); - void subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType); - void buddyListChanged(); void muteListChanged(); - void updateFriends(U32 mask); ///////////////////////////// // Sending updates of current state @@ -568,24 +563,6 @@ protected: typedef std::map buddyListMap; - // This should be called when parsing a buddy list entry sent by SLVoice. - void processBuddyListEntry(const std::string &uri, const std::string &displayName); - - buddyListEntry *addBuddy(const std::string &uri); - buddyListEntry *addBuddy(const std::string &uri, const std::string &displayName); - buddyListEntry *findBuddy(const std::string &uri); - buddyListEntry *findBuddy(const LLUUID &id); - buddyListEntry *findBuddyByDisplayName(const std::string &name); - void deleteBuddy(const std::string &uri); - void deleteAllBuddies(void); - - void deleteAllBlockRules(void); - void addBlockRule(const std::string &blockMask, const std::string &presenceOnly); - void deleteAllAutoAcceptRules(void); - void addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy); - void accountListBlockRulesResponse(int statusCode, const std::string &statusString); - void accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString); - ///////////////////////////// // session control messages @@ -754,8 +731,7 @@ private: void buildSetCaptureDevice(std::ostringstream &stream); void buildSetRenderDevice(std::ostringstream &stream); - void clearAllLists(); - void checkFriend(const LLUUID& id); + void sendFriendsListUpdates(); // start a text IM session with the specified user From 353e2977d6bade551bc6d3e32b9f180728083420 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Sat, 27 Jul 2013 16:47:35 -0400 Subject: [PATCH 002/115] [Voice Update] Further sync llvoiceclient and llvoicevivox with upstream Mainly tiny motions to ease merging as viewer-vivox2 work continues Condenses MultiVoice block --- indra/newview/llvoiceclient.cpp | 2 ++ indra/newview/llvoiceclient.h | 6 ++++++ indra/newview/llvoicevivox.cpp | 26 +++++++++++--------------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index d9fb9610d..f3709450d 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -540,6 +540,7 @@ void LLVoiceClient::setMuteMic(bool muted) { mMuteMic = muted; updateMicMuteLogic(); + mMicroChangedSignal(); } @@ -550,6 +551,7 @@ void LLVoiceClient::setUserPTTState(bool ptt) { mUserPTTState = ptt; updateMicMuteLogic(); + mMicroChangedSignal(); } bool LLVoiceClient::getUserPTTState() diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index 06bfeb3a4..b8cf474cc 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -301,6 +301,9 @@ public: LLVoiceClient(); ~LLVoiceClient(); + typedef boost::signals2::signal micro_changed_signal_t; + micro_changed_signal_t mMicroChangedSignal; + void init(LLPumpIO *pump); // Call this once at application startup (creates connector) void terminate(); // Call this to clean up during shutdown @@ -399,6 +402,8 @@ public: void keyUp(KEY key, MASK mask); void middleMouseState(bool down); + boost::signals2::connection MicroChangedCallback(const micro_changed_signal_t::slot_type& cb ) { return mMicroChangedSignal.connect(cb); } + ///////////////////////////// // Accessors for data related to nearby speakers @@ -454,6 +459,7 @@ protected: LLVoiceModuleInterface* mVoiceModule; LLPumpIO *m_servicePump; + LLCachedControl mVoiceEffectEnabled; LLCachedControl mVoiceEffectDefault; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index b6be06d64..329e08de6 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -177,6 +177,7 @@ class LLVivoxVoiceClientMuteListObserver : public LLMuteListObserver /* virtual */ void onChange() { LLVivoxVoiceClient::getInstance()->muteListChanged();} }; + static LLVivoxVoiceClientMuteListObserver mutelist_listener; static bool sMuteListListener_listening = false; @@ -836,20 +837,6 @@ void LLVivoxVoiceClient::stateMachine() // SLIM SDK: these arguments are no longer necessary. // std::string args = " -p tcp -h -c"; std::string loglevel = gSavedSettings.getString("VivoxDebugLevel"); - - // If we allow multiple instances of the viewer to start the voice - // daemon, set TEMPORARY random voice port - if (gSavedSettings.getBOOL("VoiceMultiInstance")) - { - LLControlVariable* voice_port = gSavedSettings.getControl("VoicePort"); - if (voice_port) - { - const BOOL DO_NOT_PERSIST = FALSE; - S32 port_nr = 30000 + ll_rand(20000); - voice_port->setValue(LLSD(port_nr), DO_NOT_PERSIST); - } - } - if(loglevel.empty()) { loglevel = "-0"; // turn logging off completely @@ -858,9 +845,18 @@ void LLVivoxVoiceClient::stateMachine() args += " -ll "; args += loglevel; - // Tell voice gateway to listen to a specific port + // If we allow multiple instances of the viewer to start the voicedaemon if (gSavedSettings.getBOOL("VoiceMultiInstance")) { + // Set TEMPORARY random voice port + LLControlVariable* voice_port = gSavedSettings.getControl("VoicePort"); + if (voice_port) + { + const BOOL DO_NOT_PERSIST = FALSE; + S32 port_nr = 30000 + ll_rand(20000); + voice_port->setValue(LLSD(port_nr), DO_NOT_PERSIST); + } + // Tell voice gateway to listen to a specific port args += llformat(" -i 127.0.0.1:%u", gSavedSettings.getU32("VoicePort")); } From 2450b435a730762add23570c262db2888b675a22 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Fri, 24 Jan 2014 21:41:56 -0500 Subject: [PATCH 003/115] Combine commonly created scroll list menus into single menus identified by menu_num instead of their menu_file sScrollListMenus is an array such that it will hold more menus in the future, such as groups. fmenu_file still exists and will still exhibit its old behavior if used. --- indra/llui/llscrolllistctrl.cpp | 12 +++++++++++- indra/newview/llviewermenu.cpp | 5 +++++ .../skins/default/xui/en-us/floater_about_land.xml | 4 ++-- .../default/xui/en-us/floater_active_speakers.xml | 2 +- .../skins/default/xui/en-us/floater_directory.xml | 2 +- .../skins/default/xui/en-us/floater_directory2.xml | 2 +- .../skins/default/xui/en-us/floater_directory3.xml | 2 +- .../skins/default/xui/en-us/panel_friends.xml | 2 +- .../skins/default/xui/en-us/panel_friends_horiz.xml | 2 +- .../skins/default/xui/en-us/panel_group_general.xml | 2 +- .../skins/default/xui/en-us/panel_group_roles.xml | 6 +++--- .../default/xui/en-us/panel_speaker_controls.xml | 2 +- 12 files changed, 29 insertions(+), 14 deletions(-) diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index bae86672c..fb9383ecb 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -57,6 +57,8 @@ static LLRegisterWidget r("scroll_list"); +LLMenuGL* sScrollListMenus[1] = {}; // List menus that recur, such as general avatars or groups menus + // local structures & classes. struct SortScrollListItem { @@ -2552,7 +2554,15 @@ void LLScrollListCtrl::setScrollListParameters(LLXMLNodePtr node) node->getAttribute_bool("mouse_wheel_opaque", mMouseWheelOpaque); } - if (node->hasAttribute("menu_file")) + if (node->hasAttribute("menu_num")) + { + // Some scroll lists use common menus identified by number + // 0 is menu_avs_list.xml, 1 will be for groups, 2 could be for lists of objects + S32 menu_num; + node->getAttributeS32("menu_num", menu_num); + mPopupMenu = sScrollListMenus[menu_num]; + } + else if (node->hasAttribute("menu_file")) { std::string menu_file; node->getAttributeString("menu_file", menu_file); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index ca85a2ac2..32e426544 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -239,6 +239,7 @@ extern BOOL gDebugTextEditorTips; extern BOOL gShowOverlayTitle; extern BOOL gOcclusionCull; extern AIHTTPView* gHttpView; +extern LLMenuGL* sScrollListMenus[1]; // // Globals // @@ -781,6 +782,10 @@ void init_menus() gMenuHolder->addChild(gLoginMenuBarView); + // Singu Note: Initialize common ScrollListMenus here + sScrollListMenus[0] = LLUICtrlFactory::getInstance()->buildMenu("menu_avs_list.xml", gMenuHolder); + //sScrollListMenus[1] = LLUICtrlFactory::getInstance()->buildMenu("menu_groups_list.xml"); // Singu TODO + LLView* ins = gMenuBarView->getChildView("insert_world", true, false); ins->setVisible(false); ins = gMenuBarView->getChildView("insert_agent", true, false); diff --git a/indra/newview/skins/default/xui/en-us/floater_about_land.xml b/indra/newview/skins/default/xui/en-us/floater_about_land.xml index fec011a1a..eac223645 100644 --- a/indra/newview/skins/default/xui/en-us/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en-us/floater_about_land.xml @@ -1383,7 +1383,7 @@ Select the thumbnail to choose a different texture. column_padding="0" draw_border="true" draw_heading="false" enabled="true" follows="top|bottom" heading_font="SansSerifSmall" heading_height="14" height="80" left="20" mouse_opaque="true" multi_select="true" - name="AccessList" tool_tip="([LISTED] listed, [MAX] max)" width="195" menu_file="menu_avs_list.xml"/> + name="AccessList" tool_tip="([LISTED] listed, [MAX] max)" width="195" menu_num="0"/> + diff --git a/indra/newview/skins/default/xui/en-us/notifications.xml b/indra/newview/skins/default/xui/en-us/notifications.xml index 307424ff0..eaf0d0fb7 100644 --- a/indra/newview/skins/default/xui/en-us/notifications.xml +++ b/indra/newview/skins/default/xui/en-us/notifications.xml @@ -9693,6 +9693,14 @@ Cannot create large prims that intersect other players. Please re-try when othe + + +Changes won't take effect until after you restart [APP_NAME]. + + Date: Fri, 31 Jan 2014 00:50:45 -0500 Subject: [PATCH 019/115] [RLVa] Version 1.4.9 Thanks to Trinity and, of course, her Kitty! --- indra/newview/rlvdefines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index a97ea3e16..72c504ff8 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -64,7 +64,7 @@ const S32 RLV_VERSION_BUILD = 0; // Implementation version const S32 RLVa_VERSION_MAJOR = 1; const S32 RLVa_VERSION_MINOR = 4; -const S32 RLVa_VERSION_PATCH = 8; +const S32 RLVa_VERSION_PATCH = 9; const S32 RLVa_VERSION_BUILD = 0; // Uncomment before a final release From 151afe466370e38b6c8e471f77c40ff404f08805 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Fri, 31 Jan 2014 00:52:16 -0500 Subject: [PATCH 020/115] Translations fix ups --- .../skins/default/xui/de/notifications.xml | 12 +- .../default/xui/en-us/floater_buy_land.xml | 6 +- .../skins/default/xui/es/notifications.xml | 2 +- .../default/xui/it/floater_about_land.xml | 6 +- ....xml => floater_animation_bvh_preview.xml} | 0 .../skins/default/xui/it/floater_bumps.xml | 10 +- .../default/xui/it/floater_buy_contents.xml | 2 +- .../default/xui/it/floater_buy_currency.xml | 14 +- .../skins/default/xui/it/floater_buy_land.xml | 32 +-- .../default/xui/it/floater_buy_object.xml | 2 +- .../default/xui/it/floater_chat_history.xml | 39 --- .../xui/it/floater_device_settings.xml | 2 - .../default/xui/it/floater_directory.xml | 8 +- .../default/xui/it/floater_group_info.xml | 262 ------------------ .../xui/it/floater_hardware_settings.xml | 38 --- .../skins/default/xui/it/floater_im.xml | 45 --- .../skins/default/xui/it/floater_import.xml | 17 -- .../it/floater_inventory_item_properties.xml | 2 +- .../default/xui/it/floater_media_browser.xml | 20 -- .../skins/default/xui/it/floater_new_im.xml | 11 - .../xui/it/floater_price_for_listing.xml | 2 +- .../default/xui/it/floater_report_bug.xml | 104 ------- .../default/xui/it/floater_sell_land.xml | 4 +- .../skins/default/xui/it/floater_snapshot.xml | 4 +- .../skins/default/xui/it/floater_tools.xml | 10 +- .../default/xui/it/floater_voice_wizard.xml | 9 - .../default/xui/it/floater_web_content.xml | 11 + .../skins/default/xui/it/notifications.xml | 62 ++--- .../default/xui/it/panel_audio_device.xml | 25 -- .../xui/it/panel_avatar_classified.xml | 2 +- .../skins/default/xui/it/panel_classified.xml | 2 +- .../default/xui/it/panel_group_finder.xml | 9 - .../default/xui/it/panel_group_general.xml | 8 +- .../default/xui/it/panel_group_land_money.xml | 4 +- .../skins/default/xui/it/panel_place.xml | 2 +- .../default/xui/it/panel_place_small.xml | 2 +- .../xui/it/panel_preferences_media.xml | 24 -- .../default/xui/it/panel_region_texture.xml | 57 ---- .../skins/default/xui/it/panel_top_pick.xml | 10 - .../default/xui/it/panel_voice_enable.xml | 23 -- .../newview/skins/default/xui/it/strings.xml | 46 ++- .../skins/default/xui/pt/floater_bumps.xml | 10 +- .../default/xui/pt/floater_media_browser.xml | 20 -- .../default/xui/pt/floater_web_content.xml | 12 + .../skins/default/xui/pt/notifications.xml | 12 +- 45 files changed, 176 insertions(+), 828 deletions(-) rename indra/newview/skins/default/xui/it/{floater_animation_preview.xml => floater_animation_bvh_preview.xml} (100%) delete mode 100644 indra/newview/skins/default/xui/it/floater_device_settings.xml delete mode 100644 indra/newview/skins/default/xui/it/floater_group_info.xml delete mode 100644 indra/newview/skins/default/xui/it/floater_hardware_settings.xml delete mode 100644 indra/newview/skins/default/xui/it/floater_im.xml delete mode 100644 indra/newview/skins/default/xui/it/floater_import.xml delete mode 100644 indra/newview/skins/default/xui/it/floater_media_browser.xml delete mode 100644 indra/newview/skins/default/xui/it/floater_new_im.xml delete mode 100644 indra/newview/skins/default/xui/it/floater_report_bug.xml delete mode 100644 indra/newview/skins/default/xui/it/floater_voice_wizard.xml create mode 100644 indra/newview/skins/default/xui/it/floater_web_content.xml delete mode 100644 indra/newview/skins/default/xui/it/panel_audio_device.xml delete mode 100644 indra/newview/skins/default/xui/it/panel_group_finder.xml delete mode 100644 indra/newview/skins/default/xui/it/panel_preferences_media.xml delete mode 100644 indra/newview/skins/default/xui/it/panel_region_texture.xml delete mode 100644 indra/newview/skins/default/xui/it/panel_top_pick.xml delete mode 100644 indra/newview/skins/default/xui/it/panel_voice_enable.xml delete mode 100644 indra/newview/skins/default/xui/pt/floater_media_browser.xml create mode 100644 indra/newview/skins/default/xui/pt/floater_web_content.xml diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index fd604c161..37a86b525 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -145,12 +145,12 @@ Wählen Sie ein einzelnes Objekt aus und versuchen Sie es erneut.Änderung an Kleidung/Körperteilen speichern? Die Gewährung von Änderungsrechten an andere Einwohner ermöglicht es diesen, JEDES BELIEBIGE Objekt zu ändern oder an sich zu nehmen, das Sie in der Second Life-Welt besitzen. Seien Sie SEHR vorsichtig beim Erteilen dieser Erlaubnis. -Möchten Sie [FIRST_NAME] [LAST_NAME] Änderungsrechte gewähren? +Möchten Sie [NAME] Änderungsrechte gewähren? Die Gewährung von Änderungsrechten an andere Einwohner ermöglicht es diesen, JEDES BELIEBIGE Objekt zu ändern, das Sie in der Second Life-Welt besitzen. Seien Sie SEHR vorsichtig beim Erteilen dieser Erlaubnis. Möchten Sie den ausgewählten Einwohnern Änderungsrechte gewähren? - Möchten Sie [FIRST_NAME] [LAST_NAME] die Änderungsrechte entziehen? + Möchten Sie [NAME] die Änderungsrechte entziehen? Möchten Sie den ausgewählten Einwohnern die Änderungsrechte entziehen? @@ -816,7 +816,7 @@ Sie sind nicht berechtigt, Land für die aktive Gruppe zu kaufen. - Möchten Sie [FIRST_NAME] [LAST_NAME] aus Ihrer Freundesliste entfernen? + Möchten Sie [NAME] aus Ihrer Freundesliste entfernen? Möchten Sie mehrere Freunde aus Ihrer Freundesliste entfernen? @@ -902,7 +902,7 @@ Der Gruppe „[GROUP_NAME]“ [AREA] m² Land schenken? Die Schenkung dieser Parzelle setzt voraus, dass die Gruppe über ausreichende Landnutzungsrechte verfügt. -Die Schenkung beinhaltet eine Landübertragung an die Gruppe von „[FIRST_NAME] [LAST_NAME]“. +Die Schenkung beinhaltet eine Landübertragung an die Gruppe von „[NAME]“. Dem Eigentümer wird der Kaufpreis für das Land nicht rückerstattet. Bei Verkauf der übertragenen Parzelle wird der Erlös zwischen den Gruppenmitgliedern aufgeteilt. Der Gruppe „[GROUP_NAME]“ @@ -951,9 +951,9 @@ Sie können sich später noch umentscheiden.[NAME] [PRICE] L$ Sie haben nicht genügend L$, um diese Aktion auszuführen. - Sie verfügen über Änderungsrechte für die Objekte von [FIRST_NAME] [LAST_NAME]. + Sie verfügen über Änderungsrechte für die Objekte von [NAME]. - Ihnen wurden die Änderungsrechte für die Objekte von [FIRST_NAME] [LAST_NAME] entzogen. + Ihnen wurden die Änderungsrechte für die Objekte von [NAME] entzogen. Der Kartencache dieser Region wird geleert. Diese Aktion ist nur beim Debugging sinnvoll. diff --git a/indra/newview/skins/default/xui/en-us/floater_buy_land.xml b/indra/newview/skins/default/xui/en-us/floater_buy_land.xml index 598f21d82..b5a538e5e 100644 --- a/indra/newview/skins/default/xui/en-us/floater_buy_land.xml +++ b/indra/newview/skins/default/xui/en-us/floater_buy_land.xml @@ -169,7 +169,7 @@ This parcel is 512 sq.m. of land. - for approx. US$ [AMOUNT2] + for approx. [REALCURRENCY] [AMOUNT2] You have L$ 2,100. @@ -261,7 +261,7 @@ Try selecting a smaller area. Pay [CURRENCY] [AMOUNT] to [SELLER] for this land - Buy [CURRENCY] [AMOUNT] for approx. US$ [AMOUNT2], + Buy [CURRENCY] [AMOUNT] for approx. [REALCURRENCY] [AMOUNT2], This parcel is [AMOUNT] sq.m. @@ -306,6 +306,6 @@ supports [AMOUNT2] objects (no parcel selected) - Buy [CURRENCY] [LINDENS] for approx. US$ [USD] + Buy [CURRENCY] [LINDENS] for approx. [REALCURRENCY] [USD] diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index 36bd2e17b..edbc87013 100644 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -3404,7 +3404,7 @@ Por favor, vuelve a intentarlo. - Has ofrecido una tarjeta de visita a [FIRST] [LAST] + Has ofrecido una tarjeta de visita a [NAME] diff --git a/indra/newview/skins/default/xui/it/floater_about_land.xml b/indra/newview/skins/default/xui/it/floater_about_land.xml index 550304e5d..8366add8b 100644 --- a/indra/newview/skins/default/xui/it/floater_about_land.xml +++ b/indra/newview/skins/default/xui/it/floater_about_land.xml @@ -42,7 +42,7 @@ Non in vendita. - Prezzo: [PRICE]L$ ([PRICE_PER_SQM]L$/m²). + Prezzo: [PRICE][CURRENCY] ([PRICE_PER_SQM][CURRENCY]/m²). + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2af2e37dcd127311f79bbd2fdb413b83ed6bec9f Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Thu, 27 Mar 2014 20:02:12 -0400 Subject: [PATCH 072/115] Right clicking folder with only gestures (no worn items) should still offer remove from outfit if any gesture in that folder is active. Also follow linked folders when wearing folders, this will make linked folders a lot more useful! Also fixes a warning and some spacing issues --- indra/newview/llappearancemgr.cpp | 44 ++++++++++++++++++----------- indra/newview/llinventorybridge.cpp | 15 ++++++---- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 8ab198d3b..5c6712711 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1526,7 +1526,7 @@ void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id) LLInventoryModel::item_array_t items; LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector); + gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector, true); LLInventoryModel::item_array_t::const_iterator it = items.begin(); const LLInventoryModel::item_array_t::const_iterator it_end = items.end(); @@ -1539,16 +1539,16 @@ void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id) removeItemsFromAvatar(uuids_to_remove); // deactivate all gestures in the outfit folder - LLInventoryModel::item_array_t gest_items; - getDescendentsOfAssetType(cat_id, gest_items, LLAssetType::AT_GESTURE, false); - for(U32 i = 0; i < gest_items.count(); ++i) - { - LLViewerInventoryItem* gest_item = gest_items.get(i); - if (LLGestureMgr::instance().isGestureActive(gest_item->getLinkedUUID())) - { - LLGestureMgr::instance().deactivateGesture(gest_item->getLinkedUUID()); - } - } + LLInventoryModel::item_array_t gest_items; + getDescendentsOfAssetType(cat_id, gest_items, LLAssetType::AT_GESTURE, true); + for(S32 i = 0; i < gest_items.count(); ++i) + { + LLViewerInventoryItem* gest_item = gest_items.get(i); + if (LLGestureMgr::instance().isGestureActive(gest_item->getLinkedUUID())) + { + LLGestureMgr::instance().deactivateGesture(gest_item->getLinkedUUID()); + } + } } // Create a copy of src_id + contents as a subfolder of dst_id. @@ -1724,8 +1724,18 @@ bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) cats, items, LLInventoryModel::EXCLUDE_TRASH, - is_worn); - return items.size() > 0; + is_worn, + /*follow_folder_links=*/ true); + + if (items.size()) return true; + + // Is there an active gesture in outfit_cat_id? + items.reset(); + gInventory.collectDescendentsIf(outfit_cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, LLIsType(LLAssetType::AT_GESTURE), /*follow_folder_links=*/ true); + for(S32 i = 0; i < items.count(); ++i) + if (LLGestureMgr::instance().isGestureActive(items.get(i)->getLinkedUUID())) + return true; + return false; } // static @@ -1956,10 +1966,10 @@ void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid, void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) { LLInventoryModel::item_array_t body_items_new, wear_items_new, obj_items_new, gest_items_new; - getDescendentsOfAssetType(category, body_items_new, LLAssetType::AT_BODYPART, false); - getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING, false); - getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT, false); - getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE, false); + getDescendentsOfAssetType(category, body_items_new, LLAssetType::AT_BODYPART, true); + getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING, true); + getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT, true); + getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE, true); updateCOF(body_items_new, wear_items_new, obj_items_new, gest_items_new, append, category); } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 1cf94d15e..323263d76 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1766,7 +1766,8 @@ BOOL LLItemBridge::removeItem() cat_array, item_array, LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); + is_linked_item_match, + true); const U32 num_links = cat_array.size() + item_array.size(); if (num_links > 0) @@ -3254,7 +3255,8 @@ BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInv cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, - is_type); + is_type, + true); return ((item_array.count() > 0) ? TRUE : FALSE ); } @@ -5597,7 +5599,8 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_ cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, - is_wearable); + is_wearable, + true); S32 i; S32 wearable_count = item_array.count(); @@ -5608,7 +5611,8 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_ obj_cat_array, obj_item_array, LLInventoryModel::EXCLUDE_TRASH, - is_object); + is_object, + true); S32 obj_count = obj_item_array.count(); // Find all gestures in this folder @@ -5619,7 +5623,8 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_ gest_cat_array, gest_item_array, LLInventoryModel::EXCLUDE_TRASH, - is_gesture); + is_gesture, + true); S32 gest_count = gest_item_array.count(); if (wearable_count > 0) //Loop through wearables. If worn, remove. From 70e92a1ceac1e1b514f26d5c5b77930e2f531eed Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Thu, 27 Mar 2014 20:10:06 -0400 Subject: [PATCH 073/115] More helpful fixes and touchups from Cinder --- indra/newview/app_settings/settings.xml | 2 +- .../installers/windows/installer_template.nsi | 27 +++++++++--------- indra/newview/llappviewer.cpp | 18 +----------- indra/newview/llpanellogin.cpp | 2 +- ...singularity.icns => singularity_icon.icns} | Bin indra/newview/res/viewerRes.rc.in | 6 ++-- indra/newview/res/viewerRes_bc.rc.in | 6 ++-- .../skins/default/xui/en-us/floater_about.xml | 4 +-- .../skins/default/xui/en-us/menu_login.xml | 4 +-- .../skins/default/xui/en-us/menu_viewer.xml | 10 +++---- .../skins/default/xui/en-us/strings.xml | 1 + indra/newview/viewer_manifest.py | 10 ++++--- 12 files changed, 39 insertions(+), 51 deletions(-) rename indra/newview/res/{singularity.icns => singularity_icon.icns} (100%) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e27156e5a..71d009510 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8477,7 +8477,7 @@ This should be as low as possible, but too low may break functionality Type Boolean Value - 0 + 1 ForceMandatoryUpdate diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index e78317e3f..3f2cfbd0f 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -31,6 +31,7 @@ RequestExecutionLevel admin ; on Vista we must be admin because we write to Prog ;; !define INSTNAME "SecondLife%(grid_caps)s" ;; !define SHORTCUT "Second Life (%(grid_caps)s)" ;; !define URLNAME "secondlife%(grid)s" +;; !define AUTHOR "Linden Research, Inc." ;; !define UNINSTALL_SETTINGS 1 %%GRID_VARS%% @@ -76,8 +77,8 @@ Name "${VIEWERNAME}" SubCaption 0 $(LicenseSubTitleSetup) ; override "license agreement" text BrandingText "Prepare to Implode!" ; bottom of window text -Icon %%SOURCE%%\installers\windows\install_icon_singularity.ico -UninstallIcon %%SOURCE%%\installers\windows\uninstall_icon_singularity.ico +Icon %%SOURCE%%\installers\windows\${INSTALL_ICON} +UninstallIcon %%SOURCE%%\installers\windows\${UNINSTALL_ICON} WindowIcon off ; show our icon in left corner # BGGradient 9090b0 000000 notext CRCCheck on ; make sure CRC is OK @@ -89,7 +90,7 @@ SetOverwrite on ; stomp files by default AutoCloseWindow true ; after all files install, close window InstallDir "%%INSTALLDIR%%" -InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "" +InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\${INSTNAME}" "" DirText $(DirectoryChooseTitle) $(DirectoryChooseSetup) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -191,7 +192,7 @@ FunctionEnd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function CheckIfAlreadyCurrent Push $0 - ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" + ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" "Version" StrCmp $0 ${VERSION_LONG} 0 DONE MessageBox MB_OKCANCEL $(CheckIfCurrentMB) /SD IDOK IDOK DONE Quit @@ -550,7 +551,7 @@ SetShellVarContext all Call un.CloseSecondLife ; Clean up registry keys and subkeys (these should all be !defines somewhere) -DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" ; Clean up shortcuts @@ -693,7 +694,7 @@ lbl_check_silent: ; If we currently have a version of SL installed, default to the language of that install ; Otherwise don't change $LANGUAGE and it will default to the OS UI language. - ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" + ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\${INSTNAME}" "InstallerLanguage" IfErrors lbl_build_menu StrCpy $LANGUAGE $0 @@ -711,7 +712,7 @@ lbl_build_menu: StrCpy $LANGUAGE $0 ; save language in registry - WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" $LANGUAGE + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\${INSTNAME}" "InstallerLanguage" $LANGUAGE lbl_return: Pop $0 Return @@ -721,7 +722,7 @@ FunctionEnd Function un.onInit ; read language from registry and set for uninstaller ; Key will be removed on successful uninstall - ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" + ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\${INSTNAME}" "InstallerLanguage" IfErrors lbl_end StrCpy $LANGUAGE $0 lbl_end: @@ -810,11 +811,11 @@ CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Write registry -WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "" "$INSTDIR" -WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" "${VERSION_LONG}" -WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Flags" "$INSTFLAGS" -WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut" "$INSTSHORTCUT" -WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe" "$INSTEXE" +WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" "" "$INSTDIR" +WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" "Version" "${VERSION_LONG}" +WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" "Flags" "$INSTFLAGS" +WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" "Shortcut" "$INSTSHORTCUT" +WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" "Exe" "$INSTEXE" WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayName" "$INSTPROG (remove only)" WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "UninstallString" '"$INSTDIR\uninst.exe"' diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 4647bd8cb..45fa8dcd7 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -355,6 +355,7 @@ void init_default_trans_args() { default_trans_args.insert("SECOND_LIFE"); // World default_trans_args.insert("APP_NAME"); + default_trans_args.insert("SHORT_APP_NAME"); default_trans_args.insert("CAPITALIZED_APP_NAME"); default_trans_args.insert("SECOND_LIFE_GRID"); default_trans_args.insert("SUPPORT_SITE"); @@ -2363,23 +2364,6 @@ bool LLAppViewer::initConfiguration() #if LL_DARWIN // Initialize apple menubar and various callbacks init_apple_menu(LLTrans::getString("APP_NAME").c_str()); - -#if __ppc__ - // If the CPU doesn't have Altivec (i.e. it's not at least a G4), don't go any further. - // Only test PowerPC - all Intel Macs have SSE. - if(!gSysCPU.hasAltivec()) - { - std::ostringstream msg; - msg << LLTrans::getString("MBRequiresAltiVec"); - OSMessageBox( - msg.str(), - LLStringUtil::null, - OSMB_OK); - removeMarkerFile(); - return false; - } -#endif - #endif // LL_DARWIN // Display splash screen. Must be after above check for previous diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 6f0cdf10c..a219868d3 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -647,7 +647,7 @@ void LLPanelLogin::updateLocationSelectorsVisibility() sInstance->getChildView("location_panel")->setVisible(show_start); - bool show_server = true; + bool show_server = gSavedSettings.getBOOL("ForceShowGrid"); sInstance->getChildView("grids_panel")->setVisible(show_server); } diff --git a/indra/newview/res/singularity.icns b/indra/newview/res/singularity_icon.icns similarity index 100% rename from indra/newview/res/singularity.icns rename to indra/newview/res/singularity_icon.icns diff --git a/indra/newview/res/viewerRes.rc.in b/indra/newview/res/viewerRes.rc.in index 0ca054f5a..0119f9fd9 100644 --- a/indra/newview/res/viewerRes.rc.in +++ b/indra/newview/res/viewerRes.rc.in @@ -61,8 +61,8 @@ END // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -IDI_LL_ICON ICON "singularity_icon.ico" -IDI_LCD_LL_ICON ICON "singularity_icon.ico" +IDI_LL_ICON ICON "${VIEWER_BRANDING_ID}_icon.ico" +IDI_LCD_LL_ICON ICON "${VIEWER_BRANDING_ID}_icon.ico" ///////////////////////////////////////////////////////////////////////////// // @@ -74,7 +74,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE FONT 8, "MS Sans Serif" BEGIN ICON IDI_LL_ICON,IDC_STATIC,7,7,20,20 - LTEXT "Loading Second Life...",666,36,13,91,8 + LTEXT "Loading ${VIEWER_CHANNEL}...",666,36,13,91,8 END diff --git a/indra/newview/res/viewerRes_bc.rc.in b/indra/newview/res/viewerRes_bc.rc.in index a9bdd7c8d..3413cf937 100644 --- a/indra/newview/res/viewerRes_bc.rc.in +++ b/indra/newview/res/viewerRes_bc.rc.in @@ -61,8 +61,8 @@ END // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -IDI_LL_ICON ICON "singularity_icon_bc.ico" -IDI_LCD_LL_ICON ICON "singularity_icon_bc.ico" +IDI_LL_ICON ICON "${VIEWER_BRANDING_ID}_icon_bc.ico" +IDI_LCD_LL_ICON ICON "${VIEWER_BRANDING_ID}_icon_bc.ico" ///////////////////////////////////////////////////////////////////////////// // @@ -74,7 +74,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE FONT 8, "MS Sans Serif" BEGIN ICON IDI_LL_ICON,IDC_STATIC,7,7,20,20 - LTEXT "Loading Second Life...",666,36,13,91,8 + LTEXT "Loading ${VIEWER_CHANNEL}...",666,36,13,91,8 END diff --git a/indra/newview/skins/default/xui/en-us/floater_about.xml b/indra/newview/skins/default/xui/en-us/floater_about.xml index 1d4e1d275..a94a96aa9 100644 --- a/indra/newview/skins/default/xui/en-us/floater_about.xml +++ b/indra/newview/skins/default/xui/en-us/floater_about.xml @@ -2,7 +2,7 @@ + title="About [SHORT_APP_NAME]" width="470"> @@ -31,7 +31,7 @@ Collada DOM Copyright 2006 Sony Computer Entertainment Inc. cURL Copyright (C) 1996-2010, Daniel Stenberg, (daniel@haxx.se) DBus/dbus-glib Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc. expat Copyright (C) 1998-2000 Thai Open Source Software Center Ltd., 2001-2006 Expat maintainers. -FMOD Sound System, Copyright (C) 1994-2012 Firelight Technologies Pty, Ltd. +FMOD Sound System, Copyright (C) 1994-2013 Firelight Technologies Pty, Ltd. FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org). GL Copyright (C) 1999-2004 Brian Paul. GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. diff --git a/indra/newview/skins/default/xui/en-us/menu_login.xml b/indra/newview/skins/default/xui/en-us/menu_login.xml index 6674ccd3a..35ac6f7e3 100644 --- a/indra/newview/skins/default/xui/en-us/menu_login.xml +++ b/indra/newview/skins/default/xui/en-us/menu_login.xml @@ -21,10 +21,10 @@ - - + diff --git a/indra/newview/skins/default/xui/en-us/menu_viewer.xml b/indra/newview/skins/default/xui/en-us/menu_viewer.xml index 7a18093a4..78b13ba8b 100644 --- a/indra/newview/skins/default/xui/en-us/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en-us/menu_viewer.xml @@ -895,7 +895,7 @@ - @@ -944,7 +944,7 @@ - @@ -971,8 +971,8 @@ - + @@ -985,7 +985,7 @@ - + diff --git a/indra/newview/skins/default/xui/en-us/strings.xml b/indra/newview/skins/default/xui/en-us/strings.xml index 77e3f12de..b23b8e948 100644 --- a/indra/newview/skins/default/xui/en-us/strings.xml +++ b/indra/newview/skins/default/xui/en-us/strings.xml @@ -27,6 +27,7 @@ Make sure you entered the correct Login URI. An example of a Login URI is: \"htt Second Life Singularity Viewer SINGULARITY VIEWER + Singularity Second Life Grid Second Life Support Portal diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 7b86acdf9..9a284bcf2 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -406,6 +406,8 @@ class WindowsManifest(ViewerManifest): 'inst_name':self.channel_oneword() + ' (64 bit)' if self.is_win64() else self.channel_oneword(), 'installer_file':self.installer_file(), 'viewer_name': "%s%s" % (self.channel(), " (64 bit)" if self.is_win64() else "" ), + 'install_icon': "install_icon_%s.ico" % self.viewer_branding_id(), + 'uninstall_icon': "uninstall_icon_%s.ico" % self.viewer_branding_id(), } version_vars = """ @@ -422,8 +424,9 @@ class WindowsManifest(ViewerManifest): !define INSTNAME "%(inst_name)s" !define SHORTCUT "%(viewer_name)s Viewer" !define URLNAME "secondlife" - !define INSTALL_ICON "install_icon_singularity.ico" - !define UNINSTALL_ICON "install_icon_singularity.ico" + !define INSTALL_ICON "%(install_icon)s" + !define UNINSTALL_ICON "%(uninstall_icon)s" + !define AUTHOR "Linden Research, Inc." #TODO: Hook this up to cmake et al for easier branding. Caption "${VIEWERNAME} ${VERSION_LONG}" """ if 'installer_name' in self.args: @@ -493,8 +496,7 @@ class DarwinManifest(ViewerManifest): self.path("featuretable_mac.txt") self.path("SecondLife.nib") - # SG:TODO - self.path("../newview/res/singularity.icns", dst="singularity.icns") + self.path(("../newview/res/%s_icon.icns" % self.viewer_branding_id()), dst=("%s_icon.icns" % self.viewer_branding_id())) # Translations self.path("English.lproj") From 039be1f8e90fd40f91a74b827045a48f444b02fd Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Thu, 27 Mar 2014 21:33:21 -0400 Subject: [PATCH 074/115] Fix Issue 1413: Local Texture Default Texture Update Settings, Also fix the side issue of the More section not having visible ui at first. Also I got fed up with the bad code and leaks so I did some refactoring of floaterlocalassetbrowse.*, but just a bit. --- indra/newview/app_settings/settings.xml | 11 + indra/newview/floaterlocalassetbrowse.cpp | 604 +++++++++------------- indra/newview/floaterlocalassetbrowse.h | 64 +-- 3 files changed, 289 insertions(+), 390 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 71d009510..db797127e 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1017,6 +1017,17 @@ Found in Advanced->Rendering->Info Displays Value 1 + LocalBitmapUpdate + + Comment + Default setting for whether local textures should update or not upon change, changed by toggling on or off. + Persist + 1 + Type + Boolean + Value + 0 + InstantMessageLogPathAnyAccount Comment diff --git a/indra/newview/floaterlocalassetbrowse.cpp b/indra/newview/floaterlocalassetbrowse.cpp index 24b6a192f..a3af2928d 100644 --- a/indra/newview/floaterlocalassetbrowse.cpp +++ b/indra/newview/floaterlocalassetbrowse.cpp @@ -72,6 +72,8 @@ this feature is still a work in progress. #include "llvovolume.h" #include "llface.h" +/* static pointer to self, wai? oh well. */ +static FloaterLocalAssetBrowser* sLFInstance = NULL; /*=======================================*/ /* Instantiating manager class */ @@ -79,7 +81,7 @@ this feature is still a work in progress. /*=======================================*/ LocalAssetBrowser* gLocalBrowser; LocalAssetBrowserTimer* gLocalBrowserTimer; -std::vector LocalAssetBrowser::loaded_bitmaps; +std::vector LocalAssetBrowser::loaded_bitmaps; bool LocalAssetBrowser::mLayerUpdated; bool LocalAssetBrowser::mSculptUpdated; @@ -93,54 +95,54 @@ bool LocalAssetBrowser::mSculptUpdated; LocalBitmap::LocalBitmap(std::string fullpath) { - this->valid = false; + valid = false; if ( gDirUtilp->fileExists(fullpath) ) { /* taking care of basic properties */ - this->id.generate(); - this->filename = fullpath; - this->linkstatus = LINK_OFF; - this->keep_updating = false; - this->shortname = gDirUtilp->getBaseFileName(this->filename, true); - this->bitmap_type = TYPE_TEXTURE; - this->sculpt_dirty = false; - this->volume_dirty = false; - this->valid = false; + id.generate(); + filename = fullpath; + keep_updating = gSavedSettings.getBOOL("LocalBitmapUpdate"); + linkstatus = keep_updating ? LINK_ON : LINK_OFF; + shortname = gDirUtilp->getBaseFileName(filename, true); + bitmap_type = TYPE_TEXTURE; + sculpt_dirty = false; + volume_dirty = false; + valid = false; /* taking care of extension type now to avoid switch madness */ - std::string temp_exten = gDirUtilp->getExtension(this->filename); + std::string temp_exten = gDirUtilp->getExtension(filename); - if (temp_exten == "bmp") { this->extension = IMG_EXTEN_BMP; } - else if (temp_exten == "tga") { this->extension = IMG_EXTEN_TGA; } - else if (temp_exten == "jpg" || temp_exten == "jpeg") { this->extension = IMG_EXTEN_JPG; } - else if (temp_exten == "png") { this->extension = IMG_EXTEN_PNG; } - else { return; } // no valid extension. + if (temp_exten == "bmp") extension = IMG_EXTEN_BMP; + else if (temp_exten == "tga") extension = IMG_EXTEN_TGA; + else if (temp_exten == "jpg" || temp_exten == "jpeg") extension = IMG_EXTEN_JPG; + else if (temp_exten == "png") extension = IMG_EXTEN_PNG; + else return; // no valid extension. /* getting file's last modified */ llstat temp_stat; - LLFile::stat(this->filename, &temp_stat); + LLFile::stat(filename, &temp_stat); std::time_t time = temp_stat.st_mtime; - this->last_modified = asctime( localtime(&time) ); + last_modified = asctime( localtime(&time) ); /* checking if the bitmap is valid && decoding if it is */ - LLImageRaw* raw_image = new LLImageRaw(); - if ( this->decodeSelf(raw_image) ) + LLPointer raw_image = new LLImageRaw; + if (decodeSelf(raw_image)) { /* creating a shell LLViewerTexture and fusing raw image into it */ - LLViewerFetchedTexture* viewer_image = new LLViewerFetchedTexture( "file://"+this->filename, this->id, LOCAL_USE_MIPMAPS ); + LLViewerFetchedTexture* viewer_image = new LLViewerFetchedTexture( "file://"+filename, id, LOCAL_USE_MIPMAPS ); viewer_image->createGLTexture( LOCAL_DISCARD_LEVEL, raw_image ); viewer_image->setCachedRawImage(-1,raw_image); /* making damn sure gTextureList will not delete it prematurely */ - viewer_image->ref(); + viewer_image->ref(); /* finalizing by adding LLViewerTexture instance into gTextureList */ gTextureList.addImage(viewer_image); /* filename is valid, bitmap is decoded and valid, i can haz liftoff! */ - this->valid = true; + valid = true; } } } @@ -152,60 +154,64 @@ LocalBitmap::~LocalBitmap() /* [maintenence functions] */ void LocalBitmap::updateSelf() { - if ( this->linkstatus == LINK_ON || this->linkstatus == LINK_UPDATING ) + if (linkstatus == LINK_ON || linkstatus == LINK_UPDATING) { /* making sure file still exists */ - if ( !gDirUtilp->fileExists(this->filename) ) { this->linkstatus = LINK_BROKEN; return; } + if (!gDirUtilp->fileExists(filename)) + { + linkstatus = LINK_BROKEN; + return; + } /* exists, let's check if it's lastmod has changed */ llstat temp_stat; - LLFile::stat(this->filename, &temp_stat); + LLFile::stat(filename, &temp_stat); std::time_t temp_time = temp_stat.st_mtime; LLSD new_last_modified = asctime( localtime(&temp_time) ); - if ( this->last_modified.asString() == new_last_modified.asString() ) { return; } + if (last_modified.asString() == new_last_modified.asString()) return; /* here we update the image */ - LLImageRaw* new_imgraw = new LLImageRaw(); - - if ( !decodeSelf(new_imgraw) ) { this->linkstatus = LINK_UPDATING; return; } - else { this->linkstatus = LINK_ON; } - - LLViewerFetchedTexture* image = gTextureList.findImage(this->id); - - if (!image->forSculpt()) - { image->createGLTexture( LOCAL_DISCARD_LEVEL, new_imgraw ); } + LLPointer new_imgraw = new LLImageRaw; + if (!decodeSelf(new_imgraw)) + { + linkstatus = LINK_UPDATING; + return; + } else - { image->setCachedRawImage(-1,new_imgraw); } + { + linkstatus = LINK_ON; + } + + LLViewerFetchedTexture* image = gTextureList.findImage(id); + if (!image->forSculpt()) + image->createGLTexture(LOCAL_DISCARD_LEVEL, new_imgraw); + else + image->setCachedRawImage(-1,new_imgraw); /* finalizing by updating lastmod to current */ - this->last_modified = new_last_modified; + last_modified = new_last_modified; /* setting unit property to reflect that it has been changed */ - switch (this->bitmap_type) + switch (bitmap_type) { - case TYPE_TEXTURE: - { break; } - case TYPE_SCULPT: - { - /* sets a bool to run through all visible sculpts in one go, and update the ones necessary. */ - this->sculpt_dirty = true; - this->volume_dirty = true; - gLocalBrowser->setSculptUpdated( true ); - break; - } - + { + /* sets a bool to run through all visible sculpts in one go, and update the ones necessary. */ + sculpt_dirty = true; + volume_dirty = true; + gLocalBrowser->setSculptUpdated( true ); + break; + } case TYPE_LAYER: - { - /* sets a bool to rebake layers after the iteration is done with */ - gLocalBrowser->setLayerUpdated( true ); - break; - } - + { + /* sets a bool to rebake layers after the iteration is done with */ + gLocalBrowser->setLayerUpdated( true ); + break; + } + case TYPE_TEXTURE: default: - { break; } - + break; } } @@ -213,51 +219,47 @@ void LocalBitmap::updateSelf() bool LocalBitmap::decodeSelf(LLImageRaw* rawimg) { - switch (this->extension) + switch (extension) { case IMG_EXTEN_BMP: - { - LLPointer bmp_image = new LLImageBMP; - if ( !bmp_image->load(filename) ) { break; } - if ( !bmp_image->decode(rawimg, 0.0f) ) { break; } - - rawimg->biasedScaleToPowerOfTwo( LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT ); - return true; - } + { + LLPointer bmp_image = new LLImageBMP; + if (!bmp_image->load(filename)) break; + if (!bmp_image->decode(rawimg, 0.0f)) break; + rawimg->biasedScaleToPowerOfTwo(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); + return true; + } case IMG_EXTEN_TGA: - { - LLPointer tga_image = new LLImageTGA; - if ( !tga_image->load(filename) ) { break; } - if ( !tga_image->decode(rawimg) ) { break; } - - if( ( tga_image->getComponents() != 3) && - ( tga_image->getComponents() != 4) ) { break; } - - rawimg->biasedScaleToPowerOfTwo( LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT ); - return true; - } + { + LLPointer tga_image = new LLImageTGA; + if (!tga_image->load(filename)) break; + if (!tga_image->decode(rawimg)) break; + if (( tga_image->getComponents() != 3) && + ( tga_image->getComponents() != 4) ) + break; + rawimg->biasedScaleToPowerOfTwo(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); + return true; + } case IMG_EXTEN_JPG: - { - LLPointer jpeg_image = new LLImageJPEG; - if ( !jpeg_image->load(filename) ) { break; } - if ( !jpeg_image->decode(rawimg, 0.0f) ) { break; } - - rawimg->biasedScaleToPowerOfTwo( LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT ); - return true; - } + { + LLPointer jpeg_image = new LLImageJPEG; + if (!jpeg_image->load(filename)) break; + if (!jpeg_image->decode(rawimg, 0.0f)) break; + rawimg->biasedScaleToPowerOfTwo(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); + return true; + } case IMG_EXTEN_PNG: - { - LLPointer png_image = new LLImagePNG; - if ( !png_image->load(filename) ) { break; } - if ( !png_image->decode(rawimg, 0.0f) ) { break; } - - rawimg->biasedScaleToPowerOfTwo( LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT ); - return true; - } + { + LLPointer png_image = new LLImagePNG; + if ( !png_image->load(filename) ) break; + if ( !png_image->decode(rawimg, 0.0f) ) break; + rawimg->biasedScaleToPowerOfTwo(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); + return true; + } default: break; } @@ -266,54 +268,55 @@ bool LocalBitmap::decodeSelf(LLImageRaw* rawimg) void LocalBitmap::setUpdateBool() { - if ( this->linkstatus != LINK_BROKEN ) + if (linkstatus != LINK_BROKEN) { - if ( !this->keep_updating ) + if (!keep_updating) { - this->linkstatus = LINK_ON; - this->keep_updating = true; + linkstatus = LINK_ON; + keep_updating = true; } else { - this->linkstatus = LINK_OFF; - this->keep_updating = false; + linkstatus = LINK_OFF; + keep_updating = false; } } else { - this->keep_updating = false; + keep_updating = false; } + gSavedSettings.setBOOL("LocalBitmapUpdate", keep_updating); } void LocalBitmap::setType( S32 type ) { - this->bitmap_type = type; + bitmap_type = type; } /* [information query functions] */ std::string LocalBitmap::getShortName() { - return this->shortname; + return shortname; } std::string LocalBitmap::getFileName() { - return this->filename; + return filename; } LLUUID LocalBitmap::getID() { - return this->id; + return id; } LLSD LocalBitmap::getLastModified() { - return this->last_modified; + return last_modified; } std::string LocalBitmap::getLinkStatus() { - switch(this->linkstatus) + switch(linkstatus) { case LINK_ON: return "On"; @@ -334,22 +337,17 @@ std::string LocalBitmap::getLinkStatus() bool LocalBitmap::getUpdateBool() { - return this->keep_updating; + return keep_updating; } bool LocalBitmap::getIfValidBool() { - return this->valid; -} - -LocalBitmap* LocalBitmap::getThis() -{ - return this; + return valid; } S32 LocalBitmap::getType() { - return this->bitmap_type; + return bitmap_type; } std::vector LocalBitmap::getFaceUsesThis(LLDrawable* drawable) @@ -360,8 +358,8 @@ std::vector LocalBitmap::getFaceUsesThis(LLDrawable* drawable) { LLFace* newface = drawable->getFace(face_iter); - if ( this->id == newface->getTexture()->getID() ) - { matching_faces.push_back(newface); } + if (id == newface->getTexture()->getID()) + matching_faces.push_back(newface); } return matching_faces; @@ -389,10 +387,10 @@ std::vector LocalBitmap::getUsingObjects(bool seek_by_type, boo if ( obj && obj->mDrawable ) { /* looking for textures */ - if ( seek_textures || ( seek_by_type && this->bitmap_type == TYPE_TEXTURE ) ) + if (seek_textures || (seek_by_type && bitmap_type == TYPE_TEXTURE)) { - std::vector affected_faces = this->getFaceUsesThis( obj->mDrawable ); - if ( !affected_faces.empty() ) + std::vector affected_faces = getFaceUsesThis(obj->mDrawable); + if (!affected_faces.empty()) { shell.face_list = affected_faces; obj_relevant = true; @@ -400,22 +398,18 @@ std::vector LocalBitmap::getUsingObjects(bool seek_by_type, boo } /* looking for sculptmaps */ - if ( ( seek_sculptmaps || ( seek_by_type && this->bitmap_type == TYPE_SCULPT ) ) - && obj->isSculpted() && obj->getVolume() - && this->id == obj->getVolume()->getParams().getSculptID() - ) + if ((seek_sculptmaps || (seek_by_type && bitmap_type == TYPE_SCULPT)) + && obj->isSculpted() && obj->getVolume() + && id == obj->getVolume()->getParams().getSculptID()) { shell.local_sculptmap = true; obj_relevant = true; } } - if (obj_relevant) - { affected_vector.push_back(shell); } + if (obj_relevant) affected_vector.push_back(shell); } - - return affected_vector; } @@ -423,15 +417,15 @@ void LocalBitmap::getDebugInfo() { /* debug function: dumps everything human readable into llinfos */ llinfos << "===[local bitmap debug]===" << "\n" - << "path: " << this->filename << "\n" - << "name: " << this->shortname << "\n" - << "extension: " << this->extension << "\n" - << "uuid: " << this->id << "\n" - << "last modified: " << this->last_modified << "\n" - << "link status: " << this->getLinkStatus() << "\n" - << "keep updated: " << this->keep_updating << "\n" - << "type: " << this->bitmap_type << "\n" - << "is valid: " << this->valid << "\n" + << "path: " << filename << "\n" + << "name: " << shortname << "\n" + << "extension: " << extension << "\n" + << "uuid: " << id << "\n" + << "last modified: " << last_modified << "\n" + << "link status: " << getLinkStatus() << "\n" + << "keep updated: " << keep_updating << "\n" + << "type: " << bitmap_type << "\n" + << "is valid: " << valid << "\n" << "==========================" << llendl; } @@ -447,8 +441,8 @@ void LocalBitmap::getDebugInfo() LocalAssetBrowser::LocalAssetBrowser() { - this->mLayerUpdated = false; - this->mSculptUpdated = false; + mLayerUpdated = false; + mSculptUpdated = false; } LocalAssetBrowser::~LocalAssetBrowser() @@ -472,17 +466,15 @@ void LocalAssetBrowser::AddBitmap_continued(AIFilePicker* filepicker) std::vector const& filenames(filepicker->getFilenames()); for(std::vector::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { - LocalBitmap* unit = new LocalBitmap(*filename); - - if ( unit->getIfValidBool() ) + LocalBitmap unit(*filename); + if (unit.getIfValidBool()) { - loaded_bitmaps.push_back( unit ); + loaded_bitmaps.push_back(unit); change_happened = true; } } - if ( change_happened ) - { onChangeHappened(); } + if (change_happened) onChangeHappened(); } void LocalAssetBrowser::DelBitmap( std::vector delete_vector, S32 column ) @@ -498,34 +490,26 @@ void LocalAssetBrowser::DelBitmap( std::vector delete_vector, for (local_list_iter iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end();) { - LocalBitmap* unit = (*iter)->getThis(); - - if ( unit->getID() == id ) + if ((*iter).getID() == id) { LLViewerFetchedTexture* image = gTextureList.findImage(id); gTextureList.deleteImage( image ); image->unref(); - iter = loaded_bitmaps.erase(iter); - delete unit; - unit = NULL; - change_happened = true; } else - { iter++; } + ++iter; } } } - if ( change_happened ) - { onChangeHappened(); } + if (change_happened) onChangeHappened(); } void LocalAssetBrowser::onUpdateBool(LLUUID id) { - LocalBitmap* unit = GetBitmapUnit( id ); - if ( unit ) + if (LocalBitmap* unit = GetBitmapUnit(id)) { unit->setUpdateBool(); PingTimer(); @@ -534,32 +518,22 @@ void LocalAssetBrowser::onUpdateBool(LLUUID id) void LocalAssetBrowser::onSetType(LLUUID id, S32 type) { - LocalBitmap* unit = GetBitmapUnit( id ); - if ( unit ) - { unit->setType(type); } + if (LocalBitmap* unit = GetBitmapUnit(id)) unit->setType(type); } LocalBitmap* LocalAssetBrowser::GetBitmapUnit(LLUUID id) { - local_list_iter iter = loaded_bitmaps.begin(); - for (; iter != loaded_bitmaps.end(); iter++) - { - if ( (*iter)->getID() == id ) - { - return (*iter)->getThis(); - } - } - + for (local_list_iter iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end(); ++iter) + if ((*iter).getID() == id) + return &(*iter); return NULL; } bool LocalAssetBrowser::IsDoingUpdates() { - local_list_iter iter = loaded_bitmaps.begin(); - for (; iter != loaded_bitmaps.end(); iter++) + for (local_list_iter iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end(); iter++) { - if ( (*iter)->getUpdateBool() ) - { return true; } /* if at least one unit in the list needs updates - we need a timer. */ + if ((*iter).getUpdateBool()) return true; /* if at least one unit in the list needs updates - we need a timer. */ } return false; @@ -572,7 +546,7 @@ bool LocalAssetBrowser::IsDoingUpdates() void LocalAssetBrowser::onChangeHappened() { /* own floater update */ - FloaterLocalAssetBrowser::UpdateBitmapScrollList(); + if (sLFInstance) sLFInstance->UpdateBitmapScrollList(); /* texturepicker related */ const LLView::child_list_t* child_list = gFloaterView->getChildList(); @@ -599,44 +573,37 @@ void LocalAssetBrowser::onChangeHappened() void LocalAssetBrowser::PingTimer() { - if ( !loaded_bitmaps.empty() && IsDoingUpdates() ) + if (!loaded_bitmaps.empty() && IsDoingUpdates()) { - if (!gLocalBrowserTimer) - { gLocalBrowserTimer = new LocalAssetBrowserTimer(); } - - if ( !gLocalBrowserTimer->isRunning() ) - { gLocalBrowserTimer->start(); } + if (!gLocalBrowserTimer) + gLocalBrowserTimer = new LocalAssetBrowserTimer(); + if (!gLocalBrowserTimer->isRunning()) + gLocalBrowserTimer->start(); } - - else + else if (gLocalBrowserTimer && gLocalBrowserTimer->isRunning()) { - if (gLocalBrowserTimer) - { - if ( gLocalBrowserTimer->isRunning() ) - { gLocalBrowserTimer->stop(); } - } + gLocalBrowserTimer->stop(); } } /* This function refills the texture picker floater's scrolllist with the updated contents of bitmaplist */ void LocalAssetBrowser::UpdateTextureCtrlList(LLScrollListCtrl* ctrl) { - if ( ctrl ) // checking again in case called externally for some silly reason. + if (ctrl) // checking again in case called externally for some silly reason. { ctrl->clearRows(); if ( !loaded_bitmaps.empty() ) { - local_list_iter iter = loaded_bitmaps.begin(); - for ( ; iter != loaded_bitmaps.end(); iter++ ) + for (local_list_iter iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end(); ++iter) { LLSD element; element["columns"][0]["column"] = "unit_name"; element["columns"][0]["type"] = "text"; - element["columns"][0]["value"] = (*iter)->shortname; + element["columns"][0]["value"] = (*iter).shortname; element["columns"][1]["column"] = "unit_id_HIDDEN"; element["columns"][1]["type"] = "text"; - element["columns"][1]["value"] = (*iter)->id; + element["columns"][1]["value"] = (*iter).id; ctrl->addElement(element); } @@ -644,73 +611,58 @@ void LocalAssetBrowser::UpdateTextureCtrlList(LLScrollListCtrl* ctrl) } } -void LocalAssetBrowser::PerformTimedActions(void) +void LocalAssetBrowser::PerformTimedActions() { // perform checking if updates are needed && update if so. - local_list_iter iter; - for (iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end(); iter++) - { (*iter)->updateSelf(); } - - // one or more sculpts have been updated, refreshing them. - if ( mSculptUpdated ) + for (local_list_iter iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end(); ++iter) { - LocalAssetBrowser::local_list_iter iter; - for(iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end(); iter++) + (*iter).updateSelf(); + // one or more sculpts have been updated, refreshing them. + if (mSculptUpdated && (*iter).sculpt_dirty) { - if ( (*iter)->sculpt_dirty ) - { - PerformSculptUpdates( (*iter)->getThis() ); - (*iter)->sculpt_dirty = false; - } + PerformSculptUpdates(*iter); + (*iter).sculpt_dirty = false; } - mSculptUpdated = false; } + mSculptUpdated = false; // one of the layer bitmaps has been updated, we need to rebake. - if ( mLayerUpdated ) + if (mLayerUpdated) { - if (isAgentAvatarValid()) - { + if (isAgentAvatarValid()) gAgentAvatarp->forceBakeAllTextures(SLAM_FOR_DEBUG); - } - mLayerUpdated = false; } } -void LocalAssetBrowser::PerformSculptUpdates(LocalBitmap* unit) +void LocalAssetBrowser::PerformSculptUpdates(LocalBitmap& unit) { - /* looking for sculptmap using objects only */ - std::vector object_list = unit->getUsingObjects(false, false, true); + std::vector object_list = unit.getUsingObjects(false, false, true); if (object_list.empty()) { return; } for( std::vector::iterator iter = object_list.begin(); iter != object_list.end(); iter++ ) { affected_object aobj = *iter; - if ( aobj.object ) + if (aobj.object) { - if ( !aobj.local_sculptmap ) { continue; } // should never get here. only in case of misuse. - + if (!aobj.local_sculptmap) continue; // should never get here. only in case of misuse. // update code [begin] - if ( unit->volume_dirty ) + if (unit.volume_dirty) { - LLImageRaw* rawimage = gTextureList.findImage( unit->getID() )->getCachedRawImage(); + LLImageRaw* rawimage = gTextureList.findImage(unit.getID())->getCachedRawImage(); - aobj.object->getVolume()->sculpt(rawimage->getWidth(), rawimage->getHeight(), - rawimage->getComponents(), rawimage->getData(), 0); - unit->volume_dirty = false; + aobj.object->getVolume()->sculpt(rawimage->getWidth(), rawimage->getHeight(), rawimage->getComponents(), rawimage->getData(), 0); + unit.volume_dirty = false; } - // tell affected drawable it's got updated - aobj.object->mDrawable->getVOVolume()->setSculptChanged( true ); - aobj.object->mDrawable->getVOVolume()->markForUpdate( true ); + // tell affected drawable it's got updated + aobj.object->mDrawable->getVOVolume()->setSculptChanged(true); + aobj.object->mDrawable->getVOVolume()->markForUpdate(true); // update code [end] } - } - } /*==================================================*/ @@ -722,36 +674,6 @@ void LocalAssetBrowser::PerformSculptUpdates(LocalBitmap* unit) Destroyed when the floater is closed. */ - -// Floater Globals -FloaterLocalAssetBrowser* FloaterLocalAssetBrowser::sLFInstance = NULL; - -// widgets: - LLButton* mAddBtn; - LLButton* mDelBtn; - LLButton* mMoreBtn; - LLButton* mLessBtn; - LLButton* mUploadBtn; - - - LLScrollListCtrl* mBitmapList; - LLTextureCtrl* mTextureView; - LLCheckBoxCtrl* mUpdateChkBox; - - LLLineEditor* mPathTxt; - LLLineEditor* mUUIDTxt; - LLLineEditor* mNameTxt; - - LLTextBox* mLinkTxt; - LLTextBox* mTimeTxt; - LLComboBox* mTypeComboBox; - - LLTextBox* mCaptionPathTxt; - LLTextBox* mCaptionUUIDTxt; - LLTextBox* mCaptionLinkTxt; - LLTextBox* mCaptionNameTxt; - LLTextBox* mCaptionTimeTxt; - FloaterLocalAssetBrowser::FloaterLocalAssetBrowser() : LLFloater(std::string("local_bitmap_browser_floater")) { @@ -791,12 +713,15 @@ FloaterLocalAssetBrowser::FloaterLocalAssetBrowser() mDelBtn->setEnabled( false ); mUploadBtn->setEnabled( false ); + // Initialize visibility + FloaterResize(true); + // setting button callbacks: - mAddBtn->setClickedCallback( onClickAdd, this); - mDelBtn->setClickedCallback( onClickDel, this); - mMoreBtn->setClickedCallback( onClickMore, this); - mLessBtn->setClickedCallback( onClickLess, this); - mUploadBtn->setClickedCallback( onClickUpload, this); + mAddBtn->setClickedCallback(boost::bind(&FloaterLocalAssetBrowser::onClickAdd, this)); + mDelBtn->setClickedCallback(boost::bind(&FloaterLocalAssetBrowser::onClickDel, this)); + mMoreBtn->setClickedCallback(boost::bind(&FloaterLocalAssetBrowser::FloaterResize, this, true)); + mLessBtn->setClickedCallback(boost::bind(&FloaterLocalAssetBrowser::FloaterResize, this, false)); + mUploadBtn->setClickedCallback(boost::bind(&FloaterLocalAssetBrowser::onClickUpload, this)); // combo callback mTypeComboBox->setCommitCallback(boost::bind(&FloaterLocalAssetBrowser::onCommitTypeCombo,this)); @@ -806,48 +731,35 @@ FloaterLocalAssetBrowser::FloaterLocalAssetBrowser() // checkbox callbacks mUpdateChkBox->setCommitCallback(boost::bind(&FloaterLocalAssetBrowser::onClickUpdateChkbox,this)); - } void FloaterLocalAssetBrowser::show(void*) { - if (!sLFInstance) - sLFInstance = new FloaterLocalAssetBrowser(); - sLFInstance->open(); + if (!sLFInstance) + sLFInstance = new FloaterLocalAssetBrowser(); + sLFInstance->open(); sLFInstance->UpdateBitmapScrollList(); } FloaterLocalAssetBrowser::~FloaterLocalAssetBrowser() { - sLFInstance=NULL; + sLFInstance = NULL; } -void FloaterLocalAssetBrowser::onClickAdd(void* userdata) +void FloaterLocalAssetBrowser::onClickAdd() { gLocalBrowser->AddBitmap(); } -void FloaterLocalAssetBrowser::onClickDel(void* userdata) +void FloaterLocalAssetBrowser::onClickDel() { - gLocalBrowser->DelBitmap( sLFInstance->mBitmapList->getAllSelected() ); + gLocalBrowser->DelBitmap(mBitmapList->getAllSelected()); } -/* what stopped me from using a single button and simply changing it's label - is the fact that i'd need to hardcode the button labels here, and that is griff. */ -void FloaterLocalAssetBrowser::onClickMore(void* userdata) -{ - FloaterResize(true); -} - -void FloaterLocalAssetBrowser::onClickLess(void* userdata) -{ - FloaterResize(false); -} - -void FloaterLocalAssetBrowser::onClickUpload(void* userdata) +void FloaterLocalAssetBrowser::onClickUpload() { std::string filename = gLocalBrowser->GetBitmapUnit( - (LLUUID)sLFInstance->mBitmapList->getSelectedItemLabel(BITMAPLIST_COL_ID) )->getFileName(); + (LLUUID)mBitmapList->getSelectedItemLabel(BITMAPLIST_COL_ID) )->getFileName(); if ( !filename.empty() ) { @@ -879,71 +791,59 @@ void FloaterLocalAssetBrowser::onCommitTypeCombo() { std::string temp_str = mBitmapList->getSelectedItemLabel(BITMAPLIST_COL_ID); - if ( !temp_str.empty() ) + if (!temp_str.empty()) { - S32 selection = sLFInstance->mTypeComboBox->getCurrentIndex(); - gLocalBrowser->onSetType( (LLUUID)temp_str, selection ); + S32 selection = mTypeComboBox->getCurrentIndex(); + gLocalBrowser->onSetType((LLUUID)temp_str, selection); } } void FloaterLocalAssetBrowser::FloaterResize(bool expand) { - sLFInstance->mMoreBtn->setVisible(!expand); - sLFInstance->mLessBtn->setVisible(expand); - sLFInstance->mTextureView->setVisible(expand); - sLFInstance->mUpdateChkBox->setVisible(expand); - sLFInstance->mCaptionPathTxt->setVisible(expand); - sLFInstance->mCaptionUUIDTxt->setVisible(expand); - sLFInstance->mCaptionLinkTxt->setVisible(expand); - sLFInstance->mCaptionNameTxt->setVisible(expand); - sLFInstance->mCaptionTimeTxt->setVisible(expand); - sLFInstance->mTypeComboBox->setVisible(expand); + mMoreBtn->setVisible(!expand); + mLessBtn->setVisible(expand); + mTextureView->setVisible(expand); + mUpdateChkBox->setVisible(expand); + mCaptionPathTxt->setVisible(expand); + mCaptionUUIDTxt->setVisible(expand); + mCaptionLinkTxt->setVisible(expand); + mCaptionNameTxt->setVisible(expand); + mCaptionTimeTxt->setVisible(expand); + mTypeComboBox->setVisible(expand); - sLFInstance->mTimeTxt->setVisible(expand); - sLFInstance->mPathTxt->setVisible(expand); - sLFInstance->mUUIDTxt->setVisible(expand); - sLFInstance->mLinkTxt->setVisible(expand); - sLFInstance->mNameTxt->setVisible(expand); - - if(expand) - { - sLFInstance->reshape(LF_FLOATER_EXPAND_WIDTH, LF_FLOATER_HEIGHT); - sLFInstance->setResizeLimits(LF_FLOATER_EXPAND_WIDTH, LF_FLOATER_HEIGHT); - sLFInstance->UpdateRightSide(); - } - else - { - sLFInstance->reshape(LF_FLOATER_CONTRACT_WIDTH, LF_FLOATER_HEIGHT); - sLFInstance->setResizeLimits(LF_FLOATER_CONTRACT_WIDTH, LF_FLOATER_HEIGHT); - } + mTimeTxt->setVisible(expand); + mPathTxt->setVisible(expand); + mUUIDTxt->setVisible(expand); + mLinkTxt->setVisible(expand); + mNameTxt->setVisible(expand); + reshape(expand ? LF_FLOATER_EXPAND_WIDTH : LF_FLOATER_CONTRACT_WIDTH, LF_FLOATER_HEIGHT); + setResizeLimits(expand ? LF_FLOATER_EXPAND_WIDTH : LF_FLOATER_CONTRACT_WIDTH, LF_FLOATER_HEIGHT); + if (expand) UpdateRightSide(); } void FloaterLocalAssetBrowser::UpdateBitmapScrollList() { - if ( !sLFInstance ) { return; } - - sLFInstance->mBitmapList->clearRows(); + mBitmapList->clearRows(); if (!gLocalBrowser->loaded_bitmaps.empty()) { - LocalAssetBrowser::local_list_iter iter; for(iter = gLocalBrowser->loaded_bitmaps.begin(); iter != gLocalBrowser->loaded_bitmaps.end(); iter++) { LLSD element; element["columns"][BITMAPLIST_COL_NAME]["column"] = "bitmap_name"; element["columns"][BITMAPLIST_COL_NAME]["type"] = "text"; - element["columns"][BITMAPLIST_COL_NAME]["value"] = (*iter)->getShortName(); + element["columns"][BITMAPLIST_COL_NAME]["value"] = (*iter).getShortName(); element["columns"][BITMAPLIST_COL_ID]["column"] = "bitmap_uuid"; element["columns"][BITMAPLIST_COL_ID]["type"] = "text"; - element["columns"][BITMAPLIST_COL_ID]["value"] = (*iter)->getID(); + element["columns"][BITMAPLIST_COL_ID]["value"] = (*iter).getID(); - sLFInstance->mBitmapList->addElement(element); + mBitmapList->addElement(element); } } - sLFInstance->onChooseBitmapList(); + onChooseBitmapList(); } void FloaterLocalAssetBrowser::UpdateRightSide() @@ -951,47 +851,45 @@ void FloaterLocalAssetBrowser::UpdateRightSide() /* Since i'm not keeping a bool on if the floater is expanded or not, i'll just check if one of the widgets that shows when the floater is expanded is visible. - Also obviously before updating - checking if something IS actually selected :o */ + if (!mTextureView->getVisible()) return; - if ( !sLFInstance->mTextureView->getVisible() ) { return; } - - if ( !sLFInstance->mBitmapList->getAllSelected().empty() ) - { - LocalBitmap* unit = gLocalBrowser->GetBitmapUnit( LLUUID(sLFInstance->mBitmapList->getSelectedItemLabel(BITMAPLIST_COL_ID)) ); + if (!mBitmapList->getAllSelected().empty()) + { + LocalBitmap* unit = gLocalBrowser->GetBitmapUnit( LLUUID(mBitmapList->getSelectedItemLabel(BITMAPLIST_COL_ID)) ); if ( unit ) { - sLFInstance->mTextureView->setImageAssetID( unit->getID() ); - sLFInstance->mUpdateChkBox->set( unit->getUpdateBool() ); - sLFInstance->mPathTxt->setText( unit->getFileName() ); - sLFInstance->mUUIDTxt->setText( unit->getID().asString() ); - sLFInstance->mNameTxt->setText( unit->getShortName() ); - sLFInstance->mTimeTxt->setText( unit->getLastModified().asString() ); - sLFInstance->mLinkTxt->setText( unit->getLinkStatus() ); - sLFInstance->mTypeComboBox->selectNthItem( unit->getType() ); + mTextureView->setImageAssetID(unit->getID()); + mUpdateChkBox->set(unit->getUpdateBool()); + mPathTxt->setText(unit->getFileName()); + mUUIDTxt->setText(unit->getID().asString()); + mNameTxt->setText(unit->getShortName()); + mTimeTxt->setText(unit->getLastModified().asString()); + mLinkTxt->setText(unit->getLinkStatus()); + mTypeComboBox->selectNthItem(unit->getType()); - sLFInstance->mTextureView->setEnabled(true); - sLFInstance->mUpdateChkBox->setEnabled(true); - sLFInstance->mTypeComboBox->setEnabled(true); + mTextureView->setEnabled(true); + mUpdateChkBox->setEnabled(true); + mTypeComboBox->setEnabled(true); } } else { - sLFInstance->mTextureView->setImageAssetID( NO_IMAGE ); - sLFInstance->mTextureView->setEnabled( false ); - sLFInstance->mUpdateChkBox->set( false ); - sLFInstance->mUpdateChkBox->setEnabled( false ); + mTextureView->setImageAssetID(NO_IMAGE); + mTextureView->setEnabled(false); + mUpdateChkBox->set(false); + mUpdateChkBox->setEnabled(false); - sLFInstance->mTypeComboBox->selectFirstItem(); - sLFInstance->mTypeComboBox->setEnabled( false ); - - sLFInstance->mPathTxt->setText( LLStringExplicit("None") ); - sLFInstance->mUUIDTxt->setText( LLStringExplicit("None") ); - sLFInstance->mNameTxt->setText( LLStringExplicit("None") ); - sLFInstance->mLinkTxt->setText( LLStringExplicit("None") ); - sLFInstance->mTimeTxt->setText( LLStringExplicit("None") ); + mTypeComboBox->selectFirstItem(); + mTypeComboBox->setEnabled(false); + + mPathTxt->setText(LLStringExplicit("None")); + mUUIDTxt->setText(LLStringExplicit("None")); + mNameTxt->setText(LLStringExplicit("None")); + mLinkTxt->setText(LLStringExplicit("None")); + mTimeTxt->setText(LLStringExplicit("None")); } } diff --git a/indra/newview/floaterlocalassetbrowse.h b/indra/newview/floaterlocalassetbrowse.h index b4cbc149f..dd7e618ea 100644 --- a/indra/newview/floaterlocalassetbrowse.h +++ b/indra/newview/floaterlocalassetbrowse.h @@ -98,7 +98,7 @@ class LocalBitmap { public: LocalBitmap(std::string filename); - virtual ~LocalBitmap(void); + virtual ~LocalBitmap(); friend class LocalAssetBrowser; public: /* [enums, typedefs, etc] */ @@ -127,23 +127,22 @@ class LocalBitmap }; public: /* [information query functions] */ - std::string getShortName(void); - std::string getFileName(void); - LLUUID getID(void); - LLSD getLastModified(void); - std::string getLinkStatus(void); - bool getUpdateBool(void); + std::string getShortName(); + std::string getFileName(); + LLUUID getID(); + LLSD getLastModified(); + std::string getLinkStatus(); + bool getUpdateBool(); void setType( S32 ); - bool getIfValidBool(void); - S32 getType(void); - void getDebugInfo(void); + bool getIfValidBool(); + S32 getType(); + void getDebugInfo(); private: /* [maintenence functions] */ - void updateSelf(void); + void updateSelf(); bool decodeSelf(LLImageRaw* rawimg); - void setUpdateBool(void); + void setUpdateBool(); - LocalBitmap* getThis(void); std::vector getFaceUsesThis(LLDrawable*); std::vector getUsingObjects(bool seek_by_type = true, bool seek_textures = false, bool seek_sculptmaps = false); @@ -184,7 +183,7 @@ class LocalAssetBrowser static void UpdateTextureCtrlList(LLScrollListCtrl*); static void setLayerUpdated(bool toggle) { mLayerUpdated = toggle; } static void setSculptUpdated(bool toggle) { mSculptUpdated = toggle; } - static void AddBitmap(void); + static void AddBitmap(); static void AddBitmap_continued(AIFilePicker* filepicker); static void DelBitmap( std::vector, S32 column = BITMAPLIST_COL_ID ); @@ -194,18 +193,18 @@ class LocalAssetBrowser the latter - each time the button's pressed. */ private: - static void onChangeHappened(void); + static void onChangeHappened(); static void onUpdateBool(LLUUID); static void onSetType(LLUUID, S32); static LocalBitmap* GetBitmapUnit(LLUUID); - static bool IsDoingUpdates(void); - static void PingTimer(void); - static void PerformTimedActions(void); - static void PerformSculptUpdates(LocalBitmap*); + static bool IsDoingUpdates(); + static void PingTimer(); + static void PerformTimedActions(); + static void PerformSculptUpdates(LocalBitmap&); protected: - static std::vector loaded_bitmaps; - typedef std::vector::iterator local_list_iter; + static std::vector loaded_bitmaps; + typedef std::vector::iterator local_list_iter; static bool mLayerUpdated; static bool mSculptUpdated; }; @@ -225,17 +224,13 @@ public: FloaterLocalAssetBrowser(); virtual ~FloaterLocalAssetBrowser(); static void show(void*); - - private: /* Widget related callbacks */ - // Button callback declarations - static void onClickAdd(void* userdata); - static void onClickDel(void* userdata); - static void onClickMore(void* userdata); - static void onClickLess(void* userdata); - static void onClickUpload(void* userdata); + // Button callback declarations + void onClickAdd(); + void onClickDel(); + void onClickUpload(); // ScrollList callback declarations void onChooseBitmapList(); @@ -271,17 +266,12 @@ private: LLTextBox* mCaptionNameTxt; LLTextBox* mCaptionTimeTxt; - /* static pointer to self, wai? oh well. */ - static FloaterLocalAssetBrowser* sLFInstance; - // non-widget functions - static void FloaterResize(bool expand); - static void UpdateRightSide(void); + void FloaterResize(bool expand); + void UpdateRightSide(); public: - static void UpdateBitmapScrollList(void); - - + void UpdateBitmapScrollList(); }; /*==================================================*/ From 5988f6cf88056c9c14a30efd193632e0767a130a Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 27 Mar 2014 21:27:40 -0500 Subject: [PATCH 075/115] Updated rigged mesh face batch/pool handling. Fixed issue with fullbright and glow occlusion. RenderTransparentWater toggling should work more gracefully. Fixed some bugs in general drawpool classification for faces. Bump pool was superceding more than it should have. --- indra/newview/lldrawpoolavatar.cpp | 4 +- indra/newview/lldrawpoolsimple.cpp | 14 +++- indra/newview/llface.cpp | 7 +- indra/newview/llviewercontrol.cpp | 6 ++ indra/newview/llvovolume.cpp | 129 ++++++++++++++++++++++++----- indra/newview/llvowater.cpp | 2 +- indra/newview/pipeline.cpp | 44 +++++----- 7 files changed, 157 insertions(+), 49 deletions(-) diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index eba3d2606..42dcd4547 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -1951,7 +1951,7 @@ void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar) LLRender::BF_ONE_MINUS_SOURCE_ALPHA); renderRigged(avatar, RIGGED_ALPHA); - gGL.setSceneBlendType(LLRender::BT_ALPHA); + //gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.setColorMask(true, false); } } @@ -1969,7 +1969,7 @@ void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar) LLRender::BF_ONE_MINUS_SOURCE_ALPHA); renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA); - gGL.setSceneBlendType(LLRender::BT_ALPHA); + //gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.setColorMask(true, false); } } diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index 012a4b9dd..a0d6dbf92 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -548,11 +548,17 @@ void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass) { if (LLPipeline::sUnderWaterRender) { - gDeferredFullbrightWaterProgram.bind(); + //gDeferredFullbrightWaterProgram.bind(); + //Use alpha-mask version to ignore alpha values while still allowing us to occlude glow. + gDeferredFullbrightAlphaMaskWaterProgram.bind(); + gDeferredFullbrightAlphaMaskWaterProgram.setMinimumAlpha(0.f); } else { - gDeferredFullbrightProgram.bind(); + //gDeferredFullbrightProgram.bind(); + //Use alpha-mask version to ignore alpha values while still allowing us to occlude glow. + gDeferredFullbrightAlphaMaskProgram.bind(); + gDeferredFullbrightAlphaMaskProgram.setMinimumAlpha(0.f); } } @@ -573,11 +579,11 @@ void LLDrawPoolFullbright::endPostDeferredPass(S32 pass) { if (LLPipeline::sUnderWaterRender) { - gDeferredFullbrightWaterProgram.unbind(); + gDeferredFullbrightAlphaMaskWaterProgram.unbind(); } else { - gDeferredFullbrightProgram.unbind(); + gDeferredFullbrightAlphaMaskProgram.unbind(); } LLRenderPass::endRenderPass(pass); } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 5947a0717..15430989e 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1338,9 +1338,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } } - if (shiny_in_alpha) + if(getPoolType() == LLDrawPool::POOL_FULLBRIGHT) + { + color.mV[3] = 1.f; //Simple fullbright reads alpha for fog contrib, not shiny/transparency, so since opaque, force to 1. + } + else if (shiny_in_alpha) { - GLfloat alpha[4] = { 0.00f, diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 1229fef67..bd54b6195 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -204,6 +204,12 @@ bool handleRenderAvatarComplexityLimitChanged(const LLSD& newvalue) bool handleRenderTransparentWaterChanged(const LLSD& newvalue) { + LLPipeline::sWaterReflections = gGLManager.mHasCubeMap && gSavedSettings.getBOOL("VertexShaderEnable"); + if (gPipeline.isInit()) //If water is opaque then distortion/reflection fbos will not be needed. + { + gPipeline.releaseGLBuffers(); + gPipeline.createGLBuffers(); + } LLWorld::getInstance()->updateWaterObjects(); return true; } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index ea9e5605c..121b4388c 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4191,10 +4191,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, //drawable->getVObj()->setDebugText(llformat("%d", drawable->isState(LLDrawable::ANIMATED_CHILD))); LLMaterial* mat = facep->getTextureEntry()->getMaterialParams().get(); + + U32 pool_type = facep->getPoolType(); bool cmp_bump = (type == LLRenderPass::PASS_BUMP) || (type == LLRenderPass::PASS_POST_BUMP); - bool cmp_shiny = !alt_batching ? !!mat : ((type == LLRenderPass::PASS_SHINY) || (type == LLRenderPass::PASS_FULLBRIGHT_SHINY) || (type == LLRenderPass::PASS_INVISI_SHINY)); - bool cmp_mat = !alt_batching || LLPipeline::sRenderDeferred && ((facep->getPoolType() == LLDrawPool::POOL_MATERIALS) || (facep->getPoolType() == LLDrawPool::POOL_ALPHA)); + bool cmp_mat = (!alt_batching) || LLPipeline::sRenderDeferred && facep->getTextureEntry()->getColor().mV[3] >= 0.999f && + ((pool_type == LLDrawPool::POOL_MATERIALS) || (pool_type == LLDrawPool::POOL_ALPHA)); + bool cmp_shiny = (!alt_batching) ? !!mat : (mat && cmp_mat); + bool cmp_fullbright = !alt_batching || cmp_shiny || pool_type == LLDrawPool::POOL_ALPHA; U8 bump = facep->getTextureEntry()->getBumpmap(); U8 shiny = facep->getTextureEntry()->getShiny(); @@ -4209,7 +4213,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 shader_mask = 0xFFFFFFFF; //no shader - if (mat) + if (mat && cmp_mat) { if (type == LLRenderPass::PASS_ALPHA) { @@ -4255,9 +4259,9 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, #endif (!cmp_mat || draw_vec[idx]->mMaterial == mat) && //draw_vec[idx]->mMaterialID == mat_id && - draw_vec[idx]->mFullbright == fullbright && + (!cmp_fullbright || draw_vec[idx]->mFullbright == fullbright) && (!cmp_bump || draw_vec[idx]->mBump == bump) && - (!cmp_shiny || !!draw_vec[idx]->mShiny == !!shiny) && + (!cmp_shiny || draw_vec[idx]->mShiny == shiny) && //(!mat || (draw_vec[idx]->mShiny == shiny)) && // need to break batches when a material is shared, but legacy settings are different draw_vec[idx]->mTextureMatrix == tex_mat && draw_vec[idx]->mModelMatrix == model_mat && @@ -4539,6 +4543,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) bool is_rigged = false; + static const LLCachedControl alt_batching("SHAltBatching",true); + //for each face for (S32 i = 0; i < drawablep->getNumFaces(); i++) { @@ -4647,7 +4653,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } LLMaterial* mat = te->getMaterialParams().get(); - + + if(!alt_batching) + { if (mat && LLPipeline::sRenderDeferred) { U8 alpha_mode = mat->getDiffuseAlphaMode(); @@ -4760,6 +4768,68 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } } + } + else + { + if(type == LLDrawPool::POOL_ALPHA) + { + if(te->getColor().mV[3] > 0.f) + { + U32 mask = te->getFullbright() ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA : LLDrawPoolAvatar::RIGGED_ALPHA; + if (mat && LLPipeline::sRenderDeferred && te->getColor().mV[3] >= 0.999f ) + { + if(mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) + mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND); + else + mask = mat->getShaderMask(); + } + pool->addRiggedFace(facep, mask); + } + } + else if(!LLPipeline::sRenderDeferred) + { + if(type == LLDrawPool::POOL_FULLBRIGHT || type == LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); + } + else if(type == LLDrawPool::POOL_SIMPLE || type == LLDrawPool::POOL_ALPHA_MASK) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); + } + else if(type == LLDrawPool::POOL_BUMP) //Either shiny, or bump (which isn't used in non-deferred) + { + if(te->getShiny()) + pool->addRiggedFace(facep, te->getFullbright() ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY : LLDrawPoolAvatar::RIGGED_SHINY); + else + pool->addRiggedFace(facep, te->getFullbright() ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); + } + } + + else + { + if( type == LLDrawPool::POOL_FULLBRIGHT || type == LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); + } + //Annoying exception to the rule. getPoolTypeFromTE will return POOL_ALPHA_MASK for legacy bumpmaps, but there is no POOL_ALPHA_MASK in deferred. + else if(type == LLDrawPool::POOL_MATERIALS || (type == LLDrawPool::POOL_ALPHA_MASK && mat)) + { + pool->addRiggedFace(facep, mat->getShaderMask()); + } + else if (type == LLDrawPool::POOL_BUMP && te->getBumpmap()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE); + } + } + } } continue; @@ -4804,8 +4874,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } - static const LLCachedControl alt_batching("SHAltBatching",true); - bool force_fullbright = group->isHUDGroup(); BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA); U32 type = gPipeline.getPoolTypeFromTE(te, tex); @@ -4836,7 +4904,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } } - else if (force_fullbright) + else if (force_fullbright) //Hud is done in a forward render. Fullbright cannot be shared with simple. { if(type == LLDrawPool::POOL_ALPHA_MASK) type = LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK; @@ -5368,11 +5436,9 @@ struct CompareBatchBreakerModified return lte->getMaterialParams() < rte->getMaterialParams(); } else if (LLPipeline::sRenderDeferred && (lte->getMaterialParams() == rte->getMaterialParams()) && (lte->getShiny() != rte->getShiny())) - { return lte->getShiny() < rte->getShiny(); } - else { return lhs->getTexture() < rhs->getTexture(); @@ -5396,9 +5462,11 @@ struct CompareBatchBreakerModified return !(batch_left < batch_right); } - bool batch_shiny = (!LLPipeline::sRenderDeferred || lhs->isState(LLFace::FULLBRIGHT)) && lhs->getPoolType() == LLDrawPool::POOL_BUMP; + static const LLCachedControl sh_fullbright_deferred("SHFullbrightDeferred",true); + bool batch_shiny = (!LLPipeline::sRenderDeferred || (sh_fullbright_deferred && lhs->isState(LLFace::FULLBRIGHT))) && lhs->getPoolType() == LLDrawPool::POOL_BUMP; + bool batch_fullbright = sh_fullbright_deferred || !LLPipeline::sRenderDeferred && lhs->getPoolType() == LLDrawPool::POOL_ALPHA; - if (lhs->isState(LLFace::FULLBRIGHT) != rhs->isState(LLFace::FULLBRIGHT)) + if (batch_fullbright && lhs->isState(LLFace::FULLBRIGHT) != rhs->isState(LLFace::FULLBRIGHT)) { return lhs->isState(LLFace::FULLBRIGHT) < rhs->isState(LLFace::FULLBRIGHT); } @@ -6196,21 +6264,40 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac llassert_always(mask & LLVertexBuffer::MAP_NORMAL); } - if (is_fullbright) + if(LLPipeline::sRenderDeferred) { - registerFace(group, facep, is_shiny_shader ? LLRenderPass::PASS_FULLBRIGHT_SHINY : LLRenderPass::PASS_FULLBRIGHT); - if(is_bump) - registerFace(group, facep, LLPipeline::sRenderDeferred ? LLRenderPass::PASS_POST_BUMP : LLRenderPass::PASS_BUMP); + static const LLCachedControl sh_fullbright_deferred("SHFullbrightDeferred",true); + if(sh_fullbright_deferred && is_fullbright) + { + registerFace(group, facep, is_shiny_shader ? LLRenderPass::PASS_FULLBRIGHT_SHINY : LLRenderPass::PASS_FULLBRIGHT); + if(is_bump) + { + registerFace(group, facep, LLRenderPass::PASS_POST_BUMP); + } + } + else + { + //is_bump should always be true. + registerFace(group, facep, is_bump ? LLRenderPass::PASS_BUMP : LLRenderPass::PASS_SIMPLE); + } } else { - registerFace(group, facep, (LLPipeline::sRenderDeferred || !is_shiny_shader) ? LLRenderPass::PASS_SIMPLE : LLRenderPass::PASS_SHINY); + if (is_fullbright ) + { + registerFace(group, facep, is_shiny_shader ? LLRenderPass::PASS_FULLBRIGHT_SHINY : LLRenderPass::PASS_FULLBRIGHT); + } + else + { + registerFace(group, facep, is_shiny_shader ? LLRenderPass::PASS_SHINY : LLRenderPass::PASS_SIMPLE); + } + if(is_bump) registerFace(group, facep, LLRenderPass::PASS_BUMP); - } - if(is_shiny_fixed) - registerFace(group, facep, LLRenderPass::PASS_SHINY); + if(is_shiny_fixed) + registerFace(group, facep, LLRenderPass::PASS_SHINY); + } } } if (!is_alpha && LLPipeline::sRenderGlow && te->getGlow() > 0.f) diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index c4e73d90b..b4ab34d36 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -166,7 +166,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) static const LLCachedControl render_transparent_water("RenderTransparentWater",false); static const LLCachedControl water_subdiv("SianaVoidWaterSubdivision", 16); - const S32 size = (render_transparent_water && LLGLSLShader::sNoFixedFunction) ? water_subdiv : 1; + const S32 size = ((render_transparent_water || LLPipeline::sRenderDeferred) && LLGLSLShader::sNoFixedFunction) ? water_subdiv : 1; const S32 num_quads = size * size; face->setSize(vertices_per_quad * num_quads, indices_per_quad * num_quads); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 79d6ad670..924e348d0 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1567,34 +1567,39 @@ U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* ima } else { + static const LLCachedControl sh_fullbright_deferred("SHFullbrightDeferred",true); + + //Bump goes into bump pool unless using deferred and there's a normal map that takes precedence. + bool legacy_bump = (!LLPipeline::sRenderDeferred || !mat || mat->getNormalID().isNull()) && LLPipeline::sRenderBump && te->getBumpmap() && te->getBumpmap() < 18; if (alpha) { return LLDrawPool::POOL_ALPHA; } - else if ((!LLPipeline::sRenderDeferred || !mat || mat->getNormalID().isNull()) && LLPipeline::sRenderBump && te->getBumpmap() && te->getBumpmap() < 18) - { - return LLDrawPool::POOL_BUMP; //Bump goes into bump pool unless using deferred and there's a normal map that takes precedence. - } else if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) { - if(te->getFullbright()) + if(!LLPipeline::sRenderDeferred || legacy_bump) + { + return te->getFullbright() ? LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK : LLDrawPool::POOL_ALPHA_MASK; + } + else if(te->getFullbright() && !mat->getEnvironmentIntensity() && !te->getShiny()) { return LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK; } - else - { - return LLPipeline::sRenderDeferred ? LLDrawPool::POOL_MATERIALS : LLDrawPool::POOL_ALPHA_MASK; - } + return LLDrawPool::POOL_MATERIALS; + } + else if (legacy_bump) + { + return LLDrawPool::POOL_BUMP; } else if(LLPipeline::sRenderDeferred && mat) { - if(te->getFullbright() && mat->getEnvironmentIntensity()) + if(te->getFullbright() && !mat->getEnvironmentIntensity() && !te->getShiny()) { - return LLDrawPool::POOL_FULLBRIGHT; + return sh_fullbright_deferred ? LLDrawPool::POOL_FULLBRIGHT : LLDrawPool::POOL_SIMPLE; } return LLDrawPool::POOL_MATERIALS; } - else if(te->getFullbright()) + else if((sh_fullbright_deferred || !LLPipeline::sRenderDeferred) && te->getFullbright()) { return (LLPipeline::sRenderBump && te->getShiny()) ? LLDrawPool::POOL_BUMP : LLDrawPool::POOL_FULLBRIGHT; } @@ -8558,10 +8563,10 @@ void LLPipeline::renderDeferredLighting() pushRenderTypeMask(); andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA, LLPipeline::RENDER_TYPE_FULLBRIGHT, - //LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_VOLUME, LLPipeline::RENDER_TYPE_GLOW, LLPipeline::RENDER_TYPE_BUMP, - /*LLPipeline::RENDER_TYPE_PASS_SIMPLE, //These aren't used. + LLPipeline::RENDER_TYPE_PASS_SIMPLE, LLPipeline::RENDER_TYPE_PASS_ALPHA, LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, LLPipeline::RENDER_TYPE_PASS_BUMP, @@ -8573,7 +8578,7 @@ void LLPipeline::renderDeferredLighting() LLPipeline::RENDER_TYPE_PASS_GRASS, LLPipeline::RENDER_TYPE_PASS_SHINY, LLPipeline::RENDER_TYPE_PASS_INVISIBLE, - LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,*/ + LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, LLPipeline::RENDER_TYPE_AVATAR, LLPipeline::RENDER_TYPE_ALPHA_MASK, LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK, @@ -9181,10 +9186,10 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) pushRenderTypeMask(); andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA, LLPipeline::RENDER_TYPE_FULLBRIGHT, - //LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_VOLUME, LLPipeline::RENDER_TYPE_GLOW, LLPipeline::RENDER_TYPE_BUMP, - /*LLPipeline::RENDER_TYPE_PASS_SIMPLE, //These aren't used. + LLPipeline::RENDER_TYPE_PASS_SIMPLE, LLPipeline::RENDER_TYPE_PASS_ALPHA, LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, LLPipeline::RENDER_TYPE_PASS_BUMP, @@ -9196,7 +9201,7 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) LLPipeline::RENDER_TYPE_PASS_GRASS, LLPipeline::RENDER_TYPE_PASS_SHINY, LLPipeline::RENDER_TYPE_PASS_INVISIBLE, - LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,*/ + LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, LLPipeline::RENDER_TYPE_AVATAR, LLPipeline::RENDER_TYPE_ALPHA_MASK, LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK, @@ -9401,7 +9406,8 @@ inline float sgn(float a) void LLPipeline::generateWaterReflection(LLCamera& camera_in) { - if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate) + static const LLCachedControl render_transparent_water("RenderTransparentWater",false); + if ((render_transparent_water || LLPipeline::sRenderDeferred) && LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate) { BOOL skip_avatar_update = FALSE; if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) From 34a7bf4dbb07675d15ddefa53d090172ea83c79f Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 27 Mar 2014 21:30:23 -0500 Subject: [PATCH 076/115] Comment out unused shader. --- indra/newview/llviewershadermgr.cpp | 6 +++--- indra/newview/llviewershadermgr.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index b5a819032..277fdd197 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -190,7 +190,7 @@ LLGLSLShader gDeferredWaterProgram(LLViewerShaderMgr::SHADER_DEFERRED); //calc LLGLSLShader gDeferredUnderWaterProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredDiffuseProgram(LLViewerShaderMgr::SHADER_DEFERRED);//Not in mShaderList LLGLSLShader gDeferredDiffuseAlphaMaskProgram(LLViewerShaderMgr::SHADER_DEFERRED); -LLGLSLShader gDeferredNonIndexedDiffuseProgram(LLViewerShaderMgr::SHADER_DEFERRED); +//LLGLSLShader gDeferredNonIndexedDiffuseProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredNonIndexedDiffuseAlphaMaskProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredSkinnedDiffuseProgram(LLViewerShaderMgr::SHADER_DEFERRED); @@ -1078,7 +1078,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.createShader(NULL, NULL); } - if (success) + /*if (success) { gDeferredNonIndexedDiffuseProgram.mName = "Non Indexed Deferred Diffuse Shader"; gDeferredNonIndexedDiffuseProgram.mShaderFiles.clear(); @@ -1086,7 +1086,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredNonIndexedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredNonIndexedDiffuseProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; success = gDeferredNonIndexedDiffuseProgram.createShader(NULL, NULL); - } + }*/ if (success) diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 99374c31a..feea7cfbc 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -300,7 +300,7 @@ extern LLGLSLShader gDeferredDiffuseProgram; extern LLGLSLShader gDeferredDiffuseAlphaMaskProgram; extern LLGLSLShader gDeferredNonIndexedDiffuseAlphaMaskProgram; extern LLGLSLShader gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram; -extern LLGLSLShader gDeferredNonIndexedDiffuseProgram; +//extern LLGLSLShader gDeferredNonIndexedDiffuseProgram; extern LLGLSLShader gDeferredSkinnedDiffuseProgram; extern LLGLSLShader gDeferredSkinnedBumpProgram; extern LLGLSLShader gDeferredSkinnedAlphaProgram; From 07a261a2598e16d421d7027eca53f6ce5963e702 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 27 Mar 2014 22:04:30 -0500 Subject: [PATCH 077/115] A little bit of cleanup. --- indra/newview/lldrawpoolalpha.cpp | 11 +++--- indra/newview/lldrawpoolbump.cpp | 2 +- indra/newview/llviewershadermgr.cpp | 11 ++---- indra/newview/pipeline.cpp | 55 ++++++++--------------------- 4 files changed, 25 insertions(+), 54 deletions(-) diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index ce4b19b82..3d88b34ca 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -373,6 +373,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) BOOL light_enabled = TRUE; BOOL use_shaders = gPipeline.canUseVertexShaders(); + + BOOL depth_only = (pass == 1 && !LLPipeline::sImpostorRender); for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) { @@ -387,7 +389,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) || group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_CLOUD || group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE; - bool draw_glow_for_this_partition = mVertexShaderLevel > 0; // no shaders = no glow. + bool draw_glow_for_this_partition = !depth_only && mVertexShaderLevel > 0; // no shaders = no glow. static LLFastTimer::DeclareTimer FTM_RENDER_ALPHA_GROUP_LOOP("Alpha Group"); LLFastTimer t(FTM_RENDER_ALPHA_GROUP_LOOP); @@ -410,7 +412,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) // Fix for bug - NORSPEC-271 // If the face is more than 90% transparent, then don't update the Depth buffer for Dof // We don't want the nearly invisible objects to cause of DoF effects - if(pass == 1 && !LLPipeline::sImpostorRender) + if(depth_only) { LLFace* face = params.mFace; if(face) @@ -443,9 +445,10 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) llassert_always(!LLGLSLShader::sNoFixedFunction); llassert_always(!LLGLSLShader::sCurBoundShaderPtr); - if(params.mFullbright == light_enabled || !initialized_lighting) + bool fullbright = depth_only || params.mFullbright; + if(fullbright == light_enabled || !initialized_lighting) { - light_enabled = !params.mFullbright; + light_enabled = !fullbright; initialized_lighting = true; if (light_enabled) // Turn off lighting if it hasn't already been so. diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index d9eac7b7b..6a4c1b2ba 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -270,7 +270,7 @@ void LLDrawPoolBump::render(S32 pass) { LLFastTimer t(FTM_RENDER_BUMP); - if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE)) + if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE)) { return; } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 277fdd197..453a1e076 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -552,6 +552,7 @@ void LLViewerShaderMgr::setShaders() else { LLGLSLShader::sNoFixedFunction = false; + LLGLSLShader::sIndexedTextureChannels = 1; gPipeline.mVertexShadersEnabled = FALSE; gPipeline.mVertexShadersLoaded = 0; for (S32 i = 0; i < SHADER_COUNT; i++) @@ -569,6 +570,7 @@ void LLViewerShaderMgr::setShaders() else { LLGLSLShader::sNoFixedFunction = false; + LLGLSLShader::sIndexedTextureChannels = 1; gPipeline.mVertexShadersEnabled = FALSE; gPipeline.mVertexShadersLoaded = 0; for (S32 i = 0; i < SHADER_COUNT; i++) @@ -673,14 +675,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders() // (in order of shader function call depth for reference purposes, deepest level first) shaders.clear(); - S32 ch = 1; - - if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30) - { //use indexed texture rendering for GLSL >= 1.30 - static const LLCachedControl no_texture_indexing("ShyotlUseLegacyTextureBatching",false); - if(!no_texture_indexing) - ch = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); - } + S32 ch = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); std::vector index_channels; index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsVarsF.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) ); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 924e348d0..9c83cfeb3 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -2549,15 +2549,13 @@ void LLPipeline::downsampleDepthBuffer(LLRenderTarget& source, LLRenderTarget& d { mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0); mDeferredVB->allocateBuffer(8, 0, true); - } - - LLStrider vert; - mDeferredVB->getVertexStrider(vert); - LLStrider tc0; + LLStrider vert; + mDeferredVB->getVertexStrider(vert); - vert[0].set(-1,1,0); - vert[1].set(-1,-3,0); - vert[2].set(3,1,0); + vert[0].set(-1,1,0); + vert[1].set(-1,-3,0); + vert[2].set(3,1,0); + } if (source.getUsage() == LLTexUnit::TT_RECT_TEXTURE) { @@ -7962,15 +7960,14 @@ void LLPipeline::renderDeferredLighting() { mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0); mDeferredVB->allocateBuffer(8, 0, true); + LLStrider vert; + mDeferredVB->getVertexStrider(vert); + + vert[0].set(-1,1,0); + vert[1].set(-1,-3,0); + vert[2].set(3,1,0); } - LLStrider vert; - mDeferredVB->getVertexStrider(vert); - - vert[0].set(-1,1,0); - vert[1].set(-1,-3,0); - vert[2].set(3,1,0); - { setupHWLights(NULL); //to set mSunDir; LLVector4 dir(mSunDir, 0.f); @@ -8392,12 +8389,6 @@ void LLPipeline::renderDeferredLighting() unbindDeferredShader(gDeferredSpotLightProgram); } - //reset mDeferredVB to fullscreen triangle - mDeferredVB->getVertexStrider(vert); - vert[0].set(-1,1,0); - vert[1].set(-1,-3,0); - vert[2].set(3,1,0); - { LLGLDepthTest depth(GL_FALSE); @@ -8510,14 +8501,10 @@ void LLPipeline::renderDeferredLighting() { LLGLDepthTest depth(GL_FALSE, GL_FALSE); - LLVector2 tc1(0,0); - LLVector2 tc2((F32) mScreen.getWidth()*2, - (F32) mScreen.getHeight()*2); - mScreen.bindTarget(); // Apply gamma correction to the frame here. gDeferredPostGammaCorrectProgram.bind(); - //mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); S32 channel = 0; channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); if (channel > -1) @@ -8528,21 +8515,7 @@ void LLPipeline::renderDeferredLighting() gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mScreen.getWidth(), mScreen.getHeight()); - //F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); - - //gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); gGL.getTexUnit(channel)->unbind(mScreen.getUsage()); gDeferredPostGammaCorrectProgram.unbind(); From 894261862d9af0fd768003eee55407cff755ac5b Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 27 Mar 2014 22:31:47 -0500 Subject: [PATCH 078/115] Tweaks to stencil handling to allow masking out of sky (or geometry). Reset stencil clear value to 0 after done clearing. --- indra/newview/lldrawpoolwater.cpp | 1 + indra/newview/lldrawpoolwlsky.cpp | 1 + indra/newview/llmaniptranslate.cpp | 1 + indra/newview/llspatialpartition.cpp | 3 +++ indra/newview/pipeline.cpp | 1 + 5 files changed, 7 insertions(+) diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 0872f5f9d..12f91ea67 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -253,6 +253,7 @@ void LLDrawPoolWater::render(S32 pass) glClearStencil(1); glClear(GL_STENCIL_BUFFER_BIT); + glClearStencil(0); LLGLEnable gls_stencil(GL_STENCIL_TEST); glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP); glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF); diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp index 3d0762132..864975460 100644 --- a/indra/newview/lldrawpoolwlsky.cpp +++ b/indra/newview/lldrawpoolwlsky.cpp @@ -326,6 +326,7 @@ void LLDrawPoolWLSky::renderDeferred(S32 pass) const F32 camHeightLocal = LLWLParamManager::getInstance()->getDomeOffset() * LLWLParamManager::getInstance()->getDomeRadius(); + LLGLDisable stencil(GL_STENCIL_TEST); LLGLSNoFog disableFog; LLGLDepthTest depth(GL_TRUE, GL_FALSE); LLGLDisable clip(GL_CLIP_PLANE0); diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index bdbc132c5..f9a3b0cdd 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -1676,6 +1676,7 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal, glStencilMask(stencil_mask); glClearStencil(1); glClear(GL_STENCIL_BUFFER_BIT); + glClearStencil(0); LLGLEnable cull_face(GL_CULL_FACE); LLGLEnable stencil(GL_STENCIL_TEST); LLGLDepthTest depth (GL_TRUE, GL_FALSE, GL_ALWAYS); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index c2fb74365..1919611ec 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1528,6 +1528,7 @@ static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW("Draw"); void LLSpatialGroup::doOcclusion(LLCamera* camera) { + LLGLDisable stencil(GL_STENCIL_TEST); if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1) { //static const LLCachedControl render_water_void_culling("RenderWaterVoidCulling", TRUE); @@ -3867,6 +3868,8 @@ public: return; } + LLGLDisable stencil(GL_STENCIL_TEST); + group->rebuildGeom(); group->rebuildMesh(); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 9c83cfeb3..8ac0640fd 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -2334,6 +2334,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl LLGLDisable blend(GL_BLEND); LLGLDisable test(GL_ALPHA_TEST); + LLGLDisable stencil(GL_STENCIL_TEST); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); From dc9d3fbf960ea1a169361460577b9848b52cf31a Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Fri, 28 Mar 2014 08:29:30 +0100 Subject: [PATCH 079/115] Fix build with SDL prior to 1.3.0 --- indra/llwindow/llwindowsdl.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index 48f2c1949..923b29be7 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -373,7 +373,7 @@ static int x11_detect_VRAM_kb() } #endif // LL_X11 -BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, const S32 vsync_mode, S32 vsync_mode) +BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, const S32 vsync_mode) { //bool glneedsinit = false; @@ -721,6 +721,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, c } #endif // LL_X11 +#if SDL_VERSION_ATLEAST(1,3,0) // Disable vertical sync for swap if (vsync_mode == 0) { @@ -741,6 +742,29 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, c LL_DEBUGS("Window") << "Enabling vertical sync" << LL_ENDL; SDL_GL_SetSwapInterval(1); } +#else // SDL_VERSION_ATLEAST(1,3,0) +#ifdef SDL_GL_SWAP_CONTROL + if (vsync_mode == 0) + { + LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL; + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 0); + } + else if(vsync_mode == -1) + { + LL_DEBUGS("Window") << "Enabling adaptive vertical sync" << LL_ENDL; + if(SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, -1) == -1) + { + LL_DEBUGS("Window") << "Failed to enable adaptive vertical sync. Disabling vsync." << LL_ENDL; + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 0); + } + } + else + { + LL_DEBUGS("Window") << "Enabling vertical sync" << LL_ENDL; + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); + } +#endif // SDL_GL_SWAP_CONTROL +#endif // SDL_VERSION_ATLEAST(1,3,0) //make sure multisampling is disabled by default glDisable(GL_MULTISAMPLE_ARB); @@ -1014,7 +1038,7 @@ S32 LLWindowSDL::getVsyncMode() void LLWindowSDL::setVsyncMode(const S32 vsync_mode) { - mVsyncMode = vsync_mode + mVsyncMode = vsync_mode; } F32 LLWindowSDL::getGamma() From 80076833d1b6f36a11c8860aa6aa48fe88cbe27e Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Fri, 28 Mar 2014 08:30:22 +0100 Subject: [PATCH 080/115] Fix compilation with gcc --- indra/newview/llappearancemgr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 5c6712711..c76abdf64 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1731,7 +1731,8 @@ bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) // Is there an active gesture in outfit_cat_id? items.reset(); - gInventory.collectDescendentsIf(outfit_cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, LLIsType(LLAssetType::AT_GESTURE), /*follow_folder_links=*/ true); + LLIsType is_gesture(LLAssetType::AT_GESTURE); + gInventory.collectDescendentsIf(outfit_cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_gesture, /*follow_folder_links=*/ true); for(S32 i = 0; i < items.count(); ++i) if (LLGestureMgr::instance().isGestureActive(items.get(i)->getLinkedUUID())) return true; From d6fdaa93a4b86590c8dcade84d8b894baff4679b Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 28 Mar 2014 02:34:03 -0500 Subject: [PATCH 081/115] Added adaptive vsync support (selectable in preferences->graphics->hardware, provided the driver supports it). Also hide 16x fsaa on amd hardware, as it is not supported on said hardware (unsure about intel). --- indra/llrender/llgl.cpp | 9 ++++ indra/llrender/llgl.h | 2 + indra/llwindow/llwindow.cpp | 12 +++--- indra/llwindow/llwindow.h | 6 ++- indra/llwindow/llwindowheadless.cpp | 2 +- indra/llwindow/llwindowheadless.h | 6 ++- indra/llwindow/llwindowmacosx.cpp | 23 ++++++++--- indra/llwindow/llwindowmacosx.h | 9 ++-- indra/llwindow/llwindowmesaheadless.cpp | 2 +- indra/llwindow/llwindowmesaheadless.h | 6 ++- indra/llwindow/llwindowsdl.cpp | 40 +++++++++++++++--- indra/llwindow/llwindowsdl.h | 9 ++-- indra/llwindow/llwindowwin32.cpp | 41 +++++++++++++++---- indra/llwindow/llwindowwin32.h | 7 +++- indra/newview/app_settings/settings_sh.xml | 11 +++++ indra/newview/llpaneldisplay.cpp | 25 ++++++++++- indra/newview/llpaneldisplay.h | 1 + indra/newview/llviewerwindow.cpp | 37 +++++++++++++---- indra/newview/llviewerwindow.h | 2 +- .../xui/en-us/panel_preferences_graphics1.xml | 8 +++- 20 files changed, 204 insertions(+), 54 deletions(-) diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 8b5310beb..064183d49 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -442,6 +442,8 @@ LLGLManager::LLGLManager() : mHasCubeMap(FALSE), mHasDebugOutput(FALSE), + mHasAdaptiveVsync(FALSE), + mIsATI(FALSE), mIsNVIDIA(FALSE), mIsIntel(FALSE), @@ -956,6 +958,12 @@ void LLGLManager::initExtensions() mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts)); #endif +#if LL_WINDOWS + mHasAdaptiveVsync = ExtensionExists("WGL_EXT_swap_control_tear", gGLHExts.mSysExts); +#elif LL_LINUX + mHasAdaptiveVsync = ExtensionExists("GLX_EXT_swap_control_tear", gGLHExts.mSysExts); +#endif + #if LL_LINUX || LL_SOLARIS llinfos << "initExtensions() checking shell variables to adjust features..." << llendl; // Our extension support for the Linux Client is very young with some @@ -980,6 +988,7 @@ void LLGLManager::initExtensions() mHasShaderObjects = FALSE; mHasVertexShader = FALSE; mHasFragmentShader = FALSE; + mHasAdaptiveVsync = FALSE; LL_WARNS("RenderInit") << "GL extension support DISABLED via LL_GL_NOEXT" << LL_ENDL; } else if (getenv("LL_GL_BASICEXT")) /* Flawfinder: ignore */ diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 65161a6fa..9b277c70a 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -113,6 +113,8 @@ public: BOOL mHasCubeMap; BOOL mHasDebugOutput; + BOOL mHasAdaptiveVsync; + // Vendor-specific extensions BOOL mIsATI; BOOL mIsNVIDIA; diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index 8df242331..b3b37d705 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -388,7 +388,7 @@ LLWindow* LLWindowManager::createWindow( const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, + const S32 vsync_mode, BOOL use_gl, BOOL ignore_pixel_depth, U32 fsaa_samples) @@ -400,26 +400,26 @@ LLWindow* LLWindowManager::createWindow( #if LL_MESA_HEADLESS new_window = new LLWindowMesaHeadless(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, ignore_pixel_depth); + fullscreen, clearBg, vsync_mode, ignore_pixel_depth); #elif LL_SDL new_window = new LLWindowSDL(callbacks, title, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, ignore_pixel_depth, fsaa_samples); + fullscreen, clearBg, vsync_mode, ignore_pixel_depth, fsaa_samples); #elif LL_WINDOWS new_window = new LLWindowWin32(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, ignore_pixel_depth, fsaa_samples); + fullscreen, clearBg, vsync_mode, ignore_pixel_depth, fsaa_samples); #elif LL_DARWIN new_window = new LLWindowMacOSX(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, ignore_pixel_depth, fsaa_samples); + fullscreen, clearBg, vsync_mode, ignore_pixel_depth, fsaa_samples); #endif } else { new_window = new LLWindowHeadless(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, ignore_pixel_depth); + fullscreen, clearBg, vsync_mode, ignore_pixel_depth); } if (FALSE == new_window->isValid()) diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 575c57816..0d53f5951 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -82,7 +82,7 @@ public: BOOL setSize(LLCoordScreen size); BOOL setSize(LLCoordWindow size); virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); - virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) = 0; + virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp = NULL) = 0; virtual BOOL setCursorPosition(LLCoordWindow position) = 0; virtual BOOL getCursorPosition(LLCoordWindow *position) = 0; virtual void showCursor() = 0; @@ -121,6 +121,8 @@ public: virtual BOOL setGamma(const F32 gamma) = 0; // Set the gamma virtual void setFSAASamples(const U32 fsaa_samples) = 0; //set number of FSAA samples virtual U32 getFSAASamples() = 0; + virtual void setVsyncMode(const S32 vsync_mode) = 0; + virtual S32 getVsyncMode() = 0; virtual BOOL restoreGamma() = 0; // Restore original gamma table (before updating gamma) virtual ESwapMethod getSwapMethod() { return mSwapMethod; } virtual void processMiscNativeEvents(); @@ -274,7 +276,7 @@ public: U32 flags = 0, BOOL fullscreen = FALSE, BOOL clearBg = FALSE, - BOOL disable_vsync = TRUE, + const S32 vsync_mode = 0, BOOL use_gl = TRUE, BOOL ignore_pixel_depth = FALSE, U32 fsaa_samples = 0); diff --git a/indra/llwindow/llwindowheadless.cpp b/indra/llwindow/llwindowheadless.cpp index dbdb40f5b..d07521cf2 100644 --- a/indra/llwindow/llwindowheadless.cpp +++ b/indra/llwindow/llwindowheadless.cpp @@ -35,7 +35,7 @@ // LLWindowHeadless::LLWindowHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clear_background, - BOOL disable_vsync, BOOL ignore_pixel_depth) + const S32 vsync_mode, BOOL ignore_pixel_depth) : LLWindow(callbacks, fullscreen, flags) { // Initialize a headless keyboard. diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h index 72f9684ca..491f9afd2 100644 --- a/indra/llwindow/llwindowheadless.h +++ b/indra/llwindow/llwindowheadless.h @@ -48,7 +48,7 @@ public: /*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;}; /*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;}; /*virtual*/ BOOL setSizeImpl(LLCoordWindow size) {return FALSE;}; - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;}; + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp = NULL) {return FALSE;}; /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;}; /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;}; /*virtual*/ void showCursor() {}; @@ -69,6 +69,8 @@ public: /*virtual*/ BOOL setGamma(const F32 gamma) {return FALSE; }; // Set the gamma /*virtual*/ void setFSAASamples(const U32 fsaa_samples) { } /*virtual*/ U32 getFSAASamples() { return 0; } + /*virtual*/ void setVsyncMode(const S32 vsync_mode) {} + /*virtual*/ S32 getVsyncMode() { return 0; } /*virtual*/ BOOL restoreGamma() {return FALSE; }; // Restore original gamma table (before updating gamma) //virtual ESwapMethod getSwapMethod() { return mSwapMethod; } /*virtual*/ void gatherInput() {}; @@ -96,7 +98,7 @@ public: S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clear_background, - BOOL disable_vsync, BOOL ignore_pixel_depth); + const S32 vsync_mode, BOOL ignore_pixel_depth); virtual ~LLWindowHeadless(); private: diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 303a23959..096742dc9 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -210,7 +210,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, + const S32 vsync_mode, BOOL ignore_pixel_depth, U32 fsaa_samples) : LLWindow(NULL, fullscreen, flags) @@ -253,6 +253,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, mPreeditor = NULL; mRawKeyEvent = NULL; mFSAASamples = fsaa_samples; + mVsyncMode = vsync_mode; mForceRebuild = FALSE; // For reasons that aren't clear to me, LLTimers seem to be created in the "started" state. @@ -283,7 +284,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, gWindowImplementation = this; // Create the GL context and set it up for windowed or fullscreen, as appropriate. - if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) + if(createContext(x, y, width, height, 32, fullscreen, vsync_mode)) { if(mWindow != NULL) { @@ -323,7 +324,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, stop_glerror(); } -BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync) +BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, const S32 vsync_mode) { OSStatus err; BOOL glNeedsInit = FALSE; @@ -780,7 +781,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits // Disable vertical sync for swap GLint frames_per_swap = 0; - if (disable_vsync) + if (vsync_mode != 1) { LL_DEBUGS("GLInit") << "Disabling vertical sync" << LL_ENDL; frames_per_swap = 0; @@ -816,7 +817,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits // changing fullscreen resolution, or switching between windowed and fullscreen mode. -BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) +BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp) { BOOL needsRebuild = FALSE; BOOL result = true; @@ -892,7 +893,7 @@ BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, B { mForceRebuild = FALSE; destroyContext(); - result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); + result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, vsync_mode); if (result) { if(mWindow != NULL) @@ -1341,6 +1342,16 @@ void LLWindowMacOSX::setFSAASamples(const U32 samples) mForceRebuild = TRUE; } +S32 LLWindowMacOSX::getVsyncMode() +{ + return mVsyncMode; +} +void LLWindowMacOSX::setVsyncMode(const S32 vsync_mode) +{ + mVsyncMode = vsync_mode + mForceRebuild = TRUE; +} + BOOL LLWindowMacOSX::restoreGamma() { CGDisplayRestoreColorSyncSettings(); diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 3f75dc9ab..7f7181a58 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -60,7 +60,7 @@ public: /*virtual*/ BOOL setPosition(LLCoordScreen position); /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp = NULL); /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); /*virtual*/ void showCursor(); @@ -81,6 +81,8 @@ public: /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma /*virtual*/ U32 getFSAASamples(); /*virtual*/ void setFSAASamples(const U32 fsaa_samples); + /*virtual*/ void setVsyncMode(const S32 vsync_mode); + /*virtual*/ S32 getVsyncMode(); /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } /*virtual*/ void gatherInput(); @@ -124,7 +126,7 @@ public: protected: LLWindowMacOSX(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, + BOOL fullscreen, BOOL clearBg, const S32 vsync_mode, BOOL ignore_pixel_depth, U32 fsaa_samples); ~LLWindowMacOSX(); @@ -152,7 +154,7 @@ protected: // // create or re-create the GL context/window. Called from the constructor and switchContext(). - BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync); + BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, const S32 vsync_mode); void destroyContext(); void setupFailure(const std::string& text, const std::string& caption, U32 type); static pascal OSStatus staticEventHandler (EventHandlerCallRef myHandler, EventRef event, void* userData); @@ -201,6 +203,7 @@ protected: BOOL mMaximized; BOOL mMinimized; U32 mFSAASamples; + S32 mVsyncMode; BOOL mForceRebuild; S32 mDragOverrideCursor; diff --git a/indra/llwindow/llwindowmesaheadless.cpp b/indra/llwindow/llwindowmesaheadless.cpp index 2b668d3fc..095a7d17c 100644 --- a/indra/llwindow/llwindowmesaheadless.cpp +++ b/indra/llwindow/llwindowmesaheadless.cpp @@ -41,7 +41,7 @@ U16 *gMesaBuffer = NULL; LLWindowMesaHeadless::LLWindowMesaHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, BOOL ignore_pixel_depth) + const S32 vsync_mode, BOOL ignore_pixel_depth) : LLWindow(callbacks, fullscreen, flags) { llinfos << "MESA Init" << llendl; diff --git a/indra/llwindow/llwindowmesaheadless.h b/indra/llwindow/llwindowmesaheadless.h index c8d2bf282..438964dae 100644 --- a/indra/llwindow/llwindowmesaheadless.h +++ b/indra/llwindow/llwindowmesaheadless.h @@ -52,7 +52,7 @@ public: /*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;}; /*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;}; /*virtual*/ BOOL setSizeImpl(LLCoordWindow size) {return FALSE;}; - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;}; + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp = NULL) {return FALSE;}; /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;}; /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;}; /*virtual*/ void showCursor() {}; @@ -74,6 +74,8 @@ public: /*virtual*/ BOOL restoreGamma() {return FALSE; }; // Restore original gamma table (before updating gamma) /*virtual*/ void setFSAASamples(const U32 fsaa_samples) { /* FSAA not supported yet on Mesa headless.*/ } /*virtual*/ U32 getFSAASamples() { return 0; } + /*virtual*/ void setVsyncMode(const S32 vsync_mode) {} + /*virtual*/ S32 getVsyncMode() { return 0; } //virtual ESwapMethod getSwapMethod() { return mSwapMethod; } /*virtual*/ void gatherInput() {}; /*virtual*/ void delayInputProcessing() {}; @@ -98,7 +100,7 @@ public: LLWindowMesaHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, BOOL ignore_pixel_depth); + const S32 vsync_mode, BOOL ignore_pixel_depth); ~LLWindowMesaHeadless(); private: diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index 10bcf816a..48f2c1949 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -192,7 +192,7 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, const std::string& title, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, + const S32 vsync_mode, BOOL ignore_pixel_depth, U32 fsaa_samples) : LLWindow(callbacks, fullscreen, flags), Lock_Display(NULL), @@ -233,7 +233,7 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, mWindowTitle = title; // Create the GL context and set it up for windowed or fullscreen, as appropriate. - if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) + if(createContext(x, y, width, height, 32, fullscreen, vsync_mode)) { gGLManager.initGL(); @@ -373,7 +373,7 @@ static int x11_detect_VRAM_kb() } #endif // LL_X11 -BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync) +BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, const S32 vsync_mode, S32 vsync_mode) { //bool glneedsinit = false; @@ -721,6 +721,26 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B } #endif // LL_X11 + // Disable vertical sync for swap + if (vsync_mode == 0) + { + LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL; + SDL_GL_SetSwapInterval(0); + } + else if(vsync_mode == -1) + { + LL_DEBUGS("Window") << "Enabling adaptive vertical sync" << LL_ENDL; + if(SDL_GL_SetSwapInterval(-1) == -1) + { + LL_DEBUGS("Window") << "Failed to enable adaptive vertical sync. Disabling vsync." << LL_ENDL; + SDL_GL_SetSwapInterval(0); + } + } + else + { + LL_DEBUGS("Window") << "Enabling vertical sync" << LL_ENDL; + SDL_GL_SetSwapInterval(1); + } //make sure multisampling is disabled by default glDisable(GL_MULTISAMPLE_ARB); @@ -736,7 +756,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B // changing fullscreen resolution, or switching between windowed and fullscreen mode. -BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) +BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp) { const BOOL needsRebuild = TRUE; // Just nuke the context and start over. BOOL result = true; @@ -746,7 +766,7 @@ BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL if(needsRebuild) { destroyContext(); - result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); + result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, vsync_mode); if (result) { gGLManager.initGL(); @@ -987,6 +1007,16 @@ void LLWindowSDL::setFSAASamples(const U32 samples) mFSAASamples = samples; } +S32 LLWindowSDL::getVsyncMode() +{ + return mVsyncMode; +} + +void LLWindowSDL::setVsyncMode(const S32 vsync_mode) +{ + mVsyncMode = vsync_mode +} + F32 LLWindowSDL::getGamma() { return 1/mGamma; diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index 134554e6e..3334fcb98 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -65,7 +65,7 @@ public: /*virtual*/ BOOL setPosition(LLCoordScreen position); /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp = NULL); /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); /*virtual*/ void showCursor(); @@ -92,6 +92,8 @@ public: /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma /*virtual*/ U32 getFSAASamples(); /*virtual*/ void setFSAASamples(const U32 samples); + /*virtual*/ void setVsyncMode(const S32 vsync_mode); + /*virtual*/ S32 getVsyncMode(); /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } /*virtual*/ void processMiscNativeEvents(); @@ -149,7 +151,7 @@ public: protected: LLWindowSDL(LLWindowCallbacks* callbacks, const std::string& title, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, + BOOL fullscreen, BOOL clearBg, const S32 vsync_mode, BOOL ignore_pixel_depth, U32 fsaa_samples); ~LLWindowSDL(); @@ -174,7 +176,7 @@ protected: // // create or re-create the GL context/window. Called from the constructor and switchContext(). - BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync); + BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, const S32 vsync_mode); void destroyContext(); void setupFailure(const std::string& text, const std::string& caption, U32 type); void fixWindowSize(void); @@ -194,6 +196,7 @@ protected: F32 mOverrideAspectRatio; F32 mGamma; U32 mFSAASamples; + S32 mVsyncMode; int mSDLFlags; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 807c547bd..8e6b4c57c 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -363,7 +363,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, + const S32 vsync_mode, BOOL ignore_pixel_depth, U32 fsaa_samples) : LLWindow(callbacks, fullscreen, flags) @@ -903,7 +903,7 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size) } // changing fullscreen resolution -BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) +BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp) { GLuint pixel_format; DEVMODE dev_mode; @@ -1650,14 +1650,27 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO } // Disable vertical sync for swap - if (disable_vsync && wglSwapIntervalEXT) + if(wglSwapIntervalEXT) { - LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL; - wglSwapIntervalEXT(0); - } - else - { - LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL; + if (vsync_mode == 0) + { + LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL; + wglSwapIntervalEXT(0); + } + else if(vsync_mode == -1) + { + LL_DEBUGS("Window") << "Enabling adaptive vertical sync" << LL_ENDL; + if(wglSwapIntervalEXT(-1) == 0) + { + LL_DEBUGS("Window") << "Failed to enable adaptive vertical sync. Disabling vsync." << LL_ENDL; + wglSwapIntervalEXT(0); + } + } + else + { + LL_DEBUGS("Window") << "Enabling vertical sync" << LL_ENDL; + wglSwapIntervalEXT(1); + } } SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this); @@ -3030,6 +3043,16 @@ U32 LLWindowWin32::getFSAASamples() return mFSAASamples; } +S32 LLWindowWin32::getVsyncMode() +{ + return mVsyncMode; +} + +void LLWindowWin32::setVsyncMode(const S32 vsync_mode) +{ + mVsyncMode = vsync_mode; +} + LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions) { if (!mSupportedResolutions) diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 9f678b96c..07dc67c20 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -59,7 +59,7 @@ public: /*virtual*/ BOOL setPosition(LLCoordScreen position); /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp = NULL); /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); /*virtual*/ void showCursor(); @@ -80,6 +80,8 @@ public: /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma /*virtual*/ void setFSAASamples(const U32 fsaa_samples); /*virtual*/ U32 getFSAASamples(); + /*virtual*/ void setVsyncMode(const S32 vsync_mode); + /*virtual*/ S32 getVsyncMode(); /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } /*virtual*/ void gatherInput(); @@ -121,7 +123,7 @@ public: protected: LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, + BOOL fullscreen, BOOL clearBg, const S32 vsync_mode, BOOL ignore_pixel_depth, U32 fsaa_samples); ~LLWindowWin32(); @@ -186,6 +188,7 @@ protected: F32 mCurrentGamma; U32 mFSAASamples; + S32 mVsyncMode; WORD mPrevGammaRamp[256*3]; WORD mCurrentGammaRamp[256*3]; diff --git a/indra/newview/app_settings/settings_sh.xml b/indra/newview/app_settings/settings_sh.xml index 83731c3ec..c06a6f710 100644 --- a/indra/newview/app_settings/settings_sh.xml +++ b/indra/newview/app_settings/settings_sh.xml @@ -251,5 +251,16 @@ Value 1 + SHRenderVsyncMode + + Comment + Desired vertical sychronization method. (0 = Disabled, 1 = Standard [Double-buffered], -1 = Adaptive [if supported]) + Persist + 1 + Type + S32 + Value + 0 + diff --git a/indra/newview/llpaneldisplay.cpp b/indra/newview/llpaneldisplay.cpp index 0f7184757..9fc9b96c9 100644 --- a/indra/newview/llpaneldisplay.cpp +++ b/indra/newview/llpaneldisplay.cpp @@ -334,6 +334,16 @@ BOOL LLPanelDisplay::postBuild() mVBOStream = getChild("vbo_stream"); + if(gGLManager.mIsATI) //AMD gpus don't go beyond 8x fsaa. + { + LLComboBox* fsaa = getChild("fsaa"); + fsaa->remove("16x"); + } + if(!gGLManager.mHasAdaptiveVsync) + { + LLComboBox* vsync = getChild("vsync"); + vsync->remove("VSyncAdaptive"); + } refresh(); @@ -447,8 +457,10 @@ void LLPanelDisplay::refresh() mGamma = gSavedSettings.getF32("RenderGamma"); mVideoCardMem = gSavedSettings.getS32("TextureMemory"); mFogRatio = gSavedSettings.getF32("RenderFogRatio"); + mVsyncMode = gSavedSettings.getS32("SHRenderVsyncMode"); childSetValue("fsaa", (LLSD::Integer) mFSAASamples); + childSetValue("vsync", (LLSD::Integer) mVsyncMode); refreshEnabledState(); } @@ -846,13 +858,22 @@ void LLPanelDisplay::cancel() gSavedSettings.setF32("RenderGamma", mGamma); gSavedSettings.setS32("TextureMemory", mVideoCardMem); gSavedSettings.setF32("RenderFogRatio", mFogRatio); + gSavedSettings.setS32("SHRenderVsyncMode", mVsyncMode); } void LLPanelDisplay::apply() { U32 fsaa_value = childGetValue("fsaa").asInteger(); + S32 vsync_value = childGetValue("vsync").asInteger(); + + if(vsync_value == -1 && !gGLManager.mHasAdaptiveVsync) + vsync_value = 0; + bool apply_fsaa_change = !gSavedSettings.getBOOL("RenderUseFBO") && (mFSAASamples != fsaa_value); + bool apply_vsync_change = vsync_value != mVsyncMode; + gSavedSettings.setU32("RenderFSAASamples", fsaa_value); + gSavedSettings.setS32("SHRenderVsyncMode", vsync_value); applyResolution(); @@ -865,7 +886,7 @@ void LLPanelDisplay::apply() // Hardware tab //Still do a bit of voodoo here. V2 forces restart to change FSAA with FBOs off. //Let's not do that, and instead do pre-V2 FSAA change handling for that particular case - if(apply_fsaa_change) + if(apply_fsaa_change || apply_vsync_change) { bool logged_in = (LLStartUp::getStartupState() >= STATE_STARTED); LLWindow* window = gViewerWindow->getWindow(); @@ -875,7 +896,7 @@ void LLPanelDisplay::apply() LLGLState::checkTextureChannels(); gViewerWindow->changeDisplaySettings(window->getFullscreen(), size, - gSavedSettings.getBOOL("DisableVerticalSync"), + vsync_value, logged_in); LLGLState::checkStates(); LLGLState::checkTextureChannels(); diff --git a/indra/newview/llpaneldisplay.h b/indra/newview/llpaneldisplay.h index 9b39ee555..1652b497b 100644 --- a/indra/newview/llpaneldisplay.h +++ b/indra/newview/llpaneldisplay.h @@ -194,6 +194,7 @@ protected: F32 mGamma; S32 mVideoCardMem; F32 mFogRatio; + S32 mVsyncMode; // if the quality radio buttons are changed void onChangeQuality(LLUICtrl* caller); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 4f2e5c931..455c3b272 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1640,12 +1640,18 @@ LLViewerWindow::LLViewerWindow( LLViewerWindow::sMovieBaseName = "SLmovie"; resetSnapshotLoc(); + S32 vsync_mode = gSavedSettings.getS32("SHRenderVsyncMode"); + if(vsync_mode == -1 && !gGLManager.mHasAdaptiveVsync) + { + vsync_mode = 0; //Disable vsync if adaptive is desired yet isn't supported. + } + // create window mWindow = LLWindowManager::createWindow(this, title, name, x, y, width, height, 0, fullscreen, gNoRender, - gSavedSettings.getBOOL("DisableVerticalSync"), + vsync_mode, !gNoRender, ignore_pixel_depth, gSavedSettings.getBOOL("RenderUseFBO") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled @@ -4436,14 +4442,20 @@ void LLViewerWindow::movieSize(S32 new_width, S32 new_height) BORDERHEIGHT = size.mY- y; LLCoordScreen new_size(new_width + BORDERWIDTH, new_height + BORDERHEIGHT); - BOOL disable_sync = gSavedSettings.getBOOL("DisableVerticalSync"); + + S32 vsync_mode = gSavedSettings.getS32("SHRenderVsyncMode"); + if(vsync_mode == -1 && !gGLManager.mHasAdaptiveVsync) + { + vsync_mode = 0; //Disable vsync if adaptive is desired yet isn't supported. + } + if (gViewerWindow->getWindow()->getFullscreen()) { LLGLState::checkStates(); LLGLState::checkTextureChannels(); gViewerWindow->changeDisplaySettings(FALSE, new_size, - disable_sync, + vsync_mode, TRUE); LLGLState::checkStates(); LLGLState::checkTextureChannels(); @@ -5429,9 +5441,16 @@ BOOL LLViewerWindow::checkSettings() LLGLState::checkStates(); LLGLState::checkTextureChannels(); + + S32 vsync_mode = gSavedSettings.getS32("SHRenderVsyncMode"); + if(vsync_mode == -1 && !gGLManager.mHasAdaptiveVsync) + { + vsync_mode = 0; //Disable vsync if adaptive is desired yet isn't supported. + } + changeDisplaySettings(TRUE, desired_screen_size, - gSavedSettings.getBOOL("DisableVerticalSync"), + vsync_mode, mShowFullscreenProgress); LLGLState::checkStates(); LLGLState::checkTextureChannels(); @@ -5472,7 +5491,7 @@ void LLViewerWindow::restartDisplay(BOOL show_progress_bar) } } -BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar) +BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, const S32 vsync_mode, BOOL show_progress_bar) { BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized"); mWantFullscreen = fullscreen; @@ -5491,6 +5510,7 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, U32 fsaa = gSavedSettings.getU32("RenderFSAASamples"); U32 old_fsaa = mWindow->getFSAASamples(); + // going from windowed to windowed if (!old_fullscreen && !fullscreen) { @@ -5500,7 +5520,7 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, mWindow->setSize(size); } - if (fsaa == old_fsaa) + if (fsaa == old_fsaa && vsync_mode == mWindow->getFSAASamples()) { return TRUE; } @@ -5539,13 +5559,14 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, } mWindow->setFSAASamples(fsaa); + mWindow->setVsyncMode(vsync_mode); - result_first_try = mWindow->switchContext(fullscreen, size, disable_vsync, &new_pos); + result_first_try = mWindow->switchContext(fullscreen, size, vsync_mode, &new_pos); if (!result_first_try) { // try to switch back mWindow->setFSAASamples(old_fsaa); - result_second_try = mWindow->switchContext(old_fullscreen, old_size, disable_vsync, &new_pos); + result_second_try = mWindow->switchContext(old_fullscreen, old_size, vsync_mode, &new_pos); if (!result_second_try) { diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 7ec0f3ec3..7e47a1a1b 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -386,7 +386,7 @@ public: void requestResolutionUpdate(bool fullscreen_checked); BOOL checkSettings(); void restartDisplay(BOOL show_progress_bar); - BOOL changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar); + BOOL changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, const S32 vsync_mode, BOOL show_progress_bar); BOOL getIgnoreDestroyWindow() { return mIgnoreActivate; } F32 getDisplayAspectRatio() const; const LLVector2& getDisplayScale() const { return mDisplayScale; } diff --git a/indra/newview/skins/default/xui/en-us/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en-us/panel_preferences_graphics1.xml index e2c4376ac..a2652e226 100644 --- a/indra/newview/skins/default/xui/en-us/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en-us/panel_preferences_graphics1.xml @@ -118,6 +118,12 @@ 4x 8x 16x + + VSync: + + Disabled + Standard + Adaptive - + Note: The Gamma and Fog Distance Ratio From dbd7de628faf80430066cf1793129a9b604ab875 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Fri, 28 Mar 2014 08:50:02 +0100 Subject: [PATCH 082/115] Fix compilation with gcc --- indra/newview/llfloaterexploreanimations.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llfloaterexploreanimations.cpp b/indra/newview/llfloaterexploreanimations.cpp index 41f1c1dfb..bfc08d700 100644 --- a/indra/newview/llfloaterexploreanimations.cpp +++ b/indra/newview/llfloaterexploreanimations.cpp @@ -43,7 +43,7 @@ void LLFloaterExploreAnimations::show() } LLFloaterExploreAnimations::LLFloaterExploreAnimations(const LLUUID avatarid) -: LLInstanceTracker(avatarid) +: LLInstanceTracker(avatarid) , mAnimPreview(256, 256) { mLastMouseX = 0; From ba0fd794d757bd89a834d92d2e6d187682a1d7ba Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Fri, 28 Mar 2014 16:20:38 +0100 Subject: [PATCH 083/115] Compile fix --- indra/llwindow/llwindowmacosx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 096742dc9..91e4c00cf 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1348,7 +1348,7 @@ S32 LLWindowMacOSX::getVsyncMode() } void LLWindowMacOSX::setVsyncMode(const S32 vsync_mode) { - mVsyncMode = vsync_mode + mVsyncMode = vsync_mode; mForceRebuild = TRUE; } From e70342b3560d26f8bbf7c95b03ef5b19b17fa7cd Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Fri, 28 Mar 2014 16:42:27 +0100 Subject: [PATCH 084/115] Removed duplicate check introduced in the last change --- indra/newview/llcrashlogger.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/indra/newview/llcrashlogger.cpp b/indra/newview/llcrashlogger.cpp index 7a3d7c8af..cf06a402d 100644 --- a/indra/newview/llcrashlogger.cpp +++ b/indra/newview/llcrashlogger.cpp @@ -396,8 +396,6 @@ void LLCrashLogger::checkCrashDump() if (pref == 2) return; //never send mCrashHost = gSavedSettings.getString("CrashHostUrl"); - // Don't send if there's no crash host. :O - if (mCrashHost.empty()) return; std::string dumpDir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "") + "singularity-debug"; // Do we have something to send, and somewhere to send it From 9ed2dc755c66d701d925fc2dc1a54756b19473f7 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 28 Mar 2014 17:14:57 -0500 Subject: [PATCH 085/115] Always set materials mask if deferred for materials/alpha pools. Fixes potential crash in LLDrawPoolAlpha::renderAlpha --- 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 121b4388c..e1cae3099 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4195,7 +4195,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 pool_type = facep->getPoolType(); bool cmp_bump = (type == LLRenderPass::PASS_BUMP) || (type == LLRenderPass::PASS_POST_BUMP); - bool cmp_mat = (!alt_batching) || LLPipeline::sRenderDeferred && facep->getTextureEntry()->getColor().mV[3] >= 0.999f && + bool cmp_mat = (!alt_batching) || LLPipeline::sRenderDeferred && /*facep->getTextureEntry()->getColor().mV[3] >= 0.999f &&*/ ((pool_type == LLDrawPool::POOL_MATERIALS) || (pool_type == LLDrawPool::POOL_ALPHA)); bool cmp_shiny = (!alt_batching) ? !!mat : (mat && cmp_mat); bool cmp_fullbright = !alt_batching || cmp_shiny || pool_type == LLDrawPool::POOL_ALPHA; From 8889e2de6421e489b8e0dbaf55387d81afc1f595 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Mon, 31 Mar 2014 12:22:12 -0400 Subject: [PATCH 086/115] Fix icon packaging on mac. --- indra/newview/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 03284d6e0..7cdff9888 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1140,7 +1140,7 @@ if (DARWIN) # Add resource files to the project. set(viewer_RESOURCE_FILES - ${VIEWER_BRANDING_ID}.icns + ${VIEWER_BRANDING_ID}_icon.icns macview.r gpu_table.txt SecondLife.nib/ @@ -1702,7 +1702,7 @@ if (DARWIN) PROPERTIES OUTPUT_NAME "${product}" MACOSX_BUNDLE_INFO_STRING "A stable third-party Second Life viewer." - MACOSX_BUNDLE_ICON_FILE "${VIEWER_BRANDING_ID}.icns" + MACOSX_BUNDLE_ICON_FILE "${VIEWER_BRANDING_ID}_icon.icns" MACOSX_BUNDLE_GUI_IDENTIFIER "${VIEWER_BRANDING_NAME}" MACOSX_BUNDLE_LONG_VERSION_STRING "${viewer_VERSION}" MACOSX_BUNDLE_BUNDLE_NAME "${VIEWER_BRANDING_NAME}" From f53e36c430df2ecb46d7846953c6ca834aec0e47 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Mon, 31 Mar 2014 13:12:33 -0400 Subject: [PATCH 087/115] Fix not being able to buy land because of inversed RLVa logic. --- indra/newview/llviewerparcelmgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 6a77426b9..977d8fede 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -2228,7 +2228,7 @@ bool LLViewerParcelMgr::canAgentBuyParcel(LLParcel* parcel, bool forGroup) const void LLViewerParcelMgr::startBuyLand(BOOL is_for_group) { // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) - if (RlvActions::isRlvEnabled() && RlvActions::canShowLocation()) + if (RlvActions::isRlvEnabled() && !RlvActions::canShowLocation()) return; // [/RLVa:KB] if (selectionEmpty()) selectParcelAt(gAgent.getPositionGlobal()); From a3531b931bb1b029392fb1fd6e66aa7a48a4f19d Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Thu, 3 Apr 2014 01:27:27 -0400 Subject: [PATCH 088/115] Feature Request: Ding for groups and conference chats. --- indra/newview/llimpanel.cpp | 3 ++- .../default/xui/en-us/floater_instant_message_ad_hoc.xml | 5 ++++- .../en-us/floater_instant_message_ad_hoc_concisebuttons.xml | 5 ++++- .../default/xui/en-us/floater_instant_message_group.xml | 5 ++++- .../en-us/floater_instant_message_group_concisebuttons.xml | 5 ++++- 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index af2659486..aaf79dbfc 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -60,7 +60,7 @@ #include "llviewerwindow.h" #include "llvoicechannel.h" -#include "boost/algorithm/string.hpp" +#include // [RLVa:KB] - Checked: 2013-05-10 (RLVa-1.4.9) #include "rlvactions.h" @@ -321,6 +321,7 @@ LLFloaterIMPanel::LLFloaterIMPanel( case IM_SESSION_GROUP_START: case IM_SESSION_INVITE: case IM_SESSION_CONFERENCE_START: + mCommitCallbackRegistrar.add("FlipDing", boost::bind(boost::lambda::_1 = !boost::lambda::_1, boost::ref(mDing))); // determine whether it is group or conference session if (gAgent.isInGroup(mSessionUUID)) { diff --git a/indra/newview/skins/default/xui/en-us/floater_instant_message_ad_hoc.xml b/indra/newview/skins/default/xui/en-us/floater_instant_message_ad_hoc.xml index 332def37b..54cdff914 100644 --- a/indra/newview/skins/default/xui/en-us/floater_instant_message_ad_hoc.xml +++ b/indra/newview/skins/default/xui/en-us/floater_instant_message_ad_hoc.xml @@ -11,7 +11,10 @@ + + + + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a5b68f2da24d79cc2d94b55ad05aec9e76bdd465 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 2 Dec 2013 16:13:08 +0100 Subject: [PATCH 090/115] Changes to llkeyframemotionparam.cpp as result of audit. These changes were the result of my Motion leak audit. However, there is a serious problem with LLKeyframeMotionParam in that it stores plain pointers to objects that can and will be deleted by other objects. Its the classicial LL example of coding non-Object-Oriented badly maintainable and instable code. I cannot make sure this won't go wrong for the simple fact that LLKeyframeMotionParam is not used at ALL in our code. Hence, the next commit will rather delete this file. This commit is merely to have a record of this finding. --- indra/llcharacter/llkeyframemotionparam.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp index 4df1ef46b..3f3a44e52 100644 --- a/indra/llcharacter/llkeyframemotionparam.cpp +++ b/indra/llcharacter/llkeyframemotionparam.cpp @@ -68,11 +68,18 @@ LLKeyframeMotionParam::~LLKeyframeMotionParam() iter != mParameterizedMotions.end(); ++iter) { motion_list_t& motionList = iter->second; +#if 0 + // Singu note: this class is NOT responsible for cleaning up paramMotion.mMotion. + // They were obtained in LLKeyframeMotionParam::addKeyframeMotion by calling + // LLCharacter::createMotion which returns LLMotionController::createMotion + // which is responsible for cleaning up (by storing the pointers in + // LLMotionController::mAllMotions). for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) { const ParameterizedMotion& paramMotion = *iter2; delete paramMotion.mMotion; } +#endif motionList.clear(); } mParameterizedMotions.clear(); @@ -98,7 +105,11 @@ LLMotion::LLMotionInitStatus LLKeyframeMotionParam::onInitialize(LLCharacter *ch { const ParameterizedMotion& paramMotion = *iter2; LLMotion* motion = paramMotion.mMotion; - motion->onInitialize(character); + if (motion->onInitialize(character) != STATUS_SUCCESS) + { + llwarns << "Skipping uninitialize motion!" << llendl; + continue; + } if (motion->getDuration() > mEaseInDuration) { From ba2bf9f366c6a40d2a33cce5a75665bce525ecee Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 2 Dec 2013 16:18:23 +0100 Subject: [PATCH 091/115] Get rid of unused and irrepairable code. --- indra/llcharacter/CMakeLists.txt | 2 - indra/llcharacter/llkeyframemotionparam.cpp | 467 -------------------- indra/llcharacter/llkeyframemotionparam.h | 176 -------- 3 files changed, 645 deletions(-) delete mode 100644 indra/llcharacter/llkeyframemotionparam.cpp delete mode 100644 indra/llcharacter/llkeyframemotionparam.h diff --git a/indra/llcharacter/CMakeLists.txt b/indra/llcharacter/CMakeLists.txt index 6652333ef..8dda476d9 100644 --- a/indra/llcharacter/CMakeLists.txt +++ b/indra/llcharacter/CMakeLists.txt @@ -29,7 +29,6 @@ set(llcharacter_SOURCE_FILES lljointsolverrp3.cpp llkeyframefallmotion.cpp llkeyframemotion.cpp - llkeyframemotionparam.cpp llkeyframestandmotion.cpp llkeyframewalkmotion.cpp llmotion.cpp @@ -57,7 +56,6 @@ set(llcharacter_HEADER_FILES lljointstate.h llkeyframefallmotion.h llkeyframemotion.h - llkeyframemotionparam.h llkeyframestandmotion.h llkeyframewalkmotion.h llmotion.h diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp deleted file mode 100644 index 3f3a44e52..000000000 --- a/indra/llcharacter/llkeyframemotionparam.cpp +++ /dev/null @@ -1,467 +0,0 @@ -/** - * @file llkeyframemotionparam.cpp - * @brief Implementation of LLKeyframeMotion class. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -//----------------------------------------------------------------------------- -// Header Files -//----------------------------------------------------------------------------- -#include "linden_common.h" - -#include "llkeyframemotionparam.h" -#include "llcharacter.h" -#include "llmath.h" -#include "m3math.h" -#include "lldir.h" -#include "llanimationstates.h" - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam class -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam() -// Class Constructor -//----------------------------------------------------------------------------- -LLKeyframeMotionParam::LLKeyframeMotionParam( const LLUUID &id) : LLMotion(id) -{ - mDefaultKeyframeMotion = NULL; - mCharacter = NULL; - - mEaseInDuration = 0.f; - mEaseOutDuration = 0.f; - mDuration = 0.f; - mPriority = LLJoint::LOW_PRIORITY; -} - - -//----------------------------------------------------------------------------- -// ~LLKeyframeMotionParam() -// Class Destructor -//----------------------------------------------------------------------------- -LLKeyframeMotionParam::~LLKeyframeMotionParam() -{ - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - motion_list_t& motionList = iter->second; -#if 0 - // Singu note: this class is NOT responsible for cleaning up paramMotion.mMotion. - // They were obtained in LLKeyframeMotionParam::addKeyframeMotion by calling - // LLCharacter::createMotion which returns LLMotionController::createMotion - // which is responsible for cleaning up (by storing the pointers in - // LLMotionController::mAllMotions). - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; - delete paramMotion.mMotion; - } -#endif - motionList.clear(); - } - mParameterizedMotions.clear(); -} - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::onInitialize(LLCharacter *character) -//----------------------------------------------------------------------------- -LLMotion::LLMotionInitStatus LLKeyframeMotionParam::onInitialize(LLCharacter *character) -{ - mCharacter = character; - - if (!loadMotions()) - { - return STATUS_FAILURE; - } - - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; - LLMotion* motion = paramMotion.mMotion; - if (motion->onInitialize(character) != STATUS_SUCCESS) - { - llwarns << "Skipping uninitialize motion!" << llendl; - continue; - } - - if (motion->getDuration() > mEaseInDuration) - { - mEaseInDuration = motion->getEaseInDuration(); - } - - if (motion->getEaseOutDuration() > mEaseOutDuration) - { - mEaseOutDuration = motion->getEaseOutDuration(); - } - - if (motion->getDuration() > mDuration) - { - mDuration = motion->getDuration(); - } - - if (motion->getPriority() > mPriority) - { - mPriority = motion->getPriority(); - } - - LLPose *pose = motion->getPose(); - - mPoseBlender.addMotion(motion); - for (LLJointState *jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState()) - { - LLPose *blendedPose = mPoseBlender.getBlendedPose(); - blendedPose->addJointState(jsp); - } - } - } - - return STATUS_SUCCESS; -} - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::onActivate() -//----------------------------------------------------------------------------- -BOOL LLKeyframeMotionParam::onActivate() -{ - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; - paramMotion.mMotion->activate(mActivationTimestamp); - } - } - return TRUE; -} - - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::onUpdate() -//----------------------------------------------------------------------------- -BOOL LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask) -{ - F32 weightFactor = 1.f / (F32)mParameterizedMotions.size(); - - // zero out all pose weights - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; -// llinfos << "Weight for pose " << paramMotion.mMotion->getName() << " is " << paramMotion.mMotion->getPose()->getWeight() << llendl; - paramMotion.mMotion->getPose()->setWeight(0.f); - } - } - - - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - const std::string& paramName = iter->first; - F32* paramValue = (F32 *)mCharacter->getAnimationData(paramName); - if (NULL == paramValue) // unexpected, but... - { - llwarns << "paramValue == NULL" << llendl; - continue; - } - - // DANGER! Do not modify mParameterizedMotions while using these pointers! - const ParameterizedMotion* firstMotion = NULL; - const ParameterizedMotion* secondMotion = NULL; - - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; - paramMotion.mMotion->onUpdate(time, joint_mask); - - F32 distToParam = paramMotion.mParam - *paramValue; - - if ( distToParam <= 0.f) - { - // keep track of the motion closest to the parameter value - firstMotion = ¶mMotion; - } - else - { - // we've passed the parameter value - // so store the first motion we find as the second one we want to blend... - if (firstMotion && !secondMotion ) - { - secondMotion = ¶mMotion; - } - //...or, if we've seen no other motion so far, make sure we blend to this only - else if (!firstMotion) - { - firstMotion = ¶mMotion; - secondMotion = ¶mMotion; - } - } - } - - LLPose *firstPose; - LLPose *secondPose; - - if (firstMotion) - firstPose = firstMotion->mMotion->getPose(); - else - firstPose = NULL; - - if (secondMotion) - secondPose = secondMotion->mMotion->getPose(); - else - secondPose = NULL; - - // now modify weight of the subanim (only if we are blending between two motions) - if (firstMotion && secondMotion) - { - if (firstMotion == secondMotion) - { - firstPose->setWeight(weightFactor); - } - else if (firstMotion->mParam == secondMotion->mParam) - { - firstPose->setWeight(0.5f * weightFactor); - secondPose->setWeight(0.5f * weightFactor); - } - else - { - F32 first_weight = 1.f - - ((llclamp(*paramValue - firstMotion->mParam, 0.f, (secondMotion->mParam - firstMotion->mParam))) / - (secondMotion->mParam - firstMotion->mParam)); - first_weight = llclamp(first_weight, 0.f, 1.f); - - F32 second_weight = 1.f - first_weight; - - firstPose->setWeight(first_weight * weightFactor); - secondPose->setWeight(second_weight * weightFactor); - -// llinfos << "Parameter " << *paramName << ": " << *paramValue << llendl; -// llinfos << "Weights " << firstPose->getWeight() << " " << secondPose->getWeight() << llendl; - } - } - else if (firstMotion && !secondMotion) - { - firstPose->setWeight(weightFactor); - } - } - - // blend poses - mPoseBlender.blendAndApply(); - - llinfos << "Param Motion weight " << mPoseBlender.getBlendedPose()->getWeight() << llendl; - - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::onDeactivate() -//----------------------------------------------------------------------------- -void LLKeyframeMotionParam::onDeactivate() -{ - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; - paramMotion.mMotion->onDeactivate(); - } - } -} - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::addKeyframeMotion() -//----------------------------------------------------------------------------- -BOOL LLKeyframeMotionParam::addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value) -{ - LLMotion *newMotion = mCharacter->createMotion( id ); - - if (!newMotion) - { - return FALSE; - } - - newMotion->setName(name); - - // now add motion to this list - mParameterizedMotions[param].insert(ParameterizedMotion(newMotion, value)); - - return TRUE; -} - - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::setDefaultKeyframeMotion() -//----------------------------------------------------------------------------- -void LLKeyframeMotionParam::setDefaultKeyframeMotion(char *name) -{ - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; - if (paramMotion.mMotion->getName() == name) - { - mDefaultKeyframeMotion = paramMotion.mMotion; - } - } - } -} - -//----------------------------------------------------------------------------- -// loadMotions() -//----------------------------------------------------------------------------- -BOOL LLKeyframeMotionParam::loadMotions() -{ - //------------------------------------------------------------------------- - // Load named file by concatenating the character prefix with the motion name. - // Load data into a buffer to be parsed. - //------------------------------------------------------------------------- - //std::string path = gDirUtilp->getExpandedFilename(LL_PATH_MOTIONS,mCharacter->getAnimationPrefix()) - // + "_" + getName() + ".llp"; - //RN: deprecated unused reference to "motion" directory - std::string path; - - - //------------------------------------------------------------------------- - // open the file - //------------------------------------------------------------------------- - S32 fileSize = 0; - LLAPRFile infile(path, LL_APR_R, &fileSize); - apr_file_t* fp = infile.getFileHandle() ; - if (!fp || fileSize == 0) - { - llinfos << "ERROR: can't open: " << path << llendl; - return FALSE; - } - - // allocate a text buffer - try - { - std::vector text(fileSize+1); - - //------------------------------------------------------------------------- - // load data from file into buffer - //------------------------------------------------------------------------- - bool error = false; - char *p = &text[0]; - while ( 1 ) - { - if (apr_file_eof(fp) == APR_EOF) - { - break; - } - if (apr_file_gets(p, 1024, fp) != APR_SUCCESS) - { - error = true; - break; - } - while ( *(++p) ) - ; - } - - //------------------------------------------------------------------------- - // close the file - //------------------------------------------------------------------------- - infile.close(); - - //------------------------------------------------------------------------- - // check for error - //------------------------------------------------------------------------- - llassert( p <= (&text[0] + fileSize) ); - - if ( error ) - { - llinfos << "ERROR: error while reading from " << path << llendl; - return FALSE; - } - - llinfos << "Loading parametric keyframe data for: " << getName() << llendl; - - //------------------------------------------------------------------------- - // parse the text and build keyframe data structures - //------------------------------------------------------------------------- - p = &text[0]; - S32 num; - char strA[80]; /* Flawfinder: ignore */ - char strB[80]; /* Flawfinder: ignore */ - F32 floatA = 0.0f; - - - //------------------------------------------------------------------------- - // get priority - //------------------------------------------------------------------------- - BOOL isFirstMotion = TRUE; - num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */ - - while(1) - { - if (num == 0 || num == EOF) break; - if ((num != 3)) - { - llinfos << "WARNING: can't read parametric motion" << llendl; - return FALSE; - } - - addKeyframeMotion(strA, gAnimLibrary.stringToAnimState(std::string(strA)), strB, floatA); - if (isFirstMotion) - { - isFirstMotion = FALSE; - setDefaultKeyframeMotion(strA); - } - - p = strstr(p, "\n"); - if (!p) - { - break; - } - - p++; - num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */ - } - - return TRUE; - } - catch(std::bad_alloc) - { - llinfos << "ERROR: Unable to allocate keyframe text buffer." << llendl; - return FALSE; - } -} - -// End diff --git a/indra/llcharacter/llkeyframemotionparam.h b/indra/llcharacter/llkeyframemotionparam.h deleted file mode 100644 index f74aea276..000000000 --- a/indra/llcharacter/llkeyframemotionparam.h +++ /dev/null @@ -1,176 +0,0 @@ -/** - * @file llkeyframemotionparam.h - * @brief Implementation of LLKeframeMotionParam class. - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLKEYFRAMEMOTIONPARAM_H -#define LL_LLKEYFRAMEMOTIONPARAM_H - -//----------------------------------------------------------------------------- -// Header files -//----------------------------------------------------------------------------- - -#include - -#include "llmotion.h" -#include "lljointstate.h" -#include "v3math.h" -#include "llquaternion.h" -#include "linked_lists.h" -#include "llkeyframemotion.h" - -//----------------------------------------------------------------------------- -// class LLKeyframeMotionParam -//----------------------------------------------------------------------------- -class LLKeyframeMotionParam : - public LLMotion -{ -public: - // Constructor - LLKeyframeMotionParam(const LLUUID &id); - - // Destructor - virtual ~LLKeyframeMotionParam(); - -public: - //------------------------------------------------------------------------- - // functions to support MotionController and MotionRegistry - //------------------------------------------------------------------------- - - // static constructor - // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLKeyframeMotionParam(id); } - -public: - //------------------------------------------------------------------------- - // animation callbacks to be implemented by subclasses - //------------------------------------------------------------------------- - - // motions must specify whether or not they loop - virtual BOOL getLoop() { - return TRUE; - } - - // motions must report their total duration - virtual F32 getDuration() { - return mDuration; - } - - // motions must report their "ease in" duration - virtual F32 getEaseInDuration() { - return mEaseInDuration; - } - - // motions must report their "ease out" duration. - virtual F32 getEaseOutDuration() { - return mEaseOutDuration; - } - - // motions must report their priority - virtual LLJoint::JointPriority getPriority() { - return mPriority; - } - - virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } - - // called to determine when a motion should be activated/deactivated based on avatar pixel coverage - virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_KEYFRAME; } - - // run-time (post constructor) initialization, - // called after parameters have been set - // must return true to indicate success and be available for activation - virtual LLMotionInitStatus onInitialize(LLCharacter *character); - - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate(); - - // called per time step - // must return TRUE while it is active, and - // must return FALSE when the motion is completed. - virtual BOOL onUpdate(F32 time, U8* joint_mask); - - // called when a motion is deactivated - virtual void onDeactivate(); - - virtual LLPose* getPose() { return mPoseBlender.getBlendedPose();} - -protected: - //------------------------------------------------------------------------- - // new functions defined by this subclass - //------------------------------------------------------------------------- - struct ParameterizedMotion - { - ParameterizedMotion(LLMotion* motion, F32 param) : mMotion(motion), mParam(param) {} - LLMotion* mMotion; - F32 mParam; - }; - - // add a motion and associated parameter triplet - BOOL addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value); - - // set default motion for LOD and retrieving blend constants - void setDefaultKeyframeMotion(char *); - - BOOL loadMotions(); - -protected: - //------------------------------------------------------------------------- - // Member Data - //------------------------------------------------------------------------- - - struct compare_motions - { - bool operator() (const ParameterizedMotion& a, const ParameterizedMotion& b) const - { - if (a.mParam != b.mParam) - return (a.mParam < b.mParam); - else - return a.mMotion < b.mMotion; - } - }; - - typedef std::set < ParameterizedMotion, compare_motions > motion_list_t; - typedef std::map motion_map_t; - motion_map_t mParameterizedMotions; - LLMotion* mDefaultKeyframeMotion; - LLCharacter* mCharacter; - LLPoseBlender mPoseBlender; - - F32 mEaseInDuration; - F32 mEaseOutDuration; - F32 mDuration; - LLJoint::JointPriority mPriority; - - LLUUID mTransactionID; -}; - -#endif // LL_LLKEYFRAMEMOTIONPARAM_H From 116fe01dee505ee0ffeab1f7761b632f445c5d7c Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 3 Dec 2013 02:02:07 +0100 Subject: [PATCH 092/115] Add AIDebugInstanceCounter Prints number of instances upon construction and destruction. Usage: class LLSomething : public AIDebugInstanceCounter ... --- indra/cwdebug/debug.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/indra/cwdebug/debug.h b/indra/cwdebug/debug.h index 3c59db690..58e0c6ac9 100644 --- a/indra/cwdebug/debug.h +++ b/indra/cwdebug/debug.h @@ -392,6 +392,40 @@ void InstanceTracker::dump(void) } // namespace debug +template +class AIDebugInstanceCounter +{ + public: + static int sInstanceCount; + + protected: + static void print_count(char const* name, int count, bool destruction); + + AIDebugInstanceCounter() + { + print_count(typeid(T).name(), ++sInstanceCount, false); + } + AIDebugInstanceCounter(AIDebugInstanceCounter const&) + { + print_count(typeid(T).name(), ++sInstanceCount, false); + } + ~AIDebugInstanceCounter() + { + print_count(typeid(T).name(), --sInstanceCount, true); + } +}; + +//static +template +int AIDebugInstanceCounter::sInstanceCount; + +//static +template +void AIDebugInstanceCounter::print_count(char const* name, int count, bool destruction) +{ + Dout(dc::notice, (destruction ? "Destructed " : "Constructing ") << name << ", now " << count << " instance" << ((count == 1) ? "." : "s.")); +} + //! Debugging macro. // // Print "Entering " << \a data to channel \a cntrl and increment From 61097dac7291cc37b8ab1240aebd2f4fd6f8d903 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 3 Dec 2013 03:15:25 +0100 Subject: [PATCH 093/115] Auto clean up motion cache. Conflicts: indra/llcharacter/llkeyframemotion.cpp indra/llcharacter/llkeyframemotion.h indra/newview/llfloaterbvhpreview.cpp --- indra/llcharacter/llcharacter.cpp | 1 - indra/llcharacter/llheadrotmotion.cpp | 3 + indra/llcharacter/lljoint.h | 2 +- indra/llcharacter/llkeyframemotion.cpp | 168 +++++++++++++++++------ indra/llcharacter/llkeyframemotion.h | 132 ++++++++++++++++-- indra/llcharacter/llmotioncontroller.cpp | 110 +++++++++------ indra/llcharacter/llmotioncontroller.h | 4 +- indra/newview/llfloaterbvhpreview.cpp | 4 + indra/newview/llvoavatar.cpp | 2 +- 9 files changed, 331 insertions(+), 95 deletions(-) diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 888c20cd4..25b89d2f8 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -136,7 +136,6 @@ LLMotion* LLCharacter::findMotion( const LLUUID &id ) //----------------------------------------------------------------------------- // createMotion() -// NOTE: Always assign the result to a LLPointer! //----------------------------------------------------------------------------- LLMotion* LLCharacter::createMotion( const LLUUID &id ) { diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp index 0ee378f3b..14017da10 100644 --- a/indra/llcharacter/llheadrotmotion.cpp +++ b/indra/llcharacter/llheadrotmotion.cpp @@ -104,7 +104,10 @@ LLHeadRotMotion::~LLHeadRotMotion() LLMotion::LLMotionInitStatus LLHeadRotMotion::onInitialize(LLCharacter *character) { if (!character) + { + llwarns << "character is NULL." << llendl; return STATUS_FAILURE; + } mCharacter = character; mPelvisJoint = character->getJoint("mPelvis"); diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index fe14c1e44..cb55e6ca7 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -41,7 +41,7 @@ #include "lldarray.h" const S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15; -const U32 LL_CHARACTER_MAX_JOINTS = 32; // must be divisible by 4! +const U32 LL_CHARACTER_MAX_JOINTS = 32; // must be divisible by 16! const U32 LL_HAND_JOINT_NUM = 31; const U32 LL_FACE_JOINT_NUM = 30; const S32 LL_CHARACTER_MAX_PRIORITY = 7; diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index 98906d3d4..653d3988c 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -84,38 +84,55 @@ LLKeyframeMotion::JointMotionList::~JointMotionList() for_each(mJointMotionArray.begin(), mJointMotionArray.end(), DeletePointer()); } -U32 LLKeyframeMotion::JointMotionList::dumpDiagInfo() +//Singu: add parameter 'silent'. +U32 LLKeyframeMotion::JointMotionList::dumpDiagInfo(bool silent) const { S32 total_size = sizeof(JointMotionList); for (U32 i = 0; i < getNumJointMotions(); i++) { - LLKeyframeMotion::JointMotion* joint_motion_p = mJointMotionArray[i]; + LLKeyframeMotion::JointMotion const* joint_motion_p = mJointMotionArray[i]; - llinfos << "\tJoint " << joint_motion_p->mJointName << llendl; + if (!silent) + { + llinfos << "\tJoint " << joint_motion_p->mJointName << llendl; + } if (joint_motion_p->mUsage & LLJointState::SCALE) { - llinfos << "\t" << joint_motion_p->mScaleCurve.mNumKeys << " scale keys at " - << joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey) << " bytes" << llendl; - + if (!silent) + { + llinfos << "\t" << joint_motion_p->mScaleCurve.mNumKeys << " scale keys at " + << joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey) << " bytes" << llendl; + } total_size += joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey); } if (joint_motion_p->mUsage & LLJointState::ROT) { - llinfos << "\t" << joint_motion_p->mRotationCurve.mNumKeys << " rotation keys at " - << joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey) << " bytes" << llendl; - + if (!silent) + { + llinfos << "\t" << joint_motion_p->mRotationCurve.mNumKeys << " rotation keys at " + << joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey) << " bytes" << llendl; + } total_size += joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey); } if (joint_motion_p->mUsage & LLJointState::POS) { - llinfos << "\t" << joint_motion_p->mPositionCurve.mNumKeys << " position keys at " - << joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey) << " bytes" << llendl; - + if (!silent) + { + llinfos << "\t" << joint_motion_p->mPositionCurve.mNumKeys << " position keys at " + << joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey) << " bytes" << llendl; + } total_size += joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey); } } - llinfos << "Size: " << total_size << " bytes" << llendl; + //Singu: Also add memory used by the constraints. + S32 constraints_size = mConstraints.size() * sizeof(constraint_list_t::value_type); + total_size += constraints_size; + if (!silent) + { + llinfos << "\t" << mConstraints.size() << " constraints at " << constraints_size << " bytes" << llendl; + llinfos << "Size: " << total_size << " bytes" << llendl; + } return total_size; } @@ -429,7 +446,6 @@ void LLKeyframeMotion::JointMotion::update(LLJointState* joint_state, F32 time, //----------------------------------------------------------------------------- LLKeyframeMotion::LLKeyframeMotion(const LLUUID &id) : LLMotion(id), - mJointMotionList(NULL), mPelvisp(NULL), mLastSkeletonSerialNum(0), mLastUpdateTime(0.f), @@ -517,6 +533,7 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact case ASSET_FETCHED: return STATUS_HOLD; case ASSET_FETCH_FAILED: + llwarns << "Trying to initialize a motion that failed to be fetched." << llendl; return STATUS_FAILURE; case ASSET_LOADED: return STATUS_SUCCESS; @@ -526,7 +543,7 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact break; } - LLKeyframeMotion::JointMotionList* joint_motion_list = LLKeyframeDataCache::getKeyframeData(getID()); + LLKeyframeMotion::JointMotionListPtr joint_motion_list = LLKeyframeDataCache::getKeyframeData(getID()); if(joint_motion_list) { @@ -1227,13 +1244,42 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8 } } +// Helper class. +template +struct AIAutoDestruct +{ + T* mPtr; + AIAutoDestruct() : mPtr(NULL) { } + ~AIAutoDestruct() { delete mPtr; } + void add(T* ptr) { mPtr = ptr; } +}; + //----------------------------------------------------------------------------- // deserialize() //----------------------------------------------------------------------------- BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) { BOOL old_version = FALSE; - mJointMotionList = new LLKeyframeMotion::JointMotionList; + + // + + // First add a new LLKeyframeMotion::JointMotionList to the cache, then assign a pointer + // to that to mJointMotionList. In LLs code the cache is never deleted again. Now it is + // is deleted when the last mJointMotionList pointer is destructed. + // + // It is possible that we get here for an already added animation, because animations can + // be requested multiple times (we get here from LLKeyframeMotion::onLoadComplete) when + // the animation was still downloading from a previous request for another LLMotionController + // object (avatar). In that case we just overwrite the old data while decoding it again. + mJointMotionList = LLKeyframeDataCache::getKeyframeData(getID()); + bool singu_new_joint_motion_list = !mJointMotionList; + if (singu_new_joint_motion_list) + { + // Create a new JointMotionList. + mJointMotionList = LLKeyframeDataCache::createKeyframeData(getID()); + } + + // //------------------------------------------------------------------------- // get base priority @@ -1396,8 +1442,10 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) return FALSE; } - mJointMotionList->mJointMotionArray.clear(); - mJointMotionList->mJointMotionArray.reserve(num_motions); + if (singu_new_joint_motion_list) + { + mJointMotionList->mJointMotionArray.reserve(num_motions); + } mJointStates.clear(); mJointStates.reserve(num_motions); @@ -1407,8 +1455,19 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) for(U32 i=0; i watcher; + JointMotion* joint_motion = new JointMotion; - mJointMotionList->mJointMotionArray.push_back(joint_motion); + if (singu_new_joint_motion_list) + { + // Pass ownership to mJointMotionList. + mJointMotionList->mJointMotionArray.push_back(joint_motion); + } + else + { + // Just delete this at the end. + watcher.add(joint_motion); + } std::string joint_name; if (!dp.unpackString(joint_name, "joint_name")) @@ -1836,7 +1895,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) return FALSE; } - mJointMotionList->mConstraints.push_front(constraintp); + AIAutoDestruct watcher; + if (singu_new_joint_motion_list) + { + mJointMotionList->mConstraints.push_front(constraintp); + } + else + { + watcher.add(constraintp); + } constraintp->mJointStateIndices = new S32[constraintp->mChainLength + 1]; // note: mChainLength is size-limited - comes from a byte @@ -1876,15 +1943,12 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (constraintp->mJointStateIndices[i] < 0 ) { llwarns << "No joint index for constraint " << i << llendl; - delete constraintp; return FALSE; } } } } - // *FIX: support cleanup of old keyframe data - LLKeyframeDataCache::addKeyframeData(getID(), mJointMotionList); mAssetStatus = ASSET_LOADED; setupPose(); @@ -2226,16 +2290,24 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs, //-------------------------------------------------------------------- // LLKeyframeDataCache::dumpDiagInfo() //-------------------------------------------------------------------- -void LLKeyframeDataCache::dumpDiagInfo() +// +// quiet = 0 : print everything in detail. +// 1 : print the UUIDs of all animations in the cache and the total memory usage. +// 2 : only print the total memory usage. +// +void LLKeyframeDataCache::dumpDiagInfo(int quiet) { // keep track of totals U32 total_size = 0; char buf[1024]; /* Flawfinder: ignore */ - llinfos << "-----------------------------------------------------" << llendl; - llinfos << " Global Motion Table (DEBUG only)" << llendl; - llinfos << "-----------------------------------------------------" << llendl; + if (quiet < 2) + { + llinfos << "-----------------------------------------------------" << llendl; + llinfos << " Global Motion Table" << llendl; + llinfos << "-----------------------------------------------------" << llendl; + } // print each loaded mesh, and it's memory usage for (keyframe_data_map_t::iterator map_it = sKeyframeDataMap.begin(); @@ -2243,30 +2315,46 @@ void LLKeyframeDataCache::dumpDiagInfo() { U32 joint_motion_kb; - LLKeyframeMotion::JointMotionList *motion_list_p = map_it->second; + LLKeyframeMotion::JointMotionList const* motion_list_p = map_it->get(); - llinfos << "Motion: " << map_it->first << llendl; + if (quiet < 2) + { + llinfos << "Motion: " << map_it->key() << llendl; + } - joint_motion_kb = motion_list_p->dumpDiagInfo(); - - total_size += joint_motion_kb; + if (motion_list_p) + { + joint_motion_kb = motion_list_p->dumpDiagInfo(quiet); + total_size += joint_motion_kb; + } } - llinfos << "-----------------------------------------------------" << llendl; + if (quiet < 2) + { + llinfos << "-----------------------------------------------------" << llendl; + } llinfos << "Motions\tTotal Size" << llendl; snprintf(buf, sizeof(buf), "%d\t\t%d bytes", (S32)sKeyframeDataMap.size(), total_size ); /* Flawfinder: ignore */ llinfos << buf << llendl; - llinfos << "-----------------------------------------------------" << llendl; + if (quiet < 2) + { + llinfos << "-----------------------------------------------------" << llendl; + } } //-------------------------------------------------------------------- -// LLKeyframeDataCache::addKeyframeData() +// LLKeyframeDataCache::createKeyframeData() //-------------------------------------------------------------------- -void LLKeyframeDataCache::addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList* joint_motion_listp) +// This function replaces LLKeyframeDataCache::addKeyframeData and was rewritten to fix a memory leak (aka, the usage of AICachedPointer). +LLKeyframeMotion::JointMotionListPtr LLKeyframeDataCache::createKeyframeData(LLUUID const& id) { - sKeyframeDataMap[id] = joint_motion_listp; + std::pair result = + sKeyframeDataMap.insert(AICachedPointer(id, new LLKeyframeMotion::JointMotionList, &sKeyframeDataMap)); + llassert(result.second); // id may not already exist in the cache. + return &*result.first; // Construct and return a JointMotionListPt from a pointer to the actually inserted AICachedPointer. } +// //-------------------------------------------------------------------- // LLKeyframeDataCache::removeKeyframeData() @@ -2276,7 +2364,6 @@ void LLKeyframeDataCache::removeKeyframeData(const LLUUID& id) keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id); if (found_data != sKeyframeDataMap.end()) { - delete found_data->second; sKeyframeDataMap.erase(found_data); } } @@ -2284,14 +2371,14 @@ void LLKeyframeDataCache::removeKeyframeData(const LLUUID& id) //-------------------------------------------------------------------- // LLKeyframeDataCache::getKeyframeData() //-------------------------------------------------------------------- -LLKeyframeMotion::JointMotionList* LLKeyframeDataCache::getKeyframeData(const LLUUID& id) +LLKeyframeMotion::JointMotionListPtr LLKeyframeDataCache::getKeyframeData(const LLUUID& id) { keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id); if (found_data == sKeyframeDataMap.end()) { return NULL; } - return found_data->second; + return &*found_data; // Construct and return a JointMotionListPt from a pointer to the found AICachedPointer. } //-------------------------------------------------------------------- @@ -2307,7 +2394,6 @@ LLKeyframeDataCache::~LLKeyframeDataCache() //----------------------------------------------------------------------------- void LLKeyframeDataCache::clear() { - for_each(sKeyframeDataMap.begin(), sKeyframeDataMap.end(), DeletePairedPointer()); sKeyframeDataMap.clear(); } diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index 50d9d0504..55be6df09 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -5,6 +5,7 @@ * $LicenseInfo:firstyear=2001&license=viewergpl$ * * Copyright (c) 2001-2009, Linden Research, Inc. + * AICachedPointer and AICachedPointPtr copyright (c) 2013, Aleric Inglewood. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -48,6 +49,7 @@ #include "v3dmath.h" #include "v3math.h" #include "llbvhconsts.h" +#include class LLKeyframeDataCache; class LLVFS; @@ -59,6 +61,112 @@ class LLDataPacker; const S32 KEYFRAME_MOTION_VERSION = 1; const S32 KEYFRAME_MOTION_SUBVERSION = 0; +//----------------------------------------------------------------------------- +// + +template +class AICachedPointer; + +template +void intrusive_ptr_add_ref(AICachedPointer const* p); + +template +void intrusive_ptr_release(AICachedPointer const* p); + +template +class AICachedPointer +{ + public: + typedef std::set > container_type; + + private: + KEY mKey; // The unique key. + LLPointer mData; // The actual data pointer. + container_type* mCache; // Pointer to the underlaying cache. + mutable int mRefCount; // Number of AICachedPointerPtr's pointing to this object. + + public: + // Construct a NULL pointer. This is needed when adding a new entry to a std::set, it is always first default constructed. + AICachedPointer(void) : mCache(NULL) { } + + // Copy constructor. This is needed to replace the std::set inserted instance with its actual value. + AICachedPointer(AICachedPointer const& cptr) : mKey(cptr.mKey), mData(cptr.mData), mCache(cptr.mCache), mRefCount(0) { } + + // Construct a AICachedPointer that points to 'ptr' with key 'key'. + AICachedPointer(KEY const& key, T* ptr, container_type* cache) : mKey(key), mData(ptr), mCache(cache), mRefCount(-1) { } + + // Construct a temporary NULL pointer that can be used in a search for a key. + AICachedPointer(KEY const& key) : mKey(key), mCache(NULL) { } + + // Accessors for key and data. + KEY const& key(void) const { return mKey; } + T const* get(void) const { return mData.get(); } + T* get(void) { return mData.get(); } + + // Order only by key. + friend bool operator<(AICachedPointer const& cp1, AICachedPointer const& cp2) { return cp1.mKey < cp2.mKey; } + + private: + friend void intrusive_ptr_add_ref<>(AICachedPointer const* p); + friend void intrusive_ptr_release<>(AICachedPointer const* p); + + private: + AICachedPointer& operator=(AICachedPointer const&); +}; + +template +void intrusive_ptr_add_ref(AICachedPointer const* p) +{ + llassert(p->mCache); + if (p->mCache) + { + p->mRefCount++; + } +} + +template +void intrusive_ptr_release(AICachedPointer const* p) +{ + llassert(p->mCache); + if (p->mCache) + { + if (--p->mRefCount == 0) + { + p->mCache->erase(p->mKey); + } + } +} + +template +class AICachedPointerPtr +{ + private: + boost::intrusive_ptr const> mPtr; + static int sCnt; + + public: + AICachedPointerPtr(void) { ++sCnt; } + AICachedPointerPtr(AICachedPointerPtr const& cpp) : mPtr(cpp.mPtr) { ++sCnt; } + AICachedPointerPtr(AICachedPointer const* cp) : mPtr(cp) { ++sCnt; } + ~AICachedPointerPtr() { --sCnt; } + + typedef boost::intrusive_ptr const> const AICachedPointerPtr::* const bool_type; + operator bool_type() const { return mPtr ? &AICachedPointerPtr::mPtr : NULL; } + + T const* operator->() const { return mPtr->get(); } + T* operator->() { return const_cast&>(*mPtr).get(); } + T const& operator*() const { return *mPtr->get(); } + T& operator*() { return *const_cast&>(*mPtr).get(); } + + AICachedPointerPtr& operator=(AICachedPointerPtr const& cpp) { mPtr = cpp.mPtr; return *this; } +}; + +template +int AICachedPointerPtr::sCnt; + +// +//----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- // class LLKeyframeMotion //----------------------------------------------------------------------------- @@ -158,7 +266,7 @@ public: U32 getFileSize(); BOOL serialize(LLDataPacker& dp) const; BOOL deserialize(LLDataPacker& dp); - BOOL isLoaded() { return mJointMotionList != NULL; } + BOOL isLoaded() { return !!mJointMotionList; } // setters for modifying a keyframe animation @@ -416,19 +524,22 @@ public: public: JointMotionList(); ~JointMotionList(); - U32 dumpDiagInfo(); + U32 dumpDiagInfo(bool silent = false) const; JointMotion* getJointMotion(U32 index) const { llassert(index < mJointMotionArray.size()); return mJointMotionArray[index]; } U32 getNumJointMotions() const { return mJointMotionArray.size(); } }; + // Singu: Type of a pointer to the cached pointer (in LLKeyframeDataCache::sKeyframeDataMap) to a JointMotionList object. + typedef AICachedPointerPtr JointMotionListPtr; + protected: static LLVFS* sVFS; //------------------------------------------------------------------------- // Member Data //------------------------------------------------------------------------- - JointMotionList* mJointMotionList; + JointMotionListPtr mJointMotionList; // singu: automatically clean up cache entry when destructed. std::vector > mJointStates; LLJoint* mPelvisp; LLCharacter* mCharacter; @@ -442,21 +553,24 @@ protected: class LLKeyframeDataCache { -public: - // *FIX: implement this as an actual singleton member of LLKeyframeMotion +private: + friend class LLKeyframeMotion; LLKeyframeDataCache(){}; ~LLKeyframeDataCache(); - typedef std::map keyframe_data_map_t; +public: + typedef AICachedPointer::container_type keyframe_data_map_t; // singu: add automatic cache cleanup. static keyframe_data_map_t sKeyframeDataMap; - static void addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList*); - static LLKeyframeMotion::JointMotionList* getKeyframeData(const LLUUID& id); + // + static LLKeyframeMotion::JointMotionListPtr createKeyframeData(LLUUID const& id); // id may not exist. + static LLKeyframeMotion::JointMotionListPtr getKeyframeData(LLUUID const& id); // id may or may not exists. Returns a NULL pointer when it doesn't exist. + // static void removeKeyframeData(const LLUUID& id); //print out diagnostic info - static void dumpDiagInfo(); + static void dumpDiagInfo(int quiet = 0); // singu: added param 'quiet'. static void clear(); }; diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 35dcc1057..b5d60205c 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -168,7 +168,10 @@ void LLMotionController::deleteAllMotions() mLoadingMotions.clear(); mLoadedMotions.clear(); mActiveMotions.clear(); - + // + for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer()); + mDeprecatedMotions.clear(); + // for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer()); mAllMotions.clear(); } @@ -178,26 +181,19 @@ void LLMotionController::deleteAllMotions() //----------------------------------------------------------------------------- void LLMotionController::purgeExcessMotions() { - if (mLoadedMotions.size() > MAX_MOTION_INSTANCES) + // + // The old code attempted to remove non-active motions from mDeprecatedMotions, + // but that is nonsense: there are no motions in mDeprecatedMotions that are not active. + if (mLoadedMotions.size() <= MAX_MOTION_INSTANCES) { - // clean up deprecated motions - for (motion_set_t::iterator deprecated_motion_it = mDeprecatedMotions.begin(); - deprecated_motion_it != mDeprecatedMotions.end(); ) - { - motion_set_t::iterator cur_iter = deprecated_motion_it++; - LLMotion* cur_motionp = *cur_iter; - if (!isMotionActive(cur_motionp)) - { - // Motion is deprecated so we know it's not cannonical, - // we can safely remove the instance - removeMotionInstance(cur_motionp); // modifies mDeprecatedMotions - mDeprecatedMotions.erase(cur_iter); - } - } + // Speed up, no need to create motions_to_kill. + return; } + // std::set motions_to_kill; - if (mLoadedMotions.size() > MAX_MOTION_INSTANCES) + + if (1) // Singu: leave indentation alone... { // too many motions active this frame, kill all blenders mPoseBlender.clearBlenders(); @@ -308,24 +304,44 @@ BOOL LLMotionController::registerMotion( const LLUUID& id, LLMotionConstructor c void LLMotionController::removeMotion( const LLUUID& id) { LLMotion* motionp = findMotion(id); - mAllMotions.erase(id); - removeMotionInstance(motionp); + // + // If a motion is erased from mAllMotions, it must be deleted. + if (motionp) + { + mAllMotions.erase(id); + removeMotionInstance(motionp); + delete motionp; + } + // } // removes instance of a motion from all runtime structures, but does // not erase entry by ID, as this could be a duplicate instance -// use removeMotion(id) to remove all references to a given motion by id. +// use removeMotion(id) to remove a reference to a given motion by id +// (that will not remove (active) deprecated motions). void LLMotionController::removeMotionInstance(LLMotion* motionp) { if (motionp) { llassert(findMotion(motionp->getID()) != motionp); - if (motionp->isActive()) - motionp->deactivate(); mLoadingMotions.erase(motionp); mLoadedMotions.erase(motionp); mActiveMotions.remove(motionp); - delete motionp; + // + // Deactivation moved here. Only delete motionp when it is being removed from mDeprecatedMotions. + if (motionp->isActive()) + { + motionp->deactivate(); + // If a motion is deactivated, it must be removed from mDeprecatedMotions if there. + motion_set_t::iterator found_it = mDeprecatedMotions.find(motionp); + if (found_it != mDeprecatedMotions.end()) + { + mDeprecatedMotions.erase(found_it); + // If a motion is erased from mDeprecatedMotions, it must be deleted. + delete motionp; + } + } + // } } @@ -393,6 +409,7 @@ BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset) if (motion && !mPaused && motion->canDeprecate() + && motion->isActive() // singu: do not deprecate motions that are not active. && motion->getFadeWeight() > 0.01f // not LOD-ed out && (motion->isBlending() || motion->getStopTime() != 0.f)) { @@ -782,11 +799,10 @@ void LLMotionController::updateLoadingMotions() llinfos << "Motion " << motionp->getID() << " init failed." << llendl; sRegistry.markBad(motionp->getID()); mLoadingMotions.erase(curiter); - motion_set_t::iterator found_it = mDeprecatedMotions.find(motionp); - if (found_it != mDeprecatedMotions.end()) - { - mDeprecatedMotions.erase(found_it); - } + // Singu note: a motion in mLoadingMotions will not be in mActiveMotions + // and therefore not be in mDeprecatedMotions. So, we don't have to + // check for it's existence there. + llassert(mDeprecatedMotions.find(motionp) == mDeprecatedMotions.end()); mAllMotions.erase(motionp->getID()); delete motionp; } @@ -970,18 +986,16 @@ BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time) //----------------------------------------------------------------------------- BOOL LLMotionController::deactivateMotionInstance(LLMotion *motion) { - motion->deactivate(); - motion_set_t::iterator found_it = mDeprecatedMotions.find(motion); if (found_it != mDeprecatedMotions.end()) { // deprecated motions need to be completely excised - removeMotionInstance(motion); - mDeprecatedMotions.erase(found_it); + removeMotionInstance(motion); // singu note: this deactivates motion and removes it from mDeprecatedMotions. } else { // for motions that we are keeping, simply remove from active queue + motion->deactivate(); // singu note: moved here from the top of the function. mActiveMotions.remove(motion); } @@ -1049,11 +1063,26 @@ void LLMotionController::dumpMotions() state_string += std::string("L"); if (std::find(mActiveMotions.begin(), mActiveMotions.end(), motion)!=mActiveMotions.end()) state_string += std::string("A"); - if (mDeprecatedMotions.find(motion) != mDeprecatedMotions.end()) - state_string += std::string("D"); + llassert(mDeprecatedMotions.find(motion) == mDeprecatedMotions.end()); // singu: it's impossible that a motion is in mAllMotions and mDeprecatedMotions at the same time. llinfos << gAnimLibrary.animationName(id) << " " << state_string << llendl; - } + // + // Also dump the deprecated motions. + for (motion_set_t::iterator iter = mDeprecatedMotions.begin(); + iter != mDeprecatedMotions.end(); ++iter) + { + std::string state_string; + LLMotion* motion = *iter; + LLUUID id = motion->getID(); + llassert(mLoadingMotions.find(motion) == mLoadingMotions.end()); + if (mLoadedMotions.find(motion) != mLoadedMotions.end()) + state_string += std::string("L"); + if (std::find(mActiveMotions.begin(), mActiveMotions.end(), motion)!=mActiveMotions.end()) + state_string += std::string("A"); + state_string += "D"; + llinfos << gAnimLibrary.animationName(id) << " " << state_string << llendl; + } + // } //----------------------------------------------------------------------------- @@ -1061,11 +1090,11 @@ void LLMotionController::dumpMotions() //----------------------------------------------------------------------------- void LLMotionController::deactivateAllMotions() { - for (motion_map_t::iterator iter = mAllMotions.begin(); - iter != mAllMotions.end(); iter++) + // Singu note: this must run over mActiveMotions: other motions are not active, + // and running over mAllMotions will miss the ones in mDeprecatedMotions. + for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter) { - LLMotion* motionp = iter->second; - deactivateMotionInstance(motionp); + deactivateMotionInstance(*iter); } } @@ -1086,8 +1115,7 @@ void LLMotionController::flushAllMotions() active_motions.push_back(std::make_pair(motionp->getID(),dtime)); motionp->deactivate(); // don't call deactivateMotionInstance() because we are going to reactivate it } - mActiveMotions.clear(); - + // delete all motion instances deleteAllMotions(); diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index 2de13aa36..7e0cc7ad7 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -115,7 +115,6 @@ public: // unregisters a motion with the controller // (actually just forwards call to motion registry) - // returns true if successfull void removeMotion( const LLUUID& id ); // start motion @@ -205,10 +204,13 @@ protected: // Life cycle of an animation: // // Animations are instantiated and immediately put in the mAllMotions map for their entire lifetime. +// Singu note: that is not true, they are moved to mDeprecatedMotions (often) for the last part of their lifetime. // If the animations depend on any asset data, the appropriate data is fetched from the data server, // and the animation is put on the mLoadingMotions list. // Once an animations is loaded, it will be initialized and put on the mLoadedMotions list. // Any animation that is currently playing also sits in the mActiveMotions list. +// Singu note: animations are only put in mDeprecatedMotions if and while they are playing, +// therefore animations in mDeprecatedMotions will be (must be) active and in mActiveMotions. typedef std::map motion_map_t; motion_map_t mAllMotions; diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index 58e27b914..251397fa6 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -375,6 +375,10 @@ BOOL LLFloaterBvhPreview::postBuild() } } + if (motionp && mInWorld) + { + gAgentAvatarp->removeMotion(mMotionID); + } //setEnabled(FALSE); mMotionID.setNull(); mAnimPreview = NULL; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 3b15311e7..aec11e199 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -3884,7 +3884,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) getOffObject(); // //Singu note: this appears to be a safety catch: - // when getParent() is NULL and we're note playing ANIM_AGENT_SIT_GROUND_CONSTRAINED then we aren't sitting! + // when getParent() is NULL and we're not playing ANIM_AGENT_SIT_GROUND_CONSTRAINED then we aren't sitting! // The previous call existed in an attempt to fix this inconsistent state by standing up from an object. // However, since getParent() is NULL that function would crash! // Since we never got crash reports regarding to this, that apparently never happened, except, I discovered From 94b42e7a9b7c692bf582a0b243d22f7ff321abf3 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 3 Dec 2013 04:41:12 +0100 Subject: [PATCH 094/115] Speed up of particular inefficient part related to motions. For these standard motions, the viewer likes to very frequently flood-call startMotion/stopMotion sometimes, which at the very least needs a LLUUID lookup in a std::map. In particular, this is done for two of them for every avatar in the sim every frame. This code makes it possible to test if that makes sense by merely doing a bit test. Conflicts: indra/llcharacter/llkeyframemotion.h --- indra/llcharacter/llcharacter.h | 1 + indra/llcharacter/lleditingmotion.cpp | 12 +- indra/llcharacter/lleditingmotion.h | 9 +- indra/llcharacter/llhandmotion.cpp | 12 +- indra/llcharacter/llhandmotion.h | 9 +- indra/llcharacter/llheadrotmotion.cpp | 36 +--- indra/llcharacter/llheadrotmotion.h | 25 +-- indra/llcharacter/llkeyframefallmotion.h | 2 +- indra/llcharacter/llkeyframemotion.cpp | 2 +- indra/llcharacter/llkeyframemotion.h | 3 +- indra/llcharacter/llkeyframestandmotion.h | 2 +- indra/llcharacter/llkeyframewalkmotion.cpp | 13 +- indra/llcharacter/llkeyframewalkmotion.h | 17 +- indra/llcharacter/llmotion.cpp | 16 ++ indra/llcharacter/llmotion.h | 42 ++++- indra/llcharacter/llmotioncontroller.cpp | 18 +- indra/llcharacter/llmotioncontroller.h | 16 +- indra/llcharacter/lltargetingmotion.cpp | 18 +- indra/llcharacter/lltargetingmotion.h | 14 +- indra/newview/llemote.h | 2 +- indra/newview/llhudeffectlookat.cpp | 5 +- indra/newview/llphysicsmotion.cpp | 15 +- indra/newview/llphysicsmotion.h | 14 +- indra/newview/llvoavatar.cpp | 202 ++++++++++++++------- indra/newview/llvoavatar.h | 9 + 25 files changed, 276 insertions(+), 238 deletions(-) diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index 2b872effa..74cc35187 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -146,6 +146,7 @@ public: // is this motion active? BOOL isMotionActive( const LLUUID& id ); + bool isMotionActive(U32 bit) const { return mMotionController.isactive(bit); } // Event handler for motion deactivation. // Called when a motion has completely stopped and has been deactivated. diff --git a/indra/llcharacter/lleditingmotion.cpp b/indra/llcharacter/lleditingmotion.cpp index c2a87d80a..26fca2260 100644 --- a/indra/llcharacter/lleditingmotion.cpp +++ b/indra/llcharacter/lleditingmotion.cpp @@ -49,7 +49,7 @@ S32 LLEditingMotion::sHandPosePriority = 3; // LLEditingMotion() // Class Constructor //----------------------------------------------------------------------------- -LLEditingMotion::LLEditingMotion( const LLUUID &id) : LLMotion(id) +LLEditingMotion::LLEditingMotion(LLUUID const& id, LLMotionController& controller) : AIMaskedMotion(id, controller, ANIM_AGENT_EDITING) { mCharacter = NULL; @@ -155,7 +155,7 @@ BOOL LLEditingMotion::onActivate() mShoulderJoint.setRotation( mShoulderState->getJoint()->getRotation() ); mElbowJoint.setRotation( mElbowState->getJoint()->getRotation() ); - return TRUE; + return AIMaskedMotion::onActivate(); } //----------------------------------------------------------------------------- @@ -256,12 +256,4 @@ BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask) return result; } -//----------------------------------------------------------------------------- -// LLEditingMotion::onDeactivate() -//----------------------------------------------------------------------------- -void LLEditingMotion::onDeactivate() -{ -} - - // End diff --git a/indra/llcharacter/lleditingmotion.h b/indra/llcharacter/lleditingmotion.h index 4a83d4b9f..f880a94b7 100644 --- a/indra/llcharacter/lleditingmotion.h +++ b/indra/llcharacter/lleditingmotion.h @@ -49,11 +49,11 @@ // class LLEditingMotion //----------------------------------------------------------------------------- class LLEditingMotion : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLEditingMotion(const LLUUID &id); + LLEditingMotion(LLUUID const& id, LLMotionController& controller); // Destructor virtual ~LLEditingMotion(); @@ -65,7 +65,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLEditingMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLEditingMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -107,9 +107,6 @@ public: // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask); - // called when a motion is deactivated - virtual void onDeactivate(); - public: //------------------------------------------------------------------------- // joint states to be animated diff --git a/indra/llcharacter/llhandmotion.cpp b/indra/llcharacter/llhandmotion.cpp index 696dba0d9..c479f0f5f 100644 --- a/indra/llcharacter/llhandmotion.cpp +++ b/indra/llcharacter/llhandmotion.cpp @@ -61,7 +61,7 @@ const F32 HAND_MORPH_BLEND_TIME = 0.2f; // LLHandMotion() // Class Constructor //----------------------------------------------------------------------------- -LLHandMotion::LLHandMotion(const LLUUID &id) : LLMotion(id) +LLHandMotion::LLHandMotion(LLUUID const& id, LLMotionController& controller) : AIMaskedMotion(id, controller, ANIM_AGENT_HAND_MOTION) { mCharacter = NULL; mLastTime = 0.f; @@ -112,7 +112,7 @@ BOOL LLHandMotion::onActivate() mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f); mCharacter->updateVisualParams(); } - return TRUE; + return AIMaskedMotion::onActivate(); } @@ -235,14 +235,6 @@ BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask) return TRUE; } - -//----------------------------------------------------------------------------- -// LLHandMotion::onDeactivate() -//----------------------------------------------------------------------------- -void LLHandMotion::onDeactivate() -{ -} - //----------------------------------------------------------------------------- // LLHandMotion::getHandPoseName() //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llhandmotion.h b/indra/llcharacter/llhandmotion.h index dcf169662..582c6ee2f 100644 --- a/indra/llcharacter/llhandmotion.h +++ b/indra/llcharacter/llhandmotion.h @@ -45,7 +45,7 @@ // class LLHandMotion //----------------------------------------------------------------------------- class LLHandMotion : - public LLMotion + public AIMaskedMotion { public: typedef enum e_hand_pose @@ -68,7 +68,7 @@ public: } eHandPose; // Constructor - LLHandMotion(const LLUUID &id); + LLHandMotion(LLUUID const& id, LLMotionController& controller); // Destructor virtual ~LLHandMotion(); @@ -80,7 +80,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLHandMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLHandMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -122,9 +122,6 @@ public: // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask); - // called when a motion is deactivated - virtual void onDeactivate(); - virtual BOOL canDeprecate() { return FALSE; } static std::string getHandPoseName(eHandPose pose); diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp index 14017da10..7322c996a 100644 --- a/indra/llcharacter/llheadrotmotion.cpp +++ b/indra/llcharacter/llheadrotmotion.cpp @@ -76,8 +76,8 @@ const F32 EYE_BLINK_TIME_DELTA = 0.005f; // time between one eye starting a blin // LLHeadRotMotion() // Class Constructor //----------------------------------------------------------------------------- -LLHeadRotMotion::LLHeadRotMotion(const LLUUID &id) : - LLMotion(id), +LLHeadRotMotion::LLHeadRotMotion(LLUUID const& id, LLMotionController& controller) : + AIMaskedMotion(id, controller, ANIM_AGENT_HEAD_ROT), mCharacter(NULL), mTorsoJoint(NULL), mHeadJoint(NULL) @@ -172,16 +172,6 @@ LLMotion::LLMotionInitStatus LLHeadRotMotion::onInitialize(LLCharacter *characte return STATUS_SUCCESS; } - -//----------------------------------------------------------------------------- -// LLHeadRotMotion::onActivate() -//----------------------------------------------------------------------------- -BOOL LLHeadRotMotion::onActivate() -{ - return TRUE; -} - - //----------------------------------------------------------------------------- // LLHeadRotMotion::onUpdate() //----------------------------------------------------------------------------- @@ -266,19 +256,11 @@ BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask) } -//----------------------------------------------------------------------------- -// LLHeadRotMotion::onDeactivate() -//----------------------------------------------------------------------------- -void LLHeadRotMotion::onDeactivate() -{ -} - - //----------------------------------------------------------------------------- // LLEyeMotion() // Class Constructor //----------------------------------------------------------------------------- -LLEyeMotion::LLEyeMotion(const LLUUID &id) : LLMotion(id) +LLEyeMotion::LLEyeMotion(LLUUID const& id, LLMotionController& controller) : AIMaskedMotion(id, controller, ANIM_AGENT_EYE) { mCharacter = NULL; mEyeJitterTime = 0.f; @@ -346,16 +328,6 @@ LLMotion::LLMotionInitStatus LLEyeMotion::onInitialize(LLCharacter *character) return STATUS_SUCCESS; } - -//----------------------------------------------------------------------------- -// LLEyeMotion::onActivate() -//----------------------------------------------------------------------------- -BOOL LLEyeMotion::onActivate() -{ - return TRUE; -} - - //----------------------------------------------------------------------------- // LLEyeMotion::onUpdate() //----------------------------------------------------------------------------- @@ -536,6 +508,8 @@ void LLEyeMotion::onDeactivate() { joint->setRotation(LLQuaternion::DEFAULT); } + + AIMaskedMotion::onDeactivate(); } // End diff --git a/indra/llcharacter/llheadrotmotion.h b/indra/llcharacter/llheadrotmotion.h index 97e61eac1..5342d422f 100644 --- a/indra/llcharacter/llheadrotmotion.h +++ b/indra/llcharacter/llheadrotmotion.h @@ -46,11 +46,11 @@ // class LLHeadRotMotion //----------------------------------------------------------------------------- class LLHeadRotMotion : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLHeadRotMotion(const LLUUID &id); + LLHeadRotMotion(LLUUID const& id, LLMotionController& controller); // Destructor virtual ~LLHeadRotMotion(); @@ -62,7 +62,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLHeadRotMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLHeadRotMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -94,19 +94,11 @@ public: // must return true to indicate success and be available for activation virtual LLMotionInitStatus onInitialize(LLCharacter *character); - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate(); - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask); - // called when a motion is deactivated - virtual void onDeactivate(); - public: //------------------------------------------------------------------------- // joint states to be animated @@ -129,11 +121,11 @@ public: // class LLEyeMotion //----------------------------------------------------------------------------- class LLEyeMotion : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLEyeMotion(const LLUUID &id); + LLEyeMotion(LLUUID const& id, LLMotionController& controller); // Destructor virtual ~LLEyeMotion(); @@ -145,7 +137,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create( const LLUUID &id) { return new LLEyeMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLEyeMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -177,11 +169,6 @@ public: // must return true to indicate success and be available for activation virtual LLMotionInitStatus onInitialize(LLCharacter *character); - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate(); - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. diff --git a/indra/llcharacter/llkeyframefallmotion.h b/indra/llcharacter/llkeyframefallmotion.h index 495be977f..c36c72798 100644 --- a/indra/llcharacter/llkeyframefallmotion.h +++ b/indra/llcharacter/llkeyframefallmotion.h @@ -59,7 +59,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLKeyframeFallMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController&) { return new LLKeyframeFallMotion(id); } public: //------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index 653d3988c..c6589ddf4 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -468,7 +468,7 @@ LLKeyframeMotion::~LLKeyframeMotion() //----------------------------------------------------------------------------- // create() //----------------------------------------------------------------------------- -LLMotion *LLKeyframeMotion::create(const LLUUID &id) +LLMotion* LLKeyframeMotion::create(LLUUID const& id, LLMotionController&) { return new LLKeyframeMotion(id); } diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index 55be6df09..14fa4916c 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -54,6 +54,7 @@ class LLKeyframeDataCache; class LLVFS; class LLDataPacker; +class LLMotionController; #define MIN_REQUIRED_PIXEL_AREA_KEYFRAME (40.f) #define MAX_CHAIN_LENGTH (4) @@ -193,7 +194,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID& id); + static LLMotion* create(LLUUID const& id, LLMotionController& controller); public: //------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframestandmotion.h b/indra/llcharacter/llkeyframestandmotion.h index b0500dc8e..1db798021 100644 --- a/indra/llcharacter/llkeyframestandmotion.h +++ b/indra/llcharacter/llkeyframestandmotion.h @@ -60,7 +60,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLKeyframeStandMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController&) { return new LLKeyframeStandMotion(id); } public: //------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframewalkmotion.cpp b/indra/llcharacter/llkeyframewalkmotion.cpp index f9c2e4766..2a12edd29 100644 --- a/indra/llcharacter/llkeyframewalkmotion.cpp +++ b/indra/llcharacter/llkeyframewalkmotion.cpp @@ -138,8 +138,8 @@ BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask) // LLWalkAdjustMotion() // Class Constructor //----------------------------------------------------------------------------- -LLWalkAdjustMotion::LLWalkAdjustMotion(const LLUUID &id) : - LLMotion(id), +LLWalkAdjustMotion::LLWalkAdjustMotion(LLUUID const& id, LLMotionController& controller) : + AIMaskedMotion(id, controller, ANIM_AGENT_WALK_ADJUST), mLastTime(0.f), mAnimSpeed(0.f), mAdjustedSpeed(0.f), @@ -193,7 +193,7 @@ BOOL LLWalkAdjustMotion::onActivate() F32 rightAnkleOffset = (mRightAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec(); mAnkleOffset = llmax(leftAnkleOffset, rightAnkleOffset); - return TRUE; + return AIMaskedMotion::onActivate(); } //----------------------------------------------------------------------------- @@ -325,13 +325,14 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask) void LLWalkAdjustMotion::onDeactivate() { mCharacter->removeAnimationData("Walk Speed"); + AIMaskedMotion::onDeactivate(); } //----------------------------------------------------------------------------- // LLFlyAdjustMotion::LLFlyAdjustMotion() //----------------------------------------------------------------------------- -LLFlyAdjustMotion::LLFlyAdjustMotion(const LLUUID &id) - : LLMotion(id), +LLFlyAdjustMotion::LLFlyAdjustMotion(LLUUID const& id, LLMotionController& controller) + : AIMaskedMotion(id, controller, ANIM_AGENT_FLY_ADJUST), mRoll(0.f) { mName = "fly_adjust"; @@ -368,7 +369,7 @@ BOOL LLFlyAdjustMotion::onActivate() mPelvisState->setPosition(LLVector3::zero); mPelvisState->setRotation(LLQuaternion::DEFAULT); mRoll = 0.f; - return TRUE; + return AIMaskedMotion::onActivate(); } //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframewalkmotion.h b/indra/llcharacter/llkeyframewalkmotion.h index b507e9423..caab2fef3 100644 --- a/indra/llcharacter/llkeyframewalkmotion.h +++ b/indra/llcharacter/llkeyframewalkmotion.h @@ -52,7 +52,7 @@ class LLKeyframeWalkMotion : friend class LLWalkAdjustMotion; public: // Constructor - LLKeyframeWalkMotion(const LLUUID &id); + LLKeyframeWalkMotion(LLUUID const& id); // Destructor virtual ~LLKeyframeWalkMotion(); @@ -64,7 +64,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLKeyframeWalkMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController&) { return new LLKeyframeWalkMotion(id); } public: //------------------------------------------------------------------------- @@ -86,11 +86,11 @@ public: S32 mDownFoot; }; -class LLWalkAdjustMotion : public LLMotion +class LLWalkAdjustMotion : public AIMaskedMotion { public: // Constructor - LLWalkAdjustMotion(const LLUUID &id); + LLWalkAdjustMotion(LLUUID const& id, LLMotionController& controller); public: //------------------------------------------------------------------------- @@ -99,7 +99,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLWalkAdjustMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLWalkAdjustMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -136,11 +136,11 @@ public: F32 mAnkleOffset; }; -class LLFlyAdjustMotion : public LLMotion +class LLFlyAdjustMotion : public AIMaskedMotion { public: // Constructor - LLFlyAdjustMotion(const LLUUID &id); + LLFlyAdjustMotion(LLUUID const& id, LLMotionController& controller); public: //------------------------------------------------------------------------- @@ -149,7 +149,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLFlyAdjustMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLFlyAdjustMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -157,7 +157,6 @@ public: //------------------------------------------------------------------------- virtual LLMotionInitStatus onInitialize(LLCharacter *character); virtual BOOL onActivate(); - virtual void onDeactivate() {}; virtual BOOL onUpdate(F32 time, U8* joint_mask); virtual LLJoint::JointPriority getPriority(){return LLJoint::HIGHER_PRIORITY;} virtual BOOL getLoop() { return TRUE; } diff --git a/indra/llcharacter/llmotion.cpp b/indra/llcharacter/llmotion.cpp index ce926a38a..203cf2f4c 100644 --- a/indra/llcharacter/llmotion.cpp +++ b/indra/llcharacter/llmotion.cpp @@ -37,6 +37,7 @@ #include "llmotion.h" #include "llcriticaldamp.h" +#include "llmotioncontroller.h" //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -174,4 +175,19 @@ BOOL LLMotion::canDeprecate() return TRUE; } +//----------------------------------------------------------------------------- +// AIMaskedMotion +//----------------------------------------------------------------------------- + +BOOL AIMaskedMotion::onActivate() +{ + mController.activated(mMaskBit); + return TRUE; +} + +void AIMaskedMotion::onDeactivate() +{ + mController.deactivated(mMaskBit); +} + // End diff --git a/indra/llcharacter/llmotion.h b/indra/llcharacter/llmotion.h index d6628fd99..24504980d 100644 --- a/indra/llcharacter/llmotion.h +++ b/indra/llcharacter/llmotion.h @@ -43,6 +43,7 @@ #include "lluuid.h" class LLCharacter; +class LLMotionController; //----------------------------------------------------------------------------- // class LLMotion @@ -201,7 +202,7 @@ class LLTestMotion : public LLMotion public: LLTestMotion(const LLUUID &id) : LLMotion(id){} ~LLTestMotion() {} - static LLMotion *create(const LLUUID& id) { return new LLTestMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController&) { return new LLTestMotion(id); } BOOL getLoop() { return FALSE; } F32 getDuration() { return 0.0f; } F32 getEaseInDuration() { return 0.0f; } @@ -225,7 +226,7 @@ class LLNullMotion : public LLMotion public: LLNullMotion(const LLUUID &id) : LLMotion(id) {} ~LLNullMotion() {} - static LLMotion *create(const LLUUID &id) { return new LLNullMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController&) { return new LLNullMotion(id); } // motions must specify whether or not they loop /*virtual*/ BOOL getLoop() { return TRUE; } @@ -266,5 +267,42 @@ public: // called when a motion is deactivated /*virtual*/ void onDeactivate() {} }; + + +//----------------------------------------------------------------------------- +// AIMaskedMotion +//----------------------------------------------------------------------------- + +// These motions have a bit assigned in LLMotionController::mActiveMask +// that is set and uset upon activation/deactivation. + +// This must be in the same order as ANIM_AGENT_BODY_NOISE_ID through ANIM_AGENT_WALK_ADJUST_ID in llvoavatar.cpp. +U32 const ANIM_AGENT_BODY_NOISE = 0x001; +U32 const ANIM_AGENT_BREATHE_ROT = 0x002; +U32 const ANIM_AGENT_PHYSICS_MOTION = 0x004; +U32 const ANIM_AGENT_EDITING = 0x008; +U32 const ANIM_AGENT_EYE = 0x010; +U32 const ANIM_AGENT_FLY_ADJUST = 0x020; +U32 const ANIM_AGENT_HAND_MOTION = 0x040; +U32 const ANIM_AGENT_HEAD_ROT = 0x080; +U32 const ANIM_AGENT_PELVIS_FIX = 0x100; +U32 const ANIM_AGENT_TARGET = 0x200; +U32 const ANIM_AGENT_WALK_ADJUST = 0x400; + +class AIMaskedMotion : public LLMotion +{ +private: + LLMotionController& mController; + U32 mMaskBit; + +public: + AIMaskedMotion(LLUUID const& id, LLMotionController& controller, U32 mask_bit) : LLMotion(id), mController(controller), mMaskBit(mask_bit) { } + + /*virtual*/ BOOL onActivate(); + /*virtual*/ void onDeactivate(); + + U32 getMaskBit(void) const { return mMaskBit; } +}; + #endif // LL_LLMOTION_H diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index b5d60205c..4935fb3a7 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -97,7 +97,7 @@ void LLMotionRegistry::markBad( const LLUUID& id ) //----------------------------------------------------------------------------- // createMotion() //----------------------------------------------------------------------------- -LLMotion *LLMotionRegistry::createMotion( const LLUUID &id ) +LLMotion* LLMotionRegistry::createMotion(LLUUID const& id, LLMotionController& controller) { LLMotionConstructor constructor = get_if_there(mMotionTable, id, LLMotionConstructor(NULL)); LLMotion* motion = NULL; @@ -105,11 +105,11 @@ LLMotion *LLMotionRegistry::createMotion( const LLUUID &id ) if ( constructor == NULL ) { // *FIX: need to replace with a better default scheme. RN - motion = LLKeyframeMotion::create(id); + motion = LLKeyframeMotion::create(id, controller); } else { - motion = constructor(id); + motion = constructor(id, controller); } return motion; @@ -126,18 +126,19 @@ LLMotion *LLMotionRegistry::createMotion( const LLUUID &id ) // Class Constructor //----------------------------------------------------------------------------- LLMotionController::LLMotionController() - : mTimeFactor(sCurrentTimeFactor), + : mIsSelf(FALSE), + mTimeFactor(sCurrentTimeFactor), mCharacter(NULL), - mAnimTime(0.f), + mActiveMask(0), mPrevTimerElapsed(0.f), + mAnimTime(0.f), mLastTime(0.0f), mHasRunOnce(FALSE), mPaused(FALSE), mPauseTime(0.f), mTimeStep(0.f), mTimeStepCount(0), - mLastInterp(0.f), - mIsSelf(FALSE) + mLastInterp(0.f) { } @@ -169,6 +170,7 @@ void LLMotionController::deleteAllMotions() mLoadedMotions.clear(); mActiveMotions.clear(); // + mActiveMask = 0; for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer()); mDeprecatedMotions.clear(); // @@ -357,7 +359,7 @@ LLMotion* LLMotionController::createMotion( const LLUUID &id ) if (!motion) { // look up constructor and create it - motion = sRegistry.createMotion(id); + motion = sRegistry.createMotion(id, *this); if (!motion) { return NULL; diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index 7e0cc7ad7..9b6c71ef1 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -51,11 +51,12 @@ // This is necessary because llcharacter.h includes this file. //----------------------------------------------------------------------------- class LLCharacter; +class LLMotionController; //----------------------------------------------------------------------------- // LLMotionRegistry //----------------------------------------------------------------------------- -typedef LLMotion*(*LLMotionConstructor)(const LLUUID &id); +typedef LLMotion* (*LLMotionConstructor)(LLUUID const& id, LLMotionController&); class LLMotionRegistry { @@ -72,7 +73,7 @@ public: // creates a new instance of a named motion // returns NULL motion is not registered - LLMotion *createMotion( const LLUUID &id ); + LLMotion* createMotion(LLUUID const& id, LLMotionController& controller); // initialization of motion failed, don't try to create this motion again void markBad( const LLUUID& id ); @@ -149,6 +150,12 @@ public: //Flush is a liar. void deactivateAllMotions(); + // + void activated(U32 bit) { mActiveMask |= bit; } + void deactivated(U32 bit) { mActiveMask &= ~bit; } + bool isactive(U32 bit) const { return (mActiveMask & bit) != 0; } + // + // pause and continue all motions void pauseAllMotions(); void unpauseAllMotions(); @@ -219,7 +226,10 @@ protected: motion_set_t mLoadedMotions; motion_list_t mActiveMotions; motion_set_t mDeprecatedMotions; - + + // + U32 mActiveMask; + // LLFrameTimer mTimer; F32 mPrevTimerElapsed; F32 mAnimTime; diff --git a/indra/llcharacter/lltargetingmotion.cpp b/indra/llcharacter/lltargetingmotion.cpp index a330b2265..423eca363 100644 --- a/indra/llcharacter/lltargetingmotion.cpp +++ b/indra/llcharacter/lltargetingmotion.cpp @@ -52,7 +52,7 @@ const F32 TORSO_ROT_FRACTION = 0.5f; // LLTargetingMotion() // Class Constructor //----------------------------------------------------------------------------- -LLTargetingMotion::LLTargetingMotion(const LLUUID &id) : LLMotion(id) +LLTargetingMotion::LLTargetingMotion(LLUUID const& id, LLMotionController& controller) : AIMaskedMotion(id, controller, ANIM_AGENT_TARGET) { mCharacter = NULL; mName = "targeting"; @@ -99,14 +99,6 @@ LLMotion::LLMotionInitStatus LLTargetingMotion::onInitialize(LLCharacter *charac return STATUS_SUCCESS; } -//----------------------------------------------------------------------------- -// LLTargetingMotion::onActivate() -//----------------------------------------------------------------------------- -BOOL LLTargetingMotion::onActivate() -{ - return TRUE; -} - //----------------------------------------------------------------------------- // LLTargetingMotion::onUpdate() //----------------------------------------------------------------------------- @@ -166,12 +158,4 @@ BOOL LLTargetingMotion::onUpdate(F32 time, U8* joint_mask) return result; } -//----------------------------------------------------------------------------- -// LLTargetingMotion::onDeactivate() -//----------------------------------------------------------------------------- -void LLTargetingMotion::onDeactivate() -{ -} - - // End diff --git a/indra/llcharacter/lltargetingmotion.h b/indra/llcharacter/lltargetingmotion.h index 1ec9f80d6..8dfa32500 100644 --- a/indra/llcharacter/lltargetingmotion.h +++ b/indra/llcharacter/lltargetingmotion.h @@ -48,11 +48,11 @@ // class LLTargetingMotion //----------------------------------------------------------------------------- class LLTargetingMotion : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLTargetingMotion(const LLUUID &id); + LLTargetingMotion(LLUUID const& id, LLMotionController& controller); // Destructor virtual ~LLTargetingMotion(); @@ -64,7 +64,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLTargetingMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLTargetingMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -96,19 +96,11 @@ public: // must return true to indicate success and be available for activation virtual LLMotionInitStatus onInitialize(LLCharacter *character); - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate(); - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask); - // called when a motion is deactivated - virtual void onDeactivate(); - public: LLCharacter *mCharacter; diff --git a/indra/newview/llemote.h b/indra/newview/llemote.h index 99d05b9a2..eb2af5b9d 100644 --- a/indra/newview/llemote.h +++ b/indra/newview/llemote.h @@ -67,7 +67,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLEmote(id); } + static LLMotion* create(LLUUID const& id, LLMotionController&) { return new LLEmote(id); } public: //------------------------------------------------------------------------- diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp index eef650101..9f6acb60b 100644 --- a/indra/newview/llhudeffectlookat.cpp +++ b/indra/newview/llhudeffectlookat.cpp @@ -611,8 +611,9 @@ void LLHUDEffectLookAt::update() { if (calcTargetPosition()) { - LLMotion* head_motion = ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->findMotion(ANIM_AGENT_HEAD_ROT); - if (!head_motion || head_motion->isStopped()) + //LLMotion* head_motion = ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->findMotion(ANIM_AGENT_HEAD_ROT); + //if (!head_motion || head_motion->isStopped()) + // singu: startMotion does basically the same as the above two lines... it starts it, unless it was already started. { ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->startMotion(ANIM_AGENT_HEAD_ROT); } diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index 6fc0ab438..625199b3f 100644 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -314,8 +314,8 @@ void LLPhysicsMotion::getString(std::ostringstream &oss) } } -LLPhysicsMotionController::LLPhysicsMotionController(const LLUUID &id) : - LLMotion(id), +LLPhysicsMotionController::LLPhysicsMotionController(LLUUID const& id, LLMotionController& controller) : + AIMaskedMotion(id, controller, ANIM_AGENT_PHYSICS_MOTION), mCharacter(NULL), mIsDefault(true) { @@ -332,15 +332,6 @@ LLPhysicsMotionController::~LLPhysicsMotionController() } } -BOOL LLPhysicsMotionController::onActivate() -{ - return TRUE; -} - -void LLPhysicsMotionController::onDeactivate() -{ -} - LLMotion::LLMotionInitStatus LLPhysicsMotionController::onInitialize(LLCharacter *character) { mCharacter = character; @@ -889,4 +880,4 @@ void LLPhysicsMotion::reset() mCharacter->setVisualParamWeight((*iter).mParam,(*iter).mParam->getDefaultWeight()); } } -} \ No newline at end of file +} diff --git a/indra/newview/llphysicsmotion.h b/indra/newview/llphysicsmotion.h index 7412c9d88..62e0ae658 100644 --- a/indra/newview/llphysicsmotion.h +++ b/indra/newview/llphysicsmotion.h @@ -42,14 +42,14 @@ class LLPhysicsMotion; // class LLPhysicsMotion //----------------------------------------------------------------------------- class LLPhysicsMotionController : - public LLMotion + public AIMaskedMotion { public: std::string getString(); // Constructor - LLPhysicsMotionController(const LLUUID &id); + LLPhysicsMotionController(LLUUID const& id, LLMotionController& controller); // Destructor virtual ~LLPhysicsMotionController(); @@ -61,7 +61,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLPhysicsMotionController(id); } + static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLPhysicsMotionController(id, controller); } public: //------------------------------------------------------------------------- @@ -93,19 +93,11 @@ public: // must return true to indicate success and be available for activation virtual LLMotionInitStatus onInitialize(LLCharacter *character); - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate(); - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask); - // called when a motion is deactivated - virtual void onDeactivate(); - LLCharacter* getCharacter() { return mCharacter; } protected: diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index aec11e199..943279d6b 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -145,18 +145,104 @@ using namespace LLAvatarAppearanceDefines; //----------------------------------------------------------------------------- // Global constants //----------------------------------------------------------------------------- -const LLUUID ANIM_AGENT_BODY_NOISE = LLUUID("9aa8b0a6-0c6f-9518-c7c3-4f41f2c001ad"); //"body_noise" -const LLUUID ANIM_AGENT_BREATHE_ROT = LLUUID("4c5a103e-b830-2f1c-16bc-224aa0ad5bc8"); //"breathe_rot" -const LLUUID ANIM_AGENT_EDITING = LLUUID("2a8eba1d-a7f8-5596-d44a-b4977bf8c8bb"); //"editing" -const LLUUID ANIM_AGENT_EYE = LLUUID("5c780ea8-1cd1-c463-a128-48c023f6fbea"); //"eye" -const LLUUID ANIM_AGENT_FLY_ADJUST = LLUUID("db95561f-f1b0-9f9a-7224-b12f71af126e"); //"fly_adjust" -const LLUUID ANIM_AGENT_HAND_MOTION = LLUUID("ce986325-0ba7-6e6e-cc24-b17c4b795578"); //"hand_motion" -const LLUUID ANIM_AGENT_HEAD_ROT = LLUUID("e6e8d1dd-e643-fff7-b238-c6b4b056a68d"); //"head_rot" -const LLUUID ANIM_AGENT_PELVIS_FIX = LLUUID("0c5dd2a2-514d-8893-d44d-05beffad208b"); //"pelvis_fix" -const LLUUID ANIM_AGENT_TARGET = LLUUID("0e4896cb-fba4-926c-f355-8720189d5b55"); //"target" -const LLUUID ANIM_AGENT_WALK_ADJUST = LLUUID("829bc85b-02fc-ec41-be2e-74cc6dd7215d"); //"walk_adjust" -const LLUUID ANIM_AGENT_PHYSICS_MOTION = LLUUID("7360e029-3cb8-ebc4-863e-212df440d987"); //"physics_motion" +const LLUUID ANIM_AGENT_BODY_NOISE_ID = LLUUID("9aa8b0a6-0c6f-9518-c7c3-4f41f2c001ad"); //"body_noise" +const LLUUID ANIM_AGENT_BREATHE_ROT_ID = LLUUID("4c5a103e-b830-2f1c-16bc-224aa0ad5bc8"); //"breathe_rot" +const LLUUID ANIM_AGENT_PHYSICS_MOTION_ID = LLUUID("7360e029-3cb8-ebc4-863e-212df440d987"); //"physics_motion" +const LLUUID ANIM_AGENT_EDITING_ID = LLUUID("2a8eba1d-a7f8-5596-d44a-b4977bf8c8bb"); //"editing" +const LLUUID ANIM_AGENT_EYE_ID = LLUUID("5c780ea8-1cd1-c463-a128-48c023f6fbea"); //"eye" +const LLUUID ANIM_AGENT_FLY_ADJUST_ID = LLUUID("db95561f-f1b0-9f9a-7224-b12f71af126e"); //"fly_adjust" +const LLUUID ANIM_AGENT_HAND_MOTION_ID = LLUUID("ce986325-0ba7-6e6e-cc24-b17c4b795578"); //"hand_motion" +const LLUUID ANIM_AGENT_HEAD_ROT_ID = LLUUID("e6e8d1dd-e643-fff7-b238-c6b4b056a68d"); //"head_rot" +const LLUUID ANIM_AGENT_PELVIS_FIX_ID = LLUUID("0c5dd2a2-514d-8893-d44d-05beffad208b"); //"pelvis_fix" +const LLUUID ANIM_AGENT_TARGET_ID = LLUUID("0e4896cb-fba4-926c-f355-8720189d5b55"); //"target" +const LLUUID ANIM_AGENT_WALK_ADJUST_ID = LLUUID("829bc85b-02fc-ec41-be2e-74cc6dd7215d"); //"walk_adjust" +// +// This must be in the same order as ANIM_AGENT_BODY_NOISE through ANIM_AGENT_WALK_ADJUST (see llmotion.h)! +static LLUUID const* lookup[] = { + &ANIM_AGENT_BODY_NOISE_ID, + &ANIM_AGENT_BREATHE_ROT_ID, + &ANIM_AGENT_PHYSICS_MOTION_ID, + &ANIM_AGENT_EDITING_ID, + &ANIM_AGENT_EYE_ID, + &ANIM_AGENT_FLY_ADJUST_ID, + &ANIM_AGENT_HAND_MOTION_ID, + &ANIM_AGENT_HEAD_ROT_ID, + &ANIM_AGENT_PELVIS_FIX_ID, + &ANIM_AGENT_TARGET_ID, + &ANIM_AGENT_WALK_ADJUST_ID +}; + +LLUUID const& mask2ID(U32 bit) +{ + int const lookupsize = sizeof(lookup) / sizeof(LLUUID const*); + int i = lookupsize - 1; + U32 mask = 1 << i; + for(;;) + { + if (bit == mask) + { + return *lookup[i]; + } + --i; + mask >>= 1; + llassert_always(i >= 0); + } +} + +#ifdef CWDEBUG +static char const* strlookup[] = { + "ANIM_AGENT_BODY_NOISE", + "ANIM_AGENT_BREATHE_ROT", + "ANIM_AGENT_PHYSICS_MOTION", + "ANIM_AGENT_EDITING", + "ANIM_AGENT_EYE", + "ANIM_AGENT_FLY_ADJUST", + "ANIM_AGENT_HAND_MOTION", + "ANIM_AGENT_HEAD_ROT", + "ANIM_AGENT_PELVIS_FIX", + "ANIM_AGENT_TARGET", + "ANIM_AGENT_WALK_ADJUST" +}; + +char const* mask2str(U32 bit) +{ + int const lookupsize = sizeof(lookup) / sizeof(LLUUID const*); + int i = lookupsize - 1; + U32 mask = 1 << i; + do + { + if (bit == mask) + { + return strlookup[i]; + } + --i; + mask >>= 1; + } + while(i >= 0); + return ""; +} +#endif + +// stopMotion(ANIM_AGENT_WALK_ADJUST) is called every frame, and for every avatar on the radar. +// That can be like 1000 times per second, so... speed that up a bit and lets not lookup the same LLUUID 1000 times +// per second in a std::map. Added the rest of the animations while I was at it. +void LLVOAvatar::startMotion(U32 bit, F32 time_offset) +{ + if (!isMotionActive(bit)) + { + startMotion(mask2ID(bit), time_offset); + } +} + +void LLVOAvatar::stopMotion(U32 bit, BOOL stop_immediate) +{ + if (isMotionActive(bit)) + { + stopMotion(mask2ID(bit), stop_immediate); + } +} +// //----------------------------------------------------------------------------- // Constants @@ -257,12 +343,12 @@ struct LLTextureMaskData // class LLBodyNoiseMotion //----------------------------------------------------------------------------- class LLBodyNoiseMotion : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLBodyNoiseMotion(const LLUUID &id) - : LLMotion(id) + LLBodyNoiseMotion(LLUUID const& id, LLMotionController& controller) + : AIMaskedMotion(id, controller, ANIM_AGENT_BODY_NOISE) { mName = "body_noise"; mTorsoState = new LLJointState; @@ -277,7 +363,7 @@ public: //------------------------------------------------------------------------- // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLBodyNoiseMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLBodyNoiseMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -320,11 +406,6 @@ public: return STATUS_SUCCESS; } - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate() { return TRUE; } - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. @@ -348,9 +429,6 @@ public: return TRUE; } - // called when a motion is deactivated - virtual void onDeactivate() {} - private: //------------------------------------------------------------------------- // joint states to be animated @@ -362,12 +440,12 @@ private: // class LLBreatheMotionRot //----------------------------------------------------------------------------- class LLBreatheMotionRot : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLBreatheMotionRot(const LLUUID &id) : - LLMotion(id), + LLBreatheMotionRot(LLUUID const& id, LLMotionController& controller) : + AIMaskedMotion(id, controller, ANIM_AGENT_BREATHE_ROT), mBreatheRate(1.f), mCharacter(NULL) { @@ -384,7 +462,7 @@ public: //------------------------------------------------------------------------- // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLBreatheMotionRot(id); } + static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLBreatheMotionRot(id, controller); } public: //------------------------------------------------------------------------- @@ -437,11 +515,6 @@ public: } } - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate() { return TRUE; } - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. @@ -456,9 +529,6 @@ public: return TRUE; } - // called when a motion is deactivated - virtual void onDeactivate() {} - private: //------------------------------------------------------------------------- // joint states to be animated @@ -472,12 +542,12 @@ private: // class LLPelvisFixMotion //----------------------------------------------------------------------------- class LLPelvisFixMotion : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLPelvisFixMotion(const LLUUID &id) - : LLMotion(id), mCharacter(NULL) + LLPelvisFixMotion(LLUUID const& id, LLMotionController& controller) + : AIMaskedMotion(id, controller, ANIM_AGENT_PELVIS_FIX), mCharacter(NULL) { mName = "pelvis_fix"; @@ -493,7 +563,7 @@ public: //------------------------------------------------------------------------- // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID& id) { return new LLPelvisFixMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLPelvisFixMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -538,11 +608,6 @@ public: return STATUS_SUCCESS; } - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate() { return TRUE; } - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. @@ -553,9 +618,6 @@ public: return TRUE; } - // called when a motion is deactivated - virtual void onDeactivate() {} - private: //------------------------------------------------------------------------- // joint states to be animated @@ -1438,17 +1500,17 @@ void LLVOAvatar::deleteCachedImages(bool clearAll) //------------------------------------------------------------------------ void LLVOAvatar::initClass() { - gAnimLibrary.animStateSetString(ANIM_AGENT_BODY_NOISE,"body_noise"); - gAnimLibrary.animStateSetString(ANIM_AGENT_BREATHE_ROT,"breathe_rot"); - gAnimLibrary.animStateSetString(ANIM_AGENT_PHYSICS_MOTION,"physics_motion"); - gAnimLibrary.animStateSetString(ANIM_AGENT_EDITING,"editing"); - gAnimLibrary.animStateSetString(ANIM_AGENT_EYE,"eye"); - gAnimLibrary.animStateSetString(ANIM_AGENT_FLY_ADJUST,"fly_adjust"); - gAnimLibrary.animStateSetString(ANIM_AGENT_HAND_MOTION,"hand_motion"); - gAnimLibrary.animStateSetString(ANIM_AGENT_HEAD_ROT,"head_rot"); - gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX,"pelvis_fix"); - gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET,"target"); - gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST,"walk_adjust"); + gAnimLibrary.animStateSetString(ANIM_AGENT_BODY_NOISE_ID,"body_noise"); + gAnimLibrary.animStateSetString(ANIM_AGENT_BREATHE_ROT_ID,"breathe_rot"); + gAnimLibrary.animStateSetString(ANIM_AGENT_PHYSICS_MOTION_ID,"physics_motion"); + gAnimLibrary.animStateSetString(ANIM_AGENT_EDITING_ID,"editing"); + gAnimLibrary.animStateSetString(ANIM_AGENT_EYE_ID,"eye"); + gAnimLibrary.animStateSetString(ANIM_AGENT_FLY_ADJUST_ID,"fly_adjust"); + gAnimLibrary.animStateSetString(ANIM_AGENT_HAND_MOTION_ID,"hand_motion"); + gAnimLibrary.animStateSetString(ANIM_AGENT_HEAD_ROT_ID,"head_rot"); + gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX_ID,"pelvis_fix"); + gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET_ID,"target"); + gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST_ID,"walk_adjust"); SHClientTagMgr::instance(); //Instantiate. Parse. Will fetch a new tag file if AscentUpdateTagsOnLoad is true. } @@ -1506,19 +1568,19 @@ void LLVOAvatar::initInstance(void) registerMotion( ANIM_AGENT_WALK_NEW, LLKeyframeWalkMotion::create ); //v2 // motions without a start/stop bit - registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create ); - registerMotion( ANIM_AGENT_BREATHE_ROT, LLBreatheMotionRot::create ); - registerMotion( ANIM_AGENT_PHYSICS_MOTION, LLPhysicsMotionController::create ); - registerMotion( ANIM_AGENT_EDITING, LLEditingMotion::create ); - registerMotion( ANIM_AGENT_EYE, LLEyeMotion::create ); - registerMotion( ANIM_AGENT_FLY_ADJUST, LLFlyAdjustMotion::create ); - registerMotion( ANIM_AGENT_HAND_MOTION, LLHandMotion::create ); - registerMotion( ANIM_AGENT_HEAD_ROT, LLHeadRotMotion::create ); - registerMotion( ANIM_AGENT_PELVIS_FIX, LLPelvisFixMotion::create ); - registerMotion( ANIM_AGENT_SIT_FEMALE, LLKeyframeMotion::create ); - registerMotion( ANIM_AGENT_TARGET, LLTargetingMotion::create ); - registerMotion( ANIM_AGENT_WALK_ADJUST, LLWalkAdjustMotion::create ); + registerMotion( ANIM_AGENT_BODY_NOISE_ID, LLBodyNoiseMotion::create ); + registerMotion( ANIM_AGENT_BREATHE_ROT_ID, LLBreatheMotionRot::create ); + registerMotion( ANIM_AGENT_PHYSICS_MOTION_ID, LLPhysicsMotionController::create ); + registerMotion( ANIM_AGENT_EDITING_ID, LLEditingMotion::create ); + registerMotion( ANIM_AGENT_EYE_ID, LLEyeMotion::create ); + registerMotion( ANIM_AGENT_FLY_ADJUST_ID, LLFlyAdjustMotion::create ); + registerMotion( ANIM_AGENT_HAND_MOTION_ID, LLHandMotion::create ); + registerMotion( ANIM_AGENT_HEAD_ROT_ID, LLHeadRotMotion::create ); + registerMotion( ANIM_AGENT_PELVIS_FIX_ID, LLPelvisFixMotion::create ); + registerMotion( ANIM_AGENT_TARGET_ID, LLTargetingMotion::create ); + registerMotion( ANIM_AGENT_WALK_ADJUST_ID, LLWalkAdjustMotion::create ); + registerMotion( ANIM_AGENT_SIT_FEMALE, LLKeyframeMotion::create ); } LLAvatarAppearance::initInstance(); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 891fae7d9..ded74c50b 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -54,6 +54,9 @@ #include "llavatarname.h" +// +#if 0 +// Hide these: should be using the bit masks everywhere. extern const LLUUID ANIM_AGENT_BODY_NOISE; extern const LLUUID ANIM_AGENT_BREATHE_ROT; extern const LLUUID ANIM_AGENT_PHYSICS_MOTION; @@ -65,6 +68,8 @@ extern const LLUUID ANIM_AGENT_HEAD_ROT; extern const LLUUID ANIM_AGENT_PELVIS_FIX; extern const LLUUID ANIM_AGENT_TARGET; extern const LLUUID ANIM_AGENT_WALK_ADJUST; +#endif +// class LLAPRFile; class LLViewerWearable; @@ -230,6 +235,10 @@ public: /*virtual*/ LLUUID remapMotionID(const LLUUID& id); /*virtual*/ BOOL startMotion(const LLUUID& id, F32 time_offset = 0.f); /*virtual*/ BOOL stopMotion(const LLUUID& id, BOOL stop_immediate = FALSE); + // + void startMotion(U32 bit, F32 start_offset = 0.f); + void stopMotion(U32 bit, BOOL stop_immediate = FALSE); + // virtual void stopMotionFromSource(const LLUUID& source_id); virtual void requestStopMotion(LLMotion* motion); LLMotion* findMotion(const LLUUID& id) const; From e38ec797fda86206b01fc1d3d59b000f0efa2652 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 4 Dec 2013 22:40:07 +0100 Subject: [PATCH 095/115] Fix lookat and pointat shared experience. There was a bug that when people turned off sending viewer effects, they'd also turn off sending LookAt, while there is a seperate checkbox to turn THAT off, while still seeing their own avatar happily look around, breaking shared experience (most notably, most people will be complete oblivious of the fact that they look like zombies to others and that their friends do not see the same thing on their screen). This patch fixes this: both parties now see the same thing. Lookat and PointAt are only turned off by their respective checkboxes, and no longer silently influenced by turning off other viewer effects. --- indra/newview/llhudmanager.cpp | 25 ++++++++++++++++--- indra/newview/llvoavatarself.cpp | 6 ++--- .../en-us/panel_preferences_ascent_system.xml | 4 +-- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/indra/newview/llhudmanager.cpp b/indra/newview/llhudmanager.cpp index cb9a2c1d3..15872a0db 100644 --- a/indra/newview/llhudmanager.cpp +++ b/indra/newview/llhudmanager.cpp @@ -80,14 +80,33 @@ void LLHUDManager::updateEffects() void LLHUDManager::sendEffects() { + static LLCachedControl disable_lookat_effect(gSavedSettings, "PrivateLookAt", false); + static LLCachedControl disable_pointat_effect(gSavedSettings, "DisablePointAtAndBeam", false); + static LLCachedControl broadcast_viewer_effects(gSavedSettings, "BroadcastViewerEffects", true); - if(!gSavedSettings.getBOOL("BroadcastViewerEffects")) - return; - S32 i; for (i = 0; i < mHUDEffects.count(); i++) { LLHUDEffect *hep = mHUDEffects[i]; + if (hep->mType == LLHUDObject::LL_HUD_EFFECT_LOOKAT) + { + if (disable_lookat_effect) + { + continue; + } + } + else if (hep->mType == LLHUDObject::LL_HUD_EFFECT_POINTAT || + hep->mType == LLHUDObject::LL_HUD_EFFECT_BEAM) + { + if (disable_pointat_effect) + { + continue; + } + } + else if (!broadcast_viewer_effects) + { + continue; + } if (hep->isDead()) { llwarns << "Trying to send dead effect!" << llendl; diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 6f0a4bd9f..c3ead99db 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -897,9 +897,9 @@ void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp) //virtual void LLVOAvatarSelf::idleUpdateTractorBeam() { - - - if(gSavedSettings.getBOOL("DisablePointAtAndBeam")) + // + static LLCachedControl disable_pointat_effect("DisablePointAtAndBeam"); + if (disable_pointat_effect) { return; } diff --git a/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_system.xml b/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_system.xml index e4d6537c0..72a5362fc 100644 --- a/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_system.xml +++ b/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_system.xml @@ -83,9 +83,9 @@ - + - + From 006b319c3a9be55181e0c2e02d6b9040402151f2 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 5 Dec 2013 14:53:16 +0100 Subject: [PATCH 096/115] Add AISyncClient<> (and AISyncServer). A tool to synchronize objects: Objects derived from AISyncClient can signal that they are 'ready' or 'not ready' for up to 4 events (using a bitmask) at a time. Clients that signal to be ready for anything at roughly the same time as other clients, and which return the same 'hash' (a virtual function returning a 64bit value) will be grouped together and receive events (by means of virtual functions being called) to notify them of all clients being ready or not for one of the events (syncevent1). The other three events can be polled. The memory usage is low (one pointer per client that points to its AISyncServer object), servers are released to a cache after about 100 ms (unless there is actual need for synchronization), so there aren't much of those either. The CPU usage is extremely low: all events are handled in parallel in a 32 bit value (6 bits per event to count the number of registered clients and the number of ready clients for each event, and the remaining 8 bits to count the number of reference pointers (which should only be a constant higher, so that is overkill). To signal to a server that a client has become ready or not is mostly a function call, which then takes 1 clock cycle or so before returning. Registration of a client is slightly more expensive as it requires a pointer to be added to the end of a std::list. This tool could easily be used as part of the graphics engine (not that I intend to do that :p). --- indra/llcommon/CMakeLists.txt | 2 + indra/llcommon/aisyncclient.cpp | 538 ++++++++++++++++++++++++++++++++ indra/llcommon/aisyncclient.h | 417 +++++++++++++++++++++++++ 3 files changed, 957 insertions(+) create mode 100644 indra/llcommon/aisyncclient.cpp create mode 100644 indra/llcommon/aisyncclient.h diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 31e4fa484..fd0e8208c 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -20,6 +20,7 @@ set(llcommon_SOURCE_FILES aialert.cpp aifile.cpp aiframetimer.cpp + aisyncclient.cpp aithreadid.cpp imageids.cpp indra_constants.cpp @@ -112,6 +113,7 @@ set(llcommon_HEADER_FILES aifile.h aiframetimer.h airecursive.h + aisyncclient.h aithreadid.h aithreadsafe.h bitpack.h diff --git a/indra/llcommon/aisyncclient.cpp b/indra/llcommon/aisyncclient.cpp new file mode 100644 index 000000000..18ca33edc --- /dev/null +++ b/indra/llcommon/aisyncclient.cpp @@ -0,0 +1,538 @@ +/** + * @file aisyncclient.cpp + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 05/12/2013 + * - Initial version, written by Aleric Inglewood @ SL + */ + +#include "sys.h" +#include "aisyncclient.h" +#include +#include "debug.h" + +typedef std::deque > servers_type; +static servers_type servers[syncgroup_size]; + +//static +template +void AISyncServer::register_client(AISyncClient_ServerPtr* client) +{ +#ifdef DEBUG_SYNCOUTPUT + DoutEntering(dc::notice, "AISyncServer::register_client(" << client << ")"); +#endif + + // Determine which server to use. + boost::intrusive_ptr server; + int expired = 0; + AISyncKey const sync_key(client->sync_key_hash()); + for (servers_type::iterator server_iter = servers[syncgroup].begin(); server_iter != servers[syncgroup].end(); ++server_iter) + { + boost::intrusive_ptr& server_ptr = *server_iter; + if (server_ptr->mSyncKey.expired()) + { + ++expired; + // If the server only contains a single client, then unregister it and put the server (back) in the server cache. + if (server_ptr->get_refcount() == 2) + { + server_ptr->unregister_last_client(); + AISyncServer::dispose_server(server_ptr); + } + continue; + } + if (server_ptr->mSyncKey.matches(sync_key)) + { + server = server_ptr; + break; + } + } + // Remove servers with expired keys. + if (expired) + { + if (expired == servers[syncgroup].size()) + { + servers[syncgroup].clear(); + } + else + { + servers[syncgroup].erase(servers[syncgroup].begin(), servers[syncgroup].begin() + expired); + } + } + if (!server) + { + AISyncServer::create_server(server, sync_key); + servers[syncgroup].push_back(server); + } + + // Sanity check: the client should never already be registered. + llassert(!client->mSyncServer); + // Recover from assertion failure. + if (client->mSyncServer) + { + if (client->mSyncServer == server) + { + return; + } + client->mSyncServer->unregister_client(client, syncgroup); + register_client(client); + return; + } + + // Obviously... + llassert(!client->mReadyEvents); + + // Check if the current clients are all ready: adding a new one will cause the group to become not-ready. + bool all_old_clients_are_ready = server->mNrReady && !((server->mNrClients - server->mNrReady) & synccountmask1); + // Add new client to the group. + client->mSyncServer = server; + server->mNrClients += syncevents; + llassert((server->mNrClients & syncoverflowbits) == 0); + if (all_old_clients_are_ready) + { + server->trigger_not_ready(); // Tell all old clients that the group is not ready. + } + server->mClients.push_back(client); // Actually add the new client to the list. +} + +void AISyncServer::unregister_client(AISyncClient_ServerPtr* client, syncgroups syncgroup) +{ +#ifdef DEBUG_SYNCOUTPUT + DoutEntering(dc::notice, "unregister_client(" << client << ", " << syncgroup << "), with this = " << this); +#endif + + // The client must be registered with this server. + llassert(client->mSyncServer == this); + // A client may only be unregistered after it was marked not-ready for all events. + llassert(!client->mReadyEvents); + // Run over all registered clients. + for (client_list_type::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter) + { + // Found it? + if (*client_iter == client) + { + mClients.erase(client_iter); + // Are the remaining clients ready? + if (mNrReady && !((mNrClients - syncevents - mNrReady) & synccountmask1)) + { + trigger_ready(); + } + mNrClients -= syncevents; + llassert((mNrClients & syncoverflowbits) == 0); + client->mSyncServer.reset(); // This might delete the current object. + break; + } + } + // The client must have been found. + llassert(!client->mSyncServer); +} + +void AISyncServer::unregister_last_client(void) +{ +#ifdef DEBUG_SYNCOUTPUT + DoutEntering(dc::notice, "unregister_last_client(), with this = " << this); +#endif + + // This function may only be called for servers with exactly one client. + llassert(mClients.size() == 1); + AISyncClient_ServerPtr* client = *mClients.begin(); +#ifdef DEBUG_SYNCOUTPUT + Dout(dc::notice, "unregistering client " << client); +#endif + mClients.clear(); + mNrClients -= syncevents; + mNrReady = 0; + llassert((mNrClients & syncoverflowbits) == 0); + client->mSyncServer.reset(); + client->deregistered(); +} + +synceventset AISyncServer::events_with_all_clients_ready(void) const +{ + synccount nrNotReady = mNrClients - mNrReady; + synceventset result1 = !(nrNotReady & synccountmask1) ? syncevent1 : 0; + synceventset result2 = !(nrNotReady & synccountmask2) ? syncevent2 : 0; + synceventset result3 = !(nrNotReady & synccountmask3) ? syncevent3 : 0; + synceventset result4 = !(nrNotReady & synccountmask4) ? syncevent4 : 0; + result1 |= result2; + result3 |= result4; + return result1 | result3; +} + +synceventset AISyncServer::events_with_at_least_one_client_ready(void) const +{ + synceventset result1 = (mNrReady & synccountmask1) ? syncevent1 : 0; + synceventset result2 = (mNrReady & synccountmask2) ? syncevent2 : 0; + synceventset result3 = (mNrReady & synccountmask3) ? syncevent3 : 0; + synceventset result4 = (mNrReady & synccountmask4) ? syncevent4 : 0; + result1 |= result2; + result3 |= result4; + return result1 | result3; +} + +#ifdef CWDEBUG +struct SyncEventSet { + synceventset mBits; + SyncEventSet(synceventset bits) : mBits(bits) { } +}; + +std::ostream& operator<<(std::ostream& os, SyncEventSet const& ses) +{ + os << ((ses.mBits & syncevent4) ? '1' : '0'); + os << ((ses.mBits & syncevent3) ? '1' : '0'); + os << ((ses.mBits & syncevent2) ? '1' : '0'); + os << ((ses.mBits & syncevent1) ? '1' : '0'); + return os; +} +#endif + +bool AISyncServer::ready(synceventset events, synceventset yesno/*,*/ ASSERT_ONLY_COMMA(AISyncClient_ServerPtr* client)) +{ +#ifdef DEBUG_SYNCOUTPUT + DoutEntering(dc::notice, "AISyncServer::ready(" << SyncEventSet(events) << ", " << SyncEventSet(yesno) << ", " << client << ")"); +#endif + + synceventset added_events = events & yesno; + synceventset removed_events = events & ~yesno; + // May not add events that are already ready. + llassert(!(client->mReadyEvents & added_events)); + // Cannot remove events that weren't ready. + llassert((client->mReadyEvents & removed_events) == removed_events); + // Were all clients ready for event 1? + bool ready_before = !((mNrClients - mNrReady) & synccountmask1); + // Update mNrReady counters. + mNrReady += added_events; + mNrReady -= removed_events; + // Test for under and overflow, this limits the maximum number of clients to 127 instead of 255, but well :p. + llassert((mNrReady & syncoverflowbits) == 0); + // Are all clients ready for event 1? + bool ready_after = !((mNrClients - mNrReady) & synccountmask1); + if (ready_before && !ready_after) + { + trigger_not_ready(); + } +#ifdef SHOW_ASSERT + // Update debug administration. + client->mReadyEvents ^= events; +#ifdef DEBUG_SYNCOUTPUT + Dout(dc::notice, "Client " << client << " now has ready: " << SyncEventSet(client->mReadyEvents)); +#endif +#endif + if (!ready_before && ready_after) + { + trigger_ready(); + } +} + +void AISyncServer::trigger_ready(void) +{ + for (client_list_type::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter) + { + llassert(((*client_iter)->mReadyEvents & syncevent1)); + (*client_iter)->event1_ready(); + } +} + +void AISyncServer::trigger_not_ready(void) +{ + for (client_list_type::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter) + { + llassert(((*client_iter)->mReadyEvents & syncevent1)); + (*client_iter)->event1_not_ready(); + } +} + +void intrusive_ptr_add_ref(AISyncServer* server) +{ + server->mNrClients += syncrefcountunit; + llassert((server->mNrClients & syncoverflowbits) == 0); +} + +void intrusive_ptr_release(AISyncServer* server) +{ + llassert(server->mNrClients >= syncrefcountunit); + server->mNrClients -= syncrefcountunit; + // If there are no more pointers pointing to this server, then obviously it can't have any registered clients. + llassert(server->mNrClients >= syncrefcountunit || server->mNrClients == 0); + if (server->mNrClients == 0) + { + delete server; + } +} + +//static +sync_key_hash_type const AISyncKey::sNoRequirementHash = 0x91b42f98a9fef15cULL; + + +//============================================================================= +// SYNC_TESTSUITE +//============================================================================= + +#ifdef SYNC_TESTSUITE +#include +#include +#include +#include + +//static +U32 LLFrameTimer::sFrameCount; + +double innerloop_count = 0; + +double LLFrameTimer::getCurrentTime() +{ + return innerloop_count * 0.001; +} + +class TestsuiteServerBase : public AISyncServer +{ + public: + TestsuiteServerBase(AISyncKey const& sync_key) : AISyncServer(sync_key) { } + client_list_type& clients(void) { return mClients; } +}; + +class TestsuiteServer1 : public TestsuiteServerBase +{ + public: + TestsuiteServer1(AISyncKey const& sync_key) : TestsuiteServerBase(sync_key) { } +}; + +// Specialitations that link TestsuiteServer1 to syncgroup_test1. +// +//static +template<> +void AISyncServer::create_server(boost::intrusive_ptr& server, AISyncKey const& sync_key) +{ + AISyncServerCache::create_server(server, sync_key); +} +//static +template<> +void AISyncServer::dispose_server(boost::intrusive_ptr& server) +{ + AISyncServerCache::dispose_server(server); +} + +class TestsuiteServer2 : public TestsuiteServerBase +{ + public: + TestsuiteServer2(AISyncKey const& sync_key) : TestsuiteServerBase(sync_key) { } +}; + +// Specialitations that link TestsuiteServer2 to syncgroup_test2. +// +//static +template<> +void AISyncServer::create_server(boost::intrusive_ptr& server, AISyncKey const& sync_key) +{ + AISyncServerCache::create_server(server, sync_key); +} +//static +template<> +void AISyncServer::dispose_server(boost::intrusive_ptr& server) +{ + AISyncServerCache::dispose_server(server); +} + +template +class TestsuiteClient : public AISyncClient +{ + private: + int mIndex; + bool mRequestedRegistered; + synceventset mRequestedReady; + bool mActualReady1; + + public: + TestsuiteClient() : mIndex(-1), mRequestedRegistered(false), mRequestedReady(0), mActualReady1(false) { } + ~TestsuiteClient() { this->ready(mRequestedReady, (synceventset)0); } + + void setIndex(int index) { mIndex = index; } + + protected: + /*virtual*/ void event1_ready(void) + { + llassert(!mActualReady1); + mActualReady1 = true; + } + + /*virtual*/ void event1_not_ready(void) + { + llassert(mActualReady1); + mActualReady1 = false; + } + + /*virtual*/ sync_key_hash_type sync_key_hash(void) const + { + // Sync odd clients with eachother, and even clients with eachother. + return 0xb3c919ff + (mIndex & 1); + } + + // This is called when the server expired and we're the only client on it. + /*virtual*/ void deregistered(void) + { +#ifdef DEBUG_SYNCOUTPUT + DoutEntering(dc::notice, "TestsuiteClient<" << syncgroup << ">::deregistered(), with this = " << this); +#endif + mRequestedRegistered = false; + mRequestedReady = 0; + mActualReady1 = false; + this->mReadyEvents = 0; + } + + private: + bool is_registered(void) const { return !!this->mSyncServer; } + + public: + void change_state(unsigned long r); + bool getRequestedRegistered(void) const { return mRequestedRegistered; } + synceventset getRequestedReady(void) const { return mRequestedReady; } +}; + +TestsuiteClient* client1p; +TestsuiteClient* client2p; + +int const number_of_clients_per_syncgroup = 8; + +template +void TestsuiteClient::change_state(unsigned long r) +{ + bool change_registered = r & 1; + r >>= 1; + synceventset toggle_events = ((r & 1) ? syncevent1 : 0) | ((r & 2) ? syncevent2 : 0) | ((r & 4) ? syncevent3 : 0) | ((r & 8) ? syncevent4 : 0); + r >>= 4; + if (change_registered) + { + if (mRequestedRegistered && !mRequestedReady) + { + mRequestedRegistered = false; + this->unregister_client(); + } + } + else if (toggle_events) + { + mRequestedReady ^= toggle_events; + mRequestedRegistered = true; + this->ready(toggle_events, mRequestedReady & toggle_events); + } + llassert(mRequestedRegistered == is_registered()); + TestsuiteServerBase* server = this->server(); + llassert(!mRequestedRegistered || server->number_of_clients() == server->clients().size()); + if (mRequestedRegistered) + { + synceventset all_ready = syncevents; + synceventset any_ready = 0; + int nr = 0; + for (int cl = 0; cl < number_of_clients_per_syncgroup; ++cl) + { + if (syncgroup == syncgroup_test1) + { + if (client1p[cl].server() != server) + { + continue; + } + if (client1p[cl].getRequestedRegistered()) + { + ++nr; + all_ready &= client1p[cl].getRequestedReady(); + any_ready |= client1p[cl].getRequestedReady(); + } + } + else + { + if (client2p[cl].server() != server) + { + continue; + } + if (client2p[cl].getRequestedRegistered()) + { + ++nr; + all_ready &= client2p[cl].getRequestedReady(); + any_ready |= client2p[cl].getRequestedReady(); + } + } + } + llassert(nr == server->number_of_clients()); + llassert(!!(all_ready & syncevent1) == mActualReady1); + llassert(this->server()->events_with_all_clients_ready() == all_ready); + llassert(this->server()->events_with_at_least_one_client_ready() == any_ready); + llassert(nr == 0 || (any_ready & all_ready) == all_ready); + } + llassert(mRequestedReady == this->mReadyEvents); +} + +int main() +{ + Debug(libcw_do.on()); + Debug(dc::notice.on()); + Debug(libcw_do.set_ostream(&std::cout)); + Debug(list_channels_on(libcw_do)); + + unsigned short seed16v[3] = { 0x1234, 0xfedc, 0x7091 }; + + for (int k = 0;; ++k) + { + std::cout << "Loop: " << k << "; SEED: " << std::hex << seed16v[0] << ", " << seed16v[1] << ", " << seed16v[2] << std::dec << std::endl; + ++LLFrameTimer::sFrameCount; + + seed48(seed16v); + seed16v[0] = lrand48() & 0xffff; + seed16v[1] = lrand48() & 0xffff; + seed16v[2] = lrand48() & 0xffff; + + TestsuiteClient client1[number_of_clients_per_syncgroup]; + TestsuiteClient client2[number_of_clients_per_syncgroup]; + client1p = client1; + client2p = client2; + + for (int i = 0; i < number_of_clients_per_syncgroup; ++i) + { + client1[i].setIndex(i); + client2[i].setIndex(i); + } + + for (int j = 0; j < 1000000; ++j) + { + innerloop_count += 1; + +#ifdef DEBUG_SYNCOUTPUT + Dout(dc::notice, "Innerloop: " << j); +#endif + unsigned long r = lrand48(); + syncgroups grp = (r & 1) ? syncgroup_test1 : syncgroup_test2; + r >>= 1; + int cl = (r & 255) % number_of_clients_per_syncgroup; + r >>= 8; + switch (grp) + { + case syncgroup_test1: + client1[cl].change_state(r); + break; + case syncgroup_test2: + client2[cl].change_state(r); + break; + } + } + } +} + +#endif diff --git a/indra/llcommon/aisyncclient.h b/indra/llcommon/aisyncclient.h new file mode 100644 index 000000000..b6fcbd103 --- /dev/null +++ b/indra/llcommon/aisyncclient.h @@ -0,0 +1,417 @@ +/** + * @file aisyncclient.h + * @brief Declaration of AISyncClient. + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 05/12/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AI_SYNC_CLIENT_H +#define AI_SYNC_CLIENT_H + +#ifdef SYNC_TESTSUITE +/* + * To compile the testsuite, run: + * + * cd indra/llcommon + * g++ -O3 -DCWDEBUG -DSYNC_TESTSUITE -I. -I../cwdebug aisyncclient.cpp -lcwd + */ + +#include +#include +typedef uint32_t U32; +typedef uint64_t U64; +#define LL_COMMON_API +#define SHOW_ASSERT +#define ASSERT_ONLY_COMMA(...) , __VA_ARGS__ +#define llassert assert + +struct LLFrameTimer +{ + double mStartTime; + double mExpiry; + static double getCurrentTime(void); + static U32 sFrameCount; + static U32 getFrameCount() { return sFrameCount; } + void reset(double expiration) { mStartTime = getCurrentTime(); mExpiry = mStartTime + expiration; } + bool hasExpired(void) const { return getCurrentTime() > mExpiry; } +}; + +#else // !SYNC_TESTSUITE +#include "llpreprocessor.h" +#include "stdtypes.h" +#include "llerror.h" +#include "llframetimer.h" +#endif +#include +#include + +class AISyncServer; + +/* + * AISyncClient + * + * This class allows to synchronize events between multiple client objects, + * derived from AISyncClient, where AISYNCSERVER must be + * derived from AISyncServer. + * + * Client objects call ready(mask) (or ready(event, bool), where each bit can be + * set or unset, which will result in alternating calls to event1_ready(mask) and + * event1_not_ready(mask) for all registered clients at the same time depending on + * when all clients are ready for syncevent1 or not (the other events can be + * polled, see below). + * + * For example, let a and b be two clients: + * + * { + * AISyncClient a; + * { + * AISyncClient b; + * + * a.ready(syncevent1, true); // Calls a.event1_ready(). + * a.ready(syncevent1, false); // Calls a.event1_not_ready(). + * b.ready(syncevent1, true); // Nothing happens. + * b.ready(syncevent1, false); // Nothing happens. + * b.ready(syncevent1, true); // Nothing happens. + * a.ready(syncevent1, true); // Calls a.event1_ready() and b.event1_ready(2). + * b.ready(syncevent1, false); // Calls a.event1_not_ready() and b.event1_not_ready(). + * } // Calls a.event1_ready() because b was destructed and a is still ready. + * a.ready(syncevent1, false); // Calls a.event1_not_ready(). Must set not-ready before destructing. + * } + * + * Clients can access the server by calling server() and poll it: + * + * AISyncServer* server = server(); + * + * if (server) + * { + * int n = server->number_of_clients(); + * synceventset set1 = server->events_with_all_clients_ready(); + * synceventset set2 = server->events_with_zero_clients_ready(); + * synceventset set3 = server->events_with_at_least_one_client_ready(); + * if (n == 0) + * { + * llassert(set1 == syncevents); // We define a server with no clients to have all clients ready. + * llassert(set2 == syncevents); // If there are no clients then every event has zero ready clients. + * llassert(set3 == 0); // If there are no clients then obviously set3 is the empty set. + * } + * else + * { + * llassert((set3 & set1) == set1); // set1 is a subset of set3. + * } + * llassert((set3 & (set1 & ~set2)) == (set1 & ~set2)); + * // The set of events that have all clients ready, but not zero clients, + * // is a subset of the set of events with at least one client ready. + * llassert((set2 ^ set3) == syncevents); // Each event belongs to either set2 or set3. + * } + * + * Clients can also unregister themselves without destruction, by calling unregister(); + * This might cause a call to event1_ready() for the remaining clients, if all of them + * are ready for syncevent1. + * + * Clients must be set not-ready for all events before unregistering them. + * + * Finally, it is possible to cause a server-side unregister for all clients, + * by calling server->dissolve(). This will cause an immediate call to event1_ready() + * for all clients that are ready, unless all were already ready. + */ + +enum syncgroups +{ +#ifdef SYNC_TESTSUITE + syncgroup_test1, + syncgroup_test2, +#else + syncgroup_motions, // Syncgroup used for animations. +#endif + syncgroup_size +}; + +typedef U32 sync_canonical_type; +typedef U64 sync_key_hash_type; + +int const sync_canonical_type_bits = sizeof(sync_canonical_type) * 8; +int const sync_number_of_events = 4; +int const sync_bits_per_event_counter = sync_canonical_type_bits / (sync_number_of_events + 1); + +// Each type exists of 4 event bytes. +typedef sync_canonical_type syncevent; // A single event: the least significant bit in one of the bytes. +typedef sync_canonical_type synceventset; // Zero or more events: the least significant bit in zero or more of the bytes. +typedef sync_canonical_type synccount; // A count [0, 255] in each of the bytes. +typedef sync_canonical_type synccountmask; // A single count mask: all eight bits set in one of the bytes. +typedef sync_canonical_type synccountmaskset; // Zero or more count masks: all eight bits set in zero or more of the bytes. + +syncevent const syncevent1 = 1; +syncevent const syncevent2 = syncevent1 << sync_bits_per_event_counter; +syncevent const syncevent3 = syncevent2 << sync_bits_per_event_counter; +syncevent const syncevent4 = syncevent3 << sync_bits_per_event_counter; +sync_canonical_type const syncrefcountunit = syncevent4 << sync_bits_per_event_counter; + +synccountmask const synccountmask1 = syncevent2 - 1; +synccountmask const synccountmask2 = synccountmask1 << sync_bits_per_event_counter; +synccountmask const synccountmask3 = synccountmask2 << sync_bits_per_event_counter; +synccountmask const synccountmask4 = synccountmask3 << sync_bits_per_event_counter; +synccountmask const syncrefcountmask = ((synccountmask)-1) & ~(syncrefcountunit - 1); + +synceventset const syncevents = syncevent1 | syncevent2 | syncevent3 | syncevent4; +synccountmask const syncoverflowbits = (syncevents << (sync_bits_per_event_counter - 1)) | ~(~(sync_canonical_type)0 >> 1); + +// Convert an event set into its corresponding count mask set. +inline synccountmaskset synceventset2countmaskset(synceventset events) +{ + synccountmaskset tmp1 = events << sync_bits_per_event_counter; + return (tmp1 & ~events) - (events & ~tmp1); +} + +// Convert a count mask set into an event set. +inline synceventset synccountmask2eventset(synccountmask mask) +{ + return mask & syncevents; +} + +// Interface class used to determined if a client and a server fit together. +class LL_COMMON_API AISyncKey : private LLFrameTimer +{ + private: + sync_key_hash_type mHash; + U32 mFrameCount; + + public: + // A static hash used for clients with no specific requirement. + static sync_key_hash_type const sNoRequirementHash; + + // A sync key object that returns the sNoRequirementHash. + static AISyncKey const sNoRequirement; + + public: + AISyncKey(sync_key_hash_type hash) : mHash(hash) { mFrameCount = getFrameCount(); reset(0.1); } + virtual ~AISyncKey() { } + + // Derived class should return a hash that is the same for clients which + // should be synchronized (assuming they meet the time slot requirement as well). + // The hash does not need to depend on on clock or frame number thus. + virtual sync_key_hash_type hash(void) const { return sNoRequirementHash; } + + // Return true if this key expired. + bool expired(void) const { return getFrameCount() > mFrameCount + 1 || hasExpired(); } + + // Return true if both keys are close enough to warrant synchronization. + bool matches(AISyncKey const& key) const { return key.mHash == mHash; } +}; + +class LL_COMMON_API AISyncClient_ServerPtr +{ + protected: + friend class AISyncServer; + boost::intrusive_ptr mSyncServer; + virtual ~AISyncClient_ServerPtr() { } + + // All-ready event. + virtual void event1_ready(void) = 0; // Called when, or after ready(), with the syncevent1 bit set, is called. Never called after a call to ready() with that bit unset. + // Not all-ready event. + virtual void event1_not_ready(void) = 0; // A call to event1_not_ready() follows (at most once) the call to event1_ready(), at some unspecified moment. + // Only client. Client was forcefully deregistered from expired server because it was the only client. + virtual void deregistered(void) + { +#ifdef SHOW_ASSERT + mReadyEvents = 0; +#endif + } + + // Derived classes must return a hash that determines whether or not clients can be synchronized (should be synchronized when registered at the same time). + virtual sync_key_hash_type sync_key_hash(void) const = 0; + +#ifdef SHOW_ASSERT + AISyncClient_ServerPtr(void) : mReadyEvents(0) { } + + protected: + synceventset mReadyEvents; // Used by AISyncServer for debugging only. +#endif +}; + +// AISyncServer +// +// This class represents a single group of AISyncClient's (a list of pointers to +// their AISyncClient_ServerPtr base class) that need to synchronize events. +// +class LL_COMMON_API AISyncServer +{ + public: + typedef std::list client_list_type; + + protected: + synccount mNrClients; // Four times (once in each byte) the number of registered clients (the size of mClients). + synccount mNrReady; // The number of clients that are ready (four counts, one for each syncevent). + client_list_type mClients; // The registered clients. + AISyncKey mSyncKey; // The characteristic of clients belonging to this synchronization server. + + public: + AISyncServer(AISyncKey const& sync_key) : mNrClients(0), mNrReady(0), mSyncKey(sync_key) { } + virtual ~AISyncServer() { } + + // Default creation of a server for 'syncgroup'. + template + static void create_server(boost::intrusive_ptr& server, AISyncKey const& sync_key); + // Default removal of a server for 'syncgroup'. + template + static void dispose_server(boost::intrusive_ptr& server); + + // Called from AISyncServerCache. + void setSyncKey(AISyncKey const& sync_key) { mSyncKey = sync_key; } + + // Register client with a server from group syncgroup. + template + static void register_client(AISyncClient_ServerPtr* client); + // Unregister the client (syncgroup must be the same as what was passed to register it). + void unregister_client(AISyncClient_ServerPtr* client, syncgroups syncgroup); + + // Set readiness of all events at once. + bool ready(synceventset events, synceventset yesno/*,*/ ASSERT_ONLY_COMMA(AISyncClient_ServerPtr* client)); + // One event became ready or not ready. + bool ready(syncevent event, bool yesno/*,*/ ASSERT_ONLY_COMMA(AISyncClient_ServerPtr* client)) { return ready(event, yesno ? event : 0/*,*/ ASSERT_ONLY_COMMA(client)); } + + // Returns bitwise OR of syncevent1 through syncevent4 for + // events for which all clients are ready. + synceventset events_with_all_clients_ready(void) const; + // events for which at least one client is ready. + synceventset events_with_at_least_one_client_ready(void) const; + // events for which zero clients are ready. + synceventset events_with_zero_clients_ready(void) const { return syncevents ^ events_with_at_least_one_client_ready(); } + + // Return the number registered clients. + int number_of_clients(void) const { return (int)(mNrClients & synccountmask1); } + int get_refcount(void) const { return (int)(mNrClients >> (sync_number_of_events * sync_bits_per_event_counter)); } + + private: + void trigger_ready(void); // Calls event1_ready() for all clients. + void trigger_not_ready(void); // Calls event1_not_ready for all clients. + + void unregister_last_client(void); + + friend void intrusive_ptr_add_ref(AISyncServer* server); + friend void intrusive_ptr_release(AISyncServer* server); +}; + +template +class LL_COMMON_API AISyncClient_SyncGroup : public AISyncClient_ServerPtr +{ + public: + // Call 'ready' when you are ready (or not) to get a call to start(). + // Returns true if that call was made (immediately), otherwise it may happen later. + + bool ready(synceventset events, synceventset yesno) // Set readiness of all events at once. + { + if (!mSyncServer) + { + AISyncServer::register_client(this); + } + return mSyncServer->ready(events, yesno/*,*/ ASSERT_ONLY_COMMA(this)); + } + bool ready(syncevent event, bool yesno = true) // One event became ready or not ready. + { + if (!mSyncServer) + { + AISyncServer::register_client(this); + } + return mSyncServer->ready(event, yesno/*,*/ ASSERT_ONLY_COMMA(this)); + } + + void unregister_client(void) + { + if (mSyncServer) + { + mSyncServer->unregister_client(this, syncgroup); + } + } + + protected: + virtual ~AISyncClient_SyncGroup() { unregister_client(); } +}; + +template +class LL_COMMON_API AISyncClient : public AISyncClient_SyncGroup +{ + public: + AISYNCSERVER* server(void) { return static_cast(this->mSyncServer.get()); } + AISYNCSERVER const* server(void) const { return static_cast(this->mSyncServer.get()); } + + // By default return a general sync key that will cause synchronizing solely based on time. + /*virtual*/ AISyncKey const& getSyncKey(void) const { return AISyncKey::sNoRequirement; } +}; + +template +class AISyncServerCache +{ + private: + // The server cache exists of a few pointers to unused server instances. + // The cache is empty when sSize == 0 and full when sSize == 16; + static int const cache_size = 16; + static boost::intrusive_ptr sServerCache[cache_size]; + static int sSize; + + public: + static void create_server(boost::intrusive_ptr& server, AISyncKey const& sync_key) + { + if (sSize == 0) // Cache empty? + { + server.reset(new AISYNCSERVER(sync_key)); + } + else + { + sServerCache[--sSize].swap(server); + server->setSyncKey(sync_key); + } + } + + static void dispose_server(boost::intrusive_ptr& server) + { + if (sSize < cache_size) + { + sServerCache[sSize++].swap(server); + } + server.reset(); + } +}; + +template +boost::intrusive_ptr AISyncServerCache::sServerCache[cache_size]; + +template +int AISyncServerCache::sSize; + +template +inline void AISyncServer::create_server(boost::intrusive_ptr& server, AISyncKey const& sync_key) +{ + AISyncServerCache::create_server(server, sync_key); +} + +template +inline void AISyncServer::dispose_server(boost::intrusive_ptr& server) +{ + AISyncServerCache::dispose_server(server); +} + +#endif // AI_SYNC_CLIENT_H + From 61d365e957ed50434ea49ab28f4d69f01857dd2a Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 14 Dec 2013 16:17:50 +0100 Subject: [PATCH 097/115] Removed this again... --- indra/llcommon/aisyncclient.cpp | 538 -------------------------------- indra/llcommon/aisyncclient.h | 417 ------------------------- 2 files changed, 955 deletions(-) delete mode 100644 indra/llcommon/aisyncclient.cpp delete mode 100644 indra/llcommon/aisyncclient.h diff --git a/indra/llcommon/aisyncclient.cpp b/indra/llcommon/aisyncclient.cpp deleted file mode 100644 index 18ca33edc..000000000 --- a/indra/llcommon/aisyncclient.cpp +++ /dev/null @@ -1,538 +0,0 @@ -/** - * @file aisyncclient.cpp - * - * Copyright (c) 2013, Aleric Inglewood. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution. - * - * CHANGELOG - * and additional copyright holders. - * - * 05/12/2013 - * - Initial version, written by Aleric Inglewood @ SL - */ - -#include "sys.h" -#include "aisyncclient.h" -#include -#include "debug.h" - -typedef std::deque > servers_type; -static servers_type servers[syncgroup_size]; - -//static -template -void AISyncServer::register_client(AISyncClient_ServerPtr* client) -{ -#ifdef DEBUG_SYNCOUTPUT - DoutEntering(dc::notice, "AISyncServer::register_client(" << client << ")"); -#endif - - // Determine which server to use. - boost::intrusive_ptr server; - int expired = 0; - AISyncKey const sync_key(client->sync_key_hash()); - for (servers_type::iterator server_iter = servers[syncgroup].begin(); server_iter != servers[syncgroup].end(); ++server_iter) - { - boost::intrusive_ptr& server_ptr = *server_iter; - if (server_ptr->mSyncKey.expired()) - { - ++expired; - // If the server only contains a single client, then unregister it and put the server (back) in the server cache. - if (server_ptr->get_refcount() == 2) - { - server_ptr->unregister_last_client(); - AISyncServer::dispose_server(server_ptr); - } - continue; - } - if (server_ptr->mSyncKey.matches(sync_key)) - { - server = server_ptr; - break; - } - } - // Remove servers with expired keys. - if (expired) - { - if (expired == servers[syncgroup].size()) - { - servers[syncgroup].clear(); - } - else - { - servers[syncgroup].erase(servers[syncgroup].begin(), servers[syncgroup].begin() + expired); - } - } - if (!server) - { - AISyncServer::create_server(server, sync_key); - servers[syncgroup].push_back(server); - } - - // Sanity check: the client should never already be registered. - llassert(!client->mSyncServer); - // Recover from assertion failure. - if (client->mSyncServer) - { - if (client->mSyncServer == server) - { - return; - } - client->mSyncServer->unregister_client(client, syncgroup); - register_client(client); - return; - } - - // Obviously... - llassert(!client->mReadyEvents); - - // Check if the current clients are all ready: adding a new one will cause the group to become not-ready. - bool all_old_clients_are_ready = server->mNrReady && !((server->mNrClients - server->mNrReady) & synccountmask1); - // Add new client to the group. - client->mSyncServer = server; - server->mNrClients += syncevents; - llassert((server->mNrClients & syncoverflowbits) == 0); - if (all_old_clients_are_ready) - { - server->trigger_not_ready(); // Tell all old clients that the group is not ready. - } - server->mClients.push_back(client); // Actually add the new client to the list. -} - -void AISyncServer::unregister_client(AISyncClient_ServerPtr* client, syncgroups syncgroup) -{ -#ifdef DEBUG_SYNCOUTPUT - DoutEntering(dc::notice, "unregister_client(" << client << ", " << syncgroup << "), with this = " << this); -#endif - - // The client must be registered with this server. - llassert(client->mSyncServer == this); - // A client may only be unregistered after it was marked not-ready for all events. - llassert(!client->mReadyEvents); - // Run over all registered clients. - for (client_list_type::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter) - { - // Found it? - if (*client_iter == client) - { - mClients.erase(client_iter); - // Are the remaining clients ready? - if (mNrReady && !((mNrClients - syncevents - mNrReady) & synccountmask1)) - { - trigger_ready(); - } - mNrClients -= syncevents; - llassert((mNrClients & syncoverflowbits) == 0); - client->mSyncServer.reset(); // This might delete the current object. - break; - } - } - // The client must have been found. - llassert(!client->mSyncServer); -} - -void AISyncServer::unregister_last_client(void) -{ -#ifdef DEBUG_SYNCOUTPUT - DoutEntering(dc::notice, "unregister_last_client(), with this = " << this); -#endif - - // This function may only be called for servers with exactly one client. - llassert(mClients.size() == 1); - AISyncClient_ServerPtr* client = *mClients.begin(); -#ifdef DEBUG_SYNCOUTPUT - Dout(dc::notice, "unregistering client " << client); -#endif - mClients.clear(); - mNrClients -= syncevents; - mNrReady = 0; - llassert((mNrClients & syncoverflowbits) == 0); - client->mSyncServer.reset(); - client->deregistered(); -} - -synceventset AISyncServer::events_with_all_clients_ready(void) const -{ - synccount nrNotReady = mNrClients - mNrReady; - synceventset result1 = !(nrNotReady & synccountmask1) ? syncevent1 : 0; - synceventset result2 = !(nrNotReady & synccountmask2) ? syncevent2 : 0; - synceventset result3 = !(nrNotReady & synccountmask3) ? syncevent3 : 0; - synceventset result4 = !(nrNotReady & synccountmask4) ? syncevent4 : 0; - result1 |= result2; - result3 |= result4; - return result1 | result3; -} - -synceventset AISyncServer::events_with_at_least_one_client_ready(void) const -{ - synceventset result1 = (mNrReady & synccountmask1) ? syncevent1 : 0; - synceventset result2 = (mNrReady & synccountmask2) ? syncevent2 : 0; - synceventset result3 = (mNrReady & synccountmask3) ? syncevent3 : 0; - synceventset result4 = (mNrReady & synccountmask4) ? syncevent4 : 0; - result1 |= result2; - result3 |= result4; - return result1 | result3; -} - -#ifdef CWDEBUG -struct SyncEventSet { - synceventset mBits; - SyncEventSet(synceventset bits) : mBits(bits) { } -}; - -std::ostream& operator<<(std::ostream& os, SyncEventSet const& ses) -{ - os << ((ses.mBits & syncevent4) ? '1' : '0'); - os << ((ses.mBits & syncevent3) ? '1' : '0'); - os << ((ses.mBits & syncevent2) ? '1' : '0'); - os << ((ses.mBits & syncevent1) ? '1' : '0'); - return os; -} -#endif - -bool AISyncServer::ready(synceventset events, synceventset yesno/*,*/ ASSERT_ONLY_COMMA(AISyncClient_ServerPtr* client)) -{ -#ifdef DEBUG_SYNCOUTPUT - DoutEntering(dc::notice, "AISyncServer::ready(" << SyncEventSet(events) << ", " << SyncEventSet(yesno) << ", " << client << ")"); -#endif - - synceventset added_events = events & yesno; - synceventset removed_events = events & ~yesno; - // May not add events that are already ready. - llassert(!(client->mReadyEvents & added_events)); - // Cannot remove events that weren't ready. - llassert((client->mReadyEvents & removed_events) == removed_events); - // Were all clients ready for event 1? - bool ready_before = !((mNrClients - mNrReady) & synccountmask1); - // Update mNrReady counters. - mNrReady += added_events; - mNrReady -= removed_events; - // Test for under and overflow, this limits the maximum number of clients to 127 instead of 255, but well :p. - llassert((mNrReady & syncoverflowbits) == 0); - // Are all clients ready for event 1? - bool ready_after = !((mNrClients - mNrReady) & synccountmask1); - if (ready_before && !ready_after) - { - trigger_not_ready(); - } -#ifdef SHOW_ASSERT - // Update debug administration. - client->mReadyEvents ^= events; -#ifdef DEBUG_SYNCOUTPUT - Dout(dc::notice, "Client " << client << " now has ready: " << SyncEventSet(client->mReadyEvents)); -#endif -#endif - if (!ready_before && ready_after) - { - trigger_ready(); - } -} - -void AISyncServer::trigger_ready(void) -{ - for (client_list_type::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter) - { - llassert(((*client_iter)->mReadyEvents & syncevent1)); - (*client_iter)->event1_ready(); - } -} - -void AISyncServer::trigger_not_ready(void) -{ - for (client_list_type::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter) - { - llassert(((*client_iter)->mReadyEvents & syncevent1)); - (*client_iter)->event1_not_ready(); - } -} - -void intrusive_ptr_add_ref(AISyncServer* server) -{ - server->mNrClients += syncrefcountunit; - llassert((server->mNrClients & syncoverflowbits) == 0); -} - -void intrusive_ptr_release(AISyncServer* server) -{ - llassert(server->mNrClients >= syncrefcountunit); - server->mNrClients -= syncrefcountunit; - // If there are no more pointers pointing to this server, then obviously it can't have any registered clients. - llassert(server->mNrClients >= syncrefcountunit || server->mNrClients == 0); - if (server->mNrClients == 0) - { - delete server; - } -} - -//static -sync_key_hash_type const AISyncKey::sNoRequirementHash = 0x91b42f98a9fef15cULL; - - -//============================================================================= -// SYNC_TESTSUITE -//============================================================================= - -#ifdef SYNC_TESTSUITE -#include -#include -#include -#include - -//static -U32 LLFrameTimer::sFrameCount; - -double innerloop_count = 0; - -double LLFrameTimer::getCurrentTime() -{ - return innerloop_count * 0.001; -} - -class TestsuiteServerBase : public AISyncServer -{ - public: - TestsuiteServerBase(AISyncKey const& sync_key) : AISyncServer(sync_key) { } - client_list_type& clients(void) { return mClients; } -}; - -class TestsuiteServer1 : public TestsuiteServerBase -{ - public: - TestsuiteServer1(AISyncKey const& sync_key) : TestsuiteServerBase(sync_key) { } -}; - -// Specialitations that link TestsuiteServer1 to syncgroup_test1. -// -//static -template<> -void AISyncServer::create_server(boost::intrusive_ptr& server, AISyncKey const& sync_key) -{ - AISyncServerCache::create_server(server, sync_key); -} -//static -template<> -void AISyncServer::dispose_server(boost::intrusive_ptr& server) -{ - AISyncServerCache::dispose_server(server); -} - -class TestsuiteServer2 : public TestsuiteServerBase -{ - public: - TestsuiteServer2(AISyncKey const& sync_key) : TestsuiteServerBase(sync_key) { } -}; - -// Specialitations that link TestsuiteServer2 to syncgroup_test2. -// -//static -template<> -void AISyncServer::create_server(boost::intrusive_ptr& server, AISyncKey const& sync_key) -{ - AISyncServerCache::create_server(server, sync_key); -} -//static -template<> -void AISyncServer::dispose_server(boost::intrusive_ptr& server) -{ - AISyncServerCache::dispose_server(server); -} - -template -class TestsuiteClient : public AISyncClient -{ - private: - int mIndex; - bool mRequestedRegistered; - synceventset mRequestedReady; - bool mActualReady1; - - public: - TestsuiteClient() : mIndex(-1), mRequestedRegistered(false), mRequestedReady(0), mActualReady1(false) { } - ~TestsuiteClient() { this->ready(mRequestedReady, (synceventset)0); } - - void setIndex(int index) { mIndex = index; } - - protected: - /*virtual*/ void event1_ready(void) - { - llassert(!mActualReady1); - mActualReady1 = true; - } - - /*virtual*/ void event1_not_ready(void) - { - llassert(mActualReady1); - mActualReady1 = false; - } - - /*virtual*/ sync_key_hash_type sync_key_hash(void) const - { - // Sync odd clients with eachother, and even clients with eachother. - return 0xb3c919ff + (mIndex & 1); - } - - // This is called when the server expired and we're the only client on it. - /*virtual*/ void deregistered(void) - { -#ifdef DEBUG_SYNCOUTPUT - DoutEntering(dc::notice, "TestsuiteClient<" << syncgroup << ">::deregistered(), with this = " << this); -#endif - mRequestedRegistered = false; - mRequestedReady = 0; - mActualReady1 = false; - this->mReadyEvents = 0; - } - - private: - bool is_registered(void) const { return !!this->mSyncServer; } - - public: - void change_state(unsigned long r); - bool getRequestedRegistered(void) const { return mRequestedRegistered; } - synceventset getRequestedReady(void) const { return mRequestedReady; } -}; - -TestsuiteClient* client1p; -TestsuiteClient* client2p; - -int const number_of_clients_per_syncgroup = 8; - -template -void TestsuiteClient::change_state(unsigned long r) -{ - bool change_registered = r & 1; - r >>= 1; - synceventset toggle_events = ((r & 1) ? syncevent1 : 0) | ((r & 2) ? syncevent2 : 0) | ((r & 4) ? syncevent3 : 0) | ((r & 8) ? syncevent4 : 0); - r >>= 4; - if (change_registered) - { - if (mRequestedRegistered && !mRequestedReady) - { - mRequestedRegistered = false; - this->unregister_client(); - } - } - else if (toggle_events) - { - mRequestedReady ^= toggle_events; - mRequestedRegistered = true; - this->ready(toggle_events, mRequestedReady & toggle_events); - } - llassert(mRequestedRegistered == is_registered()); - TestsuiteServerBase* server = this->server(); - llassert(!mRequestedRegistered || server->number_of_clients() == server->clients().size()); - if (mRequestedRegistered) - { - synceventset all_ready = syncevents; - synceventset any_ready = 0; - int nr = 0; - for (int cl = 0; cl < number_of_clients_per_syncgroup; ++cl) - { - if (syncgroup == syncgroup_test1) - { - if (client1p[cl].server() != server) - { - continue; - } - if (client1p[cl].getRequestedRegistered()) - { - ++nr; - all_ready &= client1p[cl].getRequestedReady(); - any_ready |= client1p[cl].getRequestedReady(); - } - } - else - { - if (client2p[cl].server() != server) - { - continue; - } - if (client2p[cl].getRequestedRegistered()) - { - ++nr; - all_ready &= client2p[cl].getRequestedReady(); - any_ready |= client2p[cl].getRequestedReady(); - } - } - } - llassert(nr == server->number_of_clients()); - llassert(!!(all_ready & syncevent1) == mActualReady1); - llassert(this->server()->events_with_all_clients_ready() == all_ready); - llassert(this->server()->events_with_at_least_one_client_ready() == any_ready); - llassert(nr == 0 || (any_ready & all_ready) == all_ready); - } - llassert(mRequestedReady == this->mReadyEvents); -} - -int main() -{ - Debug(libcw_do.on()); - Debug(dc::notice.on()); - Debug(libcw_do.set_ostream(&std::cout)); - Debug(list_channels_on(libcw_do)); - - unsigned short seed16v[3] = { 0x1234, 0xfedc, 0x7091 }; - - for (int k = 0;; ++k) - { - std::cout << "Loop: " << k << "; SEED: " << std::hex << seed16v[0] << ", " << seed16v[1] << ", " << seed16v[2] << std::dec << std::endl; - ++LLFrameTimer::sFrameCount; - - seed48(seed16v); - seed16v[0] = lrand48() & 0xffff; - seed16v[1] = lrand48() & 0xffff; - seed16v[2] = lrand48() & 0xffff; - - TestsuiteClient client1[number_of_clients_per_syncgroup]; - TestsuiteClient client2[number_of_clients_per_syncgroup]; - client1p = client1; - client2p = client2; - - for (int i = 0; i < number_of_clients_per_syncgroup; ++i) - { - client1[i].setIndex(i); - client2[i].setIndex(i); - } - - for (int j = 0; j < 1000000; ++j) - { - innerloop_count += 1; - -#ifdef DEBUG_SYNCOUTPUT - Dout(dc::notice, "Innerloop: " << j); -#endif - unsigned long r = lrand48(); - syncgroups grp = (r & 1) ? syncgroup_test1 : syncgroup_test2; - r >>= 1; - int cl = (r & 255) % number_of_clients_per_syncgroup; - r >>= 8; - switch (grp) - { - case syncgroup_test1: - client1[cl].change_state(r); - break; - case syncgroup_test2: - client2[cl].change_state(r); - break; - } - } - } -} - -#endif diff --git a/indra/llcommon/aisyncclient.h b/indra/llcommon/aisyncclient.h deleted file mode 100644 index b6fcbd103..000000000 --- a/indra/llcommon/aisyncclient.h +++ /dev/null @@ -1,417 +0,0 @@ -/** - * @file aisyncclient.h - * @brief Declaration of AISyncClient. - * - * Copyright (c) 2013, Aleric Inglewood. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution. - * - * CHANGELOG - * and additional copyright holders. - * - * 05/12/2013 - * Initial version, written by Aleric Inglewood @ SL - */ - -#ifndef AI_SYNC_CLIENT_H -#define AI_SYNC_CLIENT_H - -#ifdef SYNC_TESTSUITE -/* - * To compile the testsuite, run: - * - * cd indra/llcommon - * g++ -O3 -DCWDEBUG -DSYNC_TESTSUITE -I. -I../cwdebug aisyncclient.cpp -lcwd - */ - -#include -#include -typedef uint32_t U32; -typedef uint64_t U64; -#define LL_COMMON_API -#define SHOW_ASSERT -#define ASSERT_ONLY_COMMA(...) , __VA_ARGS__ -#define llassert assert - -struct LLFrameTimer -{ - double mStartTime; - double mExpiry; - static double getCurrentTime(void); - static U32 sFrameCount; - static U32 getFrameCount() { return sFrameCount; } - void reset(double expiration) { mStartTime = getCurrentTime(); mExpiry = mStartTime + expiration; } - bool hasExpired(void) const { return getCurrentTime() > mExpiry; } -}; - -#else // !SYNC_TESTSUITE -#include "llpreprocessor.h" -#include "stdtypes.h" -#include "llerror.h" -#include "llframetimer.h" -#endif -#include -#include - -class AISyncServer; - -/* - * AISyncClient - * - * This class allows to synchronize events between multiple client objects, - * derived from AISyncClient, where AISYNCSERVER must be - * derived from AISyncServer. - * - * Client objects call ready(mask) (or ready(event, bool), where each bit can be - * set or unset, which will result in alternating calls to event1_ready(mask) and - * event1_not_ready(mask) for all registered clients at the same time depending on - * when all clients are ready for syncevent1 or not (the other events can be - * polled, see below). - * - * For example, let a and b be two clients: - * - * { - * AISyncClient a; - * { - * AISyncClient b; - * - * a.ready(syncevent1, true); // Calls a.event1_ready(). - * a.ready(syncevent1, false); // Calls a.event1_not_ready(). - * b.ready(syncevent1, true); // Nothing happens. - * b.ready(syncevent1, false); // Nothing happens. - * b.ready(syncevent1, true); // Nothing happens. - * a.ready(syncevent1, true); // Calls a.event1_ready() and b.event1_ready(2). - * b.ready(syncevent1, false); // Calls a.event1_not_ready() and b.event1_not_ready(). - * } // Calls a.event1_ready() because b was destructed and a is still ready. - * a.ready(syncevent1, false); // Calls a.event1_not_ready(). Must set not-ready before destructing. - * } - * - * Clients can access the server by calling server() and poll it: - * - * AISyncServer* server = server(); - * - * if (server) - * { - * int n = server->number_of_clients(); - * synceventset set1 = server->events_with_all_clients_ready(); - * synceventset set2 = server->events_with_zero_clients_ready(); - * synceventset set3 = server->events_with_at_least_one_client_ready(); - * if (n == 0) - * { - * llassert(set1 == syncevents); // We define a server with no clients to have all clients ready. - * llassert(set2 == syncevents); // If there are no clients then every event has zero ready clients. - * llassert(set3 == 0); // If there are no clients then obviously set3 is the empty set. - * } - * else - * { - * llassert((set3 & set1) == set1); // set1 is a subset of set3. - * } - * llassert((set3 & (set1 & ~set2)) == (set1 & ~set2)); - * // The set of events that have all clients ready, but not zero clients, - * // is a subset of the set of events with at least one client ready. - * llassert((set2 ^ set3) == syncevents); // Each event belongs to either set2 or set3. - * } - * - * Clients can also unregister themselves without destruction, by calling unregister(); - * This might cause a call to event1_ready() for the remaining clients, if all of them - * are ready for syncevent1. - * - * Clients must be set not-ready for all events before unregistering them. - * - * Finally, it is possible to cause a server-side unregister for all clients, - * by calling server->dissolve(). This will cause an immediate call to event1_ready() - * for all clients that are ready, unless all were already ready. - */ - -enum syncgroups -{ -#ifdef SYNC_TESTSUITE - syncgroup_test1, - syncgroup_test2, -#else - syncgroup_motions, // Syncgroup used for animations. -#endif - syncgroup_size -}; - -typedef U32 sync_canonical_type; -typedef U64 sync_key_hash_type; - -int const sync_canonical_type_bits = sizeof(sync_canonical_type) * 8; -int const sync_number_of_events = 4; -int const sync_bits_per_event_counter = sync_canonical_type_bits / (sync_number_of_events + 1); - -// Each type exists of 4 event bytes. -typedef sync_canonical_type syncevent; // A single event: the least significant bit in one of the bytes. -typedef sync_canonical_type synceventset; // Zero or more events: the least significant bit in zero or more of the bytes. -typedef sync_canonical_type synccount; // A count [0, 255] in each of the bytes. -typedef sync_canonical_type synccountmask; // A single count mask: all eight bits set in one of the bytes. -typedef sync_canonical_type synccountmaskset; // Zero or more count masks: all eight bits set in zero or more of the bytes. - -syncevent const syncevent1 = 1; -syncevent const syncevent2 = syncevent1 << sync_bits_per_event_counter; -syncevent const syncevent3 = syncevent2 << sync_bits_per_event_counter; -syncevent const syncevent4 = syncevent3 << sync_bits_per_event_counter; -sync_canonical_type const syncrefcountunit = syncevent4 << sync_bits_per_event_counter; - -synccountmask const synccountmask1 = syncevent2 - 1; -synccountmask const synccountmask2 = synccountmask1 << sync_bits_per_event_counter; -synccountmask const synccountmask3 = synccountmask2 << sync_bits_per_event_counter; -synccountmask const synccountmask4 = synccountmask3 << sync_bits_per_event_counter; -synccountmask const syncrefcountmask = ((synccountmask)-1) & ~(syncrefcountunit - 1); - -synceventset const syncevents = syncevent1 | syncevent2 | syncevent3 | syncevent4; -synccountmask const syncoverflowbits = (syncevents << (sync_bits_per_event_counter - 1)) | ~(~(sync_canonical_type)0 >> 1); - -// Convert an event set into its corresponding count mask set. -inline synccountmaskset synceventset2countmaskset(synceventset events) -{ - synccountmaskset tmp1 = events << sync_bits_per_event_counter; - return (tmp1 & ~events) - (events & ~tmp1); -} - -// Convert a count mask set into an event set. -inline synceventset synccountmask2eventset(synccountmask mask) -{ - return mask & syncevents; -} - -// Interface class used to determined if a client and a server fit together. -class LL_COMMON_API AISyncKey : private LLFrameTimer -{ - private: - sync_key_hash_type mHash; - U32 mFrameCount; - - public: - // A static hash used for clients with no specific requirement. - static sync_key_hash_type const sNoRequirementHash; - - // A sync key object that returns the sNoRequirementHash. - static AISyncKey const sNoRequirement; - - public: - AISyncKey(sync_key_hash_type hash) : mHash(hash) { mFrameCount = getFrameCount(); reset(0.1); } - virtual ~AISyncKey() { } - - // Derived class should return a hash that is the same for clients which - // should be synchronized (assuming they meet the time slot requirement as well). - // The hash does not need to depend on on clock or frame number thus. - virtual sync_key_hash_type hash(void) const { return sNoRequirementHash; } - - // Return true if this key expired. - bool expired(void) const { return getFrameCount() > mFrameCount + 1 || hasExpired(); } - - // Return true if both keys are close enough to warrant synchronization. - bool matches(AISyncKey const& key) const { return key.mHash == mHash; } -}; - -class LL_COMMON_API AISyncClient_ServerPtr -{ - protected: - friend class AISyncServer; - boost::intrusive_ptr mSyncServer; - virtual ~AISyncClient_ServerPtr() { } - - // All-ready event. - virtual void event1_ready(void) = 0; // Called when, or after ready(), with the syncevent1 bit set, is called. Never called after a call to ready() with that bit unset. - // Not all-ready event. - virtual void event1_not_ready(void) = 0; // A call to event1_not_ready() follows (at most once) the call to event1_ready(), at some unspecified moment. - // Only client. Client was forcefully deregistered from expired server because it was the only client. - virtual void deregistered(void) - { -#ifdef SHOW_ASSERT - mReadyEvents = 0; -#endif - } - - // Derived classes must return a hash that determines whether or not clients can be synchronized (should be synchronized when registered at the same time). - virtual sync_key_hash_type sync_key_hash(void) const = 0; - -#ifdef SHOW_ASSERT - AISyncClient_ServerPtr(void) : mReadyEvents(0) { } - - protected: - synceventset mReadyEvents; // Used by AISyncServer for debugging only. -#endif -}; - -// AISyncServer -// -// This class represents a single group of AISyncClient's (a list of pointers to -// their AISyncClient_ServerPtr base class) that need to synchronize events. -// -class LL_COMMON_API AISyncServer -{ - public: - typedef std::list client_list_type; - - protected: - synccount mNrClients; // Four times (once in each byte) the number of registered clients (the size of mClients). - synccount mNrReady; // The number of clients that are ready (four counts, one for each syncevent). - client_list_type mClients; // The registered clients. - AISyncKey mSyncKey; // The characteristic of clients belonging to this synchronization server. - - public: - AISyncServer(AISyncKey const& sync_key) : mNrClients(0), mNrReady(0), mSyncKey(sync_key) { } - virtual ~AISyncServer() { } - - // Default creation of a server for 'syncgroup'. - template - static void create_server(boost::intrusive_ptr& server, AISyncKey const& sync_key); - // Default removal of a server for 'syncgroup'. - template - static void dispose_server(boost::intrusive_ptr& server); - - // Called from AISyncServerCache. - void setSyncKey(AISyncKey const& sync_key) { mSyncKey = sync_key; } - - // Register client with a server from group syncgroup. - template - static void register_client(AISyncClient_ServerPtr* client); - // Unregister the client (syncgroup must be the same as what was passed to register it). - void unregister_client(AISyncClient_ServerPtr* client, syncgroups syncgroup); - - // Set readiness of all events at once. - bool ready(synceventset events, synceventset yesno/*,*/ ASSERT_ONLY_COMMA(AISyncClient_ServerPtr* client)); - // One event became ready or not ready. - bool ready(syncevent event, bool yesno/*,*/ ASSERT_ONLY_COMMA(AISyncClient_ServerPtr* client)) { return ready(event, yesno ? event : 0/*,*/ ASSERT_ONLY_COMMA(client)); } - - // Returns bitwise OR of syncevent1 through syncevent4 for - // events for which all clients are ready. - synceventset events_with_all_clients_ready(void) const; - // events for which at least one client is ready. - synceventset events_with_at_least_one_client_ready(void) const; - // events for which zero clients are ready. - synceventset events_with_zero_clients_ready(void) const { return syncevents ^ events_with_at_least_one_client_ready(); } - - // Return the number registered clients. - int number_of_clients(void) const { return (int)(mNrClients & synccountmask1); } - int get_refcount(void) const { return (int)(mNrClients >> (sync_number_of_events * sync_bits_per_event_counter)); } - - private: - void trigger_ready(void); // Calls event1_ready() for all clients. - void trigger_not_ready(void); // Calls event1_not_ready for all clients. - - void unregister_last_client(void); - - friend void intrusive_ptr_add_ref(AISyncServer* server); - friend void intrusive_ptr_release(AISyncServer* server); -}; - -template -class LL_COMMON_API AISyncClient_SyncGroup : public AISyncClient_ServerPtr -{ - public: - // Call 'ready' when you are ready (or not) to get a call to start(). - // Returns true if that call was made (immediately), otherwise it may happen later. - - bool ready(synceventset events, synceventset yesno) // Set readiness of all events at once. - { - if (!mSyncServer) - { - AISyncServer::register_client(this); - } - return mSyncServer->ready(events, yesno/*,*/ ASSERT_ONLY_COMMA(this)); - } - bool ready(syncevent event, bool yesno = true) // One event became ready or not ready. - { - if (!mSyncServer) - { - AISyncServer::register_client(this); - } - return mSyncServer->ready(event, yesno/*,*/ ASSERT_ONLY_COMMA(this)); - } - - void unregister_client(void) - { - if (mSyncServer) - { - mSyncServer->unregister_client(this, syncgroup); - } - } - - protected: - virtual ~AISyncClient_SyncGroup() { unregister_client(); } -}; - -template -class LL_COMMON_API AISyncClient : public AISyncClient_SyncGroup -{ - public: - AISYNCSERVER* server(void) { return static_cast(this->mSyncServer.get()); } - AISYNCSERVER const* server(void) const { return static_cast(this->mSyncServer.get()); } - - // By default return a general sync key that will cause synchronizing solely based on time. - /*virtual*/ AISyncKey const& getSyncKey(void) const { return AISyncKey::sNoRequirement; } -}; - -template -class AISyncServerCache -{ - private: - // The server cache exists of a few pointers to unused server instances. - // The cache is empty when sSize == 0 and full when sSize == 16; - static int const cache_size = 16; - static boost::intrusive_ptr sServerCache[cache_size]; - static int sSize; - - public: - static void create_server(boost::intrusive_ptr& server, AISyncKey const& sync_key) - { - if (sSize == 0) // Cache empty? - { - server.reset(new AISYNCSERVER(sync_key)); - } - else - { - sServerCache[--sSize].swap(server); - server->setSyncKey(sync_key); - } - } - - static void dispose_server(boost::intrusive_ptr& server) - { - if (sSize < cache_size) - { - sServerCache[sSize++].swap(server); - } - server.reset(); - } -}; - -template -boost::intrusive_ptr AISyncServerCache::sServerCache[cache_size]; - -template -int AISyncServerCache::sSize; - -template -inline void AISyncServer::create_server(boost::intrusive_ptr& server, AISyncKey const& sync_key) -{ - AISyncServerCache::create_server(server, sync_key); -} - -template -inline void AISyncServer::dispose_server(boost::intrusive_ptr& server) -{ - AISyncServerCache::dispose_server(server); -} - -#endif // AI_SYNC_CLIENT_H - From 66aaa9cf80561c4d22edb65cc60849879965a974 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 21 Dec 2013 18:46:19 +0100 Subject: [PATCH 098/115] Add LLMotionController* LLMotion::mMotionController This is needed for synchronization: motions will have to start (with a specific start time offset) from a point in the code where only the motion object is available. I added/used LLMotionController& in a previous commit, this was now changed into a pointer. There is (obviously) not much reason for that, but also no disadvantage: the diff relative to LLs code doesn't get larger since the references where already added, too. Conflicts: indra/llcharacter/llkeyframemotion.cpp indra/llcharacter/llkeyframemotion.h --- indra/llcharacter/lleditingmotion.cpp | 2 +- indra/llcharacter/lleditingmotion.h | 4 ++-- indra/llcharacter/llhandmotion.cpp | 2 +- indra/llcharacter/llhandmotion.h | 4 ++-- indra/llcharacter/llheadrotmotion.cpp | 4 ++-- indra/llcharacter/llheadrotmotion.h | 8 ++++---- indra/llcharacter/llkeyframefallmotion.cpp | 2 +- indra/llcharacter/llkeyframefallmotion.h | 4 ++-- indra/llcharacter/llkeyframemotion.cpp | 8 ++++---- indra/llcharacter/llkeyframemotion.h | 4 ++-- indra/llcharacter/llkeyframestandmotion.cpp | 2 +- indra/llcharacter/llkeyframestandmotion.h | 4 ++-- indra/llcharacter/llkeyframewalkmotion.cpp | 8 ++++---- indra/llcharacter/llkeyframewalkmotion.h | 12 ++++++------ indra/llcharacter/llmotion.cpp | 7 ++++--- indra/llcharacter/llmotion.h | 16 +++++++++------- indra/llcharacter/llmotioncontroller.cpp | 4 ++-- indra/llcharacter/llmotioncontroller.h | 4 ++-- indra/llcharacter/lltargetingmotion.cpp | 2 +- indra/llcharacter/lltargetingmotion.h | 4 ++-- indra/newview/llemote.cpp | 2 +- indra/newview/llemote.h | 4 ++-- indra/newview/llphysicsmotion.cpp | 2 +- indra/newview/llphysicsmotion.h | 4 ++-- indra/newview/llvoavatar.cpp | 12 ++++++------ 25 files changed, 66 insertions(+), 63 deletions(-) diff --git a/indra/llcharacter/lleditingmotion.cpp b/indra/llcharacter/lleditingmotion.cpp index 26fca2260..d07f37779 100644 --- a/indra/llcharacter/lleditingmotion.cpp +++ b/indra/llcharacter/lleditingmotion.cpp @@ -49,7 +49,7 @@ S32 LLEditingMotion::sHandPosePriority = 3; // LLEditingMotion() // Class Constructor //----------------------------------------------------------------------------- -LLEditingMotion::LLEditingMotion(LLUUID const& id, LLMotionController& controller) : AIMaskedMotion(id, controller, ANIM_AGENT_EDITING) +LLEditingMotion::LLEditingMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_EDITING) { mCharacter = NULL; diff --git a/indra/llcharacter/lleditingmotion.h b/indra/llcharacter/lleditingmotion.h index f880a94b7..bc95ff682 100644 --- a/indra/llcharacter/lleditingmotion.h +++ b/indra/llcharacter/lleditingmotion.h @@ -53,7 +53,7 @@ class LLEditingMotion : { public: // Constructor - LLEditingMotion(LLUUID const& id, LLMotionController& controller); + LLEditingMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLEditingMotion(); @@ -65,7 +65,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLEditingMotion(id, controller); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLEditingMotion(id, controller); } public: //------------------------------------------------------------------------- diff --git a/indra/llcharacter/llhandmotion.cpp b/indra/llcharacter/llhandmotion.cpp index c479f0f5f..be6dbb050 100644 --- a/indra/llcharacter/llhandmotion.cpp +++ b/indra/llcharacter/llhandmotion.cpp @@ -61,7 +61,7 @@ const F32 HAND_MORPH_BLEND_TIME = 0.2f; // LLHandMotion() // Class Constructor //----------------------------------------------------------------------------- -LLHandMotion::LLHandMotion(LLUUID const& id, LLMotionController& controller) : AIMaskedMotion(id, controller, ANIM_AGENT_HAND_MOTION) +LLHandMotion::LLHandMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_HAND_MOTION) { mCharacter = NULL; mLastTime = 0.f; diff --git a/indra/llcharacter/llhandmotion.h b/indra/llcharacter/llhandmotion.h index 582c6ee2f..012c3c6be 100644 --- a/indra/llcharacter/llhandmotion.h +++ b/indra/llcharacter/llhandmotion.h @@ -68,7 +68,7 @@ public: } eHandPose; // Constructor - LLHandMotion(LLUUID const& id, LLMotionController& controller); + LLHandMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLHandMotion(); @@ -80,7 +80,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLHandMotion(id, controller); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLHandMotion(id, controller); } public: //------------------------------------------------------------------------- diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp index 7322c996a..79912f9d5 100644 --- a/indra/llcharacter/llheadrotmotion.cpp +++ b/indra/llcharacter/llheadrotmotion.cpp @@ -76,7 +76,7 @@ const F32 EYE_BLINK_TIME_DELTA = 0.005f; // time between one eye starting a blin // LLHeadRotMotion() // Class Constructor //----------------------------------------------------------------------------- -LLHeadRotMotion::LLHeadRotMotion(LLUUID const& id, LLMotionController& controller) : +LLHeadRotMotion::LLHeadRotMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_HEAD_ROT), mCharacter(NULL), mTorsoJoint(NULL), @@ -260,7 +260,7 @@ BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask) // LLEyeMotion() // Class Constructor //----------------------------------------------------------------------------- -LLEyeMotion::LLEyeMotion(LLUUID const& id, LLMotionController& controller) : AIMaskedMotion(id, controller, ANIM_AGENT_EYE) +LLEyeMotion::LLEyeMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_EYE) { mCharacter = NULL; mEyeJitterTime = 0.f; diff --git a/indra/llcharacter/llheadrotmotion.h b/indra/llcharacter/llheadrotmotion.h index 5342d422f..5fa4610bf 100644 --- a/indra/llcharacter/llheadrotmotion.h +++ b/indra/llcharacter/llheadrotmotion.h @@ -50,7 +50,7 @@ class LLHeadRotMotion : { public: // Constructor - LLHeadRotMotion(LLUUID const& id, LLMotionController& controller); + LLHeadRotMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLHeadRotMotion(); @@ -62,7 +62,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLHeadRotMotion(id, controller); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLHeadRotMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -125,7 +125,7 @@ class LLEyeMotion : { public: // Constructor - LLEyeMotion(LLUUID const& id, LLMotionController& controller); + LLEyeMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLEyeMotion(); @@ -137,7 +137,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLEyeMotion(id, controller); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLEyeMotion(id, controller); } public: //------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframefallmotion.cpp b/indra/llcharacter/llkeyframefallmotion.cpp index 15ad1b9e9..336d79e65 100644 --- a/indra/llcharacter/llkeyframefallmotion.cpp +++ b/indra/llcharacter/llkeyframefallmotion.cpp @@ -49,7 +49,7 @@ // LLKeyframeFallMotion() // Class Constructor //----------------------------------------------------------------------------- -LLKeyframeFallMotion::LLKeyframeFallMotion(const LLUUID &id) : LLKeyframeMotion(id) +LLKeyframeFallMotion::LLKeyframeFallMotion(LLUUID const& id, LLMotionController* controller) : LLKeyframeMotion(id, controller) { mVelocityZ = 0.f; mCharacter = NULL; diff --git a/indra/llcharacter/llkeyframefallmotion.h b/indra/llcharacter/llkeyframefallmotion.h index c36c72798..0d2553ce3 100644 --- a/indra/llcharacter/llkeyframefallmotion.h +++ b/indra/llcharacter/llkeyframefallmotion.h @@ -47,7 +47,7 @@ class LLKeyframeFallMotion : { public: // Constructor - LLKeyframeFallMotion(const LLUUID &id); + LLKeyframeFallMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLKeyframeFallMotion(); @@ -59,7 +59,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController&) { return new LLKeyframeFallMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLKeyframeFallMotion(id, controller); } public: //------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index c6589ddf4..aa6e05708 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -444,8 +444,8 @@ void LLKeyframeMotion::JointMotion::update(LLJointState* joint_state, F32 time, // LLKeyframeMotion() // Class Constructor //----------------------------------------------------------------------------- -LLKeyframeMotion::LLKeyframeMotion(const LLUUID &id) - : LLMotion(id), +LLKeyframeMotion::LLKeyframeMotion(const LLUUID &id, LLMotionController* controller) + : LLMotion(id, controller), mPelvisp(NULL), mLastSkeletonSerialNum(0), mLastUpdateTime(0.f), @@ -468,9 +468,9 @@ LLKeyframeMotion::~LLKeyframeMotion() //----------------------------------------------------------------------------- // create() //----------------------------------------------------------------------------- -LLMotion* LLKeyframeMotion::create(LLUUID const& id, LLMotionController&) +LLMotion* LLKeyframeMotion::create(LLUUID const& id, LLMotionController* controller) { - return new LLKeyframeMotion(id); + return new LLKeyframeMotion(id, controller); } //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index 14fa4916c..952ae0ca7 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -177,7 +177,7 @@ class LLKeyframeMotion : friend class LLKeyframeDataCache; public: // Constructor - LLKeyframeMotion(const LLUUID &id); + LLKeyframeMotion(const LLUUID &id, LLMotionController* controller); // Destructor virtual ~LLKeyframeMotion(); @@ -194,7 +194,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController& controller); + static LLMotion* create(LLUUID const& id, LLMotionController* controller); public: //------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframestandmotion.cpp b/indra/llcharacter/llkeyframestandmotion.cpp index 1ae0ddeea..bccc714f1 100644 --- a/indra/llcharacter/llkeyframestandmotion.cpp +++ b/indra/llcharacter/llkeyframestandmotion.cpp @@ -50,7 +50,7 @@ const F32 POSITION_THRESHOLD = 0.1f; // LLKeyframeStandMotion() // Class Constructor //----------------------------------------------------------------------------- -LLKeyframeStandMotion::LLKeyframeStandMotion(const LLUUID &id) : LLKeyframeMotion(id) +LLKeyframeStandMotion::LLKeyframeStandMotion(LLUUID const& id, LLMotionController* controller) : LLKeyframeMotion(id, controller) { mFlipFeet = FALSE; mCharacter = NULL; diff --git a/indra/llcharacter/llkeyframestandmotion.h b/indra/llcharacter/llkeyframestandmotion.h index 1db798021..346df97f0 100644 --- a/indra/llcharacter/llkeyframestandmotion.h +++ b/indra/llcharacter/llkeyframestandmotion.h @@ -48,7 +48,7 @@ class LLKeyframeStandMotion : { public: // Constructor - LLKeyframeStandMotion(const LLUUID &id); + LLKeyframeStandMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLKeyframeStandMotion(); @@ -60,7 +60,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController&) { return new LLKeyframeStandMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLKeyframeStandMotion(id, controller); } public: //------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframewalkmotion.cpp b/indra/llcharacter/llkeyframewalkmotion.cpp index 2a12edd29..21d6fce30 100644 --- a/indra/llcharacter/llkeyframewalkmotion.cpp +++ b/indra/llcharacter/llkeyframewalkmotion.cpp @@ -55,8 +55,8 @@ const F32 SPEED_ADJUST_TIME_CONSTANT = 0.1f; // time constant for speed adjustm // LLKeyframeWalkMotion() // Class Constructor //----------------------------------------------------------------------------- -LLKeyframeWalkMotion::LLKeyframeWalkMotion(const LLUUID &id) -: LLKeyframeMotion(id), +LLKeyframeWalkMotion::LLKeyframeWalkMotion(LLUUID const& id, LLMotionController* controller) +: LLKeyframeMotion(id, controller), mCharacter(NULL), mCyclePhase(0.0f), mRealTimeLast(0.0f), @@ -138,7 +138,7 @@ BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask) // LLWalkAdjustMotion() // Class Constructor //----------------------------------------------------------------------------- -LLWalkAdjustMotion::LLWalkAdjustMotion(LLUUID const& id, LLMotionController& controller) : +LLWalkAdjustMotion::LLWalkAdjustMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_WALK_ADJUST), mLastTime(0.f), mAnimSpeed(0.f), @@ -331,7 +331,7 @@ void LLWalkAdjustMotion::onDeactivate() //----------------------------------------------------------------------------- // LLFlyAdjustMotion::LLFlyAdjustMotion() //----------------------------------------------------------------------------- -LLFlyAdjustMotion::LLFlyAdjustMotion(LLUUID const& id, LLMotionController& controller) +LLFlyAdjustMotion::LLFlyAdjustMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_FLY_ADJUST), mRoll(0.f) { diff --git a/indra/llcharacter/llkeyframewalkmotion.h b/indra/llcharacter/llkeyframewalkmotion.h index caab2fef3..653c2b539 100644 --- a/indra/llcharacter/llkeyframewalkmotion.h +++ b/indra/llcharacter/llkeyframewalkmotion.h @@ -52,7 +52,7 @@ class LLKeyframeWalkMotion : friend class LLWalkAdjustMotion; public: // Constructor - LLKeyframeWalkMotion(LLUUID const& id); + LLKeyframeWalkMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLKeyframeWalkMotion(); @@ -64,7 +64,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController&) { return new LLKeyframeWalkMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLKeyframeWalkMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -90,7 +90,7 @@ class LLWalkAdjustMotion : public AIMaskedMotion { public: // Constructor - LLWalkAdjustMotion(LLUUID const& id, LLMotionController& controller); + LLWalkAdjustMotion(LLUUID const& id, LLMotionController* controller); public: //------------------------------------------------------------------------- @@ -99,7 +99,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLWalkAdjustMotion(id, controller); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLWalkAdjustMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -140,7 +140,7 @@ class LLFlyAdjustMotion : public AIMaskedMotion { public: // Constructor - LLFlyAdjustMotion(LLUUID const& id, LLMotionController& controller); + LLFlyAdjustMotion(LLUUID const& id, LLMotionController* controller); public: //------------------------------------------------------------------------- @@ -149,7 +149,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLFlyAdjustMotion(id, controller); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLFlyAdjustMotion(id, controller); } public: //------------------------------------------------------------------------- diff --git a/indra/llcharacter/llmotion.cpp b/indra/llcharacter/llmotion.cpp index 203cf2f4c..021345fb3 100644 --- a/indra/llcharacter/llmotion.cpp +++ b/indra/llcharacter/llmotion.cpp @@ -49,10 +49,11 @@ // LLMotion() // Class Constructor //----------------------------------------------------------------------------- -LLMotion::LLMotion( const LLUUID &id ) : +LLMotion::LLMotion(LLUUID const& id, LLMotionController* controller) : mStopped(TRUE), mActive(FALSE), mID(id), + mController(controller), mActivationTimestamp(0.f), mStopTimestamp(0.f), mSendStopTimestamp(F32_MAX), @@ -181,13 +182,13 @@ BOOL LLMotion::canDeprecate() BOOL AIMaskedMotion::onActivate() { - mController.activated(mMaskBit); + mController->activated(mMaskBit); return TRUE; } void AIMaskedMotion::onDeactivate() { - mController.deactivated(mMaskBit); + mController->deactivated(mMaskBit); } // End diff --git a/indra/llcharacter/llmotion.h b/indra/llcharacter/llmotion.h index 24504980d..a67138bac 100644 --- a/indra/llcharacter/llmotion.h +++ b/indra/llcharacter/llmotion.h @@ -67,7 +67,7 @@ public: }; // Constructor - LLMotion(const LLUUID &id); + LLMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLMotion(); @@ -182,6 +182,9 @@ protected: //------------------------------------------------------------------------- std::string mName; // instance name assigned by motion controller LLUUID mID; + // + LLMotionController* mController; + // F32 mActivationTimestamp; // time when motion was activated F32 mStopTimestamp; // time when motion was told to stop @@ -200,9 +203,9 @@ protected: class LLTestMotion : public LLMotion { public: - LLTestMotion(const LLUUID &id) : LLMotion(id){} + LLTestMotion(LLUUID const& id, LLMotionController* controller) : LLMotion(id, controller){} ~LLTestMotion() {} - static LLMotion* create(LLUUID const& id, LLMotionController&) { return new LLTestMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLTestMotion(id, controller); } BOOL getLoop() { return FALSE; } F32 getDuration() { return 0.0f; } F32 getEaseInDuration() { return 0.0f; } @@ -224,9 +227,9 @@ public: class LLNullMotion : public LLMotion { public: - LLNullMotion(const LLUUID &id) : LLMotion(id) {} + LLNullMotion(LLUUID const& id, LLMotionController* controller) : LLMotion(id, controller) {} ~LLNullMotion() {} - static LLMotion* create(LLUUID const& id, LLMotionController&) { return new LLNullMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLNullMotion(id, controller); } // motions must specify whether or not they loop /*virtual*/ BOOL getLoop() { return TRUE; } @@ -292,11 +295,10 @@ U32 const ANIM_AGENT_WALK_ADJUST = 0x400; class AIMaskedMotion : public LLMotion { private: - LLMotionController& mController; U32 mMaskBit; public: - AIMaskedMotion(LLUUID const& id, LLMotionController& controller, U32 mask_bit) : LLMotion(id), mController(controller), mMaskBit(mask_bit) { } + AIMaskedMotion(LLUUID const& id, LLMotionController* controller, U32 mask_bit) : LLMotion(id, controller), mMaskBit(mask_bit) { } /*virtual*/ BOOL onActivate(); /*virtual*/ void onDeactivate(); diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 4935fb3a7..099805676 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -97,7 +97,7 @@ void LLMotionRegistry::markBad( const LLUUID& id ) //----------------------------------------------------------------------------- // createMotion() //----------------------------------------------------------------------------- -LLMotion* LLMotionRegistry::createMotion(LLUUID const& id, LLMotionController& controller) +LLMotion* LLMotionRegistry::createMotion(LLUUID const& id, LLMotionController* controller) { LLMotionConstructor constructor = get_if_there(mMotionTable, id, LLMotionConstructor(NULL)); LLMotion* motion = NULL; @@ -359,7 +359,7 @@ LLMotion* LLMotionController::createMotion( const LLUUID &id ) if (!motion) { // look up constructor and create it - motion = sRegistry.createMotion(id, *this); + motion = sRegistry.createMotion(id, this); if (!motion) { return NULL; diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index 9b6c71ef1..04b15ff89 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -56,7 +56,7 @@ class LLMotionController; //----------------------------------------------------------------------------- // LLMotionRegistry //----------------------------------------------------------------------------- -typedef LLMotion* (*LLMotionConstructor)(LLUUID const& id, LLMotionController&); +typedef LLMotion* (*LLMotionConstructor)(LLUUID const& id, LLMotionController*); class LLMotionRegistry { @@ -73,7 +73,7 @@ public: // creates a new instance of a named motion // returns NULL motion is not registered - LLMotion* createMotion(LLUUID const& id, LLMotionController& controller); + LLMotion* createMotion(LLUUID const& id, LLMotionController* controller); // initialization of motion failed, don't try to create this motion again void markBad( const LLUUID& id ); diff --git a/indra/llcharacter/lltargetingmotion.cpp b/indra/llcharacter/lltargetingmotion.cpp index 423eca363..05b0fdfe8 100644 --- a/indra/llcharacter/lltargetingmotion.cpp +++ b/indra/llcharacter/lltargetingmotion.cpp @@ -52,7 +52,7 @@ const F32 TORSO_ROT_FRACTION = 0.5f; // LLTargetingMotion() // Class Constructor //----------------------------------------------------------------------------- -LLTargetingMotion::LLTargetingMotion(LLUUID const& id, LLMotionController& controller) : AIMaskedMotion(id, controller, ANIM_AGENT_TARGET) +LLTargetingMotion::LLTargetingMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_TARGET) { mCharacter = NULL; mName = "targeting"; diff --git a/indra/llcharacter/lltargetingmotion.h b/indra/llcharacter/lltargetingmotion.h index 8dfa32500..f7b08ee69 100644 --- a/indra/llcharacter/lltargetingmotion.h +++ b/indra/llcharacter/lltargetingmotion.h @@ -52,7 +52,7 @@ class LLTargetingMotion : { public: // Constructor - LLTargetingMotion(LLUUID const& id, LLMotionController& controller); + LLTargetingMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLTargetingMotion(); @@ -64,7 +64,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLTargetingMotion(id, controller); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLTargetingMotion(id, controller); } public: //------------------------------------------------------------------------- diff --git a/indra/newview/llemote.cpp b/indra/newview/llemote.cpp index c83846215..47bd57969 100644 --- a/indra/newview/llemote.cpp +++ b/indra/newview/llemote.cpp @@ -48,7 +48,7 @@ // LLEmote() // Class Constructor //----------------------------------------------------------------------------- -LLEmote::LLEmote(const LLUUID &id) : LLMotion(id) +LLEmote::LLEmote(LLUUID const& id, LLMotionController* controller) : LLMotion(id, controller) { mCharacter = NULL; diff --git a/indra/newview/llemote.h b/indra/newview/llemote.h index eb2af5b9d..173719121 100644 --- a/indra/newview/llemote.h +++ b/indra/newview/llemote.h @@ -55,7 +55,7 @@ class LLEmote : { public: // Constructor - LLEmote(const LLUUID &id); + LLEmote(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLEmote(); @@ -67,7 +67,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController&) { return new LLEmote(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLEmote(id, controller); } public: //------------------------------------------------------------------------- diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index 625199b3f..99ff385ee 100644 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -314,7 +314,7 @@ void LLPhysicsMotion::getString(std::ostringstream &oss) } } -LLPhysicsMotionController::LLPhysicsMotionController(LLUUID const& id, LLMotionController& controller) : +LLPhysicsMotionController::LLPhysicsMotionController(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_PHYSICS_MOTION), mCharacter(NULL), mIsDefault(true) diff --git a/indra/newview/llphysicsmotion.h b/indra/newview/llphysicsmotion.h index 62e0ae658..2ce79b220 100644 --- a/indra/newview/llphysicsmotion.h +++ b/indra/newview/llphysicsmotion.h @@ -49,7 +49,7 @@ public: std::string getString(); // Constructor - LLPhysicsMotionController(LLUUID const& id, LLMotionController& controller); + LLPhysicsMotionController(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLPhysicsMotionController(); @@ -61,7 +61,7 @@ public: // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLPhysicsMotionController(id, controller); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLPhysicsMotionController(id, controller); } public: //------------------------------------------------------------------------- diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 943279d6b..b34291a5f 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -347,7 +347,7 @@ class LLBodyNoiseMotion : { public: // Constructor - LLBodyNoiseMotion(LLUUID const& id, LLMotionController& controller) + LLBodyNoiseMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_BODY_NOISE) { mName = "body_noise"; @@ -363,7 +363,7 @@ public: //------------------------------------------------------------------------- // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLBodyNoiseMotion(id, controller); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLBodyNoiseMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -444,7 +444,7 @@ class LLBreatheMotionRot : { public: // Constructor - LLBreatheMotionRot(LLUUID const& id, LLMotionController& controller) : + LLBreatheMotionRot(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_BREATHE_ROT), mBreatheRate(1.f), mCharacter(NULL) @@ -462,7 +462,7 @@ public: //------------------------------------------------------------------------- // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLBreatheMotionRot(id, controller); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLBreatheMotionRot(id, controller); } public: //------------------------------------------------------------------------- @@ -546,7 +546,7 @@ class LLPelvisFixMotion : { public: // Constructor - LLPelvisFixMotion(LLUUID const& id, LLMotionController& controller) + LLPelvisFixMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_PELVIS_FIX), mCharacter(NULL) { mName = "pelvis_fix"; @@ -563,7 +563,7 @@ public: //------------------------------------------------------------------------- // static constructor // all subclasses must implement such a function and register it - static LLMotion* create(LLUUID const& id, LLMotionController& controller) { return new LLPelvisFixMotion(id, controller); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLPelvisFixMotion(id, controller); } public: //------------------------------------------------------------------------- From 1bcb6ad20d1fa1e22e22e8cb3f298d0d9c5ff77b Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 21 Dec 2013 19:18:52 +0100 Subject: [PATCH 099/115] Version 2 of AISyncClient et al. A tool to synchronize objects: Objects derived from AISyncClient can signal that they are 'ready' or 'not ready' for up to 32 events (using a bitmask) at a time. Clients that are created at roughly the same time as other clients, and which return the same 'key' (a virtual function returning an AISyncKey object) will be grouped together and receive events (by means of virtual functions being called) to notify them of all clients being ready or not for one of the events (the least significant bit)). The other events can be polled. This new version does away with all the templates and explicitly remembers what events each client is ready for instead of just updating a counter of the number of clients. This was necessary because a client is removed then the server needs to know if it was ready or not when it has to be able to update those counters. This time I chose to just run over all stored clients and AND and OR the per-client-ready-masks because 1) that information is available now and 2) the lists will normally contain only one or two clients, so it's fast enough. The new version also allows for real key comparison (and derived keys) instead of just using "hash" value that is compared. --- indra/llcommon/aisyncclient.cpp | 749 ++++++++++++++++++++++++++++++++ indra/llcommon/aisyncclient.h | 296 +++++++++++++ 2 files changed, 1045 insertions(+) create mode 100644 indra/llcommon/aisyncclient.cpp create mode 100644 indra/llcommon/aisyncclient.h diff --git a/indra/llcommon/aisyncclient.cpp b/indra/llcommon/aisyncclient.cpp new file mode 100644 index 000000000..9cadb3cb1 --- /dev/null +++ b/indra/llcommon/aisyncclient.cpp @@ -0,0 +1,749 @@ +/** + * @file aisyncclient.cpp + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 13/12/2013 + * - Initial version, written by Aleric Inglewood @ SL + */ + +/* + * AISyncClient : the base class of a client object (LLMotion) that needs to be informed + * of the state of other such objects and/or to poll a server object about the state of + * other such objects, in order to be and stay synchronized with those other objects. + * In the case of an LLMotion (animation), all clients would be started and stopped at + * the same time, as long as they are part of the same synchronization group (AISyncServer). + * + * AISyncKey: object that determines what synchronization group a client belongs to. + * When a new client is created, a new AISyncKey is created too, using information from + * the client, the current frame number and the current frame time. If two AISyncKey + * compare equal, using operator==(AISyncKey const& key1, AISyncKey const& key2), + * then the clients that created them need to be synchronized. + * + * AISyncServer: object that represents a group of clients that need to be synchronized: + * it's a wrapper around a std::list with pointers to all the clients + * that need to be synchronized. It also stores the AISyncKey of the first (oldest) client + * that was added. Clients with keys that compare equal to that will be added. + * If a client is added with a synckeytype_t that is larger then it always replaces + * the existing key however. + * + * AISyncServerMap: A wrapper around std::list > + * that stores pointers to all currently existing AISyncServer objects. New entries + * are added at the end, so the oldest key is at the front. + * + * AISyncServerMap list + - - - - - - + - - - - - - + ... The AISyncServerMap is + * | | | a list with refcounted + * V V V pointers to AISyncServers. + * AISyncClient +--> AISyncServer + * | <--- list key ---> AISyncKey Each AISyncServer is a + * DerivedClient . list of normal pointers + * . AISyncClients and one + * <--- . pointer to a AISyncKey. + * Each AISyncClient is the + * base class of a DerivedClient + * and pointers back to the + * server with a refcounted + * pointer. + * + * A new client is passed to the AISyncServerMap to be stored in a new or existing AISyncServer + * object, using the key that the client produces. A boost::intrusive_ptr member + * of the client is set to point to this server. + * + * The lifetime of the server objects is determined by the intrusive_ptr objects that + * point to it: all the clients (which have an externally determined lifetime) and one + * pointer in the AISyncServerMap. However, regularly a check is done on all servers in + * the list to find expired servers: objects with keys older than two frames and older + * than 0.1 seconds; if such a server is found and it has zero or one client, then the + * client is unregistered and the pointer (and thus the server) removed from the + * AISyncServerMap. If it has two or more clients then the entry is kept until both + * clients are removed, which therefore can only be detected in intrusive_ptr_release + * which only has access to the server object. The server then is removed from the list + * by searching through it for the pointer to the server. + */ + +#include "sys.h" +#include "aisyncclient.h" +#include +#include +#include "debug.h" + +bool operator==(AISyncKey const& key1, AISyncKey const& key2) +{ + // Test if these keys match based on time. + if (std::abs((S32)(key1.mStartFrameCount - key2.mStartFrameCount)) > 1 && + std::abs(key1.mFrameTimer.getStartTime() - key2.mFrameTimer.getStartTime()) >= AISyncKey::sExpirationTime) + { + return false; + } + // Time matches, let the derived classes determine if they also match otherwise. + return key1.equals(key2); +} + +#ifdef CWDEBUG +struct SyncEventSet { + synceventset_t mBits; + SyncEventSet(synceventset_t bits) : mBits(bits) { } +}; + +std::ostream& operator<<(std::ostream& os, SyncEventSet const& ses) +{ + for (int b = sizeof(ses.mBits) * 8 - 1; b >= 0; --b) + { + int m = 1 << b; + os << ((ses.mBits & m) ? '1' : '0'); + } + return os; +} + +void print_clients(AISyncServer const* server, AISyncServer::client_list_t const& client_list) +{ + Dout(dc::notice, "Clients of server " << server << ": "); + for (AISyncServer::client_list_t::const_iterator iter = client_list.begin(); iter != client_list.end(); ++ iter) + { + llassert(iter->mClientPtr->mReadyEvents == iter->mReadyEvents); + Dout(dc::notice, "-> " << iter->mClientPtr << " : " << SyncEventSet(iter->mReadyEvents)); + } +} +#endif + +void AISyncServerMap::register_client(AISyncClient* client) +{ +#ifdef DEBUG_SYNCOUTPUT + DoutEntering(dc::notice, "AISyncServerMap::register_client(" << client << ")"); +#endif + + // client must always be a new client that has to be stored somewhere. + llassert(client->server() == NULL); + // Obviously the client can't be ready for anything when it isn't registered yet. + llassert(!client->mReadyEvents); + + // First we need its sync key. + AISyncKey* new_key = client->createSyncKey(); + + // Find if a server with this key already exists. + AISyncServer* server = NULL; + for (server_list_t::iterator iter = mServers.begin(); iter != mServers.end();) + { + boost::intrusive_ptr& server_ptr = *iter++; // Immediately increment iter because the call to unregister_last_client will erase it. + AISyncKey const& server_key(server_ptr->key()); + if (server_key.is_older_than(*new_key)) // This means that the server key is expired: a new key will never match. + { + if (server_ptr->never_synced()) // This means that it contains one or zero clients and will never contain more. + { + // Get rid of this server. + server_ptr->unregister_last_client(); // This will cause the server to be deleted, and erased from mServers. + } + continue; + } + if (*new_key == server_key) + { + server = server_ptr.get(); + // mServers stores new servers in strict order of the creation time of the keys, + // so once we find a server with a key that is equal, none of the remaining servers + // will have expired if they were never synced and we're done with the loop. + // Servers that synced might have been added later, but we don't unregister + // clients from those anyway because their sync partner might still show up. + break; + } + } + + if (server) + { + // A server already exists. + // Keep the oldest key, unless this new key has a synckeytype_t that is larger! + if (new_key->getkeytype() > server->key().getkeytype()) + { + server->swapkey(new_key); + } + delete new_key; + } + else + { + // Create a new server for this client. Transfers the ownership of the key allocation to the server. + server = new AISyncServer(new_key); + // Add it to mServers, before the last server that is younger then the new key. + server_list_t::iterator where = mServers.end(); // Insert the new server before 'where', +#if 0 // This is probably not necessary. + server_list_t::iterator new_where = where; + while (where != mServers.begin()) // unless there exists a server before that + { + --new_where; + if (new_key->getCreationTime() > (*new_where)->key().getCreationTime()) // and the new key is not younger then that, + { + break; + } + where = new_where; // then insert it before that element (etc). + } +#elif defined(SHOW_ASSERT) + server_list_t::iterator new_where = where; + llassert(where == mServers.begin() || new_key->getCreationTime() >= (*--new_where)->key().getCreationTime()); +#endif + // This method causes a single call to intrusive_ptr_add_ref and none to intrusive_ptr_release. + server_ptr_t server_ptr = server; + mServers.insert(where, server_ptr_t())->swap(server_ptr); + } + + // Add the client to the server. + server->add(client); +} + +#ifdef SYNC_TESTSUITE +void AISyncServer::sanity_check(void) const +{ + synceventset_t ready_events = (synceventset_t)-1; // All clients are ready. + client_list_t::const_iterator client_iter = mClients.begin(); + while (client_iter != mClients.end()) + { + ready_events &= client_iter->mReadyEvents; + ++client_iter; + } + synceventset_t pending_events = 0; // At least one client is ready. + client_iter = mClients.begin(); + while (client_iter != mClients.end()) + { + pending_events |= client_iter->mReadyEvents; + ++client_iter; + } + llassert(ready_events == mReadyEvents); + llassert(pending_events == mPendingEvents); +} +#endif + +void AISyncServer::add(AISyncClient* client) +{ +#ifdef DEBUG_SYNCOUTPUT + DoutEntering(dc::notice, "AISyncServer::add(" << client << "), with this = " << this); + print_clients(this, getClients()); +#endif +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif + + // The client can't already be ready when it isn't even added to a server yet. + llassert(!client->mReadyEvents); + synceventset_t old_ready_events = mReadyEvents; + // A new client is not ready for anything. + mReadyEvents = 0; + // Set mSynchronized if after adding client we'll have more than 1 client (that prevents the + // server from being deleted unless all clients are actually destructed or explicitly unregistered). + if (!mSynchronized && mClients.size() > 0) + { + mSynchronized = true; + } + // Trigger the existing clients to be not-ready anymore (if we were before). + trigger(old_ready_events); + // Only then add the new client (so that it didn't get not-ready trigger). + mClients.push_back(client); + client->mServer = this; + +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif +} + +void AISyncServer::remove(AISyncClient* client) +{ +#ifdef DEBUG_SYNCOUTPUT + DoutEntering(dc::notice, "AISyncServer::remove(" << client << "), with this = " << this); + print_clients(this, getClients()); +#endif +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif + + // A client may only be unregistered after it was marked not-ready for all events. + llassert(!client->mReadyEvents); + client_list_t::iterator client_iter = mClients.begin(); + synceventset_t remaining_ready_events = (synceventset_t)-1; // All clients are ready. + synceventset_t remaining_pending_events = 0; // At least one client is ready (waiting for the other clients thus). + client_list_t::iterator found_client = mClients.end(); + while (client_iter != mClients.end()) + { + if (client_iter->mClientPtr == client) + { + found_client = client_iter; + } + else + { + remaining_ready_events &= client_iter->mReadyEvents; + remaining_pending_events |= client_iter->mReadyEvents; + } + ++client_iter; + } + llassert(found_client != mClients.end()); + // This must be the same as client->mReadyEvents. + llassert(!found_client->mReadyEvents); + mClients.erase(found_client); + client->mServer.reset(); + synceventset_t old_ready_events = mReadyEvents; + mReadyEvents = remaining_ready_events; + // Since client->mReadyEvents is zero, this should be the same. + llassert(mPendingEvents == remaining_pending_events); + mPendingEvents = remaining_pending_events; + trigger(old_ready_events); + +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif +} + +void AISyncServer::unregister_last_client(void) +{ +#ifdef DEBUG_SYNCOUTPUT + DoutEntering(dc::notice, "AISyncServer::unregister_last_client()"); + print_clients(this, getClients()); +#endif +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif + + // This function may only be called for servers with exactly one client that was never (potentially) synchronized. + llassert(!mSynchronized && mClients.size() == 1); + AISyncClient* client = mClients.begin()->mClientPtr; + mClients.clear(); + client->mServer.reset(); + llassert(mReadyEvents == client->mReadyEvents); + llassert(mPendingEvents == mReadyEvents); + // No need to update mReadyEvents/mPendingEvents because the server is going to be deleted, + // but inform the client that is no longer has a server. + client->deregistered(); + +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif +} + +synceventset_t AISyncServer::events_with_all_clients_ready(void) const +{ +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif + return mReadyEvents; +} + +synceventset_t AISyncServer::events_with_at_least_one_client_ready(void) const +{ +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif + return mPendingEvents; +} + +void AISyncServer::trigger(synceventset_t old_ready_events) +{ + // If event 1 changed, informat all clients about it. + if (((old_ready_events ^ mReadyEvents) & 1)) + { + for (client_list_t::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter) + { + if ((mReadyEvents & 1)) + { + client_iter->mClientPtr->event1_ready(); + } + else + { + client_iter->mClientPtr->event1_not_ready(); + } + } + } +} + +bool AISyncServer::ready(synceventset_t events, synceventset_t yesno, AISyncClient* client) +{ +#ifdef DEBUG_SYNCOUTPUT + DoutEntering(dc::notice, "AISyncServer::ready(" << SyncEventSet(events) << ", " << SyncEventSet(yesno) << ", " << client << ")"); + print_clients(this, getClients()); +#endif +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif + + synceventset_t added_events = events & yesno; + synceventset_t removed_events = events & ~yesno; + // May not add events that are already ready. + llassert(!(client->mReadyEvents & added_events)); + // Cannot remove events that weren't ready. + llassert((client->mReadyEvents & removed_events) == removed_events); + + // Run over all clients to find the client and calculate the current state. + synceventset_t remaining_ready_events = (synceventset_t)-1; // All clients are ready. + synceventset_t remaining_pending_events = 0; // At least one client is ready (waiting for the other clients thus). + client_list_t::iterator found_client = mClients.end(); + for (client_list_t::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter) + { + if (client_iter->mClientPtr == client) + { + found_client = client_iter; + } + else + { + remaining_ready_events &= client_iter->mReadyEvents; + remaining_pending_events |= client_iter->mReadyEvents; + } + } + + llassert(mReadyEvents == (remaining_ready_events & found_client->mReadyEvents)); + llassert(mPendingEvents == (remaining_pending_events | found_client->mReadyEvents)); + + found_client->mReadyEvents &= ~removed_events; + found_client->mReadyEvents |= added_events; +#ifdef SHOW_ASSERT + client->mReadyEvents = found_client->mReadyEvents; +#endif + + synceventset_t old_ready_events = mReadyEvents; + + mReadyEvents = remaining_ready_events & found_client->mReadyEvents; + mPendingEvents = remaining_pending_events | found_client->mReadyEvents; + + trigger(old_ready_events); + +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif +} + +void intrusive_ptr_add_ref(AISyncServer* server) +{ + server->mRefCount++; +} + +void intrusive_ptr_release(AISyncServer* server) +{ + llassert(server->mRefCount > 0); + server->mRefCount--; + if (server->mRefCount == 0) + { + delete server; + } + else if (server->mRefCount == 1) + { + // If the the last pointer to this server is in the the AISyncServerMap, then delete that too. + AISyncServerMap::instance().remove_server(server); + } +} + +void AISyncServerMap::remove_server(AISyncServer* server) +{ + for (server_list_t::iterator iter = mServers.begin(); iter != mServers.end(); ++iter) + { + if (server == iter->get()) + { + mServers.erase(iter); // This causes server to be deleted too. + return; + } + } + // The server must be found: this function is only called from intrusive_ptr_release for servers + // with just a single server_ptr_t left, which must be the one in mServers (otherwise it wasn't + // even registered properly!) + llassert(false); +} + + +//============================================================================= +// SYNC_TESTSUITE +//============================================================================= + +#ifdef SYNC_TESTSUITE +#include +#include +#include +#include + +//static +U32 LLFrameTimer::sFrameCount; + +double innerloop_count = 0; + +double LLFrameTimer::getCurrentTime() +{ + return innerloop_count * 0.001; +} + +template +class TestsuiteKey : public AISyncKey +{ + private: + int mIndex; + + public: + TestsuiteKey(int index) : mIndex(index) { } + + int getIndex(void) const { return mIndex; } + + // Virtual functions of AISyncKey. + public: + /*virtual*/ synckeytype_t getkeytype(void) const + { + // Return a unique identifier for this class, where the low 8 bits represent the syncgroup. + return synckeytype; + } + + /*virtual*/ bool equals(AISyncKey const& key) const + { + synckeytype_t const theotherkey = (synckeytype_t)(synckeytype ^ 0x100); + switch (key.getkeytype()) + { + case synckeytype: + { + // The other key is of the same type. + TestsuiteKey const& test_key = static_cast const&>(key); + return (mIndex & 1) == (test_key.mIndex & 1); + } + case theotherkey: + { + TestsuiteKey const& test_key = static_cast const&>(key); + return (mIndex & 2) == (test_key.getIndex() & 2); + } + default: + // The keys must be in the same syncgroup. + break; + } + return false; + } +}; + +template +class TestsuiteClient : public AISyncClient +{ + // AISyncClient events. + protected: + /*virtual*/ AISyncKey* createSyncKey(void) const + { + return new TestsuiteKey(mIndex); + } + + private: + int mIndex; + bool mRequestedRegistered; + synceventset_t mRequestedReady; + bool mActualReady1; + + public: + TestsuiteClient() : mIndex(-1), mRequestedRegistered(false), mRequestedReady(0), mActualReady1(false) { } + ~TestsuiteClient() { if (is_registered()) this->ready(mRequestedReady, (synceventset_t)0); } + + void setIndex(int index) { mIndex = index; } + + protected: + /*virtual*/ void event1_ready(void) + { +#ifdef DEBUG_SYNCOUTPUT + Dout(dc::notice, "Calling TestsuiteClient<" << synckeytype << ">::event1_ready() (mIndex = " << mIndex << ") of client " << this); +#endif + llassert(!mActualReady1); + mActualReady1 = true; + } + + /*virtual*/ void event1_not_ready(void) + { +#ifdef DEBUG_SYNCOUTPUT + Dout(dc::notice, "Calling TestsuiteClient<" << synckeytype << ">::event1_not_ready() (mIndex = " << mIndex << ") of client " << this); +#endif + llassert(mActualReady1); + mActualReady1 = false; + } + + // This is called when the server expired and we're the only client on it. + /*virtual*/ void deregistered(void) + { +#ifdef DEBUG_SYNCOUTPUT + DoutEntering(dc::notice, "TestsuiteClient<" << synckeytype << ">::deregistered(), with this = " << this); +#endif + mRequestedRegistered = false; + mRequestedReady = 0; + mActualReady1 = false; + this->mReadyEvents = 0; + } + + private: + bool is_registered(void) const { return this->server(); } + + public: + void change_state(unsigned long r); + bool getRequestedRegistered(void) const { return mRequestedRegistered; } + synceventset_t getRequestedReady(void) const { return mRequestedReady; } +}; + +TestsuiteClient* client1ap; +TestsuiteClient* client1bp; +TestsuiteClient* client2ap; +TestsuiteClient* client2bp; + +int const number_of_clients_per_syncgroup = 8; + +template +void TestsuiteClient::change_state(unsigned long r) +{ + bool change_registered = r & 1; + r >>= 1; + synceventset_t toggle_events = r & 15; + r >>= 4; + if (change_registered) + { + if (mRequestedRegistered && !mRequestedReady) + { + mRequestedRegistered = false; + this->unregister_client(); + } + } + else if (toggle_events) + { + mRequestedReady ^= toggle_events; + mRequestedRegistered = true; + this->ready(toggle_events, mRequestedReady & toggle_events); + } + llassert(mRequestedRegistered == is_registered()); + AISyncServer* server = this->server(); + if (mRequestedRegistered) + { + synceventset_t all_ready = synceventset_t(-1); + synceventset_t any_ready = 0; + int nr = 0; + for (int cl = 0; cl < number_of_clients_per_syncgroup; ++cl) + { + switch ((synckeytype & 0xff)) + { + case syncgroup_test1: + { + if (client1ap[cl].server() == server) + { + if (client1ap[cl].getRequestedRegistered()) + { + ++nr; + all_ready &= client1ap[cl].getRequestedReady(); + any_ready |= client1ap[cl].getRequestedReady(); + } + } + if (client1bp[cl].server() == server) + { + if (client1bp[cl].getRequestedRegistered()) + { + ++nr; + all_ready &= client1bp[cl].getRequestedReady(); + any_ready |= client1bp[cl].getRequestedReady(); + } + } + break; + } + case syncgroup_test2: + { + if (client2ap[cl].server() == server) + { + if (client2ap[cl].getRequestedRegistered()) + { + ++nr; + all_ready &= client2ap[cl].getRequestedReady(); + any_ready |= client2ap[cl].getRequestedReady(); + } + } + if (client2bp[cl].server() == server) + { + if (client2bp[cl].getRequestedRegistered()) + { + ++nr; + all_ready &= client2bp[cl].getRequestedReady(); + any_ready |= client2bp[cl].getRequestedReady(); + } + } + break; + } + } + } + llassert(nr == server->getClients().size()); + llassert(!!(all_ready & 1) == mActualReady1); + llassert(this->server()->events_with_all_clients_ready() == all_ready); + llassert(this->server()->events_with_at_least_one_client_ready() == any_ready); + llassert(nr == 0 || (any_ready & all_ready) == all_ready); + } + llassert(mRequestedReady == this->mReadyEvents); +} + +int main() +{ + Debug(libcw_do.on()); + Debug(dc::notice.on()); + Debug(libcw_do.set_ostream(&std::cout)); + Debug(list_channels_on(libcw_do)); + + unsigned short seed16v[3] = { 0x1234, 0xfedc, 0x7091 }; + + for (int k = 0;; ++k) + { + std::cout << "Loop: " << k << "; SEED: " << std::hex << seed16v[0] << ", " << seed16v[1] << ", " << seed16v[2] << std::dec << std::endl; + ++LLFrameTimer::sFrameCount; + + seed48(seed16v); + seed16v[0] = lrand48() & 0xffff; + seed16v[1] = lrand48() & 0xffff; + seed16v[2] = lrand48() & 0xffff; + + TestsuiteClient client1a[number_of_clients_per_syncgroup]; + TestsuiteClient client1b[number_of_clients_per_syncgroup]; + TestsuiteClient client2a[number_of_clients_per_syncgroup]; + TestsuiteClient client2b[number_of_clients_per_syncgroup]; + client1ap = client1a; + client1bp = client1b; + client2ap = client2a; + client2bp = client2b; + + for (int i = 0; i < number_of_clients_per_syncgroup; ++i) + { + client1a[i].setIndex(i); + client1b[i].setIndex(i); + client2a[i].setIndex(i); + client2b[i].setIndex(i); + } + + for (int j = 0; j < 1000000; ++j) + { + innerloop_count += 1; + +#ifdef DEBUG_SYNCOUTPUT + Dout(dc::notice, "Innerloop: " << j); +#endif + unsigned long r = lrand48(); + synckeytype_t keytype = (r & 1) ? ((r & 2) ? synckeytype_test1a : synckeytype_test1b) : ((r & 2) ? synckeytype_test2a : synckeytype_test2b); + r >>= 2; + int cl = (r & 255) % number_of_clients_per_syncgroup; + r >>= 8; + switch (keytype) + { + case synckeytype_test1a: + client1a[cl].change_state(r); + break; + case synckeytype_test1b: + client1b[cl].change_state(r); + break; + case synckeytype_test2a: + client2a[cl].change_state(r); + break; + case synckeytype_test2b: + client2b[cl].change_state(r); + break; + } + } + } +} + +#endif diff --git a/indra/llcommon/aisyncclient.h b/indra/llcommon/aisyncclient.h new file mode 100644 index 000000000..34a3644a3 --- /dev/null +++ b/indra/llcommon/aisyncclient.h @@ -0,0 +1,296 @@ +/** + * @file aisyncclient.h + * @brief Declaration of AISyncClient. + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 12/12/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AI_SYNC_CLIENT_H +#define AI_SYNC_CLIENT_H + +#ifdef SYNC_TESTSUITE +/* + * To compile the testsuite, run: + * + * cd indra/llcommon + * g++ -O3 -DCWDEBUG -DSYNC_TESTSUITE -I. -I../cwdebug aisyncclient.cpp -lcwd + */ + +#include +#include +typedef uint32_t U32; +typedef int32_t S32; +typedef uint64_t U64; +typedef float F32; +typedef double F64; +#define LL_COMMON_API +#define SHOW_ASSERT +#define ASSERT_ONLY_COMMA(...) , __VA_ARGS__ +#define llassert assert + +struct LLFrameTimer +{ + double mStartTime; + double mExpiry; + static double getCurrentTime(void); + static U32 sFrameCount; + static U32 getFrameCount() { return sFrameCount; } + F64 getStartTime() const { return mStartTime; } + void reset(double expiration) { mStartTime = getCurrentTime(); mExpiry = mStartTime + expiration; } + bool hasExpired(void) const { return getCurrentTime() > mExpiry; } +}; + +template +struct LLSingleton +{ + static T sInstance; + static T& instance(void) { return sInstance; } +}; + +template +T LLSingleton::sInstance; + +#else // !SYNC_TESTSUITE +#include "llsingleton.h" +#include "llframetimer.h" +#endif +#include +#include + +//--------------------------------------------------------------------------------------------------------------------- +// Keys with a different syncgroup are never equal (so they are never synchronized). +enum syncgroups +{ +#ifdef SYNC_TESTSUITE + syncgroup_test1, + syncgroup_test2, +#else + syncgroup_motions, // Syncgroup used for animations. +#endif + syncgroup_size +}; + +// Each key type must return a unique identifier that exists of its syncgroup (the least significant 8 bit) plus a few bit to make it unique (bit 9 and higher). +enum synckeytype_t +{ +#ifdef SYNC_TESTSUITE + synckeytype_test1a = 0x000 + syncgroup_test1, + synckeytype_test1b = 0x100 + syncgroup_test1, + synckeytype_test2a = 0x000 + syncgroup_test2, + synckeytype_test2b = 0x100 + syncgroup_test2, +#else + synckeytype_motion = syncgroup_motions // There is currently only one key type in the syncgroup_motions group: AISyncKeyMotion. +#endif +}; + +typedef U32 synceventset_t; // A mask where each bit represents a ready state. + +class LL_COMMON_API AISyncKey +{ + private: + LLFrameTimer mFrameTimer; // This timer is started at the moment the sync key is created. + U32 mStartFrameCount; // The frame count at which the timer was started. + static F32 const sExpirationTime = 0.1; // In seconds. + + public: + // Constructor. + AISyncKey(void) : mStartFrameCount(LLFrameTimer::getFrameCount()) + { + mFrameTimer.reset(sExpirationTime); + } + + // Destructor. + virtual ~AISyncKey() { } + + // Return true if this key expired. + bool expired(void) const + { + // The key has expired when sExpirationTime seconds have elapsed AND at least two frames have passed. + return mFrameTimer.getFrameCount() > mStartFrameCount + 1 && mFrameTimer.hasExpired(); + } + + // Returns true if this object and key would not compare equal based on time because this object is too old. + bool is_older_than(AISyncKey const& key) const + { + return key.mStartFrameCount > mStartFrameCount + 1 && key.mFrameTimer.getStartTime() > mFrameTimer.getStartTime() + sExpirationTime; + } + + // Return the creation time of this key (in number of seconds since application start). + F64 getCreationTime(void) const { return mFrameTimer.getStartTime(); } + + // Returns true if the two keys match, meaning that they should be synchronized. + friend bool operator==(AISyncKey const& key1, AISyncKey const& key2); + + // Returns an ID that uniquely identifies the derived type. + // Currently the only derived type is AISyncKeyMotion with ID synckeytype_motion. + virtual synckeytype_t getkeytype(void) const = 0; + + // Returns true if the data in the derived objects match, meaning that they should be synchronized. + virtual bool equals(AISyncKey const& key) const = 0; +}; + +// Forward declaration. +class AISyncClient; +class AISyncServer; +LL_COMMON_API extern void intrusive_ptr_add_ref(AISyncServer* server); +LL_COMMON_API extern void intrusive_ptr_release(AISyncServer* server); + +struct LL_COMMON_API AISyncClientData +{ + AISyncClient* mClientPtr; + synceventset_t mReadyEvents; + + AISyncClientData(AISyncClient* client) : mClientPtr(client), mReadyEvents(0) { } +}; + +class LL_COMMON_API AISyncServer +{ + public: + typedef std::list client_list_t; + + private: + int mRefCount; // Number of boost::intrusive_ptr objects pointing to this object. + AISyncKey* mKey; // The key of the first client that was added. + client_list_t mClients; // A list with pointers to all registered clients. + bool mSynchronized; // Set when a server gets more than one client, and not reset anymore after that. + synceventset_t mReadyEvents; // 0xFFFFFFFF bitwise-AND-ed with all clients. + synceventset_t mPendingEvents; // The bitwise-OR of all clients. + + public: + AISyncServer(AISyncKey* key) : mRefCount(0), mKey(key), mSynchronized(false), mReadyEvents((synceventset_t)-1), mPendingEvents(0) { } + ~AISyncServer() { delete mKey; } + + // Add a new client to this server. + void add(AISyncClient* client); + + // Add a new client to this server. + void remove(AISyncClient* client); + + // Return the key associated to this server (which is the key produced by the first client of the largest synckeytype_t that was added). + AISyncKey const& key(void) const { return *mKey; } + // Replace they key with another key (of larger synckeytype_t). + void swapkey(AISyncKey*& key_ptr) { AISyncKey* tmp = key_ptr; key_ptr = mKey; mKey = tmp; } + + // Returns true if this server never had more than one client. + bool never_synced(void) const { return !mSynchronized; } + + // Set readiness of all events at once. + bool ready(synceventset_t events, synceventset_t yesno, AISyncClient* client); + + // Unregister the (only) client because it's own its own and will never need synchronization. + void unregister_last_client(void); + + // Return the events that all clients for. + synceventset_t events_with_all_clients_ready(void) const; + + // Return events that at least one client is ready for. + synceventset_t events_with_at_least_one_client_ready(void) const; + +#ifdef SHOW_ASSERT + client_list_t const& getClients(void) const { return mClients; } +#endif + + private: + // Call event1_ready() or event1_not_ready() on all clients if the least significant bit of mReadyEvents changed. + void trigger(synceventset_t old_ready_events); + +#ifdef SYNC_TESTSUITE + void sanity_check(void) const; +#endif + + private: + friend void intrusive_ptr_add_ref(AISyncServer* server); + friend void intrusive_ptr_release(AISyncServer* server); +}; + +class LL_COMMON_API AISyncServerMap : public LLSingleton +{ + public: + typedef boost::intrusive_ptr server_ptr_t; // The type of a (stored) pointer to the server objects. + typedef std::list server_list_t; // The type of the list with pointers to the server objects. + + private: + server_list_t mServers; // A list with pointers to all server objects. + + public: + // Find or create a server object that the client belongs to and store the client in it. + // If a new server is created, it is stored in mServers. + void register_client(AISyncClient* client); + + private: + friend void intrusive_ptr_release(AISyncServer* server); + // Remove a server from the map, only called by intrusive_ptr_release when there is one pointer left; + // therefore, the server should not have any clients. + void remove_server(AISyncServer* server); +}; + +class LL_COMMON_API AISyncClient +{ + private: + friend class AISyncServer; + boost::intrusive_ptr mServer; // The server this client was registered with, or NULL when unregistered. + + public: +#ifdef SHOW_ASSERT + synceventset_t mReadyEvents; + AISyncClient(void) : mReadyEvents(0) { } +#endif + virtual ~AISyncClient() { } + virtual AISyncKey* createSyncKey(void) const = 0; + + virtual void event1_ready(void) = 0; + virtual void event1_not_ready(void) = 0; + + // Only client. Client was forcefully deregistered from expired server because it was the only client. + virtual void deregistered(void) + { +#ifdef SHOW_ASSERT + mReadyEvents = 0; +#endif + } + + AISyncServer* server(void) const { return mServer.get(); } + + // Add this client to a server with matching sync key. Optionally the server is first created. + void register_client(void) { AISyncServerMap::instance().register_client(this); } + + // Remove this client from its server. + void unregister_client(void) { mServer->remove(this); } + + // Call 'ready' when you are ready (or not) to get a call to start(). + // Returns true if that call was made (immediately), otherwise it may happen later. + + bool ready(synceventset_t events, synceventset_t yesno) // Set readiness of all events at once. + { + if (!mServer) + { + register_client(); + } + return mServer->ready(events, yesno, this); + } +}; + +#endif From 1c8876cead4e36bd71e02ae1364136cc579e294f Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 25 Dec 2013 03:14:44 +0100 Subject: [PATCH 100/115] Synchronize looping animations that start at the same moment. --- indra/llcharacter/llcharacter.cpp | 15 +++ indra/llcharacter/llkeyframemotion.cpp | 41 ++++++- indra/llcharacter/llmotion.cpp | 137 +++++++++++++++++++++++ indra/llcharacter/llmotion.h | 87 +++++++++++++- indra/llcharacter/llmotioncontroller.cpp | 134 +++++++++++++++++++++- indra/llcharacter/llmotioncontroller.h | 34 +++++- indra/llcommon/aisyncclient.cpp | 61 +--------- indra/llcommon/aisyncclient.h | 39 ++++--- indra/llcommon/llframetimer.h | 7 ++ indra/newview/llviewermessage.cpp | 2 +- indra/newview/llvoavatar.cpp | 14 ++- 11 files changed, 484 insertions(+), 87 deletions(-) diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 25b89d2f8..65d37f8e0 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -194,11 +194,26 @@ void LLCharacter::updateMotions(e_update_t update_type) { if (update_type == HIDDEN_UPDATE) { + // + // Keep updating avatars that have at least one motion that is synchronized with a still running motion. + // This call tells the other controllers that we are in principle hidden. + // It returns false if we need to keep updating anyway. + if (!mMotionController.hidden(true)) + { + mMotionController.updateMotions(LLCharacter::NORMAL_UPDATE); + return; + } + // LLFastTimer t(FTM_UPDATE_HIDDEN_ANIMATION); mMotionController.updateMotionsMinimal(); } else { + // + // This call tells the other controllers that we are visible and that they need + // to keep updating if they are synchronized with us, even if they are hidden. + mMotionController.hidden(false); + // LLFastTimer t(FTM_UPDATE_ANIMATION); // unpause if the number of outstanding pause requests has dropped to the initial one if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1) diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index aa6e05708..711ac21e5 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -818,7 +818,44 @@ void LLKeyframeMotion::onDeactivate() //----------------------------------------------------------------------------- // setStopTime() //----------------------------------------------------------------------------- -// time is in seconds since character creation +// +// Consider a looping animation of 20 frames, where the loop in point is at 3 frames +// and the loop out point at 16 frames: +// +// The first 3 frames of the animation would be the "loop in" animation. +// The last 4 frames of the animation would be the "loop out" animation. +// Frames 4 through 15 would be the looping animation frames. +// +// If the animation would not be looping, all frames would just be played once sequentially: +// +// mActivationTimestamp -. +// v +// 0 3 15 16 20 +// | | \| | +// --------------------- +// <--> <-- mLoopInPoint (relative to mActivationTimestamp) +// <--------------> <-- mLoopOutPoint (relative to mActivationTimestamp) +// <----mDuration------> +// +// When looping the animation would repeat frames 3 to 16 (loop) a few times, for example: +// +// 0 3 15 3 15 3 15 3 15 16 20 +// | | loop 1 \| loop 2 \| loop 3 \| loop 4 \| | +// ------------------------------------------------------------ +//LOOP^ ^ LOOP +// IN | <----->| OUT +// start_loop_time loop_fraction_time-' time +// +// The time at which the animation is started corresponds to frame 0 and is stored +// in mActivationTimestamp (in seconds since character creation). +// +// If setStopTime() is called with a time somewhere inside loop 4, +// then 'loop_fraction_time' is the time from the beginning of +// loop 4 till 'time'. Thus 'time - loop_fraction_time' is the first +// frame of loop 4, and '(time - loop_fraction_time) + +// (mJointMotionList->mDuration - mJointMotionList->mLoopInPoint)' +// would correspond to frame 20. +// void LLKeyframeMotion::setStopTime(F32 time) { LLMotion::setStopTime(time); @@ -836,6 +873,8 @@ void LLKeyframeMotion::setStopTime(F32 time) loop_fraction_time = fmod(time - start_loop_time, mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint); } + // This sets mStopTimestamp to the time that corresponds to the end of the animation (ie, frame 20 in the above example) + // minus the ease out duration, so that the animation eases out during the loop out and finishes exactly at the end. mStopTimestamp = llmax(time, (time - loop_fraction_time) + (mJointMotionList->mDuration - mJointMotionList->mLoopInPoint) - getEaseOutDuration()); } diff --git a/indra/llcharacter/llmotion.cpp b/indra/llcharacter/llmotion.cpp index 021345fb3..94d12c7e4 100644 --- a/indra/llcharacter/llmotion.cpp +++ b/indra/llcharacter/llmotion.cpp @@ -39,6 +39,122 @@ #include "llcriticaldamp.h" #include "llmotioncontroller.h" +// +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// AISyncClientMotion class +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +AISyncKey* AISyncClientMotion::createSyncKey(AISyncKey const* from_key) const +{ + // The const cast is needed because getDuration() is non-const while it should have been. + AISyncClientMotion* self = const_cast(this); + // Only synchronize motions with the same duration and loop value. + return new AISyncKeyMotion(from_key, self->getDuration(), self->getLoop()); +} + +void AISyncClientMotion::aisync_loading(void) +{ + // Register the motion for (possible) synchronization: this marks the time at which is should have started. + unregister_client(); // In case it is already registered. Getting here means we are being (re)started now, we need to synchronize with other motions that start now. + register_client(); +} + +void AISyncClientMotion::aisync_loaded(void) +{ + AISyncServer* server = this->server(); + if (!server) + { + // Already expired without being synchronized (no other motion was started at the same time). + return; + } + AISyncKey const& key = server->key(); // The allocation of this is owned by server. + // There is no need to resync if there was not another motion started at the same time and the key already expired. + bool need_resync = !(server->never_synced() && key.expired()); + AISyncKey* new_key; + if (need_resync) + { + // Create a new key using the old start time. + new_key = createSyncKey(&key); + } + server->remove(this); // This resets mServer and might even delete server. + if (need_resync) + { + // Add the client to another server (based on the new key). This takes ownership of the key allocation. + AISyncServerMap::instance().register_client(this, new_key); + } +} + +F32 LLMotion::getRuntime(void) const +{ + llassert(mActive); + return mController->getAnimTime() - mActivationTimestamp; +} + +F32 LLMotion::getAnimTime(void) const +{ + return mController->getAnimTime(); +} + +F32 LLMotion::syncActivationTime(F32 time) +{ + AISyncServer* server = this->server(); + if (!server) + { + register_client(); + server = this->server(); + } + AISyncServer::client_list_t const& clients = server->getClients(); + if (clients.size() > 1) + { + // Look for the client with the smallest runtime. + AISyncClientMotion* motion_with_smallest_runtime = NULL; + F32 runtime = 1e10; + // Run over all motions in this to be synchronized group. + for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client) + { + if ((client->mReadyEvents & 2)) // Is this motion active? Motions that aren't loaded yet are not active. + { + // Currently, if event 2 is set then this is an LLMotion. + llassert(dynamic_cast(client->mClientPtr)); + AISyncClientMotion* motion = static_cast(client->mClientPtr); + // Deactivated motions should have been deregistered, certainly not have event 2 set. + llassert(static_cast(motion)->isActive()); + if (motion->getRuntime() < runtime) + { + // This is a bit fuzzy since theoretically the runtime of all active motions in the list should be the same. + // Just use the smallest value to get rid of some randomness. We might even synchronizing with ourselves + // in which case 'time' would be set to a value such that mActivationTimestamp won't change. + // In practise however, this list will contain only two clients: this, being inactive, and our partner. + runtime = motion->getRuntime(); + motion_with_smallest_runtime = motion; + } + } + } + //----------------------------------------------------------------------------------------- + // Here is where the actual synchronization takes place. + // Current we only synchronize looped motions. + if (getLoop()) + { + if (motion_with_smallest_runtime) + { + // Pretend the motion was started in the past at the same time as the other motion(s). + time = getAnimTime() - runtime; + } + } + //----------------------------------------------------------------------------------------- + } + + return time; +} + +void AISyncClientMotion::deregistered(void) +{ + mReadyEvents = 0; +} +// + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // LLMotion class @@ -149,6 +265,19 @@ void LLMotion::activate(F32 time) { mActivationTimestamp = time; mStopped = FALSE; + // + if (mController && !mController->syncing_disabled()) // Avoid being registered when syncing is disabled for this motion. + { + if (mActive) + { + // If the motion is already active then we are being restarted. + // Unregister it first (if it is registered) so that the call to ready will cause it to be registered + // and be synchronized with other motions that are started at this moment. + unregister_client(); + } + ready(6, 2 | (mController->isHidden() ? 0 : 4)); // Signal that mActivationTimestamp is set/valid (2), and that this server has a visible motion (4) (or not). + } + // mActive = TRUE; onActivate(); } @@ -161,6 +290,14 @@ void LLMotion::deactivate() mActive = FALSE; mPose.setWeight(0.f); + // + if (server()) // Only when this motion is already registered. + { + ready(6, 0); // Signal that mActivationTimestamp is no longer valid. + unregister_client(); // No longer running, so no longer a part of this sync group. + } + // + if (mDeactivateCallback) { (*mDeactivateCallback)(mDeactivateCallbackUserData); diff --git a/indra/llcharacter/llmotion.h b/indra/llcharacter/llmotion.h index a67138bac..a246b08c7 100644 --- a/indra/llcharacter/llmotion.h +++ b/indra/llcharacter/llmotion.h @@ -38,6 +38,7 @@ //----------------------------------------------------------------------------- #include +#include "aisyncclient.h" #include "llerror.h" #include "llpose.h" #include "lluuid.h" @@ -45,10 +46,77 @@ class LLCharacter; class LLMotionController; +//----------------------------------------------------------------------------- +// class AISync* stuff +//----------------------------------------------------------------------------- + +class AISyncKeyMotion : public AISyncKey +{ + private: + F32 mDuration; + bool mLoop; + + public: + AISyncKeyMotion(AISyncKey const* from_key, F32 duration, bool loop) : AISyncKey(from_key), mDuration(duration), mLoop(loop) { } + + // Virtual functions of AISyncKey. + public: + /*virtual*/ synckeytype_t getkeytype(void) const + { + // Return a unique identifier for this class, where the low 8 bits represent the syncgroup. + return synckeytype_motion; + } + + /*virtual*/ bool equals(AISyncKey const& key) const + { + switch (key.getkeytype()) + { + case synckeytype_motion: + { + // The other key is of the same type. + AISyncKeyMotion const& motion_key = static_cast(key); + return mLoop == motion_key.mLoop && is_approx_equal(mDuration, motion_key.mDuration); + } + default: + // The keys must be in the same syncgroup. + break; + } + return false; + } +}; + +class AISyncClientMotion : public AISyncClient +{ + protected: + // Make sure that clients that are destroyed are first unregistered. + // This is needed, for example, when loading fails or when excess motions are being purged. + /*virtual*/ ~AISyncClientMotion() { unregister_client(); } + + // AISyncClient events. + /*virtual*/ AISyncKey* createSyncKey(AISyncKey const* from_key = NULL) const; + /*virtual*/ void event1_ready(void) { } + /*virtual*/ void event1_not_ready(void) { } + /*virtual*/ void deregistered(void); + + protected: + // This is called when the server sent us a message that it wants us to play this animation, but we can't because it isn't fully downloaded yet. + void aisync_loading(void); + // This is called when that motion is successfully loaded and it has to be re-registered because now the duration etc is known. + void aisync_loaded(void); + + public: + // Virtual functions of AISyncClientMotion. + // These are defined by classes derived from LLMotion (which is derived from this class). + virtual BOOL getLoop() = 0; + virtual F32 getDuration() = 0; + virtual F32 getAnimTime(void) const = 0; + virtual F32 getRuntime(void) const = 0; +}; + //----------------------------------------------------------------------------- // class LLMotion //----------------------------------------------------------------------------- -class LLMotion +class LLMotion : public AISyncClientMotion { friend class LLMotionController; @@ -115,7 +183,22 @@ protected: BOOL isActive() { return mActive; } public: void activate(F32 time); - + + // + // Returns the time that this motion has been running. + virtual F32 getRuntime(void) const; + + // Return the current time (in seconds since creation of the controller). + virtual F32 getAnimTime(void) const; + + // This is called when a motion is to be activated, but might need synchronization. + // It adjusts the start time to match that of other motions in the same synchronization group that were already started. + F32 syncActivationTime(F32 time); + + // Accessor. + LLMotionController* getController(void) const { return mController; } + // + public: //------------------------------------------------------------------------- // animation callbacks to be implemented by subclasses diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 099805676..8f8475576 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -130,6 +130,9 @@ LLMotionController::LLMotionController() mTimeFactor(sCurrentTimeFactor), mCharacter(NULL), mActiveMask(0), + mDisableSyncing(0), + mHidden(false), + mHaveVisibleSyncedMotions(false), mPrevTimerElapsed(0.f), mAnimTime(0.f), mLastTime(0.0f), @@ -173,6 +176,10 @@ void LLMotionController::deleteAllMotions() mActiveMask = 0; for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer()); mDeprecatedMotions.clear(); + for (motion_map_t::iterator iter = mAllMotions.begin(); iter != mAllMotions.end(); ++iter) + { + iter->second->unregister_client(); + } // for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer()); mAllMotions.clear(); @@ -437,7 +444,19 @@ BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset) } // llinfos << "Starting motion " << name << llendl; - return activateMotionInstance(motion, mAnimTime - start_offset); + // + F32 start_time = mAnimTime - start_offset; + if (!mDisableSyncing) + { + start_time = motion->syncActivationTime(start_time); + } + ++mDisableSyncing; + // + BOOL res = activateMotionInstance(motion, start_time); + // + --mDisableSyncing; + // + return res; } @@ -793,7 +812,19 @@ void LLMotionController::updateLoadingMotions() // this motion should be playing if (!motionp->isStopped()) { - activateMotionInstance(motionp, mAnimTime); + // + F32 start_time = mAnimTime; + if (!mDisableSyncing) + { + motionp->aisync_loaded(); + start_time = motionp->syncActivationTime(start_time); + } + ++mDisableSyncing; + // + activateMotionInstance(motionp, start_time); + // + --mDisableSyncing; + // } } else if (status == LLMotion::STATUS_FAILURE) @@ -806,6 +837,10 @@ void LLMotionController::updateLoadingMotions() // check for it's existence there. llassert(mDeprecatedMotions.find(motionp) == mDeprecatedMotions.end()); mAllMotions.erase(motionp->getID()); + // + // Make sure we're not registered anymore. + motionp->unregister_client(); + // delete motionp; } } @@ -933,6 +968,12 @@ BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time) if (mLoadingMotions.find(motion) != mLoadingMotions.end()) { + // + if (!syncing_disabled()) + { + motion->aisync_loading(); + } + // // we want to start this motion, but we can't yet, so flag it as started motion->setStopped(FALSE); // report pending animations as activated @@ -1094,9 +1135,9 @@ void LLMotionController::deactivateAllMotions() { // Singu note: this must run over mActiveMotions: other motions are not active, // and running over mAllMotions will miss the ones in mDeprecatedMotions. - for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter) + for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end();) { - deactivateMotionInstance(*iter); + deactivateMotionInstance(*iter++); // This might invalidate iter by erasing it from mActiveMotions. } } @@ -1126,13 +1167,98 @@ void LLMotionController::flushAllMotions() mCharacter->removeAnimationData("Hand Pose"); // restart motions + // + // Because we called motionp->deactivate() above, instead of deactivateMotionInstance(), + // prevent calling AISyncClientMotion::activateInstance in startMotion below. + disable_syncing(); + // for (std::vector >::iterator iter = active_motions.begin(); iter != active_motions.end(); ++iter) { startMotion(iter->first, iter->second); } + // + enable_syncing(); + // } +// +//----------------------------------------------------------------------------- +// toggle_hidden() +//----------------------------------------------------------------------------- +void LLMotionController::toggle_hidden(void) +{ + mHaveVisibleSyncedMotions = mHidden; // Default is false if we just became invisible (otherwise this value isn't used). + mHidden = !mHidden; + synceventset_t const visible = mHidden ? 0 : 4; + + // Run over all motions. + for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter) + { + LLMotion* motionp = *iter; + AISyncServer* server = motionp->server(); + if (server && !server->never_synced() && (motionp->mReadyEvents & 2)) // Skip motions that aren't synchronized at all or that are not active. + { + bool visible_before = server->events_with_at_least_one_client_ready() & 4; + server->ready(4, visible, motionp); // Mark that now we are visible or no longer visible. + bool visible_after = server->events_with_at_least_one_client_ready() & 4; + if (visible_after) // Are there any synchronized motions (left) that ARE visible? + { + mHaveVisibleSyncedMotions = true; + } + if (visible_before != visible_after) + { + // The group as a whole now might need to change whether or not it is animated. + AISyncServer::client_list_t const& clients = server->getClients(); + for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client) + { + LLMotion* motion = dynamic_cast(client->mClientPtr); + if (!motion) + { + continue; + } + LLMotionController* controller = motion->getController(); + if (controller == this) + { + continue; + } + if (visible_after) + { + // Us becoming visible means that all synchronized avatars need to be animated again too. + controller->setHaveVisibleSyncedMotions(); + } + else + { + // Us becoming hidden means that all synchronized avatars might stop animating. + controller->refresh_hidden(); // It is extremely unlikely, but harmless, to call this twice on the same controller. + } + } + } + } + } +} + +void LLMotionController::refresh_hidden(void) +{ + mHaveVisibleSyncedMotions = !mHidden; + + // Run over all motions. + for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter) + { + LLMotion* motionp = *iter; + AISyncServer* server = motionp->server(); + if (server && !server->never_synced() && (motionp->mReadyEvents & 2)) // Skip motions that aren't synchronized at all or that are not active. + { + bool visible_after = server->events_with_at_least_one_client_ready() & 4; + if (visible_after) // Are there any synchronized motions (left) that ARE visible? + { + mHaveVisibleSyncedMotions = true; + } + } + } +} +// + //----------------------------------------------------------------------------- // pause() //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index 04b15ff89..ac3d6d1f2 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -150,11 +150,11 @@ public: //Flush is a liar. void deactivateAllMotions(); - // + // void activated(U32 bit) { mActiveMask |= bit; } void deactivated(U32 bit) { mActiveMask &= ~bit; } bool isactive(U32 bit) const { return (mActiveMask & bit) != 0; } - // + // // pause and continue all motions void pauseAllMotions(); @@ -186,7 +186,10 @@ protected: // internal operations act on motion instances directly // as there can be duplicate motions per id during blending overlap void deleteAllMotions(); + // singu: LLMotion needs access to activateMotionInstance. +public: BOOL activateMotionInstance(LLMotion *motion, F32 time); +protected: BOOL deactivateMotionInstance(LLMotion *motion); void deprecateMotionInstance(LLMotion* motion); BOOL stopMotionInstance(LLMotion *motion, BOOL stop_imemdiate); @@ -227,9 +230,12 @@ protected: motion_list_t mActiveMotions; motion_set_t mDeprecatedMotions; - // + // U32 mActiveMask; - // + int mDisableSyncing; // Set while LLMotion::onActivate (and onDeactivate) are called for this controller. + bool mHidden; // The value of the last call to hidden(). + bool mHaveVisibleSyncedMotions; // Set when we are synchronized with one or more motions of a controller that is not hidden. + // LLFrameTimer mTimer; F32 mPrevTimerElapsed; F32 mAnimTime; @@ -242,6 +248,26 @@ protected: F32 mLastInterp; U8 mJointSignature[2][LL_CHARACTER_MAX_JOINTS]; + + // +public: + // Internal administration for AISync. + void disable_syncing(void) { mDisableSyncing += 100; } + void enable_syncing(void) { mDisableSyncing -= 100; } + bool syncing_disabled(void) const { return mDisableSyncing >= 100; } + + // Accessors needed for synchronization. + F32 getAnimTime(void) const { return mAnimTime; } + bool isHidden(void) const { return mHidden; } + + // Called often. Should return false if we still need to keep updating our motions even if we're not visible. + bool hidden(bool not_visible) { if (mHidden != not_visible) toggle_hidden(); return !mHaveVisibleSyncedMotions; } + +private: + void toggle_hidden(void); + void refresh_hidden(void); + void setHaveVisibleSyncedMotions(void) { mHaveVisibleSyncedMotions = true; } + // }; //----------------------------------------------------------------------------- diff --git a/indra/llcommon/aisyncclient.cpp b/indra/llcommon/aisyncclient.cpp index 9cadb3cb1..e1865fec8 100644 --- a/indra/llcommon/aisyncclient.cpp +++ b/indra/llcommon/aisyncclient.cpp @@ -126,20 +126,13 @@ void print_clients(AISyncServer const* server, AISyncServer::client_list_t const } #endif -void AISyncServerMap::register_client(AISyncClient* client) +void AISyncServerMap::register_client(AISyncClient* client, AISyncKey* new_key) { -#ifdef DEBUG_SYNCOUTPUT - DoutEntering(dc::notice, "AISyncServerMap::register_client(" << client << ")"); -#endif - // client must always be a new client that has to be stored somewhere. llassert(client->server() == NULL); // Obviously the client can't be ready for anything when it isn't registered yet. llassert(!client->mReadyEvents); - // First we need its sync key. - AISyncKey* new_key = client->createSyncKey(); - // Find if a server with this key already exists. AISyncServer* server = NULL; for (server_list_t::iterator iter = mServers.begin(); iter != mServers.end();) @@ -183,7 +176,6 @@ void AISyncServerMap::register_client(AISyncClient* client) server = new AISyncServer(new_key); // Add it to mServers, before the last server that is younger then the new key. server_list_t::iterator where = mServers.end(); // Insert the new server before 'where', -#if 0 // This is probably not necessary. server_list_t::iterator new_where = where; while (where != mServers.begin()) // unless there exists a server before that { @@ -194,10 +186,6 @@ void AISyncServerMap::register_client(AISyncClient* client) } where = new_where; // then insert it before that element (etc). } -#elif defined(SHOW_ASSERT) - server_list_t::iterator new_where = where; - llassert(where == mServers.begin() || new_key->getCreationTime() >= (*--new_where)->key().getCreationTime()); -#endif // This method causes a single call to intrusive_ptr_add_ref and none to intrusive_ptr_release. server_ptr_t server_ptr = server; mServers.insert(where, server_ptr_t())->swap(server_ptr); @@ -231,10 +219,6 @@ void AISyncServer::sanity_check(void) const void AISyncServer::add(AISyncClient* client) { -#ifdef DEBUG_SYNCOUTPUT - DoutEntering(dc::notice, "AISyncServer::add(" << client << "), with this = " << this); - print_clients(this, getClients()); -#endif #ifdef SYNC_TESTSUITE sanity_check(); #endif @@ -263,16 +247,10 @@ void AISyncServer::add(AISyncClient* client) void AISyncServer::remove(AISyncClient* client) { -#ifdef DEBUG_SYNCOUTPUT - DoutEntering(dc::notice, "AISyncServer::remove(" << client << "), with this = " << this); - print_clients(this, getClients()); -#endif #ifdef SYNC_TESTSUITE sanity_check(); #endif - // A client may only be unregistered after it was marked not-ready for all events. - llassert(!client->mReadyEvents); client_list_t::iterator client_iter = mClients.begin(); synceventset_t remaining_ready_events = (synceventset_t)-1; // All clients are ready. synceventset_t remaining_pending_events = 0; // At least one client is ready (waiting for the other clients thus). @@ -292,15 +270,14 @@ void AISyncServer::remove(AISyncClient* client) } llassert(found_client != mClients.end()); // This must be the same as client->mReadyEvents. - llassert(!found_client->mReadyEvents); + llassert(found_client->mReadyEvents == client->mReadyEvents); mClients.erase(found_client); - client->mServer.reset(); synceventset_t old_ready_events = mReadyEvents; mReadyEvents = remaining_ready_events; - // Since client->mReadyEvents is zero, this should be the same. - llassert(mPendingEvents == remaining_pending_events); mPendingEvents = remaining_pending_events; trigger(old_ready_events); + client->mServer.reset(); + client->deregistered(); #ifdef SYNC_TESTSUITE sanity_check(); @@ -309,10 +286,6 @@ void AISyncServer::remove(AISyncClient* client) void AISyncServer::unregister_last_client(void) { -#ifdef DEBUG_SYNCOUTPUT - DoutEntering(dc::notice, "AISyncServer::unregister_last_client()"); - print_clients(this, getClients()); -#endif #ifdef SYNC_TESTSUITE sanity_check(); #endif @@ -333,22 +306,6 @@ void AISyncServer::unregister_last_client(void) #endif } -synceventset_t AISyncServer::events_with_all_clients_ready(void) const -{ -#ifdef SYNC_TESTSUITE - sanity_check(); -#endif - return mReadyEvents; -} - -synceventset_t AISyncServer::events_with_at_least_one_client_ready(void) const -{ -#ifdef SYNC_TESTSUITE - sanity_check(); -#endif - return mPendingEvents; -} - void AISyncServer::trigger(synceventset_t old_ready_events) { // If event 1 changed, informat all clients about it. @@ -368,22 +325,14 @@ void AISyncServer::trigger(synceventset_t old_ready_events) } } -bool AISyncServer::ready(synceventset_t events, synceventset_t yesno, AISyncClient* client) +void AISyncServer::ready(synceventset_t events, synceventset_t yesno, AISyncClient* client) { -#ifdef DEBUG_SYNCOUTPUT - DoutEntering(dc::notice, "AISyncServer::ready(" << SyncEventSet(events) << ", " << SyncEventSet(yesno) << ", " << client << ")"); - print_clients(this, getClients()); -#endif #ifdef SYNC_TESTSUITE sanity_check(); #endif synceventset_t added_events = events & yesno; synceventset_t removed_events = events & ~yesno; - // May not add events that are already ready. - llassert(!(client->mReadyEvents & added_events)); - // Cannot remove events that weren't ready. - llassert((client->mReadyEvents & removed_events) == removed_events); // Run over all clients to find the client and calculate the current state. synceventset_t remaining_ready_events = (synceventset_t)-1; // All clients are ready. diff --git a/indra/llcommon/aisyncclient.h b/indra/llcommon/aisyncclient.h index 34a3644a3..b810f143a 100644 --- a/indra/llcommon/aisyncclient.h +++ b/indra/llcommon/aisyncclient.h @@ -117,9 +117,16 @@ class LL_COMMON_API AISyncKey public: // Constructor. - AISyncKey(void) : mStartFrameCount(LLFrameTimer::getFrameCount()) + AISyncKey(AISyncKey const* from_key) : mStartFrameCount(from_key ? from_key->mStartFrameCount : LLFrameTimer::getFrameCount()) { - mFrameTimer.reset(sExpirationTime); + if (from_key) + { + mFrameTimer.copy(from_key->mFrameTimer); + } + else + { + mFrameTimer.reset(sExpirationTime); + } } // Destructor. @@ -186,7 +193,7 @@ class LL_COMMON_API AISyncServer // Add a new client to this server. void add(AISyncClient* client); - // Add a new client to this server. + // Remove a client from this server. void remove(AISyncClient* client); // Return the key associated to this server (which is the key produced by the first client of the largest synckeytype_t that was added). @@ -198,20 +205,19 @@ class LL_COMMON_API AISyncServer bool never_synced(void) const { return !mSynchronized; } // Set readiness of all events at once. - bool ready(synceventset_t events, synceventset_t yesno, AISyncClient* client); + void ready(synceventset_t events, synceventset_t yesno, AISyncClient* client); // Unregister the (only) client because it's own its own and will never need synchronization. void unregister_last_client(void); // Return the events that all clients for. - synceventset_t events_with_all_clients_ready(void) const; + synceventset_t events_with_all_clients_ready(void) const { return mReadyEvents; } // Return events that at least one client is ready for. - synceventset_t events_with_at_least_one_client_ready(void) const; + synceventset_t events_with_at_least_one_client_ready(void) const { return mPendingEvents; } -#ifdef SHOW_ASSERT + // Return a list of all registered clients. client_list_t const& getClients(void) const { return mClients; } -#endif private: // Call event1_ready() or event1_not_ready() on all clients if the least significant bit of mReadyEvents changed. @@ -238,7 +244,7 @@ class LL_COMMON_API AISyncServerMap : public LLSingleton public: // Find or create a server object that the client belongs to and store the client in it. // If a new server is created, it is stored in mServers. - void register_client(AISyncClient* client); + void register_client(AISyncClient* client, AISyncKey* new_key); private: friend void intrusive_ptr_release(AISyncServer* server); @@ -258,8 +264,8 @@ class LL_COMMON_API AISyncClient synceventset_t mReadyEvents; AISyncClient(void) : mReadyEvents(0) { } #endif - virtual ~AISyncClient() { } - virtual AISyncKey* createSyncKey(void) const = 0; + virtual ~AISyncClient() { llassert(!mServer); /* If this fails then you need to add unregister_client() to the top of the destructor of the derived class that implements deregistered(). */ } + virtual AISyncKey* createSyncKey(AISyncKey const* from_key = NULL) const = 0; virtual void event1_ready(void) = 0; virtual void event1_not_ready(void) = 0; @@ -275,21 +281,22 @@ class LL_COMMON_API AISyncClient AISyncServer* server(void) const { return mServer.get(); } // Add this client to a server with matching sync key. Optionally the server is first created. - void register_client(void) { AISyncServerMap::instance().register_client(this); } + void register_client(void) { AISyncServerMap::instance().register_client(this, createSyncKey()); } - // Remove this client from its server. - void unregister_client(void) { mServer->remove(this); } + // Remove this client from its server, if any. + void unregister_client(void) { if (mServer) mServer->remove(this); } // Call 'ready' when you are ready (or not) to get a call to start(). // Returns true if that call was made (immediately), otherwise it may happen later. - bool ready(synceventset_t events, synceventset_t yesno) // Set readiness of all events at once. + // Set readiness of all events at once. + void ready(synceventset_t events, synceventset_t yesno) { if (!mServer) { register_client(); } - return mServer->ready(events, yesno, this); + mServer->ready(events, yesno, this); } }; diff --git a/indra/llcommon/llframetimer.h b/indra/llcommon/llframetimer.h index 2813150c5..30bc58dd9 100644 --- a/indra/llcommon/llframetimer.h +++ b/indra/llcommon/llframetimer.h @@ -47,6 +47,10 @@ public: // Create an LLFrameTimer and start it. After creation it is running and in the state expired (hasExpired will return true). LLFrameTimer(void) : mExpiry(0), mRunning(true), mPaused(false) { if (!sGlobalMutex) global_initialization(); setAge(0.0); } + // + void copy(LLFrameTimer const& timer) { mStartTime = timer.mStartTime; mExpiry = timer.mExpiry; mRunning = timer.mRunning; mPaused = timer.mPaused; } + // + // Atomic reads of static variables. // Return the number of seconds since the start of the application. @@ -142,6 +146,9 @@ public: bool hasExpired() const { return getElapsedSeconds() >= mExpiry; } F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(getElapsedSeconds() - mStartTime); } bool getStarted() const { return mRunning; } + // + F64 getStartTime() const { llassert(!mPaused); return mStartTime; } + // // return the seconds since epoch when this timer will expire. F64 expiresAt() const; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index a2adc49a9..ceea596b0 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5772,7 +5772,7 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) } } - if (num_blocks) + //if (num_blocks) Singu note: commented out; having blocks or not is totally irrelevant! { avatarp->processAnimationStateChanges(); } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b34291a5f..8562edb7a 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -231,7 +231,9 @@ void LLVOAvatar::startMotion(U32 bit, F32 time_offset) { if (!isMotionActive(bit)) { + mMotionController.disable_syncing(); // Don't attempt to synchronize AIMaskedMotion. startMotion(mask2ID(bit), time_offset); + mMotionController.enable_syncing(); } } @@ -3810,6 +3812,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) if (LLVOAvatar::sShowAnimationDebug) { + addDebugText(llformat("at=%.1f", mMotionController.getAnimTime())); for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin(); iter != mMotionController.getActiveMotions().end(); ++iter) { @@ -3829,6 +3832,10 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) motionp->getName().c_str(), (U32)motionp->getPriority()); } + if (motionp->server()) + { + output += llformat(" rt=%.1f r=%d s=0x%xl", motionp->getRuntime(), motionp->mReadyEvents, motionp->server()); + } addDebugText(output); } } @@ -5499,6 +5506,7 @@ void LLVOAvatar::processAnimationStateChanges() } // clear all current animations + BOOL const AOEnabled = gSavedSettings.getBOOL("AOEnabled"); // Singu note: put this outside the loop. AnimIterator anim_it; for (anim_it = mPlayingAnimations.begin(); anim_it != mPlayingAnimations.end();) { @@ -5508,9 +5516,9 @@ void LLVOAvatar::processAnimationStateChanges() if (found_anim == mSignaledAnimations.end()) { - if (isSelf()) + if (AOEnabled && isSelf()) { - if ((gSavedSettings.getBOOL("AOEnabled")) && LLFloaterAO::stopMotion(anim_it->first, FALSE)) // if the AO replaced this anim serverside then stop it serverside + if (LLFloaterAO::stopMotion(anim_it->first, FALSE)) // if the AO replaced this anim serverside then stop it serverside { // return TRUE; //no local stop needed } @@ -5540,7 +5548,7 @@ void LLVOAvatar::processAnimationStateChanges() // if (processSingleAnimationStateChange(anim_it->first, TRUE)) { - if (isSelf() && gSavedSettings.getBOOL("AOEnabled")) // AO is only for ME + if (AOEnabled && isSelf()) // AO is only for ME { LLFloaterAO::startMotion(anim_it->first, 0,FALSE); // AO overrides the anim if needed } From b4848f308ff35668309ce7d36a10e0b6dbfe1266 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 28 Dec 2013 00:00:30 +0100 Subject: [PATCH 101/115] Compile fix for Release --- indra/llcharacter/llmotion.cpp | 2 ++ indra/llcharacter/llmotioncontroller.cpp | 4 ++-- indra/newview/llvoavatar.cpp | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/indra/llcharacter/llmotion.cpp b/indra/llcharacter/llmotion.cpp index 94d12c7e4..efd1ad158 100644 --- a/indra/llcharacter/llmotion.cpp +++ b/indra/llcharacter/llmotion.cpp @@ -151,7 +151,9 @@ F32 LLMotion::syncActivationTime(F32 time) void AISyncClientMotion::deregistered(void) { +#ifdef SHOW_ASSERT mReadyEvents = 0; +#endif } // diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 8f8475576..7c7192be0 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -1197,7 +1197,7 @@ void LLMotionController::toggle_hidden(void) { LLMotion* motionp = *iter; AISyncServer* server = motionp->server(); - if (server && !server->never_synced() && (motionp->mReadyEvents & 2)) // Skip motions that aren't synchronized at all or that are not active. + if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active. { bool visible_before = server->events_with_at_least_one_client_ready() & 4; server->ready(4, visible, motionp); // Mark that now we are visible or no longer visible. @@ -1247,7 +1247,7 @@ void LLMotionController::refresh_hidden(void) { LLMotion* motionp = *iter; AISyncServer* server = motionp->server(); - if (server && !server->never_synced() && (motionp->mReadyEvents & 2)) // Skip motions that aren't synchronized at all or that are not active. + if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active. { bool visible_after = server->events_with_at_least_one_client_ready() & 4; if (visible_after) // Are there any synchronized motions (left) that ARE visible? diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 8562edb7a..901340a57 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -3834,7 +3834,11 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) } if (motionp->server()) { +#ifdef SHOW_ASSERT output += llformat(" rt=%.1f r=%d s=0x%xl", motionp->getRuntime(), motionp->mReadyEvents, motionp->server()); +#else + output += llformat(" rt=%.1f s=0x%xl", motionp->getRuntime(), motionp->server()); +#endif } addDebugText(output); } From 4d2517d163cf34c9b7b8fc387e45da2ea0848213 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 29 Dec 2013 21:49:05 +0100 Subject: [PATCH 102/115] Freeze also synchronized avatars when editing an attachment. On the removal of permYouOwner(): Calling permYouOwner() to determine if an attachment is yours is not correct: grid gods (and that includes BEFORE requesting admin status) are marked as owner of everything in their sim. The reason for that is that otherwise, if they only had it when actually godding u, the viewer would have to have an option to either show the proper menus (it doesn't) or allow the sim to refresh the object flags without full object updates (it hasn't). gods often have to act fast, for instance with griefers. Having transition to god mode take as long as a full rez just isn't an option, apart from the sim load caused by resending all objects. Then i tried resending only the object that was selected but there the arriving object update would close the pie menu. So you right-click a prim and the pie menu would close again. The result has always been that if you are on your own sim, in opensim, and select an attachment on another avatar, then YOU would freeze, not the selected avatar. This patch fixes that "opensim related" bug as well. --- indra/llcharacter/llcharacter.cpp | 14 +++++++++ indra/llcharacter/llcharacter.h | 2 ++ indra/llcharacter/llmotioncontroller.cpp | 38 ++++++++++++++++++++++++ indra/llcharacter/llmotioncontroller.h | 6 ++++ indra/newview/llselectmgr.cpp | 25 +++++----------- indra/newview/llselectmgr.h | 2 +- 6 files changed, 69 insertions(+), 18 deletions(-) diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 65d37f8e0..12960ac01 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -543,3 +543,17 @@ LLAnimPauseRequest LLCharacter::requestPause() return mPauseRequest; } +void LLCharacter::requestPause(std::vector& avatar_pause_handles) +{ + mMotionController.pauseAllMotions(); + avatar_pause_handles.push_back(mPauseRequest); +} + +void LLCharacter::pauseAllSyncedCharacters(std::vector& avatar_pause_handles) +{ + // Pause this avatar. + requestPause(avatar_pause_handles); + // Also pause all avatars with synchronized motions. + mMotionController.pauseAllSyncedCharacters(avatar_pause_handles); +} + diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index 74cc35187..f618b446f 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -159,6 +159,8 @@ public: void updateMotions(e_update_t update_type); LLAnimPauseRequest requestPause(); + void requestPause(std::vector& avatar_pause_handles); + void pauseAllSyncedCharacters(std::vector& avatar_pause_handles); BOOL areAnimationsPaused() const { return mMotionController.isPaused(); } void setAnimTimeFactor(F32 factor) { mMotionController.setTimeFactor(factor); } void setTimeStep(F32 time_step) { mMotionController.setTimeStep(time_step); } diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 7c7192be0..f5380957f 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -1257,6 +1257,44 @@ void LLMotionController::refresh_hidden(void) } } } + +void LLMotionController::pauseAllSyncedCharacters(std::vector& avatar_pause_handles) +{ + // Run over all motions. + for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter) + { + LLMotion* motionp = *iter; + AISyncServer* server = motionp->server(); + if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active. + { + // Run over all clients of the found servers. + AISyncServer::client_list_t const& clients = server->getClients(); + for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client) + { + LLMotion* motion = dynamic_cast(client->mClientPtr); + if (!motion) + { + continue; + } + LLMotionController* controller = motion->getController(); + if (controller == this) + { + continue; + } + controller->requestPause(avatar_pause_handles); + } + } + } +} + +void LLMotionController::requestPause(std::vector& avatar_pause_handles) +{ + if (mCharacter) + { + mCharacter->requestPause(avatar_pause_handles); + } +} + // //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index ac3d6d1f2..054f1c2f9 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -52,6 +52,8 @@ //----------------------------------------------------------------------------- class LLCharacter; class LLMotionController; +class LLPauseRequestHandle; +typedef LLPointer LLAnimPauseRequest; //----------------------------------------------------------------------------- // LLMotionRegistry @@ -160,6 +162,10 @@ public: void pauseAllMotions(); void unpauseAllMotions(); BOOL isPaused() const { return mPaused; } + // + void requestPause(std::vector& avatar_pause_handles); + void pauseAllSyncedCharacters(std::vector& avatar_pause_handles); + // void setTimeStep(F32 step); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 4881139df..976397931 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -6506,7 +6506,7 @@ void LLSelectMgr::updateSelectionCenter() mSelectionCenterGlobal.clearVec(); mShowSelection = FALSE; mSelectionBBox = LLBBox(); - mPauseRequest = NULL; + mPauseRequests.clear(); resetAgentHUDZoom(); } @@ -6516,27 +6516,18 @@ void LLSelectMgr::updateSelectionCenter() if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid()) { - // Singu Note: Chalice Yao's pause agent on attachment selection - if (object->permYouOwner()) + // Freeze avatars with a selected attachment, and all avatars with synchronized motions, if any. + LLVOAvatar* avatar = object->getAvatar(); + // It is possible that 'avatar' is NULL despite this being an attachment because of some race condition. + // In that case just don't freeze the avatar. + if (avatar) { - mPauseRequest = gAgentAvatarp->requestPause(); - } - else if (LLViewerObject* objectp = mSelectedObjects->getPrimaryObject()) - { - while (objectp && !objectp->isAvatar()) - { - objectp = (LLViewerObject*)objectp->getParent(); - } - - if (objectp) - { - mPauseRequest = objectp->asAvatar()->requestPause(); - } + avatar->pauseAllSyncedCharacters(mPauseRequests); } } else { - mPauseRequest = NULL; + mPauseRequests.clear(); } if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid()) diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 16c960ba8..145c25005 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -793,7 +793,7 @@ private: LLFrameTimer mEffectsTimer; BOOL mForceSelection; - LLAnimPauseRequest mPauseRequest; + std::vector mPauseRequests; // Selected avatar and all synchronized avatars. friend class LLObjectBackup; }; From 2fb945a4890caa6d1a2fd154b126fada42f7db8d Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 26 Jan 2014 20:59:01 +0100 Subject: [PATCH 103/115] Fix floating point round off error bug that caused mAnimTime to be decreased in value. Conflicts: indra/llcharacter/llmotioncontroller.cpp --- indra/llcharacter/llmotioncontroller.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index f5380957f..d12b3ddb6 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -874,8 +874,15 @@ void LLMotionController::updateMotions(bool force_update) { F32 time_interval = fmodf(update_time, mTimeStep); - // always animate *ahead* of actual time - S32 quantum_count = llmax(0, llfloor((update_time - time_interval) / mTimeStep)) + 1; + // + // This old code is nonsense. + //S32 quantum_count = llmax(0, llround((update_time - time_interval) / mTimeStep)) + 1; + // (update_time - time_interval) / mTimeStep is an integer! We need llround to get rid of floating point errors, not llfloor. + // Moreover, just rounding off to the nearest integer with llround(update_time / mTimeStep) makes a lot more sense: + // it is the best we can do to get as close to what we should draw as possible. + // However, mAnimTime may only be incremented; therefore make sure of that with the llmax. + S32 quantum_count = llmax(llround(update_time / mTimeStep), llceil(mAnimTime / mTimeStep)); + // if (quantum_count == mTimeStepCount) { // we're still in same time quantum as before, so just interpolate and exit @@ -901,7 +908,8 @@ void LLMotionController::updateMotions(bool force_update) } else { - mAnimTime = update_time; + // Singu note: mAnimTime may never be set back in time. + mAnimTime = llmax(mAnimTime, update_time); } } From a332a7fc3572406874c76cba32bc7ab671be14eb Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 4 Apr 2014 17:33:45 +0200 Subject: [PATCH 104/115] Compile fix for motions backport. --- indra/llcharacter/llkeyframemotion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index 952ae0ca7..4c54d5500 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -502,7 +502,7 @@ public: //------------------------------------------------------------------------- // JointMotionList //------------------------------------------------------------------------- - class JointMotionList + class JointMotionList : public LLRefCount { public: std::vector mJointMotionArray; From 7d124012c27b0cd900d72ddc96724f174d9ec8ba Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 4 Apr 2014 20:58:33 +0200 Subject: [PATCH 105/115] First attempt to fix windows compile errors. --- indra/llcommon/aisyncclient.cpp | 2 +- indra/llcommon/aisyncclient.h | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/indra/llcommon/aisyncclient.cpp b/indra/llcommon/aisyncclient.cpp index e1865fec8..c62d88efb 100644 --- a/indra/llcommon/aisyncclient.cpp +++ b/indra/llcommon/aisyncclient.cpp @@ -91,7 +91,7 @@ bool operator==(AISyncKey const& key1, AISyncKey const& key2) { // Test if these keys match based on time. if (std::abs((S32)(key1.mStartFrameCount - key2.mStartFrameCount)) > 1 && - std::abs(key1.mFrameTimer.getStartTime() - key2.mFrameTimer.getStartTime()) >= AISyncKey::sExpirationTime) + std::abs(key1.mFrameTimer.getStartTime() - key2.mFrameTimer.getStartTime()) >= sSyncKeyExpirationTime) { return false; } diff --git a/indra/llcommon/aisyncclient.h b/indra/llcommon/aisyncclient.h index b810f143a..5e7d66d16 100644 --- a/indra/llcommon/aisyncclient.h +++ b/indra/llcommon/aisyncclient.h @@ -108,12 +108,13 @@ enum synckeytype_t typedef U32 synceventset_t; // A mask where each bit represents a ready state. +static F32 const sSyncKeyExpirationTime = 0.25; // In seconds. + class LL_COMMON_API AISyncKey { private: LLFrameTimer mFrameTimer; // This timer is started at the moment the sync key is created. U32 mStartFrameCount; // The frame count at which the timer was started. - static F32 const sExpirationTime = 0.1; // In seconds. public: // Constructor. @@ -125,7 +126,7 @@ class LL_COMMON_API AISyncKey } else { - mFrameTimer.reset(sExpirationTime); + mFrameTimer.reset(sSyncKeyExpirationTime); } } @@ -135,14 +136,14 @@ class LL_COMMON_API AISyncKey // Return true if this key expired. bool expired(void) const { - // The key has expired when sExpirationTime seconds have elapsed AND at least two frames have passed. + // The key has expired when sSyncKeyExpirationTime seconds have elapsed AND at least two frames have passed. return mFrameTimer.getFrameCount() > mStartFrameCount + 1 && mFrameTimer.hasExpired(); } // Returns true if this object and key would not compare equal based on time because this object is too old. bool is_older_than(AISyncKey const& key) const { - return key.mStartFrameCount > mStartFrameCount + 1 && key.mFrameTimer.getStartTime() > mFrameTimer.getStartTime() + sExpirationTime; + return key.mStartFrameCount > mStartFrameCount + 1 && key.mFrameTimer.getStartTime() > mFrameTimer.getStartTime() + sSyncKeyExpirationTime; } // Return the creation time of this key (in number of seconds since application start). @@ -228,8 +229,8 @@ class LL_COMMON_API AISyncServer #endif private: - friend void intrusive_ptr_add_ref(AISyncServer* server); - friend void intrusive_ptr_release(AISyncServer* server); + friend LL_COMMON_API void intrusive_ptr_add_ref(AISyncServer* server); + friend LL_COMMON_API void intrusive_ptr_release(AISyncServer* server); }; class LL_COMMON_API AISyncServerMap : public LLSingleton From 994f40929101da33e3d7b5de96dc8c9247c281b9 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 4 Apr 2014 21:06:30 +0200 Subject: [PATCH 106/115] Attempt 2 --- indra/llcommon/aisyncclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcommon/aisyncclient.h b/indra/llcommon/aisyncclient.h index 5e7d66d16..0f5237f99 100644 --- a/indra/llcommon/aisyncclient.h +++ b/indra/llcommon/aisyncclient.h @@ -248,7 +248,7 @@ class LL_COMMON_API AISyncServerMap : public LLSingleton void register_client(AISyncClient* client, AISyncKey* new_key); private: - friend void intrusive_ptr_release(AISyncServer* server); + friend LL_COMMON_API void intrusive_ptr_release(AISyncServer* server); // Remove a server from the map, only called by intrusive_ptr_release when there is one pointer left; // therefore, the server should not have any clients. void remove_server(AISyncServer* server); From e61cabf1ce2116faa4b8dcc678cca4a8fbd2e723 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 4 Apr 2014 21:13:57 +0200 Subject: [PATCH 107/115] Remove compiler warning. --- indra/llcharacter/llmotion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcharacter/llmotion.cpp b/indra/llcharacter/llmotion.cpp index efd1ad158..526341d20 100644 --- a/indra/llcharacter/llmotion.cpp +++ b/indra/llcharacter/llmotion.cpp @@ -72,7 +72,7 @@ void AISyncClientMotion::aisync_loaded(void) AISyncKey const& key = server->key(); // The allocation of this is owned by server. // There is no need to resync if there was not another motion started at the same time and the key already expired. bool need_resync = !(server->never_synced() && key.expired()); - AISyncKey* new_key; + AISyncKey* new_key = NULL; if (need_resync) { // Create a new key using the old start time. From 2c7459e08dfd524529661159fb5af876181a6d7c Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Fri, 4 Apr 2014 21:29:17 +0200 Subject: [PATCH 108/115] Supress bool/BOOL comparison warning --- indra/newview/lldrawpoolalpha.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 3d88b34ca..b27bb9a14 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -446,7 +446,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) llassert_always(!LLGLSLShader::sCurBoundShaderPtr); bool fullbright = depth_only || params.mFullbright; - if(fullbright == light_enabled || !initialized_lighting) + if(fullbright == !!light_enabled || !initialized_lighting) { light_enabled = !fullbright; initialized_lighting = true; From 094d284e62d8949b77b7639e12576e00971eebe7 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Fri, 4 Apr 2014 17:28:19 -0400 Subject: [PATCH 109/115] Missed a git mv, mac should build after this. --- .../{singularity.icns => singularity_icon.icns} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename indra/newview/{singularity.icns => singularity_icon.icns} (100%) diff --git a/indra/newview/singularity.icns b/indra/newview/singularity_icon.icns similarity index 100% rename from indra/newview/singularity.icns rename to indra/newview/singularity_icon.icns From 3642e401da6f4d7388ac0320989135a76fef7e4e Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Fri, 4 Apr 2014 19:57:32 -0400 Subject: [PATCH 110/115] Fix About and Toolbar prefs buttons being mushed together, thanks for the heads-up Friti! --- .../skins/default/xui/en-us/panel_toolbar.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/indra/newview/skins/default/xui/en-us/panel_toolbar.xml b/indra/newview/skins/default/xui/en-us/panel_toolbar.xml index 667b1703f..534b86529 100644 --- a/indra/newview/skins/default/xui/en-us/panel_toolbar.xml +++ b/indra/newview/skins/default/xui/en-us/panel_toolbar.xml @@ -446,15 +446,15 @@ - - - - + + + + From ef01d2af82a6268b2474c59cb91961a6f3574699 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Mon, 7 Apr 2014 16:06:33 -0400 Subject: [PATCH 111/115] Fix "zombie" lie and tabs/spaces inconsistency in xml. --- .../skins/default/xui/en-us/panel_preferences_ascent_system.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_system.xml b/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_system.xml index 72a5362fc..a3a85a6d4 100644 --- a/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_system.xml +++ b/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_system.xml @@ -85,7 +85,7 @@ - + From ab0dde7fe82650192dc0d11fca725b0103cb2a54 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Tue, 8 Apr 2014 00:36:44 -0400 Subject: [PATCH 112/115] [Floater Flexibility] Part three and a half: Toolbar code cleanup, toolbar in mouselook option Go into Preferences->Input and Camera, to find the new option~ Thanks to Cinder for checking that the mac changes build and look nice. --- indra/newview/app_settings/settings.xml | 11 ++ indra/newview/lltoolbar.cpp | 151 +++++++----------- indra/newview/lltoolbar.h | 13 -- .../xui/en-us/panel_preferences_input.xml | 1 + 4 files changed, 67 insertions(+), 109 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index db797127e..360d0c8f0 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -834,6 +834,17 @@ Value 0 + LiruMouselookHidesToolbar + + Comment + Whether or not the toolbar will be hidden in mouselook + Persist + 1 + Type + Boolean + Value + 1 + LiruMouselookMenu Comment diff --git a/indra/newview/lltoolbar.cpp b/indra/newview/lltoolbar.cpp index f924b93c2..5612088d8 100644 --- a/indra/newview/lltoolbar.cpp +++ b/indra/newview/lltoolbar.cpp @@ -58,24 +58,30 @@ #if LL_DARWIN - #include "llresizehandle.h" - #include "llviewerwindow.h" +#include "llresizehandle.h" +#include "llviewerwindow.h" - // This class draws like an LLResizeHandle but has no interactivity. - // It's just there to provide a cue to the user that the lower right corner of the window functions as a resize handle. - class LLFakeResizeHandle : public LLResizeHandle +// This class draws like an LLResizeHandle but has no interactivity. +// It's just there to provide a cue to the user that the lower right corner of the window functions as a resize handle. +class LLFakeResizeHandle : public LLResizeHandle +{ +public: + LLFakeResizeHandle(const LLResizeHandle::Params& p) : LLResizeHandle(p) {} + + virtual BOOL handleHover(S32 x, S32 y, MASK mask) { return false; } + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return false; } + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) { return false; } + virtual void reshape(S32 width, S32 height, BOOL called_from_parent) { - public: - LLFakeResizeHandle(const LLResizeHandle::Params& p) - : LLResizeHandle(p) - { - } + // Only when running in windowed mode on the Mac, leave room for a resize widget on the right edge of the bar. + if (gViewerWindow->getWindow()->getFullscreen()) + return setVisible(false); - virtual BOOL handleHover(S32 x, S32 y, MASK mask) { return FALSE; }; - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) { return FALSE; }; - - }; + setVisible(true); + const F32 wide(gViewerWindow->getWindowWidth() + 2); + setRect(LLRect(wide - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, wide, 0)); + } +}; #endif // LL_DARWIN @@ -98,9 +104,6 @@ void show_floater(const std::string& floater_name); LLToolBar::LLToolBar() : LLLayoutPanel() -#if LL_DARWIN - , mResizeHandle(NULL) -#endif // LL_DARWIN { setIsChrome(TRUE); setFocusRoot(TRUE); @@ -130,22 +133,16 @@ BOOL LLToolBar::postBuild() } #if LL_DARWIN - if(mResizeHandle == NULL) - { - LLResizeHandle::Params p; - p.rect(LLRect(0, 0, RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT)); - p.name(std::string("")); - p.min_width(RESIZE_HANDLE_WIDTH); - p.min_height(RESIZE_HANDLE_HEIGHT); - p.corner(LLResizeHandle::RIGHT_BOTTOM); - mResizeHandle = new LLFakeResizeHandle(p); this->addChildInBack(mResizeHandle); - LLLayoutStack* toolbar_stack = getChild("toolbar_stack"); - toolbar_stack->reshape(toolbar_stack->getRect().getWidth() - RESIZE_HANDLE_WIDTH, toolbar_stack->getRect().getHeight()); - } + LLResizeHandle::Params p; + p.rect(LLRect(0, 0, RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT)); + p.name(std::string("")); + p.min_width(RESIZE_HANDLE_WIDTH); + p.min_height(RESIZE_HANDLE_HEIGHT); + p.corner(LLResizeHandle::RIGHT_BOTTOM); + addChildInBack(new LLFakeResizeHandle(p)); + reshape(getRect().getWidth(), getRect().getHeight()); #endif // LL_DARWIN - layoutButtons(); - return TRUE; } @@ -161,18 +158,18 @@ BOOL LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EAcceptance* accept, std::string& tooltip_msg) { - LLButton* inventory_btn = getChild("inventory_btn"); + LLButton* inventory_btn = mInventoryBtn; if (!inventory_btn || !inventory_btn->getVisible()) return FALSE; LLInventoryView* active_inventory = LLInventoryView::getActiveInventory(); if (active_inventory && active_inventory->getVisible()) { - mInventoryAutoOpen = FALSE; + mInventoryAutoOpenTimer.stop(); } else if (inventory_btn->getRect().pointInRect(x, y)) { - if (mInventoryAutoOpen) + if (mInventoryAutoOpenTimer.getStarted()) { if (!(active_inventory && active_inventory->getVisible()) && mInventoryAutoOpenTimer.getElapsedTimeF32() > sInventoryAutoOpenTime) @@ -182,71 +179,35 @@ BOOL LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, } else { - mInventoryAutoOpen = TRUE; - mInventoryAutoOpenTimer.reset(); + mInventoryAutoOpenTimer.start(); } } return LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); } -void LLToolBar::layoutButtons() -{ -#if LL_DARWIN - const S32 FUDGE_WIDTH_OF_SCREEN = 4; - S32 width = gViewerWindow->getWindowWidth() + FUDGE_WIDTH_OF_SCREEN; - S32 pad = 2; - - // this function may be called before postBuild(), in which case mResizeHandle won't have been set up yet. - if(mResizeHandle != NULL) - { - if(!gViewerWindow->getWindow()->getFullscreen()) - { - // Only when running in windowed mode on the Mac, leave room for a resize widget on the right edge of the bar. - width -= RESIZE_HANDLE_WIDTH; - - LLRect r; - r.mLeft = width - pad; - r.mBottom = 0; - r.mRight = r.mLeft + RESIZE_HANDLE_WIDTH; - r.mTop = r.mBottom + RESIZE_HANDLE_HEIGHT; - mResizeHandle->setRect(r); - mResizeHandle->setVisible(TRUE); - } - else - { - mResizeHandle->setVisible(FALSE); - } - } -#endif // LL_DARWIN -} - - -// virtual -void LLToolBar::reshape(S32 width, S32 height, BOOL called_from_parent) -{ - LLPanel::reshape(width, height, called_from_parent); - - layoutButtons(); -} - // Per-frame updates of visibility void LLToolBar::refresh() { - if(!isAgentAvatarValid()) - return; + static const LLCachedControl show_toolbar("ShowToolBar", true); + bool show = show_toolbar; + if (show && gAgentCamera.cameraMouselook()) + { + static const LLCachedControl hidden("LiruMouselookHidesToolbar"); + show = !hidden; + } + setVisible(show); + if (!show) return; // Everything below this point manipulates visible UI, anyway - static LLCachedControl show("ShowToolBar", true); - BOOL mouselook = gAgentCamera.cameraMouselook(); - setVisible(show && !mouselook); + updateCommunicateList(); - static LLCachedControl continue_flying_on_unsit("LiruContinueFlyingOnUnsit"); - bool sitting = !continue_flying_on_unsit && gAgentAvatarp && gAgentAvatarp->isSitting(); + if (!isAgentAvatarValid()) return; - mFlyBtn->setEnabled((gAgent.canFly() || gAgent.getFlying()) && !sitting ); - static LLCachedControl ascent_build_always_enabled("AscentBuildAlwaysEnabled", true); - mBuildBtn->setEnabled((LLViewerParcelMgr::getInstance()->allowAgentBuild() || ascent_build_always_enabled)); + static const LLCachedControl continue_flying_on_unsit("LiruContinueFlyingOnUnsit"); + mFlyBtn->setEnabled((gAgent.canFly() || gAgent.getFlying()) && (continue_flying_on_unsit || !gAgentAvatarp->isSitting())); + static const LLCachedControl ascent_build_always_enabled("AscentBuildAlwaysEnabled", true); + mBuildBtn->setEnabled(ascent_build_always_enabled || LLViewerParcelMgr::getInstance()->allowAgentBuild()); // Check to see if we're in build mode // And not just clicking on a scripted object @@ -268,11 +229,6 @@ void LLToolBar::refresh() mInventoryBtn->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWINV)); } // [/RLVa:KB] - - if (isInVisibleChain() && mCommunicateBtn->getVisible()) - { - updateCommunicateList(); - } } void bold_if_equal(const LLFloater* f1, const LLFloater* f2, LLScrollListItem* itemp) @@ -283,11 +239,13 @@ void bold_if_equal(const LLFloater* f1, const LLFloater* f2, LLScrollListItem* i void LLToolBar::updateCommunicateList() { + if (!mCommunicateBtn->getVisible()) return; + LLSD selected = mCommunicateBtn->getValue(); mCommunicateBtn->removeall(); - LLFloater* frontmost_floater = LLFloaterChatterBox::getInstance()->getActiveFloater(); + const LLFloater* frontmost_floater = LLFloaterChatterBox::getInstance()->getActiveFloater(); bold_if_equal(LLFloaterMyFriends::getInstance(), frontmost_floater, mCommunicateBtn->add(LLFloaterMyFriends::getInstance()->getShortTitle(), LLSD("contacts"), ADD_TOP)); bold_if_equal(LLFloaterChat::getInstance(), frontmost_floater, mCommunicateBtn->add(LLFloaterChat::getInstance()->getShortTitle(), LLSD("local chat"), ADD_TOP)); mCommunicateBtn->addSeparator(ADD_TOP); @@ -300,11 +258,11 @@ void LLToolBar::updateCommunicateList() { if (LLFloaterIMPanel* im_floaterp = (LLFloaterIMPanel*)floater_handle_it->get()) { - S32 count = im_floaterp->getNumUnreadMessages(); + const S32 count = im_floaterp->getNumUnreadMessages(); std::string floater_title; if (count > 0) floater_title = "*"; floater_title.append(im_floaterp->getShortTitle()); - static LLCachedControl show_counts("ShowUnreadIMsCounts", true); + static const LLCachedControl show_counts("ShowUnreadIMsCounts", true); if (show_counts && count > 0) { floater_title += " - "; @@ -323,7 +281,8 @@ void LLToolBar::updateCommunicateList() } } - mCommunicateBtn->setToggleState(gSavedSettings.getBOOL("ShowCommunicate")); + static const LLCachedControl show_comm("ShowCommunicate", true); + mCommunicateBtn->setToggleState(show_comm); if (!selected.isUndefined()) mCommunicateBtn->setValue(selected); } diff --git a/indra/newview/lltoolbar.h b/indra/newview/lltoolbar.h index 23307a78b..958c0b4bc 100644 --- a/indra/newview/lltoolbar.h +++ b/indra/newview/lltoolbar.h @@ -41,10 +41,6 @@ // "Constants" loaded from settings.xml at start time extern S32 TOOL_BAR_HEIGHT; -#if LL_DARWIN - class LLFakeResizeHandle; -#endif // LL_DARWIN - class LLFlyoutButton; class LLToolBar @@ -62,11 +58,6 @@ public: EAcceptance* accept, std::string& tooltip_msg); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - - // Move buttons to appropriate locations based on rect. - void layoutButtons(); - // Per-frame refresh call void refresh(); @@ -79,12 +70,8 @@ private: void updateCommunicateList(); private: - BOOL mInventoryAutoOpen; LLFrameTimer mInventoryAutoOpenTimer; S32 mNumUnreadIMs; -#if LL_DARWIN - LLFakeResizeHandle *mResizeHandle; -#endif // LL_DARWIN CachedUICtrl mCommunicateBtn; CachedUICtrl mFlyBtn; diff --git a/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml b/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml index aadd1526c..0baf30023 100644 --- a/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml +++ b/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml @@ -9,6 +9,7 @@ + Movement Options: From 0b2d019e612a5162d4d699a897ad57396d0e8f5e Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Tue, 8 Apr 2014 01:07:19 -0400 Subject: [PATCH 113/115] Latif's requested touch-ups for IM windows in concise mode. Profile option for concise flyout. Fix for ding in multi-user chats breaking button alignment. --- indra/newview/llimpanel.cpp | 2 +- .../en-us/floater_instant_message_ad_hoc_concisebuttons.xml | 6 +++--- .../xui/en-us/floater_instant_message_concisebuttons.xml | 1 + .../en-us/floater_instant_message_group_concisebuttons.xml | 6 +++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index aaf79dbfc..76e81a87b 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -969,7 +969,7 @@ void copy_profile_uri(const LLUUID& id, bool group = false); void LLFloaterIMPanel::onFlyoutCommit(LLComboBox* flyout, const LLSD& value) { - if (value.isUndefined()) + if (value.isUndefined() || value == LLSD(0)) { LLAvatarActions::showProfile(mOtherParticipantUUID); return; diff --git a/indra/newview/skins/default/xui/en-us/floater_instant_message_ad_hoc_concisebuttons.xml b/indra/newview/skins/default/xui/en-us/floater_instant_message_ad_hoc_concisebuttons.xml index 57188eac1..88bb69bcb 100644 --- a/indra/newview/skins/default/xui/en-us/floater_instant_message_ad_hoc_concisebuttons.xml +++ b/indra/newview/skins/default/xui/en-us/floater_instant_message_ad_hoc_concisebuttons.xml @@ -1,5 +1,5 @@ - + Joining Voice Chat... Connected, click End Call to hang up Left Voice Chat @@ -8,8 +8,8 @@ [NAME] is typing... Starting session with [NAME], please wait. Click here to instant message. - + + +