diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 8b9354b5bc..5c52dd98dc 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -259,3 +259,4 @@ INSTALL(TARGETS ${TARGET_NAME} BUNDLE DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/install COMPONENT Runtime RUNTIME DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/install COMPONENT Runtime ) + diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 810c93f4b9..c048c2464e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1352,8 +1352,9 @@ void Application::timer() { // ask the node list to check in with the domain server NodeList::getInstance()->sendDomainServerCheckIn(); - // give the MyAvatar object position to the Profile so it can propagate to the data-server + // give the MyAvatar object position, orientation to the Profile so it can propagate to the data-server _profile.updatePosition(_myAvatar.getPosition()); + _profile.updateOrientation(_myAvatar.getOrientation()); } static glm::vec3 getFaceVector(BoxFace face) { @@ -2133,9 +2134,12 @@ void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm:: for (vector::iterator fade = _avatarFades.begin(); fade != _avatarFades.end(); fade++) { Avatar* avatar = *fade; const float SHRINK_RATE = 0.9f; - avatar->setNewScale(avatar->getNewScale() * SHRINK_RATE); - const float MINIMUM_SCALE = 0.001f; - if (avatar->getNewScale() < MINIMUM_SCALE) { + + avatar->setTargetScale(avatar->getScale() * SHRINK_RATE); + + const float MIN_FADE_SCALE = 0.001; + + if (avatar->getTargetScale() < MIN_FADE_SCALE) { delete avatar; _avatarFades.erase(fade--); diff --git a/interface/src/DataServerClient.cpp b/interface/src/DataServerClient.cpp index 072689e863..1eb4738b0d 100644 --- a/interface/src/DataServerClient.cpp +++ b/interface/src/DataServerClient.cpp @@ -175,25 +175,34 @@ void DataServerClient::processSendFromDataServer(unsigned char* packetData, int } } } - } else if (keyList[i] == DataServerKey::Domain && keyList[i + 1] == DataServerKey::Position - && valueList[i] != " " && valueList[i + 1] != " ") { + } else if (keyList[i] == DataServerKey::Domain && keyList[i + 1] == DataServerKey::Position && + keyList[i + 2] == DataServerKey::Orientation && valueList[i] != " " && + valueList[i + 1] != " " && valueList[i + 2] != " ") { QStringList coordinateItems = valueList[i + 1].split(','); + QStringList orientationItems = valueList[i + 2].split(','); - if (coordinateItems.size() == 3) { + if (coordinateItems.size() == 3 && orientationItems.size() == 3) { // send a node kill request, indicating to other clients that they should play the "disappeared" effect NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1); qDebug() << "Changing domain to" << valueList[i].toLocal8Bit().constData() << - "and position to" << valueList[i + 1].toLocal8Bit().constData() << + ", position to" << valueList[i + 1].toLocal8Bit().constData() << + ", and orientation to" << valueList[i + 2].toLocal8Bit().constData() << "to go to" << userString << "\n"; NodeList::getInstance()->setDomainHostname(valueList[i]); + // orient the user to face the target + glm::quat newOrientation = glm::quat(glm::radians(glm::vec3(orientationItems[0].toFloat(), + orientationItems[1].toFloat(), orientationItems[2].toFloat()))) * + glm::angleAxis(180.0f, 0.0f, 1.0f, 0.0f); + Application::getInstance()->getAvatar()->setOrientation(newOrientation); - glm::vec3 newPosition(coordinateItems[0].toFloat(), - coordinateItems[1].toFloat(), - coordinateItems[2].toFloat()); + // move the user a couple units away + const float DISTANCE_TO_USER = 2.0f; + glm::vec3 newPosition = glm::vec3(coordinateItems[0].toFloat(), coordinateItems[1].toFloat(), + coordinateItems[2].toFloat()) - newOrientation * IDENTITY_FRONT * DISTANCE_TO_USER; Application::getInstance()->getAvatar()->setPosition(newPosition); } diff --git a/interface/src/DataServerClient.h b/interface/src/DataServerClient.h index b0ccbe13ee..89ec944eb6 100644 --- a/interface/src/DataServerClient.h +++ b/interface/src/DataServerClient.h @@ -41,6 +41,7 @@ namespace DataServerKey { const QString FaceMeshURL = "mesh"; const QString SkeletonURL = "skeleton"; const QString Position = "position"; + const QString Orientation = "orientation"; const QString UUID = "uuid"; } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0a9ee86cf2..8871d22a2b 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -897,7 +897,7 @@ void Menu::editPreferences() { _maxVoxelPacketsPerSecond = maxVoxelsPPS->value(); applicationInstance->getAvatar()->setLeanScale(leanScale->value()); - applicationInstance->getAvatar()->setNewScale(avatarScale->value()); + applicationInstance->getAvatar()->setClampedTargetScale(avatarScale->value()); _audioJitterBufferSamples = audioJitterBufferSamples->value(); @@ -1005,8 +1005,9 @@ void Menu::goToUser() { int dialogReturn = userDialog.exec(); if (dialogReturn == QDialog::Accepted && !userDialog.textValue().isEmpty()) { // there's a username entered by the user, make a request to the data-server - DataServerClient::getValuesForKeysAndUserString((QStringList() << DataServerKey::Domain << DataServerKey::Position), - userDialog.textValue()); + DataServerClient::getValuesForKeysAndUserString( + QStringList() << DataServerKey::Domain << DataServerKey::Position << DataServerKey::Orientation, + userDialog.textValue()); } sendFakeEnterEvent(); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a2e1510db5..e2a80e2f60 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -167,8 +167,8 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { follow(NULL); } - if (_scale != _newScale) { - setScale(_newScale); + if (_scale != _targetScale) { + setScale(_targetScale); } // copy velocity so we can use it later for acceleration @@ -439,30 +439,30 @@ void Avatar::goHome() { } void Avatar::increaseSize() { - if ((1.f + SCALING_RATIO) * _newScale < MAX_SCALE) { - _newScale *= (1.f + SCALING_RATIO); - qDebug("Changed scale to %f\n", _newScale); + if ((1.f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) { + _targetScale *= (1.f + SCALING_RATIO); + qDebug("Changed scale to %f\n", _targetScale); } } void Avatar::decreaseSize() { - if (MIN_SCALE < (1.f - SCALING_RATIO) * _newScale) { - _newScale *= (1.f - SCALING_RATIO); - qDebug("Changed scale to %f\n", _newScale); + if (MIN_AVATAR_SCALE < (1.f - SCALING_RATIO) * _targetScale) { + _targetScale *= (1.f - SCALING_RATIO); + qDebug("Changed scale to %f\n", _targetScale); } } void Avatar::resetSize() { - _newScale = 1.0f; - qDebug("Reseted scale to %f\n", _newScale); + _targetScale = 1.0f; + qDebug("Reseted scale to %f\n", _targetScale); } void Avatar::setScale(const float scale) { _scale = scale; - if (_newScale * (1.f - RESCALING_TOLERANCE) < _scale && - _scale < _newScale * (1.f + RESCALING_TOLERANCE)) { - _scale = _newScale; + if (_targetScale * (1.f - RESCALING_TOLERANCE) < _scale && + _scale < _targetScale * (1.f + RESCALING_TOLERANCE)) { + _scale = _targetScale; } _skeleton.setScale(_scale); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ce7a21d577..ca9a6a9476 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -93,12 +93,12 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) { } // Ajust, scale, position and lookAt position when following an other avatar - if (_leadingAvatar && _newScale != _leadingAvatar->getScale()) { - _newScale = _leadingAvatar->getScale(); + if (_leadingAvatar && _targetScale != _leadingAvatar->getScale()) { + _targetScale = _leadingAvatar->getScale(); } - if (_scale != _newScale) { - float scale = (1.f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _newScale; + if (_scale != _targetScale) { + float scale = (1.f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale; setScale(scale); Application::getInstance()->getCamera()->setScale(scale); } @@ -514,7 +514,7 @@ void MyAvatar::saveData(QSettings* settings) { settings->setValue("pupilDilation", _head.getPupilDilation()); settings->setValue("leanScale", _leanScale); - settings->setValue("scale", _newScale); + settings->setValue("scale", _targetScale); settings->endGroup(); } @@ -536,8 +536,7 @@ void MyAvatar::loadData(QSettings* settings) { _head.setPupilDilation(settings->value("pupilDilation", 0.0f).toFloat()); _leanScale = loadSetting(settings, "leanScale", 0.05f); - - _newScale = loadSetting(settings, "scale", 1.0f); + _targetScale = loadSetting(settings, "scale", 1.0f); setScale(_scale); Application::getInstance()->getCamera()->setScale(_scale); diff --git a/interface/src/avatar/Profile.cpp b/interface/src/avatar/Profile.cpp index 4a185f5788..316ca195c9 100644 --- a/interface/src/avatar/Profile.cpp +++ b/interface/src/avatar/Profile.cpp @@ -18,6 +18,7 @@ Profile::Profile(const QString &username) : _uuid(), _lastDomain(), _lastPosition(0.0, 0.0, 0.0), + _lastOrientationSend(0), _faceModelURL() { if (!_username.isEmpty()) { @@ -69,6 +70,10 @@ void Profile::updateDomain(const QString& domain) { } } +static QByteArray createByteArray(const glm::vec3& vector) { + return QByteArray::number(vector.x) + ',' + QByteArray::number(vector.y) + ',' + QByteArray::number(vector.z); +} + void Profile::updatePosition(const glm::vec3 position) { if (_lastPosition != position) { @@ -90,12 +95,29 @@ void Profile::updatePosition(const glm::vec3 position) { gettimeofday(&lastPositionSend, NULL); // send the changed position to the data-server - QString positionString = QString("%1,%2,%3").arg(position.x).arg(position.y).arg(position.z); - DataServerClient::putValueForKey(DataServerKey::Position, positionString.toLocal8Bit().constData()); + DataServerClient::putValueForKey(DataServerKey::Position, createByteArray(position).constData()); } } } +void Profile::updateOrientation(const glm::quat& orientation) { + glm::vec3 eulerAngles = safeEulerAngles(orientation); + if (_lastOrientation == eulerAngles) { + return; + } + const uint64_t DATA_SERVER_ORIENTATION_UPDATE_INTERVAL_USECS = 5 * 1000 * 1000; + const float DATA_SERVER_ORIENTATION_CHANGE_THRESHOLD_DEGREES = 5.0f; + + uint64_t now = usecTimestampNow(); + if (now - _lastOrientationSend >= DATA_SERVER_ORIENTATION_UPDATE_INTERVAL_USECS && + glm::distance(_lastOrientation, eulerAngles) >= DATA_SERVER_ORIENTATION_CHANGE_THRESHOLD_DEGREES) { + DataServerClient::putValueForKey(DataServerKey::Orientation, createByteArray(eulerAngles).constData()); + + _lastOrientation = eulerAngles; + _lastOrientationSend = now; + } +} + void Profile::saveData(QSettings* settings) { settings->beginGroup("Profile"); diff --git a/interface/src/avatar/Profile.h b/interface/src/avatar/Profile.h index eb3f531819..06f8de94a3 100644 --- a/interface/src/avatar/Profile.h +++ b/interface/src/avatar/Profile.h @@ -9,11 +9,14 @@ #ifndef __hifi__Profile__ #define __hifi__Profile__ +#include + #include #include #include #include +#include class Profile { public: @@ -34,6 +37,7 @@ public: void updateDomain(const QString& domain); void updatePosition(const glm::vec3 position); + void updateOrientation(const glm::quat& orientation); QString getLastDomain() const { return _lastDomain; } const glm::vec3& getLastPosition() const { return _lastPosition; } @@ -45,6 +49,8 @@ private: QUuid _uuid; QString _lastDomain; glm::vec3 _lastPosition; + glm::vec3 _lastOrientation; + uint64_t _lastOrientationSend; QUrl _faceModelURL; QUrl _skeletonModelURL; }; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 14115ced47..f663f26cbf 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -29,7 +29,7 @@ AvatarData::AvatarData(Node* owningNode) : _bodyYaw(-90.0), _bodyPitch(0.0), _bodyRoll(0.0), - _newScale(1.0f), + _targetScale(1.0f), _leaderUUID(), _handState(0), _keyState(NO_KEY_DOWN), @@ -76,7 +76,7 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyRoll); // Body scale - destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _newScale); + destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale); // Follow mode info memcpy(destinationBuffer, _leaderUUID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); @@ -198,7 +198,7 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyRoll); // Body scale - sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _newScale); + sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _targetScale); // Follow mode info _leaderUUID = QUuid::fromRfc4122(QByteArray((char*) sourceBuffer, NUM_BYTES_RFC4122_UUID)); @@ -296,12 +296,10 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { return sourceBuffer - startPosition; } -void AvatarData::setNewScale(float newScale) { - if (newScale > MAX_SCALE) { - newScale = MAX_SCALE; - } else if (newScale < MIN_SCALE) { - newScale = MIN_SCALE; - } - _newScale = newScale; - qDebug() << "Changed scale to " << _newScale << "\n"; +void AvatarData::setClampedTargetScale(float targetScale) { + + targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); + + _targetScale = targetScale; + qDebug() << "Changed scale to " << _targetScale << "\n"; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index c730041bcf..67e234c67e 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -45,8 +45,8 @@ const int HAND_STATE_START_BIT = 2; // 3rd and 4th bits const int IS_FACESHIFT_CONNECTED = 4; // 5th bit const int IS_CHAT_CIRCLING_ENABLED = 5; -static const float MAX_SCALE = 1000.f; -static const float MIN_SCALE = .005f; +static const float MAX_AVATAR_SCALE = 1000.f; +static const float MIN_AVATAR_SCALE = .005f; const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation @@ -95,8 +95,9 @@ public: void setBodyRoll(float bodyRoll) { _bodyRoll = bodyRoll; } // Scale - float getNewScale() const { return _newScale; } - void setNewScale(float); + float getTargetScale() const { return _targetScale; } + void setTargetScale(float targetScale) { _targetScale = targetScale; } + void setClampedTargetScale(float targetScale); // Hand State void setHandState(char s) { _handState = s; } @@ -145,7 +146,7 @@ protected: float _bodyRoll; // Body scale - float _newScale; + float _targetScale; // Following mode infos QUuid _leaderUUID;