From af5c7a7a674618f16d20f69ccf980c9c2476d63c Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Tue, 21 Aug 2018 16:35:47 -0300 Subject: [PATCH 01/16] Android - Domains List - cache in memory only on this instance (deleted if app restarts) allows for fast list display. Showing again also asks for update so in some seconds the list gets updated in case of changes --- .../hifiinterface/fragment/HomeFragment.java | 25 ++++++++---- .../hifiinterface/view/DomainAdapter.java | 38 +++++++++++++++---- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/HomeFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/HomeFragment.java index 7bd373cf1d..86b8625cfe 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/HomeFragment.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/HomeFragment.java @@ -76,18 +76,22 @@ public class HomeFragment extends Fragment { }); mDomainAdapter.setListener(new DomainAdapter.AdapterListener() { @Override - public void onEmptyAdapter() { + public void onEmptyAdapter(boolean shouldStopRefreshing) { searchNoResultsView.setText(R.string.search_no_results); searchNoResultsView.setVisibility(View.VISIBLE); mDomainsView.setVisibility(View.GONE); - mSwipeRefreshLayout.setRefreshing(false); + if (shouldStopRefreshing) { + mSwipeRefreshLayout.setRefreshing(false); + } } @Override - public void onNonEmptyAdapter() { + public void onNonEmptyAdapter(boolean shouldStopRefreshing) { searchNoResultsView.setVisibility(View.GONE); mDomainsView.setVisibility(View.VISIBLE); - mSwipeRefreshLayout.setRefreshing(false); + if (shouldStopRefreshing) { + mSwipeRefreshLayout.setRefreshing(false); + } } @Override @@ -96,11 +100,20 @@ public class HomeFragment extends Fragment { } }); mDomainsView.setAdapter(mDomainAdapter); + mDomainAdapter.startLoad(); mSearchView = rootView.findViewById(R.id.searchView); mSearchIconView = rootView.findViewById(R.id.search_mag_icon); mClearSearch = rootView.findViewById(R.id.search_clear); + getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); + + return rootView; + } + + @Override + public void onStart() { + super.onStart(); mSearchView.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} @@ -142,10 +155,6 @@ public class HomeFragment extends Fragment { mDomainAdapter.loadDomains(mSearchView.getText().toString(), true); } }); - - getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); - - return rootView; } @Override diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java b/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java index 71d634e9ea..6860742a0d 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java @@ -12,6 +12,7 @@ import android.widget.TextView; import com.squareup.picasso.Picasso; +import java.util.Arrays; import java.util.List; import io.highfidelity.hifiinterface.R; @@ -36,19 +37,39 @@ public class DomainAdapter extends RecyclerView.Adapter 0) { + mDomains = Arrays.copyOf(DOMAINS_TMP_CACHE, DOMAINS_TMP_CACHE.length); + notifyDataSetChanged(); + if (mAdapterListener != null) { + if (mDomains.length == 0) { + mAdapterListener.onEmptyAdapter(false); + } else { + mAdapterListener.onNonEmptyAdapter(false); + } + } + } + } + public void loadDomains(String filterText, boolean forceRefresh) { domainProvider.retrieve(filterText, new DomainProvider.DomainCallback() { @Override @@ -60,13 +81,16 @@ public class DomainAdapter extends RecyclerView.Adapter Date: Tue, 21 Aug 2018 17:47:40 -0300 Subject: [PATCH 02/16] Android - People List - cache in memory only on this instance (deleted if app restarts) allows for fast list display. Showing again also asks for update so in some ms the list gets updated in case of changes --- .../fragment/FriendsFragment.java | 14 +++++--- .../hifiinterface/view/UserListAdapter.java | 35 ++++++++++++++++--- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java index 2a008d7950..2475c4d887 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java @@ -98,13 +98,17 @@ public class FriendsFragment extends Fragment { mUsersAdapter.setListener(new UserListAdapter.AdapterListener() { @Override - public void onEmptyAdapter() { - mSwipeRefreshLayout.setRefreshing(false); + public void onEmptyAdapter(boolean shouldStopRefreshing) { + if (shouldStopRefreshing) { + mSwipeRefreshLayout.setRefreshing(false); + } } @Override - public void onNonEmptyAdapter() { - mSwipeRefreshLayout.setRefreshing(false); + public void onNonEmptyAdapter(boolean shouldStopRefreshing) { + if (shouldStopRefreshing) { + mSwipeRefreshLayout.setRefreshing(false); + } } @Override @@ -115,6 +119,8 @@ public class FriendsFragment extends Fragment { mUsersView.setAdapter(mUsersAdapter); + mUsersAdapter.startLoad(); + mSlidingUpPanelLayout.setFadeOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/view/UserListAdapter.java b/android/app/src/main/java/io/highfidelity/hifiinterface/view/UserListAdapter.java index 9f62b21250..a34de5b34e 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/view/UserListAdapter.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/view/UserListAdapter.java @@ -37,28 +37,53 @@ public class UserListAdapter extends RecyclerView.Adapter USERS_TMP_CACHE; + public UserListAdapter(Context c, UsersProvider usersProvider) { mContext = c; mInflater = LayoutInflater.from(mContext); mProvider = usersProvider; - loadUsers(); } public void setListener(AdapterListener adapterListener) { mAdapterListener = adapterListener; } + public void startLoad() { + useTmpCachedUsers(); + loadUsers(); + } + + private void useTmpCachedUsers() { + if (USERS_TMP_CACHE != null && USERS_TMP_CACHE.size() > 0) { + mUsers = new ArrayList<>(USERS_TMP_CACHE.size()); + mUsers.addAll(USERS_TMP_CACHE); + notifyDataSetChanged(); + if (mAdapterListener != null) { + if (mUsers.isEmpty()) { + mAdapterListener.onEmptyAdapter(false); + } else { + mAdapterListener.onNonEmptyAdapter(false); + } + } + } + } + public void loadUsers() { mProvider.retrieve(new UsersProvider.UsersCallback() { @Override public void retrieveOk(List users) { mUsers = new ArrayList<>(users); notifyDataSetChanged(); + + USERS_TMP_CACHE = new ArrayList<>(mUsers.size()); + USERS_TMP_CACHE.addAll(mUsers); + if (mAdapterListener != null) { if (mUsers.isEmpty()) { - mAdapterListener.onEmptyAdapter(); + mAdapterListener.onEmptyAdapter(true); } else { - mAdapterListener.onNonEmptyAdapter(); + mAdapterListener.onNonEmptyAdapter(true); } } } @@ -240,8 +265,8 @@ public class UserListAdapter extends RecyclerView.Adapter Date: Tue, 21 Aug 2018 18:40:10 -0300 Subject: [PATCH 03/16] Android - People and Domain list - synchronize cache and request code --- .../hifiinterface/view/DomainAdapter.java | 40 ++++++++++--------- .../hifiinterface/view/UserListAdapter.java | 37 +++++++++-------- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java b/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java index 6860742a0d..78251ac4a4 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java @@ -57,14 +57,16 @@ public class DomainAdapter extends RecyclerView.Adapter 0) { - mDomains = Arrays.copyOf(DOMAINS_TMP_CACHE, DOMAINS_TMP_CACHE.length); - notifyDataSetChanged(); - if (mAdapterListener != null) { - if (mDomains.length == 0) { - mAdapterListener.onEmptyAdapter(false); - } else { - mAdapterListener.onNonEmptyAdapter(false); + synchronized (this) { + if (DOMAINS_TMP_CACHE != null && DOMAINS_TMP_CACHE.length > 0) { + mDomains = Arrays.copyOf(DOMAINS_TMP_CACHE, DOMAINS_TMP_CACHE.length); + notifyDataSetChanged(); + if (mAdapterListener != null) { + if (mDomains.length == 0) { + mAdapterListener.onEmptyAdapter(false); + } else { + mAdapterListener.onNonEmptyAdapter(false); + } } } } @@ -81,16 +83,18 @@ public class DomainAdapter extends RecyclerView.Adapter 0) { - mUsers = new ArrayList<>(USERS_TMP_CACHE.size()); - mUsers.addAll(USERS_TMP_CACHE); - notifyDataSetChanged(); - if (mAdapterListener != null) { - if (mUsers.isEmpty()) { - mAdapterListener.onEmptyAdapter(false); - } else { - mAdapterListener.onNonEmptyAdapter(false); + synchronized (this) { + if (USERS_TMP_CACHE != null && USERS_TMP_CACHE.size() > 0) { + mUsers = new ArrayList<>(USERS_TMP_CACHE.size()); + mUsers.addAll(USERS_TMP_CACHE); + notifyDataSetChanged(); + if (mAdapterListener != null) { + if (mUsers.isEmpty()) { + mAdapterListener.onEmptyAdapter(false); + } else { + mAdapterListener.onNonEmptyAdapter(false); + } } } } @@ -76,14 +78,16 @@ public class UserListAdapter extends RecyclerView.Adapter(users); notifyDataSetChanged(); - USERS_TMP_CACHE = new ArrayList<>(mUsers.size()); - USERS_TMP_CACHE.addAll(mUsers); + synchronized (this) { + USERS_TMP_CACHE = new ArrayList<>(mUsers.size()); + USERS_TMP_CACHE.addAll(mUsers); - if (mAdapterListener != null) { - if (mUsers.isEmpty()) { - mAdapterListener.onEmptyAdapter(true); - } else { - mAdapterListener.onNonEmptyAdapter(true); + if (mAdapterListener != null) { + if (mUsers.isEmpty()) { + mAdapterListener.onEmptyAdapter(true); + } else { + mAdapterListener.onNonEmptyAdapter(true); + } } } } @@ -269,4 +273,5 @@ public class UserListAdapter extends RecyclerView.Adapter Date: Thu, 23 Aug 2018 06:49:35 -0700 Subject: [PATCH 04/16] first approach vertical alignment --- libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/AvatarData.h | 4 ++ libraries/avatars/src/AvatarHashMap.cpp | 72 +++++++++++++++++++++++-- libraries/avatars/src/AvatarHashMap.h | 2 + 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index c1ec19b307..63a905aa6e 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -918,7 +918,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { PACKET_READ_CHECK(AvatarGlobalPosition, sizeof(AvatarDataPacket::AvatarGlobalPosition)); auto data = reinterpret_cast(sourceBuffer); - auto newValue = glm::vec3(data->globalPosition[0], data->globalPosition[1], data->globalPosition[2]); + auto newValue = glm::vec3(data->globalPosition[0], data->globalPosition[1], data->globalPosition[2]) + glm::vec3(0, 2 * _surrogateIndex, 0); if (_globalPosition != newValue) { _globalPosition = newValue; _globalPositionChanged = usecTimestampNow(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 53a2a69119..b3443dbd8a 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -1186,6 +1186,9 @@ public: virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {} virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {} + void setSurrogateIndex(int surrogateIndex) { _surrogateIndex = surrogateIndex; } + int getSurrogateIndex() { return _surrogateIndex; } + signals: /**jsdoc @@ -1443,6 +1446,7 @@ protected: udt::SequenceNumber _identitySequenceNumber { 0 }; bool _hasProcessedFirstIdentity { false }; float _density; + int _surrogateIndex{ 0 }; // null unless MyAvatar or ScriptableAvatar sending traits data to mixer std::unique_ptr _clientTraitsHandler; diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 64b26131be..a84d83e663 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -21,6 +21,8 @@ #include "AvatarLogging.h" #include "AvatarTraits.h" +const int SURROGATE_COUNT = 2; + AvatarHashMap::AvatarHashMap() { auto nodeList = DependencyManager::get(); @@ -139,14 +141,37 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointerisIgnoringNode(sessionUUID) || nodeList->getRequestsDomainListData())) { auto avatar = newOrExistingAvatar(sessionUUID, sendingNode, isNewAvatar); + + if (isNewAvatar) { QWriteLocker locker(&_hashLock); _pendingAvatars.insert(sessionUUID, { std::chrono::steady_clock::now(), 0, avatar }); + std::vector surrogateIDs; + for (int i = 0; i < SURROGATE_COUNT; i++) { + QUuid surrogateID = QUuid::createUuid(); + surrogateIDs.push_back(surrogateID); + auto surrogateAvatar = addAvatar(surrogateID, sendingNode); + surrogateAvatar->setSurrogateIndex(i + 1); + surrogateAvatar->parseDataFromBuffer(byteArray); + _pendingAvatars.insert(surrogateID, { std::chrono::steady_clock::now(), 0, surrogateAvatar }); + } + _surrogates.insert(std::pair>(sessionUUID, surrogateIDs)); + } else { + auto surrogateIDs = _surrogates[sessionUUID]; + for (auto id : surrogateIDs) { + auto surrogateAvatar = newOrExistingAvatar(id, sendingNode, isNewAvatar); + if (!isNewAvatar) { + surrogateAvatar->parseDataFromBuffer(byteArray); + } + } + } // have the matching (or new) avatar parse the data from the packet int bytesRead = avatar->parseDataFromBuffer(byteArray); message->seek(positionBeforeRead + bytesRead); + + avatar->parseDataFromBuffer(byteArray); return avatar; } else { // create a dummy AvatarData class to throw this data on the ground @@ -191,13 +216,22 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer bool displayNameChanged = false; // In this case, the "sendingNode" is the Avatar Mixer. avatar->processAvatarIdentity(message->getMessage(), identityChanged, displayNameChanged); + auto surrogateIDs = _surrogates[identityUUID]; + for (auto id : surrogateIDs) { + auto surrogateAvatar = newOrExistingAvatar(id, sendingNode, isNewAvatar); + if (!isNewAvatar) { + surrogateAvatar->processAvatarIdentity(message->getMessage(), identityChanged, displayNameChanged); + } + } } } -void AvatarHashMap::processBulkAvatarTraits(QSharedPointer message, SharedNodePointer sendingNode) { +void AvatarHashMap::processAvatarTraits(QUuid sessionUUID, QSharedPointer message, SharedNodePointer sendingNode) { + message->seek(0); while (message->getBytesLeftToRead()) { // read the avatar ID to figure out which avatar this is for auto avatarID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + avatarID = sessionUUID; // grab the avatar so we can ask it to process trait data bool isNewAvatar; @@ -225,10 +259,12 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess if (packetTraitVersion > lastProcessedVersions[traitType]) { avatar->processTrait(traitType, message->read(traitBinarySize)); lastProcessedVersions[traitType] = packetTraitVersion; - } else { + } + else { skipBinaryTrait = true; } - } else { + } + else { AvatarTraits::TraitInstanceID traitInstanceID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); @@ -238,11 +274,13 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess if (packetTraitVersion > processedInstanceVersion) { if (traitBinarySize == AvatarTraits::DELETED_TRAIT_SIZE) { avatar->processDeletedTraitInstance(traitType, traitInstanceID); - } else { + } + else { avatar->processTraitInstance(traitType, traitInstanceID, message->read(traitBinarySize)); } processedInstanceVersion = packetTraitVersion; - } else { + } + else { skipBinaryTrait = true; } } @@ -258,6 +296,18 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess } } +void AvatarHashMap::processBulkAvatarTraits(QSharedPointer message, SharedNodePointer sendingNode) { + while (message->getBytesLeftToRead()) { + // read the avatar ID to figure out which avatar this is for + auto avatarID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + processAvatarTraits(avatarID, message, sendingNode); + auto surrogateIDs = _surrogates[avatarID]; + for (auto id : surrogateIDs) { + processAvatarTraits(id, message, sendingNode); + } + } +} + void AvatarHashMap::processKillAvatar(QSharedPointer message, SharedNodePointer sendingNode) { // read the node id QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); @@ -265,6 +315,10 @@ void AvatarHashMap::processKillAvatar(QSharedPointer message, S KillAvatarReason reason; message->readPrimitive(&reason); removeAvatar(sessionUUID, reason); + auto surrogateIDs = _surrogates[sessionUUID]; + for (auto id : surrogateIDs) { + removeAvatar(id, reason); + } } void AvatarHashMap::removeAvatar(const QUuid& sessionUUID, KillAvatarReason removalReason) { @@ -276,6 +330,14 @@ void AvatarHashMap::removeAvatar(const QUuid& sessionUUID, KillAvatarReason remo if (removedAvatar) { handleRemovedAvatar(removedAvatar, removalReason); } + auto surrogateIDs = _surrogates[sessionUUID]; + for (auto id : surrogateIDs) { + _pendingAvatars.remove(id); + auto removedSurrogate = _avatarHash.take(id); + if (removedSurrogate) { + handleRemovedAvatar(removedSurrogate, removalReason); + } + } } void AvatarHashMap::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index ba16fa9568..41981df693 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -134,6 +134,7 @@ protected slots: */ void processAvatarIdentityPacket(QSharedPointer message, SharedNodePointer sendingNode); + void processAvatarTraits(QUuid sessionUUID, QSharedPointer message, SharedNodePointer sendingNode); void processBulkAvatarTraits(QSharedPointer message, SharedNodePointer sendingNode); /**jsdoc @@ -167,6 +168,7 @@ protected: mutable QReadWriteLock _hashLock; std::unordered_map _processedTraitVersions; + std::map> _surrogates; private: QUuid _lastOwnerSessionUUID; }; From 3d959ca7ee6c59496f30dc15f6da02f666376166 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 23 Aug 2018 15:52:42 -0700 Subject: [PATCH 05/16] Refactoring and cleaning --- .../src/avatars-renderer/Avatar.h | 1 - libraries/avatars/src/AvatarData.cpp | 21 +- libraries/avatars/src/AvatarData.h | 8 +- libraries/avatars/src/AvatarHashMap.cpp | 223 ++++++++++++++---- libraries/avatars/src/AvatarHashMap.h | 23 +- 5 files changed, 223 insertions(+), 53 deletions(-) diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index c6e8ac59f1..63aa6d9b6f 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -464,7 +464,6 @@ protected: glm::vec3 _lastAngularVelocity; glm::vec3 _angularAcceleration; glm::quat _lastOrientation; - glm::vec3 _worldUpDirection { Vectors::UP }; bool _moving { false }; ///< set when position is changing diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 63a905aa6e..ddb53f8acb 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -918,7 +918,26 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { PACKET_READ_CHECK(AvatarGlobalPosition, sizeof(AvatarDataPacket::AvatarGlobalPosition)); auto data = reinterpret_cast(sourceBuffer); - auto newValue = glm::vec3(data->globalPosition[0], data->globalPosition[1], data->globalPosition[2]) + glm::vec3(0, 2 * _surrogateIndex, 0); + + const float SPACE_BETWEEN_AVATARS = 2.0f; + const int RANDOM_RADIUS = 100; + const int AVATARS_PER_ROW = 3; + + glm::vec3 offset; + + if (false) { + qsrand(static_cast(getID().toByteArray().toInt())); + float xrand = float((qrand() % ((RANDOM_RADIUS + 1) - 10) + 10) / 10.0f); + float yrand = float((qrand() % ((RANDOM_RADIUS + 1) - 10) + 10) / 10.0f); + offset = glm::vec3(xrand, 0.0f, yrand); + } + else { + int row = _replicaIndex % AVATARS_PER_ROW; + int col = floor(_replicaIndex / AVATARS_PER_ROW); + offset = glm::vec3(row * SPACE_BETWEEN_AVATARS, 0.0f, col * SPACE_BETWEEN_AVATARS); + } + + auto newValue = glm::vec3(data->globalPosition[0], data->globalPosition[1], data->globalPosition[2]) + offset; if (_globalPosition != newValue) { _globalPosition = newValue; _globalPositionChanged = usecTimestampNow(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index b3443dbd8a..36cc0f936d 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -337,6 +337,7 @@ enum KillAvatarReason : uint8_t { TheirAvatarEnteredYourBubble, YourAvatarEnteredTheirBubble }; + Q_DECLARE_METATYPE(KillAvatarReason); class QDataStream; @@ -1185,9 +1186,8 @@ public: virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {} virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {} - - void setSurrogateIndex(int surrogateIndex) { _surrogateIndex = surrogateIndex; } - int getSurrogateIndex() { return _surrogateIndex; } + void setReplicaIndex(int replicaIndex) { _replicaIndex = replicaIndex; } + int getReplicaIndex() { return _replicaIndex; } signals: @@ -1446,7 +1446,7 @@ protected: udt::SequenceNumber _identitySequenceNumber { 0 }; bool _hasProcessedFirstIdentity { false }; float _density; - int _surrogateIndex{ 0 }; + int _replicaIndex { 0 }; // null unless MyAvatar or ScriptableAvatar sending traits data to mixer std::unique_ptr _clientTraitsHandler; diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index a84d83e663..800825f574 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -21,7 +21,80 @@ #include "AvatarLogging.h" #include "AvatarTraits.h" -const int SURROGATE_COUNT = 2; + +void AvatarReplicas::addReplica(const QUuid& parentID, AvatarSharedPointer replica) { + if (_replicasMap.find(parentID) == _replicasMap.end()) { + std::vector emptyReplicas = std::vector(); + _replicasMap.insert(std::pair>(parentID, emptyReplicas)); + } + auto &replicas = _replicasMap[parentID]; + replica->setReplicaIndex((int)replicas.size() + 1); + replicas.push_back(replica); +} + +std::vector AvatarReplicas::getReplicaIDs(const QUuid& parentID, int count) { + std::vector ids; + if (_replicasMap.find(parentID) != _replicasMap.end()) { + auto &replicas = _replicasMap[parentID]; + for (int i = 0; i < replicas.size(); i++) { + ids.push_back(replicas[i]->getID()); + } + } else if (count > 0) { + for (int i = 0; i < count; i++) { + ids.push_back(QUuid::createUuid()); + } + } + return ids; +} + +void AvatarReplicas::parseDataFromBuffer(const QUuid& parentID, const QByteArray& buffer) { + if (_replicasMap.find(parentID) != _replicasMap.end()) { + auto &replicas = _replicasMap[parentID]; + for (auto avatar : replicas) { + avatar->parseDataFromBuffer(buffer); + } + } +} + +void AvatarReplicas::removeReplicas(const QUuid& parentID) { + if (_replicasMap.find(parentID) != _replicasMap.end()) { + _replicasMap.erase(parentID); + } +} + +void AvatarReplicas::processAvatarIdentity(const QUuid& parentID, const QByteArray& identityData, bool& identityChanged, bool& displayNameChanged) { + if (_replicasMap.find(parentID) != _replicasMap.end()) { + auto &replicas = _replicasMap[parentID]; + for (auto avatar : replicas) { + avatar->processAvatarIdentity(identityData, identityChanged, displayNameChanged); + } + } +} +void AvatarReplicas::processTrait(const QUuid& parentID, AvatarTraits::TraitType traitType, QByteArray traitBinaryData) { + if (_replicasMap.find(parentID) != _replicasMap.end()) { + auto &replicas = _replicasMap[parentID]; + for (auto avatar : replicas) { + avatar->processTrait(traitType, traitBinaryData); + } + } +} +void AvatarReplicas::processDeletedTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID) { + if (_replicasMap.find(parentID) != _replicasMap.end()) { + auto &replicas = _replicasMap[parentID]; + for (auto avatar : replicas) { + avatar->processDeletedTraitInstance(traitType, instanceID); + } + } +} +void AvatarReplicas::processTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType, + AvatarTraits::TraitInstanceID instanceID, QByteArray traitBinaryData) { + if (_replicasMap.find(parentID) != _replicasMap.end()) { + auto &replicas = _replicasMap[parentID]; + for (auto avatar : replicas) { + avatar->processTraitInstance(traitType, instanceID, traitBinaryData); + } + } +} AvatarHashMap::AvatarHashMap() { auto nodeList = DependencyManager::get(); @@ -138,40 +211,28 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointer(); + const int REPLICAS_COUNT = 8; + bool isNewAvatar; if (sessionUUID != _lastOwnerSessionUUID && (!nodeList->isIgnoringNode(sessionUUID) || nodeList->getRequestsDomainListData())) { auto avatar = newOrExistingAvatar(sessionUUID, sendingNode, isNewAvatar); - - + if (isNewAvatar) { QWriteLocker locker(&_hashLock); _pendingAvatars.insert(sessionUUID, { std::chrono::steady_clock::now(), 0, avatar }); - std::vector surrogateIDs; - for (int i = 0; i < SURROGATE_COUNT; i++) { - QUuid surrogateID = QUuid::createUuid(); - surrogateIDs.push_back(surrogateID); - auto surrogateAvatar = addAvatar(surrogateID, sendingNode); - surrogateAvatar->setSurrogateIndex(i + 1); - surrogateAvatar->parseDataFromBuffer(byteArray); - _pendingAvatars.insert(surrogateID, { std::chrono::steady_clock::now(), 0, surrogateAvatar }); + auto replicaIDs = _replicas.getReplicaIDs(sessionUUID, REPLICAS_COUNT); + for (auto replicaID : replicaIDs) { + auto replicaAvatar = addAvatar(replicaID, sendingNode); + _replicas.addReplica(sessionUUID, replicaAvatar); + _pendingAvatars.insert(replicaID, { std::chrono::steady_clock::now(), 0, replicaAvatar }); } - _surrogates.insert(std::pair>(sessionUUID, surrogateIDs)); - } else { - auto surrogateIDs = _surrogates[sessionUUID]; - for (auto id : surrogateIDs) { - auto surrogateAvatar = newOrExistingAvatar(id, sendingNode, isNewAvatar); - if (!isNewAvatar) { - surrogateAvatar->parseDataFromBuffer(byteArray); - } - } - - } + } // have the matching (or new) avatar parse the data from the packet int bytesRead = avatar->parseDataFromBuffer(byteArray); message->seek(positionBeforeRead + bytesRead); + _replicas.parseDataFromBuffer(sessionUUID, byteArray); - avatar->parseDataFromBuffer(byteArray); return avatar; } else { // create a dummy AvatarData class to throw this data on the ground @@ -216,17 +277,11 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer bool displayNameChanged = false; // In this case, the "sendingNode" is the Avatar Mixer. avatar->processAvatarIdentity(message->getMessage(), identityChanged, displayNameChanged); - auto surrogateIDs = _surrogates[identityUUID]; - for (auto id : surrogateIDs) { - auto surrogateAvatar = newOrExistingAvatar(id, sendingNode, isNewAvatar); - if (!isNewAvatar) { - surrogateAvatar->processAvatarIdentity(message->getMessage(), identityChanged, displayNameChanged); - } - } + _replicas.processAvatarIdentity(identityUUID, message->getMessage(), identityChanged, displayNameChanged); } } -void AvatarHashMap::processAvatarTraits(QUuid sessionUUID, QSharedPointer message, SharedNodePointer sendingNode) { +void AvatarHashMap::processBulkAvatarTraitsForID(QUuid sessionUUID, QSharedPointer message, SharedNodePointer sendingNode) { message->seek(0); while (message->getBytesLeftToRead()) { // read the avatar ID to figure out which avatar this is for @@ -297,13 +352,88 @@ void AvatarHashMap::processAvatarTraits(QUuid sessionUUID, QSharedPointer message, SharedNodePointer sendingNode) { + /* while (message->getBytesLeftToRead()) { // read the avatar ID to figure out which avatar this is for auto avatarID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - processAvatarTraits(avatarID, message, sendingNode); - auto surrogateIDs = _surrogates[avatarID]; - for (auto id : surrogateIDs) { - processAvatarTraits(id, message, sendingNode); + processBulkAvatarTraitsForID(avatarID, message, sendingNode); + auto replicaIDs = _replicas.getReplicaIDs(avatarID); + for (auto id : replicaIDs) { + processBulkAvatarTraitsForID(id, message, sendingNode); + } + } + */ + int position = 0; + while (message->getBytesLeftToRead()) { + // read the avatar ID to figure out which avatar this is for + auto avatarID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + + // grab the avatar so we can ask it to process trait data + bool isNewAvatar; + auto avatar = newOrExistingAvatar(avatarID, sendingNode, isNewAvatar); + + // read the first trait type for this avatar + AvatarTraits::TraitType traitType; + message->readPrimitive(&traitType); + + // grab the last trait versions for this avatar + auto& lastProcessedVersions = _processedTraitVersions[avatarID]; + + while (traitType != AvatarTraits::NullTrait) { + AvatarTraits::TraitVersion packetTraitVersion; + message->readPrimitive(&packetTraitVersion); + + AvatarTraits::TraitWireSize traitBinarySize; + bool skipBinaryTrait = false; + + + if (AvatarTraits::isSimpleTrait(traitType)) { + message->readPrimitive(&traitBinarySize); + + // check if this trait version is newer than what we already have for this avatar + if (packetTraitVersion > lastProcessedVersions[traitType]) { + position = message->getPosition(); + avatar->processTrait(traitType, message->read(traitBinarySize)); + message->seek(position); + _replicas.processTrait(avatarID, traitType, message->read(traitBinarySize)); + lastProcessedVersions[traitType] = packetTraitVersion; + } + else { + skipBinaryTrait = true; + } + } + else { + AvatarTraits::TraitInstanceID traitInstanceID = + QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + + message->readPrimitive(&traitBinarySize); + + auto& processedInstanceVersion = lastProcessedVersions.getInstanceValueRef(traitType, traitInstanceID); + if (packetTraitVersion > processedInstanceVersion) { + if (traitBinarySize == AvatarTraits::DELETED_TRAIT_SIZE) { + avatar->processDeletedTraitInstance(traitType, traitInstanceID); + _replicas.processDeletedTraitInstance(avatarID, traitType, traitInstanceID); + } + else { + position = message->getPosition(); + avatar->processTraitInstance(traitType, traitInstanceID, message->read(traitBinarySize)); + message->seek(position); + _replicas.processTraitInstance(avatarID, traitType, traitInstanceID, message->read(traitBinarySize)); + } + processedInstanceVersion = packetTraitVersion; + } + else { + skipBinaryTrait = true; + } + } + + if (skipBinaryTrait) { + // we didn't read this trait because it was older or because we didn't have an avatar to process it for + message->seek(message->getPosition() + traitBinarySize); + } + + // read the next trait type, which is null if there are no more traits for this avatar + message->readPrimitive(&traitType); } } } @@ -315,8 +445,8 @@ void AvatarHashMap::processKillAvatar(QSharedPointer message, S KillAvatarReason reason; message->readPrimitive(&reason); removeAvatar(sessionUUID, reason); - auto surrogateIDs = _surrogates[sessionUUID]; - for (auto id : surrogateIDs) { + auto replicaIDs = _replicas.getReplicaIDs(sessionUUID); + for (auto id : replicaIDs) { removeAvatar(id, reason); } } @@ -324,20 +454,23 @@ void AvatarHashMap::processKillAvatar(QSharedPointer message, S void AvatarHashMap::removeAvatar(const QUuid& sessionUUID, KillAvatarReason removalReason) { QWriteLocker locker(&_hashLock); + auto replicaIDs = _replicas.getReplicaIDs(sessionUUID); + _replicas.removeReplicas(sessionUUID); + for (auto id : replicaIDs) { + _pendingAvatars.remove(id); + auto removedReplica = _avatarHash.take(id); + if (removedReplica) { + handleRemovedAvatar(removedReplica, removalReason); + } + } + _pendingAvatars.remove(sessionUUID); auto removedAvatar = _avatarHash.take(sessionUUID); if (removedAvatar) { handleRemovedAvatar(removedAvatar, removalReason); } - auto surrogateIDs = _surrogates[sessionUUID]; - for (auto id : surrogateIDs) { - _pendingAvatars.remove(id); - auto removedSurrogate = _avatarHash.take(id); - if (removedSurrogate) { - handleRemovedAvatar(removedSurrogate, removalReason); - } - } + } void AvatarHashMap::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index 41981df693..2d8d7f907f 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -41,6 +41,24 @@ * @hifi-assignment-client */ +class AvatarReplicas { +public: + AvatarReplicas() {}; + void addReplica(const QUuid& parentID, AvatarSharedPointer replica); + std::vector getReplicaIDs(const QUuid& parentID, int count = 0); + void parseDataFromBuffer(const QUuid& parentID, const QByteArray& buffer); + void processAvatarIdentity(const QUuid& parentID, const QByteArray& identityData, bool& identityChanged, bool& displayNameChanged); + void removeReplicas(const QUuid& parentID); + void processTrait(const QUuid& parentID, AvatarTraits::TraitType traitType, QByteArray traitBinaryData); + void processDeletedTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID); + void processTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType, + AvatarTraits::TraitInstanceID instanceID, QByteArray traitBinaryData); + +private: + std::map> _replicasMap; +}; + + class AvatarHashMap : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY @@ -134,7 +152,7 @@ protected slots: */ void processAvatarIdentityPacket(QSharedPointer message, SharedNodePointer sendingNode); - void processAvatarTraits(QUuid sessionUUID, QSharedPointer message, SharedNodePointer sendingNode); + void processBulkAvatarTraitsForID(QUuid sessionUUID, QSharedPointer message, SharedNodePointer sendingNode); void processBulkAvatarTraits(QSharedPointer message, SharedNodePointer sendingNode); /**jsdoc @@ -168,7 +186,8 @@ protected: mutable QReadWriteLock _hashLock; std::unordered_map _processedTraitVersions; - std::map> _surrogates; + AvatarReplicas _replicas; + private: QUuid _lastOwnerSessionUUID; }; From 220dbf586f6e6382d8dc8338c48ec9b42e210ce2 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 23 Aug 2018 16:46:58 -0700 Subject: [PATCH 06/16] set the phase to 0.0 when it is negative --- libraries/animation/src/AnimBlendLinearMove.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/animation/src/AnimBlendLinearMove.cpp b/libraries/animation/src/AnimBlendLinearMove.cpp index 6313d4cbe9..27352fd546 100644 --- a/libraries/animation/src/AnimBlendLinearMove.cpp +++ b/libraries/animation/src/AnimBlendLinearMove.cpp @@ -155,6 +155,7 @@ void AnimBlendLinearMove::setFrameAndPhase(float dt, float alpha, int prevPoseIn // integrate phase forward in time. _phase += omega * dt; + qCDebug(animation) << "the _phase is " << _phase; // detect loop trigger events if (_phase >= 1.0f) { @@ -172,4 +173,7 @@ void AnimBlendLinearMove::setCurrentFrameInternal(float frame) { assert(clipNode); const float NUM_FRAMES = (clipNode->getEndFrame() - clipNode->getStartFrame()) + 1.0f; _phase = fmodf(frame / NUM_FRAMES, 1.0f); + if (_phase < 0.0f) { + _phase = 0.0f; // 1.0f + _phase; + } } From 0cc302f68c9812325f19a55158503b5339ccd82b Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 23 Aug 2018 17:28:38 -0700 Subject: [PATCH 07/16] set phase to 0.0 --- libraries/animation/src/AnimBlendLinearMove.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/libraries/animation/src/AnimBlendLinearMove.cpp b/libraries/animation/src/AnimBlendLinearMove.cpp index 27352fd546..d648b9966f 100644 --- a/libraries/animation/src/AnimBlendLinearMove.cpp +++ b/libraries/animation/src/AnimBlendLinearMove.cpp @@ -139,6 +139,8 @@ void AnimBlendLinearMove::setFrameAndPhase(float dt, float alpha, int prevPoseIn auto nextClipNode = std::dynamic_pointer_cast(_children[nextPoseIndex]); assert(nextClipNode); + + float v0 = _characteristicSpeeds[prevPoseIndex]; float n0 = (prevClipNode->getEndFrame() - prevClipNode->getStartFrame()) + 1.0f; float v1 = _characteristicSpeeds[nextPoseIndex]; @@ -153,9 +155,17 @@ void AnimBlendLinearMove::setFrameAndPhase(float dt, float alpha, int prevPoseIn float f1 = nextClipNode->getStartFrame() + _phase * n1; nextClipNode->setCurrentFrame(f1); + + // integrate phase forward in time. _phase += omega * dt; - qCDebug(animation) << "the _phase is " << _phase; + + qCDebug(animation) << "the _phase is " << _phase << " and omega " << omega << _desiredSpeed; + + if (_phase < 0.0f) { + _phase = 0.0f; // 1.0f + _phase; + } + // detect loop trigger events if (_phase >= 1.0f) { @@ -173,7 +183,4 @@ void AnimBlendLinearMove::setCurrentFrameInternal(float frame) { assert(clipNode); const float NUM_FRAMES = (clipNode->getEndFrame() - clipNode->getStartFrame()) + 1.0f; _phase = fmodf(frame / NUM_FRAMES, 1.0f); - if (_phase < 0.0f) { - _phase = 0.0f; // 1.0f + _phase; - } } From 884be2f99d4a7ea417260902880e412264ad2d5a Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 23 Aug 2018 17:30:03 -0700 Subject: [PATCH 08/16] removed comment and whitespace --- libraries/animation/src/AnimBlendLinearMove.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/libraries/animation/src/AnimBlendLinearMove.cpp b/libraries/animation/src/AnimBlendLinearMove.cpp index d648b9966f..8879f3d9d4 100644 --- a/libraries/animation/src/AnimBlendLinearMove.cpp +++ b/libraries/animation/src/AnimBlendLinearMove.cpp @@ -155,18 +155,13 @@ void AnimBlendLinearMove::setFrameAndPhase(float dt, float alpha, int prevPoseIn float f1 = nextClipNode->getStartFrame() + _phase * n1; nextClipNode->setCurrentFrame(f1); - - // integrate phase forward in time. _phase += omega * dt; - - qCDebug(animation) << "the _phase is " << _phase << " and omega " << omega << _desiredSpeed; if (_phase < 0.0f) { - _phase = 0.0f; // 1.0f + _phase; + _phase = 0.0f; } - // detect loop trigger events if (_phase >= 1.0f) { triggersOut.setTrigger(_id + "Loop"); From 671bf32d5813ef84837e7d22fd83933d4f9cba5e Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 23 Aug 2018 17:36:35 -0700 Subject: [PATCH 09/16] removed whitespace --- libraries/animation/src/AnimBlendLinearMove.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/animation/src/AnimBlendLinearMove.cpp b/libraries/animation/src/AnimBlendLinearMove.cpp index 8879f3d9d4..42098eb072 100644 --- a/libraries/animation/src/AnimBlendLinearMove.cpp +++ b/libraries/animation/src/AnimBlendLinearMove.cpp @@ -139,8 +139,6 @@ void AnimBlendLinearMove::setFrameAndPhase(float dt, float alpha, int prevPoseIn auto nextClipNode = std::dynamic_pointer_cast(_children[nextPoseIndex]); assert(nextClipNode); - - float v0 = _characteristicSpeeds[prevPoseIndex]; float n0 = (prevClipNode->getEndFrame() - prevClipNode->getStartFrame()) + 1.0f; float v1 = _characteristicSpeeds[nextPoseIndex]; From 1fd0d7da94c3cca2f4dc367cc41f8e84eed1f072 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 23 Aug 2018 18:03:27 -0700 Subject: [PATCH 10/16] Create API call --- libraries/avatars/src/AvatarHashMap.cpp | 24 +++++++++++++++++------- libraries/avatars/src/AvatarHashMap.h | 12 ++++++++++-- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 800825f574..6949efc19c 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -32,15 +32,15 @@ void AvatarReplicas::addReplica(const QUuid& parentID, AvatarSharedPointer repli replicas.push_back(replica); } -std::vector AvatarReplicas::getReplicaIDs(const QUuid& parentID, int count) { +std::vector AvatarReplicas::getReplicaIDs(const QUuid& parentID) { std::vector ids; if (_replicasMap.find(parentID) != _replicasMap.end()) { auto &replicas = _replicasMap[parentID]; for (int i = 0; i < replicas.size(); i++) { ids.push_back(replicas[i]->getID()); } - } else if (count > 0) { - for (int i = 0; i < count; i++) { + } else if (_replicaCount > 0) { + for (int i = 0; i < _replicaCount; i++) { ids.push_back(QUuid::createUuid()); } } @@ -139,6 +139,19 @@ bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range return false; } +void AvatarHashMap::setReplicaCount(int count) { + _replicas.setReplicaCount(count); + auto avatars = getAvatarIdentifiers(); + for (int i = 0; i < avatars.size(); i++) { + KillAvatarReason reason = KillAvatarReason::NoReason; + removeAvatar(avatars[i], reason); + auto replicaIDs = _replicas.getReplicaIDs(avatars[i]); + for (auto id : replicaIDs) { + removeAvatar(id, reason); + } + } +} + int AvatarHashMap::numberOfAvatarsInRange(const glm::vec3& position, float rangeMeters) { auto hashCopy = getHashCopy(); auto rangeMeters2 = rangeMeters * rangeMeters; @@ -210,9 +223,6 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointer(); - - const int REPLICAS_COUNT = 8; - bool isNewAvatar; if (sessionUUID != _lastOwnerSessionUUID && (!nodeList->isIgnoringNode(sessionUUID) || nodeList->getRequestsDomainListData())) { auto avatar = newOrExistingAvatar(sessionUUID, sendingNode, isNewAvatar); @@ -220,7 +230,7 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointer getReplicaIDs(const QUuid& parentID, int count = 0); + std::vector getReplicaIDs(const QUuid& parentID); void parseDataFromBuffer(const QUuid& parentID, const QByteArray& buffer); void processAvatarIdentity(const QUuid& parentID, const QByteArray& identityData, bool& identityChanged, bool& displayNameChanged); void removeReplicas(const QUuid& parentID); @@ -53,9 +53,11 @@ public: void processDeletedTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID); void processTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID, QByteArray traitBinaryData); + void setReplicaCount(int count) { _replicaCount = count; } private: std::map> _replicasMap; + int _replicaCount; }; @@ -92,6 +94,12 @@ public: // Null/Default-constructed QUuids will return MyAvatar Q_INVOKABLE virtual ScriptAvatarData* getAvatar(QUuid avatarID) { return new ScriptAvatarData(getAvatarBySessionID(avatarID)); } + /**jsdoc + * @function AvatarList.setReplicaCount + * @param {number} count // The times an avatar will get replicated + */ + Q_INVOKABLE void setReplicaCount(int count); + virtual AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) const { return findAvatar(sessionID); } int numberOfAvatarsInRange(const glm::vec3& position, float rangeMeters); From 5654acf5bf28c9476402a1bc6a2cb4ef3545bf07 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 24 Aug 2018 09:24:58 -0700 Subject: [PATCH 11/16] Fix warnings --- libraries/avatars/src/AvatarHashMap.cpp | 99 ++----------------------- libraries/avatars/src/AvatarHashMap.h | 8 +- 2 files changed, 15 insertions(+), 92 deletions(-) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 6949efc19c..67cc9f0563 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -36,7 +36,7 @@ std::vector AvatarReplicas::getReplicaIDs(const QUuid& parentID) { std::vector ids; if (_replicasMap.find(parentID) != _replicasMap.end()) { auto &replicas = _replicasMap[parentID]; - for (int i = 0; i < replicas.size(); i++) { + for (int i = 0; i < (int)replicas.size(); i++) { ids.push_back(replicas[i]->getID()); } } else if (_replicaCount > 0) { @@ -288,92 +288,12 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer // In this case, the "sendingNode" is the Avatar Mixer. avatar->processAvatarIdentity(message->getMessage(), identityChanged, displayNameChanged); _replicas.processAvatarIdentity(identityUUID, message->getMessage(), identityChanged, displayNameChanged); - } -} -void AvatarHashMap::processBulkAvatarTraitsForID(QUuid sessionUUID, QSharedPointer message, SharedNodePointer sendingNode) { - message->seek(0); - while (message->getBytesLeftToRead()) { - // read the avatar ID to figure out which avatar this is for - auto avatarID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - avatarID = sessionUUID; - - // grab the avatar so we can ask it to process trait data - bool isNewAvatar; - auto avatar = newOrExistingAvatar(avatarID, sendingNode, isNewAvatar); - - // read the first trait type for this avatar - AvatarTraits::TraitType traitType; - message->readPrimitive(&traitType); - - // grab the last trait versions for this avatar - auto& lastProcessedVersions = _processedTraitVersions[avatarID]; - - while (traitType != AvatarTraits::NullTrait) { - AvatarTraits::TraitVersion packetTraitVersion; - message->readPrimitive(&packetTraitVersion); - - AvatarTraits::TraitWireSize traitBinarySize; - bool skipBinaryTrait = false; - - - if (AvatarTraits::isSimpleTrait(traitType)) { - message->readPrimitive(&traitBinarySize); - - // check if this trait version is newer than what we already have for this avatar - if (packetTraitVersion > lastProcessedVersions[traitType]) { - avatar->processTrait(traitType, message->read(traitBinarySize)); - lastProcessedVersions[traitType] = packetTraitVersion; - } - else { - skipBinaryTrait = true; - } - } - else { - AvatarTraits::TraitInstanceID traitInstanceID = - QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - - message->readPrimitive(&traitBinarySize); - - auto& processedInstanceVersion = lastProcessedVersions.getInstanceValueRef(traitType, traitInstanceID); - if (packetTraitVersion > processedInstanceVersion) { - if (traitBinarySize == AvatarTraits::DELETED_TRAIT_SIZE) { - avatar->processDeletedTraitInstance(traitType, traitInstanceID); - } - else { - avatar->processTraitInstance(traitType, traitInstanceID, message->read(traitBinarySize)); - } - processedInstanceVersion = packetTraitVersion; - } - else { - skipBinaryTrait = true; - } - } - - if (skipBinaryTrait) { - // we didn't read this trait because it was older or because we didn't have an avatar to process it for - message->seek(message->getPosition() + traitBinarySize); - } - - // read the next trait type, which is null if there are no more traits for this avatar - message->readPrimitive(&traitType); - } } } void AvatarHashMap::processBulkAvatarTraits(QSharedPointer message, SharedNodePointer sendingNode) { - /* - while (message->getBytesLeftToRead()) { - // read the avatar ID to figure out which avatar this is for - auto avatarID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - processBulkAvatarTraitsForID(avatarID, message, sendingNode); - auto replicaIDs = _replicas.getReplicaIDs(avatarID); - for (auto id : replicaIDs) { - processBulkAvatarTraitsForID(id, message, sendingNode); - } - } - */ - int position = 0; + while (message->getBytesLeftToRead()) { // read the avatar ID to figure out which avatar this is for auto avatarID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); @@ -381,7 +301,6 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess // grab the avatar so we can ask it to process trait data bool isNewAvatar; auto avatar = newOrExistingAvatar(avatarID, sendingNode, isNewAvatar); - // read the first trait type for this avatar AvatarTraits::TraitType traitType; message->readPrimitive(&traitType); @@ -402,10 +321,9 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess // check if this trait version is newer than what we already have for this avatar if (packetTraitVersion > lastProcessedVersions[traitType]) { - position = message->getPosition(); - avatar->processTrait(traitType, message->read(traitBinarySize)); - message->seek(position); - _replicas.processTrait(avatarID, traitType, message->read(traitBinarySize)); + auto traitData = message->read(traitBinarySize); + avatar->processTrait(traitType, traitData); + _replicas.processTrait(avatarID, traitType, traitData); lastProcessedVersions[traitType] = packetTraitVersion; } else { @@ -425,10 +343,9 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess _replicas.processDeletedTraitInstance(avatarID, traitType, traitInstanceID); } else { - position = message->getPosition(); - avatar->processTraitInstance(traitType, traitInstanceID, message->read(traitBinarySize)); - message->seek(position); - _replicas.processTraitInstance(avatarID, traitType, traitInstanceID, message->read(traitBinarySize)); + auto traitData = message->read(traitBinarySize); + avatar->processTraitInstance(traitType, traitInstanceID, traitData); + _replicas.processTraitInstance(avatarID, traitType, traitInstanceID, traitData); } processedInstanceVersion = packetTraitVersion; } diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index b7199d25ac..97c54e1787 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -54,6 +54,7 @@ public: void processTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID, QByteArray traitBinaryData); void setReplicaCount(int count) { _replicaCount = count; } + int getReplicaCount() { return _replicaCount; } private: std::map> _replicasMap; @@ -99,6 +100,12 @@ public: * @param {number} count // The times an avatar will get replicated */ Q_INVOKABLE void setReplicaCount(int count); + + /**jsdoc + * @function AvatarList.setReplicaCount + * @param {number} count // The times an avatar will get replicated + */ + Q_INVOKABLE int getReplicaCount() { return _replicas.getReplicaCount(); }; virtual AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) const { return findAvatar(sessionID); } int numberOfAvatarsInRange(const glm::vec3& position, float rangeMeters); @@ -160,7 +167,6 @@ protected slots: */ void processAvatarIdentityPacket(QSharedPointer message, SharedNodePointer sendingNode); - void processBulkAvatarTraitsForID(QUuid sessionUUID, QSharedPointer message, SharedNodePointer sendingNode); void processBulkAvatarTraits(QSharedPointer message, SharedNodePointer sendingNode); /**jsdoc From ddbadf5a6936e29a426bd862ffca06129cfd1fac Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 24 Aug 2018 11:59:46 -0700 Subject: [PATCH 12/16] change to Test API --- interface/src/Application.h | 3 +++ .../src/scripting/TestScriptingInterface.cpp | 8 ++++++++ interface/src/scripting/TestScriptingInterface.h | 14 ++++++++++++++ libraries/avatars/src/AvatarHashMap.h | 15 +++------------ 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index 742cf075f6..0d4417cd91 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -311,6 +311,9 @@ public: Q_INVOKABLE void copyToClipboard(const QString& text); + int getOtherAvatarsReplicaCount() { return DependencyManager::get()->getReplicaCount(); } + void setOtherAvatarsReplicaCount(int count) { DependencyManager::get()->setReplicaCount(count); } + #if defined(Q_OS_ANDROID) void beforeEnterBackground(); void enterBackground(); diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index 430441226f..52f6a3ebc0 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -190,4 +190,12 @@ void TestScriptingInterface::saveObject(QVariant variant, const QString& filenam void TestScriptingInterface::showMaximized() { qApp->getWindow()->showMaximized(); +} + +void TestScriptingInterface::setOtherAvatarsReplicaCount(int count) { + qApp->setOtherAvatarsReplicaCount(count); +} + +int TestScriptingInterface::getOtherAvatarsReplicaCount() { + return qApp->getOtherAvatarsReplicaCount(); } \ No newline at end of file diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h index c47e39d1f3..4a1d1a3eeb 100644 --- a/interface/src/scripting/TestScriptingInterface.h +++ b/interface/src/scripting/TestScriptingInterface.h @@ -149,6 +149,20 @@ public slots: */ void showMaximized(); + /**jsdoc + * Values higher than 0 will create replicas of other-avatars when entering a domain for testing purpouses + * @function Test.setOtherAvatarsReplicaCount + * @param {number} count - Number of replicas we want to create + */ + Q_INVOKABLE void setOtherAvatarsReplicaCount(int count); + + /**jsdoc + * Return the number of replicas that are being created of other-avatars when entering a domain + * @function Test.getOtherAvatarsReplicaCount + * @returns {number} Current number of replicas of other-avatars. + */ + Q_INVOKABLE int getOtherAvatarsReplicaCount(); + private: bool waitForCondition(qint64 maxWaitMs, std::function condition); QString _testResultsLocation; diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index 97c54e1787..e4e197a080 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -95,21 +95,12 @@ public: // Null/Default-constructed QUuids will return MyAvatar Q_INVOKABLE virtual ScriptAvatarData* getAvatar(QUuid avatarID) { return new ScriptAvatarData(getAvatarBySessionID(avatarID)); } - /**jsdoc - * @function AvatarList.setReplicaCount - * @param {number} count // The times an avatar will get replicated - */ - Q_INVOKABLE void setReplicaCount(int count); - - /**jsdoc - * @function AvatarList.setReplicaCount - * @param {number} count // The times an avatar will get replicated - */ - Q_INVOKABLE int getReplicaCount() { return _replicas.getReplicaCount(); }; - virtual AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) const { return findAvatar(sessionID); } int numberOfAvatarsInRange(const glm::vec3& position, float rangeMeters); + void setReplicaCount(int count); + int getReplicaCount() { return _replicas.getReplicaCount(); }; + signals: /**jsdoc From 98d145dc2487508bcf1d4076892cb6f0cf14e3dc Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 24 Aug 2018 15:19:48 -0700 Subject: [PATCH 13/16] fix crash on shutdown in domain with material --- interface/src/Application.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e290531471..44bba6250b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1841,6 +1841,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo }); EntityTree::setAddMaterialToEntityOperator([this](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + if (_aboutToQuit) { + return false; + } + // try to find the renderable auto renderable = getEntities()->renderableForEntityId(entityID); if (renderable) { @@ -1856,6 +1860,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo return false; }); EntityTree::setRemoveMaterialFromEntityOperator([this](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + if (_aboutToQuit) { + return false; + } + // try to find the renderable auto renderable = getEntities()->renderableForEntityId(entityID); if (renderable) { From 8ede6f1cd09cf2ed33a006fa9629dae134fe0d5f Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 27 Aug 2018 06:55:52 -0700 Subject: [PATCH 14/16] Fix removing my avatar and code standards --- libraries/avatars/src/AvatarData.cpp | 16 ++++----------- libraries/avatars/src/AvatarHashMap.cpp | 26 ++++++++++++------------- libraries/avatars/src/AvatarHashMap.h | 4 ++-- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index ddb53f8acb..5e1094276c 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -919,19 +919,11 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { PACKET_READ_CHECK(AvatarGlobalPosition, sizeof(AvatarDataPacket::AvatarGlobalPosition)); auto data = reinterpret_cast(sourceBuffer); - const float SPACE_BETWEEN_AVATARS = 2.0f; - const int RANDOM_RADIUS = 100; - const int AVATARS_PER_ROW = 3; + glm::vec3 offset = glm::vec3(0.0f, 0.0f, 0.0f); - glm::vec3 offset; - - if (false) { - qsrand(static_cast(getID().toByteArray().toInt())); - float xrand = float((qrand() % ((RANDOM_RADIUS + 1) - 10) + 10) / 10.0f); - float yrand = float((qrand() % ((RANDOM_RADIUS + 1) - 10) + 10) / 10.0f); - offset = glm::vec3(xrand, 0.0f, yrand); - } - else { + if (_replicaIndex > 0) { + const float SPACE_BETWEEN_AVATARS = 2.0f; + const int AVATARS_PER_ROW = 3; int row = _replicaIndex % AVATARS_PER_ROW; int col = floor(_replicaIndex / AVATARS_PER_ROW); offset = glm::vec3(row * SPACE_BETWEEN_AVATARS, 0.0f, col * SPACE_BETWEEN_AVATARS); diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 67cc9f0563..8dfee3551e 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -23,6 +23,9 @@ void AvatarReplicas::addReplica(const QUuid& parentID, AvatarSharedPointer replica) { + if (parentID == QUuid()) { + return; + } if (_replicasMap.find(parentID) == _replicasMap.end()) { std::vector emptyReplicas = std::vector(); _replicasMap.insert(std::pair>(parentID, emptyReplicas)); @@ -144,10 +147,12 @@ void AvatarHashMap::setReplicaCount(int count) { auto avatars = getAvatarIdentifiers(); for (int i = 0; i < avatars.size(); i++) { KillAvatarReason reason = KillAvatarReason::NoReason; - removeAvatar(avatars[i], reason); - auto replicaIDs = _replicas.getReplicaIDs(avatars[i]); - for (auto id : replicaIDs) { - removeAvatar(id, reason); + if (avatars[i] != QUuid()) { + removeAvatar(avatars[i], reason); + auto replicaIDs = _replicas.getReplicaIDs(avatars[i]); + for (auto id : replicaIDs) { + removeAvatar(id, reason); + } } } } @@ -315,7 +320,6 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess AvatarTraits::TraitWireSize traitBinarySize; bool skipBinaryTrait = false; - if (AvatarTraits::isSimpleTrait(traitType)) { message->readPrimitive(&traitBinarySize); @@ -325,12 +329,10 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess avatar->processTrait(traitType, traitData); _replicas.processTrait(avatarID, traitType, traitData); lastProcessedVersions[traitType] = packetTraitVersion; - } - else { + } else { skipBinaryTrait = true; } - } - else { + } else { AvatarTraits::TraitInstanceID traitInstanceID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); @@ -341,15 +343,13 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess if (traitBinarySize == AvatarTraits::DELETED_TRAIT_SIZE) { avatar->processDeletedTraitInstance(traitType, traitInstanceID); _replicas.processDeletedTraitInstance(avatarID, traitType, traitInstanceID); - } - else { + } else { auto traitData = message->read(traitBinarySize); avatar->processTraitInstance(traitType, traitInstanceID, traitData); _replicas.processTraitInstance(avatarID, traitType, traitInstanceID, traitData); } processedInstanceVersion = packetTraitVersion; - } - else { + } else { skipBinaryTrait = true; } } diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index e4e197a080..0f847b2a61 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -43,7 +43,7 @@ class AvatarReplicas { public: - AvatarReplicas() : _replicaCount(0) {} + AvatarReplicas() {} void addReplica(const QUuid& parentID, AvatarSharedPointer replica); std::vector getReplicaIDs(const QUuid& parentID); void parseDataFromBuffer(const QUuid& parentID, const QByteArray& buffer); @@ -58,7 +58,7 @@ public: private: std::map> _replicasMap; - int _replicaCount; + int _replicaCount { 0 }; }; From 52bbb4d2abac51afe38fe5050a168464625d1ce3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Aug 2018 12:47:17 -0700 Subject: [PATCH 15/16] fix ray-pick results on entities with non-default registration point. clean up grab scripts to correctly use this fix. --- interface/src/raypick/PathPointer.cpp | 4 +-- .../controllerModules/farActionGrabEntity.js | 18 +++-------- .../farActionGrabEntityDynOnly.js | 17 +++------- .../controllerModules/farParentGrabEntity.js | 18 +++-------- .../libraries/controllerDispatcherUtils.js | 32 +++++++++++++++++-- 5 files changed, 45 insertions(+), 44 deletions(-) diff --git a/interface/src/raypick/PathPointer.cpp b/interface/src/raypick/PathPointer.cpp index 685611d77b..d434c667de 100644 --- a/interface/src/raypick/PathPointer.cpp +++ b/interface/src/raypick/PathPointer.cpp @@ -105,7 +105,7 @@ PickResultPointer PathPointer::getVisualPickResult(const PickResultPointer& pick glm::mat4 entityMat = createMatFromQuatAndPos(props.getRotation(), props.getPosition()); glm::mat4 finalPosAndRotMat = entityMat * _lockEndObject.offsetMat; pos = extractTranslation(finalPosAndRotMat); - rot = glmExtractRotation(finalPosAndRotMat); + rot = props.getRotation(); dim = props.getDimensions(); registrationPoint = props.getRegistrationPoint(); } @@ -350,4 +350,4 @@ glm::vec2 PathPointer::findPos2D(const PickedObject& pickedObject, const glm::ve default: return glm::vec2(NAN); } -} \ No newline at end of file +} diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index e4563fda14..5e798ed680 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -14,7 +14,8 @@ PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic, getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI - Picks, makeLaserLockInfo Xform, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST + Picks, makeLaserLockInfo Xform, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST, + worldPositionToRegistrationFrameMatrix */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -593,18 +594,9 @@ Script.include("/~/system/libraries/Xform.js"); this.calculateOffset = function(controllerData) { if (this.distanceHolding || this.distanceRotating) { - var targetProps = Entities.getEntityProperties(this.targetObject.entityID, [ - "position", - "rotation" - ]); - var zeroVector = { x: 0, y: 0, z:0, w: 0 }; - var intersection = controllerData.rayPicks[this.hand].intersection; - var intersectionMat = new Xform(zeroVector, intersection); - var modelMat = new Xform(targetProps.rotation, targetProps.position); - var modelMatInv = modelMat.inv(); - var xformMat = Xform.mul(modelMatInv, intersectionMat); - var offsetMat = Mat4.createFromRotAndTrans(xformMat.rot, xformMat.pos); - return offsetMat; + var targetProps = Entities.getEntityProperties(this.targetObject.entityID, + [ "position", "rotation", "registrationPoint", "dimensions" ]); + return worldPositionToRegistrationFrameMatrix(targetProps, controllerData.rayPicks[this.hand].intersection); } return undefined; }; diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js b/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js index a080e75325..78abcb9b20 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js @@ -12,7 +12,7 @@ makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Picks, makeLaserLockInfo, Xform, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST, - Uuid + Uuid, worldPositionToRegistrationFrameMatrix */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -572,18 +572,9 @@ Script.include("/~/system/libraries/Xform.js"); this.calculateOffset = function(controllerData) { if (this.distanceHolding || this.distanceRotating) { - var targetProps = Entities.getEntityProperties(this.targetObject.entityID, [ - "position", - "rotation" - ]); - var zeroVector = { x: 0, y: 0, z:0, w: 0 }; - var intersection = controllerData.rayPicks[this.hand].intersection; - var intersectionMat = new Xform(zeroVector, intersection); - var modelMat = new Xform(targetProps.rotation, targetProps.position); - var modelMatInv = modelMat.inv(); - var xformMat = Xform.mul(modelMatInv, intersectionMat); - var offsetMat = Mat4.createFromRotAndTrans(xformMat.rot, xformMat.pos); - return offsetMat; + var targetProps = Entities.getEntityProperties(this.targetObject.entityID, + [ "position", "rotation", "registrationPoint", "dimensions" ]); + return worldPositionToRegistrationFrameMatrix(targetProps, controllerData.rayPicks[this.hand].intersection); } return undefined; }; diff --git a/scripts/system/controllers/controllerModules/farParentGrabEntity.js b/scripts/system/controllers/controllerModules/farParentGrabEntity.js index 439b5e5f51..a9ec246a32 100644 --- a/scripts/system/controllers/controllerModules/farParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farParentGrabEntity.js @@ -11,7 +11,8 @@ Entities, enableDispatcherModule, disableDispatcherModule, entityIsGrabbable, makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Picks, makeLaserLockInfo, Xform, makeLaserParams, AddressManager, - getEntityParents, Selection, DISPATCHER_HOVERING_LIST, unhighlightTargetEntity, Messages, Uuid, findGroupParent + getEntityParents, Selection, DISPATCHER_HOVERING_LIST, unhighlightTargetEntity, Messages, Uuid, findGroupParent, + worldPositionToRegistrationFrameMatrix */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -615,18 +616,9 @@ Script.include("/~/system/libraries/Xform.js"); this.calculateOffset = function(controllerData) { if (this.distanceHolding || this.distanceRotating) { - var targetProps = Entities.getEntityProperties(this.targetObject.entityID, [ - "position", - "rotation" - ]); - var zeroVector = { x: 0, y: 0, z:0, w: 0 }; - var intersection = controllerData.rayPicks[this.hand].intersection; - var intersectionMat = new Xform(zeroVector, intersection); - var modelMat = new Xform(targetProps.rotation, targetProps.position); - var modelMatInv = modelMat.inv(); - var xformMat = Xform.mul(modelMatInv, intersectionMat); - var offsetMat = Mat4.createFromRotAndTrans(xformMat.rot, xformMat.pos); - return offsetMat; + var targetProps = Entities.getEntityProperties(this.targetObject.entityID, + [ "position", "rotation", "registrationPoint", "dimensions" ]); + return worldPositionToRegistrationFrameMatrix(targetProps, controllerData.rayPicks[this.hand].intersection); } return undefined; }; diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index a386dcf5b4..c34fd76802 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -5,7 +5,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global module, Camera, HMD, MyAvatar, controllerDispatcherPlugins:true, Quat, Vec3, Overlays, Xform, +/* global module, Camera, HMD, MyAvatar, controllerDispatcherPlugins:true, Quat, Vec3, Overlays, Xform, Mat4, Selection, Uuid, MSECS_PER_SEC:true , LEFT_HAND:true, RIGHT_HAND:true, FORBIDDEN_GRAB_TYPES:true, HAPTIC_PULSE_STRENGTH:true, HAPTIC_PULSE_DURATION:true, ZERO_VEC:true, ONE_VEC:true, @@ -58,7 +58,8 @@ highlightTargetEntity:true, clearHighlightedEntities:true, unhighlightTargetEntity:true, - distanceBetweenEntityLocalPositionAndBoundingBox: true + distanceBetweenEntityLocalPositionAndBoundingBox: true, + worldPositionToRegistrationFrameMatrix: true */ MSECS_PER_SEC = 1000.0; @@ -487,6 +488,30 @@ entityIsFarGrabbedByOther = function(entityID) { return false; }; + +worldPositionToRegistrationFrameMatrix = function(wptrProps, pos) { + // get world matrix for intersection point + var intersectionMat = new Xform({ x: 0, y: 0, z:0, w: 1 }, pos); + + // calculate world matrix for registrationPoint addjusted entity + var DEFAULT_REGISTRATION_POINT = { x: 0.5, y: 0.5, z: 0.5 }; + var regRatio = Vec3.subtract(DEFAULT_REGISTRATION_POINT, wptrProps.registrationPoint); + var regOffset = Vec3.multiplyVbyV(regRatio, wptrProps.dimensions); + var regOffsetRot = Vec3.multiplyQbyV(wptrProps.rotation, regOffset); + var modelMat = new Xform(wptrProps.rotation, Vec3.sum(wptrProps.position, regOffsetRot)); + + // get inverse of model matrix + var modelMatInv = modelMat.inv(); + + // transform world intersection point into object's registrationPoint frame + var xformMat = Xform.mul(modelMatInv, intersectionMat); + + // convert to Mat4 + var offsetMat = Mat4.createFromRotAndTrans(xformMat.rot, xformMat.pos); + return offsetMat; +}; + + if (typeof module !== 'undefined') { module.exports = { makeDispatcherModuleParameters: makeDispatcherModuleParameters, @@ -508,6 +533,7 @@ if (typeof module !== 'undefined') { projectOntoEntityXYPlane: projectOntoEntityXYPlane, TRIGGER_OFF_VALUE: TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE: TRIGGER_ON_VALUE, - DISPATCHER_HOVERING_LIST: DISPATCHER_HOVERING_LIST + DISPATCHER_HOVERING_LIST: DISPATCHER_HOVERING_LIST, + worldPositionToRegistrationFrameMatrix: worldPositionToRegistrationFrameMatrix }; } From c19bd8968ad315df6abdfc336ba58fcafe47e041 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 27 Aug 2018 16:48:47 -0700 Subject: [PATCH 16/16] Fix mixer crash --- libraries/avatars/src/AvatarHashMap.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 8dfee3551e..c437b56f32 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -239,7 +239,6 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointer