diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 679b3eb76a..e633faf510 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4097,23 +4097,12 @@ bool Application::askToSetAvatarUrl(const QString& url) { QMessageBox msgBox; msgBox.setIcon(QMessageBox::Question); msgBox.setWindowTitle("Set Avatar"); - QPushButton* headButton = NULL; - 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 '") + 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 '") + 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 '") + modelName + QString("' for your avatar?"); @@ -4121,10 +4110,7 @@ bool Application::askToSetAvatarUrl(const QString& url) { break; default: - 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); + message = QString(modelName + QString("Does not support a head and body as required.")); break; } @@ -4133,14 +4119,7 @@ bool Application::askToSetAvatarUrl(const QString& url) { msgBox.exec(); - if (msgBox.clickedButton() == headButton) { - _myAvatar->useHeadURL(url, modelName); - emit headURLChanged(url, modelName); - } else if (msgBox.clickedButton() == bodyButton) { - _myAvatar->useBodyURL(url, modelName); - emit bodyURLChanged(url, modelName); - } else if (msgBox.clickedButton() == bodyAndHeadButton) { - _myAvatar->useFullAvatarURL(url, modelName); + if (msgBox.clickedButton() == bodyAndHeadButton) { emit fullAvatarURLChanged(url, modelName); } else { qCDebug(interfaceapp) << "Declined to use the avatar: " << url; @@ -4627,7 +4606,7 @@ void Application::checkSkeleton() { msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); - _myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL, "Default"); + _myAvatar->useFullAvatarURL(AvatarData::defaultFullAvatarModelUrl(), DEFAULT_FULL_AVATAR_MODEL_NAME); } else { _physicsEngine.setCharacterController(_myAvatar->getCharacterController()); } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 4d8e3d99dd..c1a1d11268 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -979,20 +978,12 @@ void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const { void Avatar::setFaceModelURL(const QUrl& faceModelURL) { AvatarData::setFaceModelURL(faceModelURL); - const QUrl DEFAULT_FACE_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_head.fst"); - getHead()->getFaceModel().setURL(_faceModelURL, DEFAULT_FACE_MODEL_URL, true, !isMyAvatar()); + getHead()->getFaceModel().setURL(_faceModelURL, AvatarData::defaultFullAvatarModelUrl(), true, !isMyAvatar()); } void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { AvatarData::setSkeletonModelURL(skeletonModelURL); - const QUrl DEFAULT_FULL_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full.fst"); - const QUrl DEFAULT_SKELETON_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_body.fst"); - if (isMyAvatar()) { - _skeletonModel.setURL(_skeletonModelURL, - getUseFullAvatar() ? DEFAULT_FULL_MODEL_URL : DEFAULT_SKELETON_MODEL_URL, true, !isMyAvatar()); - } else { - _skeletonModel.setURL(_skeletonModelURL, DEFAULT_SKELETON_MODEL_URL, true, !isMyAvatar()); - } + _skeletonModel.setURL(_skeletonModelURL, AvatarData::defaultFullAvatarModelUrl(), true, !isMyAvatar()); } void Avatar::setAttachmentData(const QVector& attachmentData) { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 44e26b617f..a7cece2b45 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -150,8 +150,6 @@ public: Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; } Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; } Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; } - - virtual bool getUseFullAvatar() const { return false; } /// Scales a world space position vector relative to the avatar position and scale /// \param vector position to be scaled. Will store the result diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index e31c804185..0e8e5a6a91 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -47,66 +47,10 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) { if (isActive()) { setOffset(-_geometry->getFBXGeometry().neckPivot); - - for (int i = 0; i < _rig->getJointStateCount(); i++) { - maybeUpdateNeckAndEyeRotation(i); - } - Model::simulateInternal(deltaTime); } } -void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const JointState& state, int index) { - // get the rotation axes in joint space and use them to adjust the rotation - glm::mat3 axes = glm::mat3_cast(glm::quat()); - glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * - glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) * - state.getPreTransform() * glm::mat4_cast(state.getPreRotation()))); - glm::vec3 pitchYawRoll = safeEulerAngles(_owningHead->getFinalOrientationInLocalFrame()); - glm::vec3 lean = glm::radians(glm::vec3(_owningHead->getFinalLeanForward(), - _owningHead->getTorsoTwist(), - _owningHead->getFinalLeanSideways())); - pitchYawRoll -= lean; - _rig->setJointRotationInConstrainedFrame(index, - glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2])) - * glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1])) - * glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0])) - * state.getDefaultRotation(), DEFAULT_PRIORITY); -} - -void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentState, const JointState& state, int index) { - // likewise with the eye joints - // NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual. - glm::mat4 inverse = glm::inverse(glm::mat4_cast(model->getRotation()) * parentState.getTransform() * - glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) * - state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getDefaultRotation())); - glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientationInWorldFrame() * IDENTITY_FRONT, 0.0f)); - glm::vec3 lookAtDelta = _owningHead->getCorrectedLookAtPosition() - model->getTranslation(); - glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * _owningHead->getSaccade(), 1.0f)); - glm::quat between = rotationBetween(front, lookAt); - const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; - _rig->setJointRotationInConstrainedFrame(index, glm::angleAxis(glm::clamp(glm::angle(between), - -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) * - state.getDefaultRotation(), DEFAULT_PRIORITY); -} - -void FaceModel::maybeUpdateNeckAndEyeRotation(int index) { - const JointState& state = _rig->getJointState(index); - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - const int parentIndex = state.getParentIndex(); - - // guard against out-of-bounds access to _jointStates - if (parentIndex != -1 && parentIndex >= 0 && parentIndex < _rig->getJointStateCount()) { - const JointState& parentState = _rig->getJointState(parentIndex); - if (index == geometry.neckJointIndex) { - maybeUpdateNeckRotation(parentState, state, index); - - } else if (index == geometry.leftEyeJointIndex || index == geometry.rightEyeJointIndex) { - maybeUpdateEyeRotation(this, parentState, state, index); - } - } -} - bool FaceModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { if (!isActive()) { return false; diff --git a/interface/src/avatar/FaceModel.h b/interface/src/avatar/FaceModel.h index ed1ea28508..5a19a8ea29 100644 --- a/interface/src/avatar/FaceModel.h +++ b/interface/src/avatar/FaceModel.h @@ -26,10 +26,6 @@ public: virtual void simulate(float deltaTime, bool fullUpdate = true); - void maybeUpdateNeckRotation(const JointState& parentState, const JointState& state, int index); - void maybeUpdateEyeRotation(Model* model, const JointState& parentState, const JointState& state, int index); - void maybeUpdateNeckAndEyeRotation(int index); - /// Retrieve the positions of up to two eye meshes. /// \return whether or not both eye meshes were found bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f51a077304..52473a6d47 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -652,12 +652,7 @@ void MyAvatar::saveData() { settings.setValue("leanScale", _leanScale); settings.setValue("scale", _targetScale); - settings.setValue("useFullAvatar", _useFullAvatar); 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"); @@ -727,61 +722,10 @@ void MyAvatar::loadData() { _targetScale = loadSetting(settings, "scale", 1.0f); setScale(_scale); - // 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... - bool isOldSettings = !(settings.contains("useFullAvatar") || settings.contains("fullAvatarURL")); - - _useFullAvatar = settings.value("useFullAvatar").toBool(); - _headURLFromPreferences = settings.value("faceModelURL", DEFAULT_HEAD_MODEL_URL).toUrl(); - _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", DEFAULT_FULL_AVATAR_MODEL_URL).toUrl(); - _skeletonURLFromPreferences = settings.value("skeletonModelURL", DEFAULT_BODY_MODEL_URL).toUrl(); - _headModelName = settings.value("headModelName", DEFAULT_HEAD_MODEL_NAME).toString(); - _bodyModelName = settings.value("bodyModelName", DEFAULT_BODY_MODEL_NAME).toString(); + _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()).toUrl(); _fullAvatarModelName = settings.value("fullAvatarModelName", DEFAULT_FULL_AVATAR_MODEL_NAME).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", DEFAULT_BODY_MODEL_URL).toUrl(); - - if (_skeletonURLFromPreferences == DEFAULT_BODY_MODEL_URL) { - _bodyModelName = DEFAULT_BODY_MODEL_NAME; - } else { - QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); - _bodyModelName = bodyFST["name"].toString(); - } - - if (_headURLFromPreferences == DEFAULT_HEAD_MODEL_URL) { - _headModelName = DEFAULT_HEAD_MODEL_NAME; - } else { - QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); - _headModelName = headFST["name"].toString(); - } - - _fullAvatarModelName = "Default"; - } - } - - if (_useFullAvatar) { - useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName); - } else { - useHeadAndBodyURLs(_headURLFromPreferences, _skeletonURLFromPreferences, _headModelName, _bodyModelName); - } + useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName); QVector attachmentData; int attachmentCount = settings.beginReadArray("attachmentData"); @@ -1012,29 +956,6 @@ void MyAvatar::clearJointAnimationPriorities() { } } -QString MyAvatar::getModelDescription() const { - QString result; - if (_useFullAvatar) { - if (!getFullAvartarModelName().isEmpty()) { - result = "Full Avatar \"" + getFullAvartarModelName() + "\""; - } else { - result = "Full Avatar \"" + _fullAvatarURLFromPreferences.fileName() + "\""; - } - } else { - if (!getHeadModelName().isEmpty()) { - result = "Head \"" + getHeadModelName() + "\""; - } else { - result = "Head \"" + _headURLFromPreferences.fileName() + "\""; - } - if (!getBodyModelName().isEmpty()) { - result += " and Body \"" + getBodyModelName() + "\""; - } else { - result += " and Body \"" + _skeletonURLFromPreferences.fileName() + "\""; - } - } - return result; -} - void MyAvatar::setFaceModelURL(const QUrl& faceModelURL) { Avatar::setFaceModelURL(faceModelURL); @@ -1061,8 +982,6 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN return; } - _useFullAvatar = true; - if (_fullAvatarURLFromPreferences != fullAvatarURL) { _fullAvatarURLFromPreferences = fullAvatarURL; if (modelName.isEmpty()) { @@ -1077,66 +996,14 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN setFaceModelURL(QString()); } - if (fullAvatarURL != getSkeletonModelURL()) { + const QString& urlString = fullAvatarURL.toString(); + if (urlString.isEmpty() || (fullAvatarURL != getSkeletonModelURL())) { setSkeletonModelURL(fullAvatarURL); - UserActivityLogger::getInstance().changedModel("skeleton", fullAvatarURL.toString()); + UserActivityLogger::getInstance().changedModel("skeleton", urlString); } sendIdentityPacket(); } -void MyAvatar::useHeadURL(const QUrl& headURL, const QString& modelName) { - useHeadAndBodyURLs(headURL, _skeletonURLFromPreferences, modelName, _bodyModelName); -} - -void MyAvatar::useBodyURL(const QUrl& bodyURL, const QString& modelName) { - useHeadAndBodyURLs(_headURLFromPreferences, bodyURL, _headModelName, modelName); -} - -void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, const QString& headName, const QString& bodyName) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "useFullAvatarURL", Qt::BlockingQueuedConnection, - Q_ARG(const QUrl&, headURL), - Q_ARG(const QUrl&, bodyURL), - Q_ARG(const QString&, headName), - Q_ARG(const QString&, bodyName)); - return; - } - - _useFullAvatar = false; - - if (_headURLFromPreferences != headURL) { - _headURLFromPreferences = headURL; - if (headName.isEmpty()) { - QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); - _headModelName = headFST["name"].toString(); - } else { - _headModelName = headName; - } - } - - if (_skeletonURLFromPreferences != bodyURL) { - _skeletonURLFromPreferences = bodyURL; - if (bodyName.isEmpty()) { - QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); - _bodyModelName = bodyFST["name"].toString(); - } else { - _bodyModelName = bodyName; - } - } - - if (headURL != getFaceModelURL()) { - setFaceModelURL(headURL); - UserActivityLogger::getInstance().changedModel("head", headURL.toString()); - } - - if (bodyURL != getSkeletonModelURL()) { - setSkeletonModelURL(bodyURL); - UserActivityLogger::getInstance().changedModel("skeleton", bodyURL.toString()); - } - sendIdentityPacket(); -} - - void MyAvatar::setAttachmentData(const QVector& attachmentData) { Avatar::setAttachmentData(attachmentData); if (QThread::currentThread() != thread()) { @@ -1310,11 +1177,7 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { } if (shouldDrawHead != _prevShouldDrawHead) { - if (_useFullAvatar) { - _skeletonModel.setCauterizeBones(!shouldDrawHead); - } else { - getHead()->getFaceModel().setVisibleInScene(shouldDrawHead, scene); - } + _skeletonModel.setCauterizeBones(!shouldDrawHead); } _prevShouldDrawHead = shouldDrawHead; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 88649429f5..8ff9211101 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -126,21 +126,8 @@ public: virtual void clearJointsData(); Q_INVOKABLE void useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName = QString()); - Q_INVOKABLE void useHeadURL(const QUrl& headURL, const QString& modelName = QString()); - Q_INVOKABLE void useBodyURL(const QUrl& bodyURL, const QString& modelName = QString()); - Q_INVOKABLE void useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, - const QString& headName = QString(), const QString& bodyName = QString()); - - Q_INVOKABLE virtual bool getUseFullAvatar() const { return _useFullAvatar; } Q_INVOKABLE const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; } - Q_INVOKABLE const QUrl& getHeadURLFromPreferences() const { return _headURLFromPreferences; } - Q_INVOKABLE const QUrl& getBodyURLFromPreferences() const { return _skeletonURLFromPreferences; } - - Q_INVOKABLE const QString& getHeadModelName() const { return _headModelName; } - Q_INVOKABLE const QString& getBodyModelName() const { return _bodyModelName; } - Q_INVOKABLE const QString& getFullAvartarModelName() const { return _fullAvatarModelName; } - - Q_INVOKABLE QString getModelDescription() const; + Q_INVOKABLE const QString& getFullAvatarModelName() const { return _fullAvatarModelName; } virtual void setAttachmentData(const QVector& attachmentData); @@ -298,18 +285,9 @@ private: void initHeadBones(); // Avatar Preferences - bool _useFullAvatar = false; QUrl _fullAvatarURLFromPreferences; - QUrl _headURLFromPreferences; - QUrl _skeletonURLFromPreferences; - - QString _headModelName; - QString _bodyModelName; QString _fullAvatarModelName; - RigPointer _rig; - bool _prevShouldDrawHead; - // cache of the current HMD sensor position and orientation // in sensor space. glm::mat4 _hmdSensorMatrix; @@ -330,6 +308,8 @@ private: glm::quat _goToOrientation; std::unordered_set _headBoneSet; + RigPointer _rig; + bool _prevShouldDrawHead; }; #endif // hifi_MyAvatar_h diff --git a/interface/src/ui/AvatarAppearanceDialog.cpp b/interface/src/ui/AvatarAppearanceDialog.cpp deleted file mode 100644 index 54e48dca26..0000000000 --- a/interface/src/ui/AvatarAppearanceDialog.cpp +++ /dev/null @@ -1,215 +0,0 @@ -// -// AvatarAppearanceDialog.cpp -// interface/src/ui -// -// Created by Stojce Slavkovski on 2/20/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include - -#include -#include -#include -#include - -#include "Application.h" -#include "MainWindow.h" -#include "LODManager.h" -#include "Menu.h" -#include "AvatarAppearanceDialog.h" -#include "Snapshot.h" -#include "UserActivityLogger.h" -#include "UIUtil.h" -#include "ui/DialogsManager.h" -#include "ui/PreferencesDialog.h" - -AvatarAppearanceDialog::AvatarAppearanceDialog(QWidget* parent) : - QDialog(parent) { - - setAttribute(Qt::WA_DeleteOnClose); - - ui.setupUi(this); - - loadAvatarAppearance(); - - connect(ui.defaultButton, &QPushButton::clicked, this, &AvatarAppearanceDialog::accept); - - connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &AvatarAppearanceDialog::openHeadModelBrowser); - connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &AvatarAppearanceDialog::openBodyModelBrowser); - connect(ui.buttonBrowseFullAvatar, &QPushButton::clicked, this, &AvatarAppearanceDialog::openFullAvatarModelBrowser); - - connect(ui.useSeparateBodyAndHead, &QRadioButton::clicked, this, &AvatarAppearanceDialog::useSeparateBodyAndHead); - connect(ui.useFullAvatar, &QRadioButton::clicked, this, &AvatarAppearanceDialog::useFullAvatar); - - connect(Application::getInstance(), &Application::headURLChanged, this, &AvatarAppearanceDialog::headURLChanged); - connect(Application::getInstance(), &Application::bodyURLChanged, this, &AvatarAppearanceDialog::bodyURLChanged); - connect(Application::getInstance(), &Application::fullAvatarURLChanged, this, &AvatarAppearanceDialog::fullAvatarURLChanged); - - 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); -} - -void AvatarAppearanceDialog::useSeparateBodyAndHead(bool checked) { - QUrl headURL(ui.faceURLEdit->text()); - QUrl bodyURL(ui.skeletonURLEdit->text()); - DependencyManager::get()->getMyAvatar()->useHeadAndBodyURLs(headURL, bodyURL); - setUseFullAvatar(!checked); -} - -void AvatarAppearanceDialog::useFullAvatar(bool checked) { - QUrl fullAvatarURL(ui.fullAvatarURLEdit->text()); - DependencyManager::get()->getMyAvatar()->useFullAvatarURL(fullAvatarURL); - setUseFullAvatar(checked); -} - -void AvatarAppearanceDialog::setUseFullAvatar(bool useFullAvatar) { - _useFullAvatar = useFullAvatar; - ui.faceURLEdit->setEnabled(!_useFullAvatar); - ui.skeletonURLEdit->setEnabled(!_useFullAvatar); - ui.fullAvatarURLEdit->setEnabled(_useFullAvatar); - - ui.useFullAvatar->setChecked(_useFullAvatar); - ui.useSeparateBodyAndHead->setChecked(!_useFullAvatar); - - QPointer prefs = DependencyManager::get()->getPreferencesDialog(); - if (prefs) { // Preferences dialog may have been closed - prefs->avatarDescriptionChanged(); - } -} - -void AvatarAppearanceDialog::headURLChanged(const QString& newValue, const QString& modelName) { - ui.faceURLEdit->setText(newValue); - setUseFullAvatar(false); - ui.headNameLabel->setText("Head - " + modelName); -} - -void AvatarAppearanceDialog::bodyURLChanged(const QString& newValue, const QString& modelName) { - ui.skeletonURLEdit->setText(newValue); - setUseFullAvatar(false); - ui.bodyNameLabel->setText("Body - " + modelName); -} - -void AvatarAppearanceDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) { - ui.fullAvatarURLEdit->setText(newValue); - setUseFullAvatar(true); - ui.fullAvatarNameLabel->setText("Full Avatar - " + modelName); -} - -void AvatarAppearanceDialog::accept() { - saveAvatarAppearance(); - - QPointer prefs = DependencyManager::get()->getPreferencesDialog(); - if (prefs) { // Preferences dialog may have been closed - prefs->avatarDescriptionChanged(); - } - - close(); - delete _marketplaceWindow; - _marketplaceWindow = NULL; -} - -void AvatarAppearanceDialog::setHeadUrl(QString modelUrl) { - ui.faceURLEdit->setText(modelUrl); -} - -void AvatarAppearanceDialog::setSkeletonUrl(QString modelUrl) { - ui.skeletonURLEdit->setText(modelUrl); -} - -void AvatarAppearanceDialog::openFullAvatarModelBrowser() { - auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars"; - auto WIDTH = 900; - auto HEIGHT = 700; - if (!_marketplaceWindow) { - _marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false); - } - _marketplaceWindow->setVisible(true); -} - -void AvatarAppearanceDialog::openHeadModelBrowser() { - auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars"; - auto WIDTH = 900; - auto HEIGHT = 700; - if (!_marketplaceWindow) { - _marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false); - } - _marketplaceWindow->setVisible(true); -} - -void AvatarAppearanceDialog::openBodyModelBrowser() { - auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars"; - auto WIDTH = 900; - auto HEIGHT = 700; - if (!_marketplaceWindow) { - _marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false); - } - _marketplaceWindow->setVisible(true); -} - -void AvatarAppearanceDialog::resizeEvent(QResizeEvent *resizeEvent) { - - // keep buttons panel at the bottom - ui.buttonsPanel->setGeometry(0, - size().height() - ui.buttonsPanel->height(), - size().width(), - ui.buttonsPanel->height()); - - // set width and height of srcollarea to match bottom panel and width - ui.scrollArea->setGeometry(ui.scrollArea->geometry().x(), ui.scrollArea->geometry().y(), - size().width(), - size().height() - ui.buttonsPanel->height() - ui.scrollArea->geometry().y()); - -} - -void AvatarAppearanceDialog::loadAvatarAppearance() { - - MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - - _useFullAvatar = myAvatar->getUseFullAvatar(); - _fullAvatarURLString = myAvatar->getFullAvatarURLFromPreferences().toString(); - _headURLString = myAvatar->getHeadURLFromPreferences().toString(); - _bodyURLString = myAvatar->getBodyURLFromPreferences().toString(); - - ui.fullAvatarURLEdit->setText(_fullAvatarURLString); - ui.faceURLEdit->setText(_headURLString); - ui.skeletonURLEdit->setText(_bodyURLString); - setUseFullAvatar(_useFullAvatar); -} - -void AvatarAppearanceDialog::saveAvatarAppearance() { - - MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - - QUrl headURL(ui.faceURLEdit->text()); - QString headURLString = headURL.toString(); - - QUrl bodyURL(ui.skeletonURLEdit->text()); - QString bodyURLString = bodyURL.toString(); - - QUrl fullAvatarURL(ui.fullAvatarURLEdit->text()); - QString fullAvatarURLString = fullAvatarURL.toString(); - - bool somethingChanged = - _useFullAvatar != myAvatar->getUseFullAvatar() || - fullAvatarURLString != myAvatar->getFullAvatarURLFromPreferences().toString() || - headURLString != myAvatar->getHeadURLFromPreferences().toString() || - bodyURLString != myAvatar->getBodyURLFromPreferences().toString(); - - if (somethingChanged) { - if (_useFullAvatar) { - myAvatar->useFullAvatarURL(fullAvatarURL); - } else { - myAvatar->useHeadAndBodyURLs(headURL, bodyURL); - } - } -} diff --git a/interface/src/ui/AvatarAppearanceDialog.h b/interface/src/ui/AvatarAppearanceDialog.h deleted file mode 100644 index be30caeedb..0000000000 --- a/interface/src/ui/AvatarAppearanceDialog.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// AvatarAppearanceDialog.h -// interface/src/ui -// -// Created by Stojce Slavkovski on 2/20/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_AvatarAppearanceDialog_h -#define hifi_AvatarAppearanceDialog_h - -#include "ui_avatarAppearance.h" - -#include -#include - -#include "scripting/WebWindowClass.h" - -class AvatarAppearanceDialog : public QDialog { - Q_OBJECT - -public: - AvatarAppearanceDialog(QWidget* parent = nullptr); - -protected: - void resizeEvent(QResizeEvent* resizeEvent); - -private: - void loadAvatarAppearance(); - void saveAvatarAppearance(); - void openHeadModelBrowser(); - void openBodyModelBrowser(); - void openFullAvatarModelBrowser(); - void setUseFullAvatar(bool useFullAvatar); - - Ui_AvatarAppearanceDialog ui; - - bool _useFullAvatar; - QString _headURLString; - QString _bodyURLString; - QString _fullAvatarURLString; - - - QString _displayNameString; - - WebWindowClass* _marketplaceWindow = NULL; - -private slots: - void accept(); - void setHeadUrl(QString modelUrl); - void setSkeletonUrl(QString modelUrl); - 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); - - -}; - -#endif // hifi_AvatarAppearanceDialog_h diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 8131aa49f2..58d2550752 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -20,7 +20,6 @@ #include "AddressBarDialog.h" #include "AnimationsDialog.h" #include "AttachmentsDialog.h" -#include "AvatarAppearanceDialog.h" #include "BandwidthDialog.h" #include "CachesSizeDialog.h" #include "DiskCacheEditor.h" @@ -88,15 +87,6 @@ void DialogsManager::editPreferences() { } } -void DialogsManager::changeAvatarAppearance() { - if (!_avatarAppearanceDialog) { - maybeCreateDialog(_avatarAppearanceDialog); - _avatarAppearanceDialog->show(); - } else { - _avatarAppearanceDialog->close(); - } -} - void DialogsManager::editAttachments() { if (!_attachmentsDialog) { maybeCreateDialog(_attachmentsDialog); diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h index 09e0274d86..2db700e72a 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -34,7 +34,6 @@ class OctreeStatsDialog; class PreferencesDialog; class ScriptEditorWindow; class QMessageBox; -class AvatarAppearanceDialog; class DomainConnectionDialog; class UpdateDialog; @@ -66,7 +65,6 @@ public slots: void hmdTools(bool showTools); void showScriptEditor(); void showIRCLink(); - void changeAvatarAppearance(); void showDomainConnectionDialog(); // Application Update @@ -110,7 +108,6 @@ private: QPointer _octreeStatsDialog; QPointer _preferencesDialog; QPointer _scriptEditor; - QPointer _avatarAppearanceDialog; QPointer _domainConnectionDialog; QPointer _updateDialog; }; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 8e9c164563..a6340d3955 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -47,45 +47,45 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : connect(ui.buttonBrowseScriptsLocation, &QPushButton::clicked, this, &PreferencesDialog::openScriptsLocationBrowser); connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, Application::getInstance(), &Application::loadDefaultScripts); - DialogsManager* dialogsManager = DependencyManager::get().data(); - connect(ui.buttonChangeApperance, &QPushButton::clicked, dialogsManager, &DialogsManager::changeAvatarAppearance); - - connect(Application::getInstance(), &Application::headURLChanged, this, &PreferencesDialog::headURLChanged); - connect(Application::getInstance(), &Application::bodyURLChanged, this, &PreferencesDialog::bodyURLChanged); + connect(ui.buttonChangeAppearance, &QPushButton::clicked, this, &PreferencesDialog::openFullAvatarModelBrowser); + connect(ui.appearanceDescription, &QLineEdit::textChanged, this, [this](const QString& url) { + this->fullAvatarURLChanged(url, ""); + }); connect(Application::getInstance(), &Application::fullAvatarURLChanged, this, &PreferencesDialog::fullAvatarURLChanged); // move dialog to left side move(parentWidget()->geometry().topLeft()); setFixedHeight(parentWidget()->size().height() - PREFERENCES_HEIGHT_PADDING); - ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); - UIUtil::scaleWidgetFontSizes(this); } -void PreferencesDialog::avatarDescriptionChanged() { - ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); -} - -void PreferencesDialog::headURLChanged(const QString& newValue, const QString& modelName) { - ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); -} - -void PreferencesDialog::bodyURLChanged(const QString& newValue, const QString& modelName) { - ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); -} - void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) { - ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); + ui.appearanceDescription->setText(newValue); + const QString APPEARANCE_LABEL_TEXT("Appearance: "); + ui.appearanceLabel->setText(APPEARANCE_LABEL_TEXT + modelName); + DependencyManager::get()->getMyAvatar()->useFullAvatarURL(newValue, modelName); } void PreferencesDialog::accept() { + MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); + _lastGoodAvatarURL = myAvatar->getFullAvatarURLFromPreferences(); + _lastGoodAvatarName = myAvatar->getFullAvatarModelName(); savePreferences(); close(); delete _marketplaceWindow; _marketplaceWindow = NULL; } +void PreferencesDialog::restoreLastGoodAvatar() { + fullAvatarURLChanged(_lastGoodAvatarURL.toString(), _lastGoodAvatarName); +} + +void PreferencesDialog::reject() { + restoreLastGoodAvatar(); + QDialog::reject(); +} + void PreferencesDialog::openSnapshotLocationBrowser() { QString dir = QFileDialog::getExistingDirectory(this, tr("Snapshots Location"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), @@ -103,6 +103,16 @@ void PreferencesDialog::openScriptsLocationBrowser() { ui.scriptsLocationEdit->setText(dir); } } +void PreferencesDialog::openFullAvatarModelBrowser() { + const auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars"; + const auto WIDTH = 900; + const auto HEIGHT = 700; + if (!_marketplaceWindow) { + _marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false); + } + _marketplaceWindow->setVisible(true); + +} void PreferencesDialog::resizeEvent(QResizeEvent *resizeEvent) { @@ -129,6 +139,10 @@ void PreferencesDialog::loadPreferences() { ui.collisionSoundURLEdit->setText(myAvatar->getCollisionSoundURL()); + _lastGoodAvatarURL = myAvatar->getFullAvatarURLFromPreferences(); + _lastGoodAvatarName = myAvatar->getFullAvatarModelName(); + fullAvatarURLChanged(_lastGoodAvatarURL.toString(), _lastGoodAvatarName); + ui.sendDataCheckBox->setChecked(!menuInstance->isOptionChecked(MenuOption::DisableActivityLogger)); ui.snapshotLocationEdit->setText(Snapshot::snapshotsLocation.get()); @@ -211,6 +225,11 @@ void PreferencesDialog::savePreferences() { myAvatar->setCollisionSoundURL(ui.collisionSoundURLEdit->text()); + // MyAvatar persists its own data. If it doesn't agree with what the user has explicitly accepted, set it back to old values. + if (_lastGoodAvatarURL != myAvatar->getFullAvatarURLFromPreferences()) { + restoreLastGoodAvatar(); + } + if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger) != ui.sendDataCheckBox->isChecked()) { Menu::getInstance()->triggerOption(MenuOption::DisableActivityLogger); diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h index 8e699c80a2..6d7a87b97c 100644 --- a/interface/src/ui/PreferencesDialog.h +++ b/interface/src/ui/PreferencesDialog.h @@ -33,6 +33,9 @@ protected: private: void loadPreferences(); void savePreferences(); + QUrl _lastGoodAvatarURL; + QString _lastGoodAvatarName; + void restoreLastGoodAvatar(); Ui_PreferencesDialog ui; @@ -42,10 +45,10 @@ private: private slots: void accept(); + void reject(); + void openFullAvatarModelBrowser(); void openSnapshotLocationBrowser(); void openScriptsLocationBrowser(); - void headURLChanged(const QString& newValue, const QString& modelName); - void bodyURLChanged(const QString& newValue, const QString& modelName); void fullAvatarURLChanged(const QString& newValue, const QString& modelName); }; diff --git a/interface/ui/avatarAppearance.ui b/interface/ui/avatarAppearance.ui deleted file mode 100644 index 5ebf2c705b..0000000000 --- a/interface/ui/avatarAppearance.ui +++ /dev/null @@ -1,471 +0,0 @@ - - - AvatarAppearanceDialog - - - - 0 - 0 - 500 - 350 - - - - - 0 - 0 - - - - - 500 - 350 - - - - - 500 - 16777215 - - - - - 13 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - QFrame::NoFrame - - - QFrame::Plain - - - 0 - - - true - - - - - 0 - -107 - 485 - 1550 - - - - - 0 - - - 30 - - - 0 - - - 30 - - - 10 - - - - - - - 0 - - - 7 - - - 7 - - - - - - - - - Arial - - - - Use single avatar with Body and Head - - - - - - - - - - 0 - - - 10 - - - 0 - - - 0 - - - - - - - - Arial - - - - Full Avatar - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - fullAvatarURLEdit - - - - - - - - - - - - 0 - 0 - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 0 - - - - - - - - - - Arial - - - - Browse - - - - 0 - 0 - - - - - - - - - - - - - - - - - - - - - - - - Arial - - - - Use separate Body and Head avatar files - - - - - - - - - 0 - - - 10 - - - 7 - - - 7 - - - - - - - - - Arial - - - - Head - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - - - - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - - - - - Arial - - - - Browse - - - - 0 - 0 - - - - - - - - - - - - - - - 0 - - - 10 - - - 7 - - - 7 - - - - - - - Arial - - - - Body - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - skeletonURLEdit - - - - - - - - 0 - - - - - - 0 - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - - - - - Arial - - - - Browse - - - - 0 - 0 - - - - - - - - - - - - - - - - - - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - Arial - - - - Close - - - true - - - false - - - - - - - - - - - - diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index df6d28c07b..b91367dcf1 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -275,7 +275,7 @@ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - apperanceDescription + appearanceDescription @@ -283,26 +283,21 @@ - + 0 - + Arial - - - false - - - + Qt::Horizontal @@ -318,7 +313,7 @@ - + Arial diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 02a4a4408a..9ef1f94c55 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -70,6 +70,16 @@ AvatarData::~AvatarData() { delete _referential; } +// We cannot have a file-level variable (const or otherwise) in the header if it uses PathUtils, because that references Application, which will not yet initialized. +// Thus we have a static class getter, referencing a static class var. +QUrl AvatarData::_defaultFullAvatarModelUrl = {}; // In C++, if this initialization were in the header, every file would have it's own copy, even for class vars. +const QUrl AvatarData::defaultFullAvatarModelUrl() { + if (_defaultFullAvatarModelUrl.isEmpty()) { + _defaultFullAvatarModelUrl = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full.fst"); + } + return _defaultFullAvatarModelUrl; +} + const glm::vec3& AvatarData::getPosition() const { if (_referential) { _referential->update(); @@ -899,7 +909,7 @@ void AvatarData::setFaceModelURL(const QUrl& faceModelURL) { } void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { - _skeletonModelURL = skeletonModelURL.isEmpty() ? DEFAULT_BODY_MODEL_URL : skeletonModelURL; + _skeletonModelURL = skeletonModelURL.isEmpty() ? AvatarData::defaultFullAvatarModelUrl() : skeletonModelURL; qCDebug(avatars) << "Changing skeleton model for avatar to" << _skeletonModelURL.toString(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index dbc7b9b9ec..8bb874bc71 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -54,6 +54,7 @@ typedef unsigned long long quint64; #include "AABox.h" #include "HandData.h" #include "HeadData.h" +#include "PathUtils.h" #include "Player.h" #include "Recorder.h" #include "Referential.h" @@ -107,12 +108,7 @@ const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000; 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"); - -const QString DEFAULT_HEAD_MODEL_NAME = QString("Robot"); -const QString DEFAULT_BODY_MODEL_NAME = QString("Robot"); +// See also static AvatarData::defaultFullAvatarModelUrl(). const QString DEFAULT_FULL_AVATAR_MODEL_NAME = QString("Default"); @@ -163,6 +159,8 @@ public: AvatarData(); virtual ~AvatarData(); + static const QUrl defaultFullAvatarModelUrl(); + virtual bool isMyAvatar() const { return false; } const QUuid& getSessionUUID() const { return _sessionUUID; } @@ -401,6 +399,7 @@ protected: SimpleMovingAverage _averageBytesReceived; private: + static QUrl _defaultFullAvatarModelUrl; // privatize the copy constructor and assignment operator so they cannot be called AvatarData(const AvatarData&); AvatarData& operator= (const AvatarData&);