diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c2560a9a54..c2bab11065 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3689,17 +3689,7 @@ bool Application::askToSetAvatarUrl(const QString& url) { } // Download the FST file, to attempt to determine its model type - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest networkRequest = QNetworkRequest(url); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - QNetworkReply* reply = networkAccessManager.get(networkRequest); - qDebug() << "Downloading avatar file at " << url; - QEventLoop loop; - QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); - loop.exec(); - QByteArray fstContents = reply->readAll(); - delete reply; - QVariantHash fstMapping = FSTReader::readMapping(fstContents); + QVariantHash fstMapping = FSTReader::downloadMapping(url); FSTReader::ModelType modelType = FSTReader::predictModelType(fstMapping); @@ -3710,26 +3700,27 @@ bool Application::askToSetAvatarUrl(const QString& url) { QPushButton* bodyButton = NULL; QPushButton* bodyAndHeadButton = NULL; + QString modelName = fstMapping["name"].toString(); QString message; QString typeInfo; switch (modelType) { case FSTReader::HEAD_MODEL: - message = QString("Would you like to use '") + fstMapping["name"].toString() + QString("' for your avatar head?"); + message = QString("Would you like to use '") + modelName + QString("' for your avatar head?"); headButton = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole); break; case FSTReader::BODY_ONLY_MODEL: - message = QString("Would you like to use '") + fstMapping["name"].toString() + QString("' for your avatar body?"); + message = QString("Would you like to use '") + modelName + QString("' for your avatar body?"); bodyButton = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole); break; case FSTReader::HEAD_AND_BODY_MODEL: - message = QString("Would you like to use '") + fstMapping["name"].toString() + QString("' for your avatar?"); + message = QString("Would you like to use '") + modelName + QString("' for your avatar?"); bodyAndHeadButton = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole); break; default: - message = QString("Would you like to use '") + fstMapping["name"].toString() + QString("' for some part of your avatar head?"); + message = QString("Would you like to use '") + modelName + QString("' for some part of your avatar head?"); headButton = msgBox.addButton(tr("Use for Head"), QMessageBox::ActionRole); bodyButton = msgBox.addButton(tr("Use for Body"), QMessageBox::ActionRole); bodyAndHeadButton = msgBox.addButton(tr("Use for Body and Head"), QMessageBox::ActionRole); @@ -3743,16 +3734,16 @@ bool Application::askToSetAvatarUrl(const QString& url) { if (msgBox.clickedButton() == headButton) { qDebug() << "Chose to use for head: " << url; - _myAvatar->useHeadURL(url); - emit headURLChanged(url); + _myAvatar->useHeadURL(url, modelName); + emit headURLChanged(url, modelName); } else if (msgBox.clickedButton() == bodyButton) { qDebug() << "Chose to use for body: " << url; - _myAvatar->useBodyURL(url); - emit bodyURLChanged(url); + _myAvatar->useBodyURL(url, modelName); + emit bodyURLChanged(url, modelName); } else if (msgBox.clickedButton() == bodyAndHeadButton) { qDebug() << "Chose to use for body + head: " << url; - _myAvatar->useFullAvatarURL(url); - emit fullAvatarURLChanged(url); + _myAvatar->useFullAvatarURL(url, modelName); + emit fullAvatarURLChanged(url, modelName); } else { qDebug() << "Declined to use the avatar: " << url; } diff --git a/interface/src/Application.h b/interface/src/Application.h index 387de78e49..57a2f07216 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -335,9 +335,9 @@ signals: void checkBackgroundDownloads(); void domainConnectionRefused(const QString& reason); - void headURLChanged(const QString& newValue); - void bodyURLChanged(const QString& newValue); - void fullAvatarURLChanged(const QString& newValue); + void headURLChanged(const QString& newValue, const QString& modelName); + void bodyURLChanged(const QString& newValue, const QString& modelName); + void fullAvatarURLChanged(const QString& newValue, const QString& modelName); public slots: void domainChanged(const QString& domainHostname); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 418f978451..085b7bccab 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -610,7 +610,10 @@ void MyAvatar::saveData() { settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences); settings.setValue("faceModelURL", _headURLFromPreferences); settings.setValue("skeletonModelURL", _skeletonURLFromPreferences); - + settings.setValue("headModelName", _headModelName); + settings.setValue("bodyModelName", _bodyModelName); + settings.setValue("fullAvatarModelName", _fullAvatarModelName); + settings.beginWriteArray("attachmentData"); for (int i = 0; i < _attachmentData.size(); i++) { settings.setArrayIndex(i); @@ -675,20 +678,48 @@ void MyAvatar::loadData() { // The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls // for their avatar, So we need to attempt to detect this old case and set our new preferences accordingly. If // the head URL is empty, then we will assume they are using a full url... - _headURLFromPreferences = settings.value("faceModelURL", DEFAULT_HEAD_MODEL_URL).toUrl(); - - bool assumeFullAvatar = _headURLFromPreferences.isEmpty(); + bool isOldSettings = !(settings.contains("useFullAvatar") || settings.contains("fullAvatarURL")); - _useFullAvatar = settings.value("useFullAvatar", assumeFullAvatar).toBool(); + _useFullAvatar = settings.value("useFullAvatar").toBool(); + _headURLFromPreferences = settings.value("faceModelURL", DEFAULT_HEAD_MODEL_URL).toUrl(); _fullAvatarURLFromPreferences = settings.value("fullAvatarURL").toUrl(); _skeletonURLFromPreferences = settings.value("skeletonModelURL").toUrl(); - + _headModelName = settings.value("headModelName").toString(); + _bodyModelName = settings.value("bodyModelName").toString(); + _fullAvatarModelName = settings.value("fullAvatarModelName").toString();; + + if (isOldSettings) { + bool assumeFullAvatar = _headURLFromPreferences.isEmpty(); + _useFullAvatar = assumeFullAvatar; + + if (_useFullAvatar) { + _fullAvatarURLFromPreferences = settings.value("skeletonModelURL").toUrl(); + _headURLFromPreferences = DEFAULT_HEAD_MODEL_URL; + _skeletonURLFromPreferences = DEFAULT_BODY_MODEL_URL; + + QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString()); + + _headModelName = "Default"; + _bodyModelName = "Default"; + _fullAvatarModelName = fullAvatarFST["name"].toString(); + + } else { + _fullAvatarURLFromPreferences = DEFAULT_FULL_AVATAR_MODEL_URL; + _skeletonURLFromPreferences = settings.value("skeletonModelURL").toUrl(); + + QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); + QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); + + _headModelName = headFST["name"].toString(); + _bodyModelName = bodyFST["name"].toString(); + _fullAvatarModelName = "Default"; + } + } + if (_useFullAvatar) { - setFaceModelURL(QUrl()); - setSkeletonModelURL(_fullAvatarURLFromPreferences); + useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName); } else { - setFaceModelURL(_headURLFromPreferences); - setSkeletonModelURL(_skeletonURLFromPreferences); + useHeadAndBodyURLs(_headURLFromPreferences, _skeletonURLFromPreferences, _headModelName, _bodyModelName); } QVector attachmentData; @@ -922,9 +953,10 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { _billboardValid = false; } -void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL) { +void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) { _useFullAvatar = true; _fullAvatarURLFromPreferences = fullAvatarURL; + _fullAvatarModelName = modelName; if (!getFaceModelURLString().isEmpty()) { setFaceModelURL(QString()); @@ -937,18 +969,20 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL) { sendIdentityPacket(); } -void MyAvatar::useHeadURL(const QUrl& headURL) { - useHeadAndBodyURLs(headURL, _skeletonURLFromPreferences); +void MyAvatar::useHeadURL(const QUrl& headURL, const QString& modelName) { + useHeadAndBodyURLs(headURL, _skeletonURLFromPreferences, modelName, _bodyModelName); } -void MyAvatar::useBodyURL(const QUrl& bodyURL) { - useHeadAndBodyURLs(_headURLFromPreferences, bodyURL); +void MyAvatar::useBodyURL(const QUrl& bodyURL, const QString& modelName) { + useHeadAndBodyURLs(_headURLFromPreferences, bodyURL, _headModelName, modelName); } -void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL) { +void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, const QString& headName, const QString& bodyName) { _useFullAvatar = false; _headURLFromPreferences = headURL; _skeletonURLFromPreferences = bodyURL; + _headModelName = headName; + _bodyModelName = bodyName; if (headURL != getFaceModelURL()) { setFaceModelURL(headURL); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 57c8ca9e96..9c1f78c696 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -117,16 +117,20 @@ public: virtual void clearJointData(int index); virtual void clearJointsData(); - void useFullAvatarURL(const QUrl& fullAvatarURL); - void useHeadURL(const QUrl& headURL); - void useBodyURL(const QUrl& bodyURL); - void useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL); + void useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName = QString()); + void useHeadURL(const QUrl& headURL, const QString& modelName = QString()); + void useBodyURL(const QUrl& bodyURL, const QString& modelName = QString()); + void useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, const QString& headName = QString(), const QString& bodyName = QString()); bool getUseFullAvatar() const { return _useFullAvatar; } const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; } const QUrl& getHeadURLFromPreferences() const { return _headURLFromPreferences; } const QUrl& getBodyURLFromPreferences() const { return _skeletonURLFromPreferences; } + const QString& getHeadModelName() const { return _headModelName; } + const QString& getBodyModelName() const { return _bodyModelName; } + const QString& getFullAvartarModelName() const { return _fullAvatarModelName; } + virtual void setAttachmentData(const QVector& attachmentData); virtual glm::vec3 getSkeletonPosition() const; @@ -249,6 +253,10 @@ private: QUrl _fullAvatarURLFromPreferences; QUrl _headURLFromPreferences; QUrl _skeletonURLFromPreferences; + + QString _headModelName; + QString _bodyModelName; + QString _fullAvatarModelName; }; #endif // hifi_MyAvatar_h diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 4879bbfffc..9b6cd03dfa 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -61,11 +61,11 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : move(parentWidget()->geometry().topLeft()); setFixedHeight(parentWidget()->size().height() - PREFERENCES_HEIGHT_PADDING); - - ui.bodyNameLabel->setText("Body - name of model here"); - ui.headNameLabel->setText("Head - name of model here"); - ui.fullAvatarNameLabel->setText("Full Avatar - name of model here"); - + auto myAvatar = DependencyManager::get()->getMyAvatar(); + + ui.bodyNameLabel->setText("Body - " + myAvatar->getBodyModelName()); + ui.headNameLabel->setText("Head - " + myAvatar->getHeadModelName()); + ui.fullAvatarNameLabel->setText("Full Avatar - " + myAvatar->getFullAvartarModelName()); UIUtil::scaleWidgetFontSizes(this); } @@ -95,19 +95,22 @@ void PreferencesDialog::setUseFullAvatar(bool useFullAvatar) { ui.useSeparateBodyAndHead->setChecked(!_useFullAvatar); } -void PreferencesDialog::headURLChanged(const QString& newValue) { +void PreferencesDialog::headURLChanged(const QString& newValue, const QString& modelName) { ui.faceURLEdit->setText(newValue); setUseFullAvatar(false); + ui.headNameLabel->setText("Head - " + modelName); } -void PreferencesDialog::bodyURLChanged(const QString& newValue) { +void PreferencesDialog::bodyURLChanged(const QString& newValue, const QString& modelName) { ui.skeletonURLEdit->setText(newValue); setUseFullAvatar(false); + ui.bodyNameLabel->setText("Body - " + modelName); } -void PreferencesDialog::fullAvatarURLChanged(const QString& newValue) { +void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) { ui.fullAvatarURLEdit->setText(newValue); setUseFullAvatar(true); + ui.fullAvatarNameLabel->setText("Full Avatar - " + modelName); } void PreferencesDialog::accept() { diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h index 961ef6287d..3f097ca9ab 100644 --- a/interface/src/ui/PreferencesDialog.h +++ b/interface/src/ui/PreferencesDialog.h @@ -54,9 +54,9 @@ private slots: void setSkeletonUrl(QString modelUrl); void openSnapshotLocationBrowser(); void openScriptsLocationBrowser(); - void headURLChanged(const QString& newValue); - void bodyURLChanged(const QString& newValue); - void fullAvatarURLChanged(const QString& newValue); + void headURLChanged(const QString& newValue, const QString& modelName); + void bodyURLChanged(const QString& newValue, const QString& modelName); + void fullAvatarURLChanged(const QString& newValue, const QString& modelName); void useSeparateBodyAndHead(bool checked); void useFullAvatar(bool checked); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index ad90c88aaa..eb94557bd5 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -103,6 +103,8 @@ const int AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS = 5000; const QUrl DEFAULT_HEAD_MODEL_URL = QUrl("http://public.highfidelity.io/models/heads/defaultAvatar_head.fst"); const QUrl DEFAULT_BODY_MODEL_URL = QUrl("http://public.highfidelity.io/models/skeletons/defaultAvatar_body.fst"); +const QUrl DEFAULT_FULL_AVATAR_MODEL_URL = QUrl("http://public.highfidelity.io/marketplace/contents/029db3d4-da2c-4cb2-9c08-b9612ba576f5/02949063e7c4aed42ad9d1a58461f56d.fst"); + // Where one's own Avatar begins in the world (will be overwritten if avatar data file is found). // This is the start location in the Sandbox (xyz: 6270, 211, 6000). diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp index 6a5cc2bd53..d7f0ff4e70 100644 --- a/libraries/fbx/src/FSTReader.cpp +++ b/libraries/fbx/src/FSTReader.cpp @@ -10,6 +10,13 @@ // #include +#include +#include +#include + +#include +#include +#include #include "FSTReader.h" @@ -169,3 +176,17 @@ FSTReader::ModelType FSTReader::predictModelType(const QVariantHash& mapping) { return ENTITY_MODEL; } + +QVariantHash FSTReader::downloadMapping(const QString& url) { + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkRequest networkRequest = QNetworkRequest(url); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + QNetworkReply* reply = networkAccessManager.get(networkRequest); + qDebug() << "Downloading avatar file at " << url; + QEventLoop loop; + QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + QByteArray fstContents = reply->readAll(); + delete reply; + return FSTReader::readMapping(fstContents); +} \ No newline at end of file diff --git a/libraries/fbx/src/FSTReader.h b/libraries/fbx/src/FSTReader.h index 5752a224c6..981bae4feb 100644 --- a/libraries/fbx/src/FSTReader.h +++ b/libraries/fbx/src/FSTReader.h @@ -51,6 +51,7 @@ public: static QString getNameFromType(ModelType modelType); static FSTReader::ModelType getTypeFromName(const QString& name); + static QVariantHash downloadMapping(const QString& url); private: static void writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it);