From c424f6ce69b41f9b65bc2a320cbf700562d798fd Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 8 May 2014 18:00:41 -0700 Subject: [PATCH] Save attachment data for attachment model/skeleton model combinations, let scripts use those saved parameters so that you can tweak the location of (for example) the gun and have it saved appropriately. --- interface/src/avatar/MyAvatar.cpp | 66 ++++++++++++++++++++++++++ interface/src/avatar/MyAvatar.h | 7 +++ interface/src/ui/AttachmentsDialog.cpp | 56 ++++++++++++++++------ interface/src/ui/AttachmentsDialog.h | 3 ++ libraries/avatars/src/AvatarData.cpp | 4 +- libraries/avatars/src/AvatarData.h | 2 +- 6 files changed, 120 insertions(+), 18 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7bc35ebd6d..c46135f069 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -513,6 +513,55 @@ void MyAvatar::loadData(QSettings* settings) { settings->endGroup(); } +void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { + QSettings* settings = Application::getInstance()->lockSettings(); + settings->beginGroup("savedAttachmentData"); + settings->beginGroup(_skeletonModel.getURL().toString()); + settings->beginGroup(attachment.modelURL.toString()); + + settings->setValue("jointName", attachment.jointName); + settings->setValue("translation_x", attachment.translation.x); + settings->setValue("translation_y", attachment.translation.y); + settings->setValue("translation_z", attachment.translation.z); + glm::vec3 eulers = safeEulerAngles(attachment.rotation); + settings->setValue("rotation_x", eulers.x); + settings->setValue("rotation_y", eulers.y); + settings->setValue("rotation_z", eulers.z); + settings->setValue("scale", attachment.scale); + + settings->endGroup(); + settings->endGroup(); + settings->endGroup(); + Application::getInstance()->unlockSettings(); +} + +AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL) const { + QSettings* settings = Application::getInstance()->lockSettings(); + settings->beginGroup("savedAttachmentData"); + settings->beginGroup(_skeletonModel.getURL().toString()); + settings->beginGroup(modelURL.toString()); + + AttachmentData attachment; + attachment.modelURL = modelURL; + attachment.jointName = settings->value("jointName").toString(); + attachment.translation.x = loadSetting(settings, "translation_x", 0.0f); + attachment.translation.y = loadSetting(settings, "translation_y", 0.0f); + attachment.translation.z = loadSetting(settings, "translation_z", 0.0f); + glm::vec3 eulers; + eulers.x = loadSetting(settings, "rotation_x", 0.0f); + eulers.y = loadSetting(settings, "rotation_y", 0.0f); + eulers.z = loadSetting(settings, "rotation_z", 0.0f); + attachment.rotation = glm::quat(eulers); + attachment.scale = loadSetting(settings, "scale", 1.0f); + + settings->endGroup(); + settings->endGroup(); + settings->endGroup(); + Application::getInstance()->unlockSettings(); + + return attachment; +} + int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) { qDebug() << "Error: ignoring update packet for MyAvatar" << " packetLength = " << packet.size() @@ -592,6 +641,23 @@ void MyAvatar::setAttachmentData(const QVector& attachmentData) _billboardValid = false; } +void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation, + const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) { + if (QThread::currentThread() != thread()) { + Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); + return; + } + if (useSaved) { + AttachmentData attachment = loadAttachmentData(modelURL); + if (!attachment.jointName.isEmpty()) { + Avatar::attach(modelURL, attachment.jointName, attachment.translation, + attachment.rotation, attachment.scale, allowDuplicates, useSaved); + return; + } + } + Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); +} + void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) { if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { return; // wait until both models are loaded diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 885d56b61f..b41c2b6d99 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -66,6 +66,9 @@ public: void saveData(QSettings* settings); void loadData(QSettings* settings); + void saveAttachmentData(const AttachmentData& attachment) const; + AttachmentData loadAttachmentData(const QUrl& modelURL) const; + // Set what driving keys are being pressed to control thrust levels void setDriveKeys(int key, float val) { _driveKeys[key] = val; }; bool getDriveKeys(int key) { return _driveKeys[key] != 0.f; }; @@ -88,6 +91,10 @@ public: virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setAttachmentData(const QVector& attachmentData); + virtual void attach(const QString& modelURL, const QString& jointName = QString(), + const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f, + bool allowDuplicates = false, bool useSaved = true); + virtual void setCollisionGroups(quint32 collisionGroups); void setMotionBehaviorsByScript(quint32 flags); diff --git a/interface/src/ui/AttachmentsDialog.cpp b/interface/src/ui/AttachmentsDialog.cpp index 016098699b..f9f49738e9 100644 --- a/interface/src/ui/AttachmentsDialog.cpp +++ b/interface/src/ui/AttachmentsDialog.cpp @@ -76,27 +76,28 @@ void AttachmentsDialog::addAttachment(const AttachmentData& data) { _attachments->insertWidget(_attachments->count() - 1, new AttachmentPanel(this, data)); } -static QDoubleSpinBox* createTranslationBox(AttachmentsDialog* dialog, float value) { +static QDoubleSpinBox* createTranslationBox(AttachmentPanel* panel, float value) { QDoubleSpinBox* box = new QDoubleSpinBox(); box->setSingleStep(0.01); box->setMinimum(-FLT_MAX); box->setMaximum(FLT_MAX); box->setValue(value); - dialog->connect(box, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData())); + panel->connect(box, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData())); return box; } -static QDoubleSpinBox* createRotationBox(AttachmentsDialog* dialog, float value) { +static QDoubleSpinBox* createRotationBox(AttachmentPanel* panel, float value) { QDoubleSpinBox* box = new QDoubleSpinBox(); box->setMinimum(-180.0); box->setMaximum(180.0); box->setWrapping(true); box->setValue(value); - dialog->connect(box, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData())); + panel->connect(box, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData())); return box; } -AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData& data) { +AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData& data) : + _dialog(dialog) { setFrameStyle(QFrame::StyledPanel); QFormLayout* layout = new QFormLayout(); @@ -107,7 +108,7 @@ AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData layout->addRow("Model URL:", urlBox); urlBox->addWidget(_modelURL = new QLineEdit(data.modelURL.toString()), 1); _modelURL->setText(data.modelURL.toString()); - dialog->connect(_modelURL, SIGNAL(returnPressed()), SLOT(updateAttachmentData())); + connect(_modelURL, SIGNAL(returnPressed()), SLOT(modelURLChanged())); QPushButton* chooseURL = new QPushButton("Choose"); urlBox->addWidget(chooseURL); connect(chooseURL, SIGNAL(clicked(bool)), SLOT(chooseModelURL())); @@ -120,26 +121,26 @@ AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData } } _jointName->setCurrentText(data.jointName); - dialog->connect(_jointName, SIGNAL(currentIndexChanged(int)), SLOT(updateAttachmentData())); + connect(_jointName, SIGNAL(currentIndexChanged(int)), SLOT(updateAttachmentData())); QHBoxLayout* translationBox = new QHBoxLayout(); - translationBox->addWidget(_translationX = createTranslationBox(dialog, data.translation.x)); - translationBox->addWidget(_translationY = createTranslationBox(dialog, data.translation.y)); - translationBox->addWidget(_translationZ = createTranslationBox(dialog, data.translation.z)); + translationBox->addWidget(_translationX = createTranslationBox(this, data.translation.x)); + translationBox->addWidget(_translationY = createTranslationBox(this, data.translation.y)); + translationBox->addWidget(_translationZ = createTranslationBox(this, data.translation.z)); layout->addRow("Translation:", translationBox); QHBoxLayout* rotationBox = new QHBoxLayout(); glm::vec3 eulers = glm::degrees(safeEulerAngles(data.rotation)); - rotationBox->addWidget(_rotationX = createRotationBox(dialog, eulers.x)); - rotationBox->addWidget(_rotationY = createRotationBox(dialog, eulers.y)); - rotationBox->addWidget(_rotationZ = createRotationBox(dialog, eulers.z)); + rotationBox->addWidget(_rotationX = createRotationBox(this, eulers.x)); + rotationBox->addWidget(_rotationY = createRotationBox(this, eulers.y)); + rotationBox->addWidget(_rotationZ = createRotationBox(this, eulers.z)); layout->addRow("Rotation:", rotationBox); layout->addRow("Scale:", _scale = new QDoubleSpinBox()); _scale->setSingleStep(0.01); _scale->setMaximum(FLT_MAX); _scale->setValue(data.scale); - dialog->connect(_scale, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData())); + connect(_scale, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData())); QPushButton* remove = new QPushButton("Delete"); layout->addRow(remove); @@ -165,5 +166,30 @@ void AttachmentPanel::chooseModelURL() { void AttachmentPanel::setModelURL(const QString& url) { _modelURL->setText(url); - emit _modelURL->returnPressed(); + modelURLChanged(); +} + +void AttachmentPanel::modelURLChanged() { + // check for saved attachment data + AttachmentData attachment = Application::getInstance()->getAvatar()->loadAttachmentData(_modelURL->text()); + if (!attachment.jointName.isEmpty()) { + _jointName->setCurrentText(attachment.jointName); + _translationX->setValue(attachment.translation.x); + _translationY->setValue(attachment.translation.y); + _translationZ->setValue(attachment.translation.z); + glm::vec3 eulers = glm::degrees(safeEulerAngles(attachment.rotation)); + _rotationX->setValue(eulers.x); + _rotationY->setValue(eulers.y); + _rotationZ->setValue(eulers.z); + _scale->setValue(attachment.scale); + } + _dialog->updateAttachmentData(); +} + +void AttachmentPanel::updateAttachmentData() { + // save the attachment data under the model URL (if any) + if (!_modelURL->text().isEmpty()) { + Application::getInstance()->getAvatar()->saveAttachmentData(getAttachmentData()); + } + _dialog->updateAttachmentData(); } diff --git a/interface/src/ui/AttachmentsDialog.h b/interface/src/ui/AttachmentsDialog.h index 4e67ae8882..7e9319fba8 100644 --- a/interface/src/ui/AttachmentsDialog.h +++ b/interface/src/ui/AttachmentsDialog.h @@ -60,9 +60,12 @@ private slots: void chooseModelURL(); void setModelURL(const QString& url); + void modelURLChanged(); + void updateAttachmentData(); private: + AttachmentsDialog* _dialog; QLineEdit* _modelURL; QComboBox* _jointName; QDoubleSpinBox* _translationX; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 26613e51d0..94066d9a1c 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -686,11 +686,11 @@ void AvatarData::setAttachmentData(const QVector& attachmentData } void AvatarData::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation, - const glm::quat& rotation, float scale, bool allowDuplicates) { + const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "attach", Q_ARG(const QString&, modelURL), Q_ARG(const QString&, jointName), Q_ARG(const glm::vec3&, translation), Q_ARG(const glm::quat&, rotation), - Q_ARG(float, scale), Q_ARG(bool, allowDuplicates)); + Q_ARG(float, scale), Q_ARG(bool, allowDuplicates), Q_ARG(bool, useSaved)); return; } QVector attachmentData = getAttachmentData(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index cc5ab16e35..dd604d06f5 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -242,7 +242,7 @@ public: Q_INVOKABLE virtual void attach(const QString& modelURL, const QString& jointName = QString(), const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f, - bool allowDuplicates = false); + bool allowDuplicates = false, bool useSaved = true); Q_INVOKABLE void detachOne(const QString& modelURL, const QString& jointName = QString()); Q_INVOKABLE void detachAll(const QString& modelURL, const QString& jointName = QString());