mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 15:43:08 +02:00
Merge pull request #2822 from ey6es/master
Save attachment data for skeleton/attachment combinations so that they persist even when the attachment isn't present, and users can tweak script-attached models.
This commit is contained in:
commit
8c5a1c7bc8
6 changed files with 120 additions and 18 deletions
|
@ -516,6 +516,55 @@ void MyAvatar::loadData(QSettings* settings) {
|
||||||
settings->endGroup();
|
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) {
|
int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||||
qDebug() << "Error: ignoring update packet for MyAvatar"
|
qDebug() << "Error: ignoring update packet for MyAvatar"
|
||||||
<< " packetLength = " << packet.size()
|
<< " packetLength = " << packet.size()
|
||||||
|
@ -595,6 +644,23 @@ void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData)
|
||||||
_billboardValid = false;
|
_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) {
|
void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) {
|
||||||
if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
|
if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
|
||||||
return; // wait until both models are loaded
|
return; // wait until both models are loaded
|
||||||
|
|
|
@ -66,6 +66,9 @@ public:
|
||||||
void saveData(QSettings* settings);
|
void saveData(QSettings* settings);
|
||||||
void loadData(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
|
// Set what driving keys are being pressed to control thrust levels
|
||||||
void setDriveKeys(int key, float val) { _driveKeys[key] = val; };
|
void setDriveKeys(int key, float val) { _driveKeys[key] = val; };
|
||||||
bool getDriveKeys(int key) { return _driveKeys[key] != 0.f; };
|
bool getDriveKeys(int key) { return _driveKeys[key] != 0.f; };
|
||||||
|
@ -88,6 +91,10 @@ public:
|
||||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||||
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
|
virtual void setAttachmentData(const QVector<AttachmentData>& 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);
|
virtual void setCollisionGroups(quint32 collisionGroups);
|
||||||
|
|
||||||
void setMotionBehaviorsByScript(quint32 flags);
|
void setMotionBehaviorsByScript(quint32 flags);
|
||||||
|
|
|
@ -76,27 +76,28 @@ void AttachmentsDialog::addAttachment(const AttachmentData& data) {
|
||||||
_attachments->insertWidget(_attachments->count() - 1, new AttachmentPanel(this, 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();
|
QDoubleSpinBox* box = new QDoubleSpinBox();
|
||||||
box->setSingleStep(0.01);
|
box->setSingleStep(0.01);
|
||||||
box->setMinimum(-FLT_MAX);
|
box->setMinimum(-FLT_MAX);
|
||||||
box->setMaximum(FLT_MAX);
|
box->setMaximum(FLT_MAX);
|
||||||
box->setValue(value);
|
box->setValue(value);
|
||||||
dialog->connect(box, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData()));
|
panel->connect(box, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData()));
|
||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QDoubleSpinBox* createRotationBox(AttachmentsDialog* dialog, float value) {
|
static QDoubleSpinBox* createRotationBox(AttachmentPanel* panel, float value) {
|
||||||
QDoubleSpinBox* box = new QDoubleSpinBox();
|
QDoubleSpinBox* box = new QDoubleSpinBox();
|
||||||
box->setMinimum(-180.0);
|
box->setMinimum(-180.0);
|
||||||
box->setMaximum(180.0);
|
box->setMaximum(180.0);
|
||||||
box->setWrapping(true);
|
box->setWrapping(true);
|
||||||
box->setValue(value);
|
box->setValue(value);
|
||||||
dialog->connect(box, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData()));
|
panel->connect(box, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData()));
|
||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData& data) {
|
AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData& data) :
|
||||||
|
_dialog(dialog) {
|
||||||
setFrameStyle(QFrame::StyledPanel);
|
setFrameStyle(QFrame::StyledPanel);
|
||||||
|
|
||||||
QFormLayout* layout = new QFormLayout();
|
QFormLayout* layout = new QFormLayout();
|
||||||
|
@ -107,7 +108,7 @@ AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData
|
||||||
layout->addRow("Model URL:", urlBox);
|
layout->addRow("Model URL:", urlBox);
|
||||||
urlBox->addWidget(_modelURL = new QLineEdit(data.modelURL.toString()), 1);
|
urlBox->addWidget(_modelURL = new QLineEdit(data.modelURL.toString()), 1);
|
||||||
_modelURL->setText(data.modelURL.toString());
|
_modelURL->setText(data.modelURL.toString());
|
||||||
dialog->connect(_modelURL, SIGNAL(returnPressed()), SLOT(updateAttachmentData()));
|
connect(_modelURL, SIGNAL(returnPressed()), SLOT(modelURLChanged()));
|
||||||
QPushButton* chooseURL = new QPushButton("Choose");
|
QPushButton* chooseURL = new QPushButton("Choose");
|
||||||
urlBox->addWidget(chooseURL);
|
urlBox->addWidget(chooseURL);
|
||||||
connect(chooseURL, SIGNAL(clicked(bool)), SLOT(chooseModelURL()));
|
connect(chooseURL, SIGNAL(clicked(bool)), SLOT(chooseModelURL()));
|
||||||
|
@ -120,26 +121,26 @@ AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_jointName->setCurrentText(data.jointName);
|
_jointName->setCurrentText(data.jointName);
|
||||||
dialog->connect(_jointName, SIGNAL(currentIndexChanged(int)), SLOT(updateAttachmentData()));
|
connect(_jointName, SIGNAL(currentIndexChanged(int)), SLOT(updateAttachmentData()));
|
||||||
|
|
||||||
QHBoxLayout* translationBox = new QHBoxLayout();
|
QHBoxLayout* translationBox = new QHBoxLayout();
|
||||||
translationBox->addWidget(_translationX = createTranslationBox(dialog, data.translation.x));
|
translationBox->addWidget(_translationX = createTranslationBox(this, data.translation.x));
|
||||||
translationBox->addWidget(_translationY = createTranslationBox(dialog, data.translation.y));
|
translationBox->addWidget(_translationY = createTranslationBox(this, data.translation.y));
|
||||||
translationBox->addWidget(_translationZ = createTranslationBox(dialog, data.translation.z));
|
translationBox->addWidget(_translationZ = createTranslationBox(this, data.translation.z));
|
||||||
layout->addRow("Translation:", translationBox);
|
layout->addRow("Translation:", translationBox);
|
||||||
|
|
||||||
QHBoxLayout* rotationBox = new QHBoxLayout();
|
QHBoxLayout* rotationBox = new QHBoxLayout();
|
||||||
glm::vec3 eulers = glm::degrees(safeEulerAngles(data.rotation));
|
glm::vec3 eulers = glm::degrees(safeEulerAngles(data.rotation));
|
||||||
rotationBox->addWidget(_rotationX = createRotationBox(dialog, eulers.x));
|
rotationBox->addWidget(_rotationX = createRotationBox(this, eulers.x));
|
||||||
rotationBox->addWidget(_rotationY = createRotationBox(dialog, eulers.y));
|
rotationBox->addWidget(_rotationY = createRotationBox(this, eulers.y));
|
||||||
rotationBox->addWidget(_rotationZ = createRotationBox(dialog, eulers.z));
|
rotationBox->addWidget(_rotationZ = createRotationBox(this, eulers.z));
|
||||||
layout->addRow("Rotation:", rotationBox);
|
layout->addRow("Rotation:", rotationBox);
|
||||||
|
|
||||||
layout->addRow("Scale:", _scale = new QDoubleSpinBox());
|
layout->addRow("Scale:", _scale = new QDoubleSpinBox());
|
||||||
_scale->setSingleStep(0.01);
|
_scale->setSingleStep(0.01);
|
||||||
_scale->setMaximum(FLT_MAX);
|
_scale->setMaximum(FLT_MAX);
|
||||||
_scale->setValue(data.scale);
|
_scale->setValue(data.scale);
|
||||||
dialog->connect(_scale, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData()));
|
connect(_scale, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData()));
|
||||||
|
|
||||||
QPushButton* remove = new QPushButton("Delete");
|
QPushButton* remove = new QPushButton("Delete");
|
||||||
layout->addRow(remove);
|
layout->addRow(remove);
|
||||||
|
@ -165,5 +166,30 @@ void AttachmentPanel::chooseModelURL() {
|
||||||
|
|
||||||
void AttachmentPanel::setModelURL(const QString& url) {
|
void AttachmentPanel::setModelURL(const QString& url) {
|
||||||
_modelURL->setText(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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,9 +60,12 @@ private slots:
|
||||||
|
|
||||||
void chooseModelURL();
|
void chooseModelURL();
|
||||||
void setModelURL(const QString& url);
|
void setModelURL(const QString& url);
|
||||||
|
void modelURLChanged();
|
||||||
|
void updateAttachmentData();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
AttachmentsDialog* _dialog;
|
||||||
QLineEdit* _modelURL;
|
QLineEdit* _modelURL;
|
||||||
QComboBox* _jointName;
|
QComboBox* _jointName;
|
||||||
QDoubleSpinBox* _translationX;
|
QDoubleSpinBox* _translationX;
|
||||||
|
|
|
@ -686,11 +686,11 @@ void AvatarData::setAttachmentData(const QVector<AttachmentData>& attachmentData
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation,
|
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()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "attach", Q_ARG(const QString&, modelURL), Q_ARG(const QString&, jointName),
|
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(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;
|
return;
|
||||||
}
|
}
|
||||||
QVector<AttachmentData> attachmentData = getAttachmentData();
|
QVector<AttachmentData> attachmentData = getAttachmentData();
|
||||||
|
|
|
@ -242,7 +242,7 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE virtual void attach(const QString& modelURL, const QString& jointName = QString(),
|
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,
|
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 detachOne(const QString& modelURL, const QString& jointName = QString());
|
||||||
Q_INVOKABLE void detachAll(const QString& modelURL, const QString& jointName = QString());
|
Q_INVOKABLE void detachAll(const QString& modelURL, const QString& jointName = QString());
|
||||||
|
|
Loading…
Reference in a new issue